Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs. Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
"use client";
|
||
|
||
import {
|
||
exchangeCode,
|
||
consumePostLoginRedirect,
|
||
fetchAuthConfig,
|
||
fetchMe,
|
||
redeemHandoff,
|
||
storeTokens,
|
||
} from "@/lib/auth";
|
||
import { useRouter, useSearchParams } from "next/navigation";
|
||
import { Suspense, useEffect, useRef, useState } from "react";
|
||
|
||
function CallbackInner() {
|
||
const params = useSearchParams();
|
||
const router = useRouter();
|
||
const [error, setError] = useState<string | null>(null);
|
||
const exchangeStarted = useRef(false);
|
||
|
||
useEffect(() => {
|
||
if (exchangeStarted.current) return;
|
||
|
||
const handoff = params.get("handoff");
|
||
const code = params.get("code");
|
||
|
||
if (!handoff && !code) {
|
||
setError("کد احراز هویت دریافت نشد");
|
||
return;
|
||
}
|
||
|
||
exchangeStarted.current = true;
|
||
(async () => {
|
||
try {
|
||
let tokens;
|
||
if (handoff) {
|
||
tokens = await redeemHandoff(handoff);
|
||
} else {
|
||
const config = await fetchAuthConfig();
|
||
tokens = await exchangeCode(code!, config.callback_url, params.get("state"));
|
||
}
|
||
storeTokens(tokens);
|
||
const me = await fetchMe(tokens.access_token);
|
||
if (me.requires_mobile_verification) {
|
||
router.replace("/auth/verify-mobile");
|
||
return;
|
||
}
|
||
const dest = consumePostLoginRedirect("/dashboard");
|
||
if (/^https?:\/\//i.test(dest)) {
|
||
window.location.href = dest;
|
||
} else {
|
||
router.replace(dest);
|
||
}
|
||
} catch (e) {
|
||
exchangeStarted.current = false;
|
||
setError(e instanceof Error ? e.message : "خطای ناشناخته");
|
||
}
|
||
})();
|
||
}, [params, router]);
|
||
|
||
if (error) {
|
||
return <p className="mt-8 text-red-600">{error}</p>;
|
||
}
|
||
|
||
return <p className="mt-8 text-gray-600">در حال تکمیل ورود...</p>;
|
||
}
|
||
|
||
export default function AuthCallbackPage() {
|
||
return (
|
||
<Suspense fallback={<p className="mt-8">...</p>}>
|
||
<CallbackInner />
|
||
</Suspense>
|
||
);
|
||
}
|