Browse Source

feat: enhance authentication flow and improve request handling in Intro and AuthBridge

master
mortezaei 2 months ago
parent
commit
f9417728cf
  1. 48
      src/app/intro/page.tsx
  2. 78
      src/lib/auth-bridge.ts
  3. 4
      src/lib/http.ts

48
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<typeof useMarriageProfileQuery>["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 (
<div className="pt-7">
@ -123,7 +155,9 @@ export default function Intro() {
/>
</div>
<div className="mt-7 pb-5">
<Button href={submitHref}>{t.common.submit}</Button>
<Button onClick={handleSubmit} disabled={isSubmitting}>
{t.common.submit}
</Button>
</div>
</main>
</div>

78
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<string | null>((resolve) => {
this.pendingResolvers.push(resolve);
if (!this.requestLogin()) {
this.resolvePending(null);
}
});
}

4
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}`;

Loading…
Cancel
Save