diff --git a/src/app/intro/page.tsx b/src/app/intro/page.tsx index 2117e45..e9a0361 100644 --- a/src/app/intro/page.tsx +++ b/src/app/intro/page.tsx @@ -2,24 +2,24 @@ import Image from "next/image"; import { useState } from "react"; +import { useRouter } from "next/navigation"; import Button from "@/components/ui/button"; import NavigationButton from "@/components/ui/navigation-button"; import ReportActionsSheet from "@/components/ui/report-actions-sheet"; +import { authBridge } from "@/lib/auth-bridge"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; import { localizePath } from "@/i18n/config"; import { useI18n } from "@/i18n/provider"; -export default function Intro() { - const { dictionary: t, locale } = useI18n(); - const { data: profile } = useMarriageProfileQuery(); - const [isReportSheetOpen, setIsReportSheetOpen] = useState(false); +function getSubmitPath(profile: ReturnType["data"]) { const isInCase = profile?.status === "in_case"; const isFemaleAcceptedFlow = isInCase && (profile?.active_case?.status === "payment_pending" || profile?.active_case?.status === "female_accepted" || profile?.active_case?.status === "payment_done"); - const submitPath = isFemaleAcceptedFlow + + return isFemaleAcceptedFlow ? "/request-accepted" : isInCase && profile?.active_case?.status === "male_accepted" ? "/request-sent" @@ -32,7 +32,39 @@ export default function Intro() { : profile?.status === "in_case" || profile?.status === "matched" ? "/new-match" : "/terms"; - const submitHref = localizePath(submitPath, locale); +} + +export default function Intro() { + const router = useRouter(); + const { dictionary: t, locale } = useI18n(); + const { data: profile, refetch } = useMarriageProfileQuery({ + enabled: authBridge.isAuthenticated(), + }); + const [isReportSheetOpen, setIsReportSheetOpen] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleSubmit = async () => { + if (isSubmitting) { + return; + } + + setIsSubmitting(true); + + try { + if (!authBridge.isAuthenticated()) { + const token = await authBridge.ensureToken(); + if (!token) { + return; + } + } + + const profileResponse = profile ?? (await refetch()).data; + const nextPath = localizePath(getSubmitPath(profileResponse), locale); + router.push(nextPath); + } finally { + setIsSubmitting(false); + } + }; return (
@@ -123,7 +155,9 @@ export default function Intro() { />
- +
diff --git a/src/lib/auth-bridge.ts b/src/lib/auth-bridge.ts index 0e64fa9..54061b1 100644 --- a/src/lib/auth-bridge.ts +++ b/src/lib/auth-bridge.ts @@ -26,7 +26,6 @@ class AuthBridge { private readyCallbacks: Array<() => void> = []; private pendingResolvers: Array<(token: string | null) => void> = []; private flutterResponseUnsubscribe?: () => void; - private loginTimeoutId?: number; constructor() { this.init(); @@ -70,45 +69,63 @@ class AuthBridge { ) => () => void; }; - if (typeof win.addFlutterResponseListener === "function") { + const attach = () => { + if (typeof win.addFlutterResponseListener !== "function") { + return false; + } + this.flutterResponseUnsubscribe = win.addFlutterResponseListener((event) => { if (event.action === "login") { this.handleLoginResponse(event.success); } }); + + return true; + }; + + if (attach()) { return; } const fallbackInterval = window.setInterval(() => { - if (typeof win.addFlutterResponseListener === "function") { + if (attach()) { window.clearInterval(fallbackInterval); - this.flutterResponseUnsubscribe = win.addFlutterResponseListener((event) => { - if (event.action === "login") { - this.handleLoginResponse(event.success); - } - }); } }, 50); } private handleLoginResponse(success: boolean) { - if (success && this.syncFromStorage()) { - this.loginRequested = false; - this.markReady(this.token); + if (success) { + if (this.syncFromStorage()) { + this.loginRequested = false; + this.markReady(this.token); + return; + } + + window.setTimeout(() => { + if (this.syncFromStorage()) { + this.loginRequested = false; + this.markReady(this.token); + return; + } + + console.warn("⚠️ Flutter login response arrived before token"); + this.loginRequested = false; + this.resolvePending(null); + this.markReady(null); + }, 50); return; } - if (!success) { - this.loginRequested = false; - console.warn("⚠️ Flutter login failed"); - this.resolvePending(null); - this.markReady(null); - } + this.loginRequested = false; + console.warn("⚠️ Flutter login failed"); + this.resolvePending(null); + this.markReady(null); } private requestLogin() { if (this.loginRequested || this.token) { - return; + return true; } this.loginRequested = true; @@ -116,28 +133,21 @@ class AuthBridge { if (!sent) { this.loginRequested = false; - return; - } - - if (this.loginTimeoutId) { - window.clearTimeout(this.loginTimeoutId); + return false; } - this.loginTimeoutId = window.setTimeout(() => { + window.setTimeout(() => { if (!this.token) { console.warn("⚠️ Flutter login timeout"); this.loginRequested = false; this.resolvePending(null); } }, LOGIN_TIMEOUT_MS); + + return true; } private markReady(token: string | null) { - if (this.loginTimeoutId) { - window.clearTimeout(this.loginTimeoutId); - this.loginTimeoutId = undefined; - } - this.isReady = true; this.resolvePending(token); this.notifyReady(); @@ -162,13 +172,15 @@ class AuthBridge { return; } + this.setupFlutterResponseListener(); + if (this.syncFromStorage()) { this.markReady(this.token); return; } - this.setupFlutterResponseListener(); - this.requestLogin(); + this.isReady = true; + this.notifyReady(); } public onReady(callback: () => void) { @@ -190,10 +202,12 @@ class AuthBridge { } this.setupFlutterResponseListener(); - this.requestLogin(); return await new Promise((resolve) => { this.pendingResolvers.push(resolve); + if (!this.requestLogin()) { + this.resolvePending(null); + } }); } diff --git a/src/lib/http.ts b/src/lib/http.ts index a1b0efa..7fc9440 100644 --- a/src/lib/http.ts +++ b/src/lib/http.ts @@ -60,13 +60,13 @@ export const http = axios.create({ withCredentials: true, }); -http.interceptors.request.use(async (config) => { +http.interceptors.request.use((config) => { if (shouldUseProxy() && config.url && !isAbsoluteUrl(config.url)) { config.params = withProxyPathParam(config.params, config.url); config.url = ""; } - const token = await authBridge.ensureToken(); + const token = authBridge.getToken() ?? getClientCookie("HABIB_TOKEN"); if (token) { config.headers.Authorization = `Token ${token}`;