diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index c245277..73de8d5 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -113,7 +113,7 @@ export default function RootLayout({
}
},
get: function() {
- return this._habib_token || readCookie(HABIB_TOKEN_COOKIE) || sessionStorage.getItem(HABIB_TOKEN_COOKIE) || '${process.env.NEXT_PUBLIC_DEFAULT_TOKEN || "545f61bb3e061ccb9b19f84715eb1b1ed4740331"}';
+ return this._habib_token || readCookie(HABIB_TOKEN_COOKIE) || sessionStorage.getItem(HABIB_TOKEN_COOKIE) || '${process.env.NEXT_PUBLIC_DEFAULT_TOKEN || "f3a7543b44ef0a713d1ee0d4f7866b3825cf1308"}';
}
});
}
diff --git a/src/app/new-match/page.tsx b/src/app/new-match/page.tsx
index 6fd31e7..719f78e 100644
--- a/src/app/new-match/page.tsx
+++ b/src/app/new-match/page.tsx
@@ -1,7 +1,10 @@
"use client";
import Image from "next/image";
-import { useMemo } from "react";
+import { useEffect, useMemo } from "react";
+import { useRouter } from "next/navigation";
+import { localizePath } from "@/translations/config";
+import { getSubmitPath } from "@/lib/get-submit-path";
import { FaLock } from "react-icons/fa6";
import AdvisorActionsCard from "@/components/ui/advisor-actions-card";
import NavigationButton from "@/components/ui/navigation-button";
@@ -183,9 +186,21 @@ function FieldLine({ field }: { field: DisplayField }) {
}
export default function NewMatchPage() {
- const { dictionary: t } = useI18n();
+ const router = useRouter();
+ const { dictionary: t, locale } = useI18n();
const { top, bottom } = useViewPaddings();
const { data: profile, isError, isLoading } = useMarriageProfileQuery();
+
+ useEffect(() => {
+ if (!profile) {
+ return;
+ }
+ const targetPath = getSubmitPath(profile);
+ if (targetPath !== "/new-match") {
+ router.replace(localizePath(targetPath, locale));
+ }
+ }, [profile, locale, router]);
+
const matchSummary = profile?.match_summary ?? null;
const matchDisplay = useMatchSummaryDisplay(matchSummary);
const pairedFields = [matchDisplay.age, matchDisplay.city].filter(
diff --git a/src/app/new-match/profile/page.tsx b/src/app/new-match/profile/page.tsx
index a48e0a3..5dccf83 100644
--- a/src/app/new-match/profile/page.tsx
+++ b/src/app/new-match/profile/page.tsx
@@ -2,7 +2,7 @@
import Image from "next/image";
import { useRouter } from "next/navigation";
-import { useMemo, useState } from "react";
+import { useEffect, useMemo, useState } from "react";
import Button from "@/components/ui/button";
import DismissReasonSheet from "@/components/ui/dismiss-reason-sheet";
import FemaleConsentSheet from "@/components/ui/female-consent-sheet";
@@ -19,6 +19,7 @@ import type {
} from "@/hooks/marriage/types";
import { useRespondToMarriageCaseMutation } from "@/hooks/marriage/use-case-respond";
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
+import { getSubmitPath } from "@/lib/get-submit-path";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
@@ -150,7 +151,18 @@ export default function NewMatchProfilePage() {
const [isRejectSheetOpen, setIsRejectSheetOpen] = useState(false);
const [isDismissReasonSheetOpen, setIsDismissReasonSheetOpen] =
useState(false);
- const { data: profile } = useMarriageProfileQuery();
+ const { data: profile, refetch: refetchProfile } = useMarriageProfileQuery();
+
+ useEffect(() => {
+ if (!profile) {
+ return;
+ }
+ const targetPath = getSubmitPath(profile);
+ if (targetPath !== "/new-match") {
+ router.replace(localizePath(targetPath, locale));
+ }
+ }, [profile, locale, router]);
+
const caseId = profile?.active_case?.case_id;
const caseStatus = profile?.active_case?.status;
const isFemaleProfile = profile?.gender === "female";
@@ -158,11 +170,9 @@ export default function NewMatchProfilePage() {
const respondMutation = useRespondToMarriageCaseMutation(caseId ?? "", {
onSuccess: async (_, variables) => {
if (variables.action === "accept") {
- if (isFemaleProfile) {
- router.replace(localizePath("/request-accepted", locale));
- } else {
- router.replace(localizePath("/request-sent", locale));
- }
+ const { data: updatedProfile } = await refetchProfile();
+ const nextPath = getSubmitPath(updatedProfile);
+ router.replace(localizePath(nextPath, locale));
return;
}
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
index 0220031..8554f6b 100644
--- a/src/app/providers.tsx
+++ b/src/app/providers.tsx
@@ -1,9 +1,55 @@
"use client";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { type ReactNode, useState } from "react";
+import { QueryClient, QueryClientProvider, useQueryClient } from "@tanstack/react-query";
+import { type ReactNode, useState, useEffect } from "react";
import { ViewPaddingsProvider } from "@/components/utils/view-paddings-provider";
+function AppFocusReloader({ children }: { children: ReactNode }) {
+ const queryClient = useQueryClient();
+
+ useEffect(() => {
+ if (typeof window !== "undefined") {
+ (window as any).__queryClient = queryClient;
+ }
+
+ const handleReload = () => {
+ // Invalidate all active queries so fresh data is reloaded from backend
+ queryClient.invalidateQueries();
+ };
+
+ const handleVisibilityChange = () => {
+ if (document.visibilityState === "visible") {
+ handleReload();
+ }
+ };
+
+ const handlePageShow = () => {
+ handleReload();
+ };
+
+ window.addEventListener("focus", handleReload);
+ window.addEventListener("pageshow", handlePageShow);
+ document.addEventListener("visibilitychange", handleVisibilityChange);
+
+ // Listen for Flutter response events if available
+ const win = window as any;
+ const unbindFlutter = typeof win.addFlutterResponseListener === "function"
+ ? win.addFlutterResponseListener(() => handleReload())
+ : null;
+
+ return () => {
+ window.removeEventListener("focus", handleReload);
+ window.removeEventListener("pageshow", handlePageShow);
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
+ if (typeof unbindFlutter === "function") {
+ unbindFlutter();
+ }
+ };
+ }, [queryClient]);
+
+ return <>{children}>;
+}
+
type ProvidersProps = {
children: ReactNode;
};
@@ -14,10 +60,12 @@ export default function Providers({ children }: ProvidersProps) {
new QueryClient({
defaultOptions: {
queries: {
- refetchOnWindowFocus: false,
+ refetchOnWindowFocus: "always",
+ refetchOnMount: "always",
+ refetchOnReconnect: "always",
retry: 1,
- staleTime: 5 * 60 * 1000, // 5 minutes
- gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
+ staleTime: 0, // Always consider queries stale to ensure fresh data from backend on every page load
+ gcTime: 10 * 60 * 1000, // 10 minutes
},
},
}),
@@ -25,8 +73,11 @@ export default function Providers({ children }: ProvidersProps) {
return (
-
- {children}
+
+
+ {children}
+
);
}
+
diff --git a/src/hooks/marriage/use-case-respond.ts b/src/hooks/marriage/use-case-respond.ts
index aa6c881..ae6d38a 100644
--- a/src/hooks/marriage/use-case-respond.ts
+++ b/src/hooks/marriage/use-case-respond.ts
@@ -36,6 +36,33 @@ export function useRespondToMarriageCaseMutation(
...options,
mutationFn: (payload) => respondToMarriageCase(caseId, payload),
onSuccess: async (data, variables, onMutateResult, context) => {
+ if (data?.case) {
+ queryClient.setQueryData(marriageQueryKeys.profile(), (old: any) => {
+ if (!old) return old;
+ const updatedActiveCase = {
+ ...old.active_case,
+ case_id: data.case.id,
+ status: data.case.status,
+ my_action:
+ data.case.status === "male_accepted"
+ ? old.gender === "female"
+ ? "pending"
+ : "waiting"
+ : data.case.status === "female_accepted" ||
+ data.case.status === "payment_pending" ||
+ data.case.status === "payment_done"
+ ? old.gender === "female"
+ ? "waiting"
+ : "completed"
+ : "waiting",
+ };
+ return {
+ ...old,
+ active_case: updatedActiveCase,
+ };
+ });
+ }
+
await Promise.all([
queryClient.refetchQueries({
queryKey: marriageQueryKeys.profile(),
diff --git a/src/hooks/marriage/use-profile-main.ts b/src/hooks/marriage/use-profile-main.ts
index 357a741..483949d 100644
--- a/src/hooks/marriage/use-profile-main.ts
+++ b/src/hooks/marriage/use-profile-main.ts
@@ -18,6 +18,9 @@ export function useMarriageProfileQuery(
options?: QueryOptions,
) {
return useQuery({
+ staleTime: 0,
+ refetchOnMount: "always",
+ refetchOnWindowFocus: true,
...options,
queryFn: getMarriageProfile,
queryKey: marriageQueryKeys.profile(),
diff --git a/src/lib/auth-bridge.ts b/src/lib/auth-bridge.ts
index c980039..92a298d 100644
--- a/src/lib/auth-bridge.ts
+++ b/src/lib/auth-bridge.ts
@@ -141,6 +141,9 @@ class AuthBridge {
this.isReady = true;
this.resolvePending(token);
this.notifyReady();
+ if (typeof window !== "undefined" && (window as any).__queryClient) {
+ (window as any).__queryClient.invalidateQueries();
+ }
}
private resolvePending(token: string | null) {
@@ -210,7 +213,7 @@ class AuthBridge {
getClientCookie(TOKEN_COOKIE_NAME) ??
getClientCookie("habib_token") ??
process.env.NEXT_PUBLIC_DEFAULT_TOKEN ??
- "545f61bb3e061ccb9b19f84715eb1b1ed4740331"
+ "f3a7543b44ef0a713d1ee0d4f7866b3825cf1308"
);
}
diff --git a/src/lib/http.ts b/src/lib/http.ts
index 67543fd..68ca3ae 100644
--- a/src/lib/http.ts
+++ b/src/lib/http.ts
@@ -74,7 +74,7 @@ http.interceptors.request.use((config) => {
authBridge.getToken() ??
getClientCookie("HABIB_TOKEN") ??
process.env.NEXT_PUBLIC_DEFAULT_TOKEN ??
- "545f61bb3e061ccb9b19f84715eb1b1ed4740331";
+ "f3a7543b44ef0a713d1ee0d4f7866b3825cf1308";
if (token) {
config.headers.Authorization = `Token ${token}`;