Browse Source
refactor: simplify routing by removing server-side data fetching and hydration across all app pages
master
refactor: simplify routing by removing server-side data fetching and hydration across all app pages
master
12 changed files with 23 additions and 314 deletions
-
31src/app/[lang]/page.tsx
-
4src/app/candidate-contact/candidate-contact-client.tsx
-
38src/app/candidate-contact/page.tsx
-
38src/app/finding-match/page.tsx
-
41src/app/intro/page.tsx
-
38src/app/new-match/page.tsx
-
13src/app/page.tsx
-
48src/app/questions-list/page.tsx
-
5src/app/questions-list/questions-list-client.tsx
-
38src/app/request-accepted/page.tsx
-
38src/app/request-sent/page.tsx
-
5src/app/terms/page.tsx
@ -1,39 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import CandidateContactClient from "./candidate-contact-client"; |
import CandidateContactClient from "./candidate-contact-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
export default async function CandidateContactPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<CandidateContactClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function CandidateContactPage() { |
||||
|
return <CandidateContactClient />; |
||||
} |
} |
||||
@ -1,39 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import FindingMatchClient from "./finding-match-client"; |
import FindingMatchClient from "./finding-match-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
export default async function FindingMatchPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<FindingMatchClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function FindingMatchPage() { |
||||
|
return <FindingMatchClient />; |
||||
} |
} |
||||
@ -1,42 +1,5 @@ |
|||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import { fetchConfigSSR } from "@/lib/ssr-fetch"; |
|
||||
import IntroClient from "./intro-client"; |
import IntroClient from "./intro-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
/** |
|
||||
* Server Component wrapper for the Intro page. |
|
||||
* |
|
||||
* Follows the same SSR-prefetch pattern as questions-list/page.tsx: |
|
||||
* create a server QueryClient, prefetch critical data, dehydrate, and |
|
||||
* wrap the client component in HydrationBoundary so TanStack Query |
|
||||
* hydrates the cache instantly — no client-side waterfall. |
|
||||
* |
|
||||
* Config is the only data Intro needs. Even if the fetch fails, IntroClient |
|
||||
* has a local fallback image so the UI is never broken. |
|
||||
*/ |
|
||||
export default async function IntroPage() { |
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 30 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
// Prefetch marriage config — Intro uses it for the video thumbnail.
|
|
||||
// Failure is non-blocking because IntroClient has a fallbackSrc.
|
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.config(), |
|
||||
queryFn: () => fetchConfigSSR(), |
|
||||
}); |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<IntroClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function IntroPage() { |
||||
|
return <IntroClient />; |
||||
} |
} |
||||
@ -1,39 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import NewMatchClient from "./new-match-client"; |
import NewMatchClient from "./new-match-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
export default async function NewMatchPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<NewMatchClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function NewMatchPage() { |
||||
|
return <NewMatchClient />; |
||||
} |
} |
||||
@ -1,49 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import QuestionsListClient from "./questions-list-client"; |
import QuestionsListClient from "./questions-list-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
/** |
|
||||
* Server Component wrapper for questions-list. |
|
||||
* |
|
||||
* Prefetches the marriage profile server-side using the HABIB_TOKEN cookie |
|
||||
* (Flutter sets it via WebViewCookieManager before loadRequest). The profile |
|
||||
* determines which page the user should see — having it in the HTML avoids |
|
||||
* the white-flash caused by waiting for the client-side API call. |
|
||||
* |
|
||||
* The sections/form-overview loads client-side with shimmer — that's fine. |
|
||||
*/ |
|
||||
export default async function QuestionsListPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<QuestionsListClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function QuestionsListPage() { |
||||
|
return <QuestionsListClient />; |
||||
} |
} |
||||
@ -1,39 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import RequestAcceptedClient from "./request-accepted-client"; |
import RequestAcceptedClient from "./request-accepted-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
export default async function RequestAcceptedPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<RequestAcceptedClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function RequestAcceptedPage() { |
||||
|
return <RequestAcceptedClient />; |
||||
} |
} |
||||
@ -1,39 +1,5 @@ |
|||||
import { cookies } from "next/headers"; |
|
||||
import { |
|
||||
dehydrate, |
|
||||
HydrationBoundary, |
|
||||
QueryClient, |
|
||||
} from "@tanstack/react-query"; |
|
||||
import { isAuthenticatedToken } from "@/lib/entry-route-cache"; |
|
||||
import { fetchProfileSSR } from "@/lib/ssr-fetch"; |
|
||||
import { marriageQueryKeys } from "@/hooks/marriage/query-keys"; |
|
||||
import RequestSentClient from "./request-sent-client"; |
import RequestSentClient from "./request-sent-client"; |
||||
|
|
||||
export const dynamic = "force-dynamic"; |
|
||||
|
|
||||
export default async function RequestSentPage() { |
|
||||
const cookieStore = await cookies(); |
|
||||
|
|
||||
const token = |
|
||||
cookieStore.get("HABIB_TOKEN")?.value ?? |
|
||||
cookieStore.get("habib_token")?.value; |
|
||||
|
|
||||
const queryClient = new QueryClient({ |
|
||||
defaultOptions: { |
|
||||
queries: { staleTime: 10 * 1000 }, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
if (isAuthenticatedToken(token)) { |
|
||||
await queryClient.prefetchQuery({ |
|
||||
queryKey: marriageQueryKeys.profile(), |
|
||||
queryFn: () => fetchProfileSSR(token!), |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<HydrationBoundary state={dehydrate(queryClient)}> |
|
||||
<RequestSentClient /> |
|
||||
</HydrationBoundary> |
|
||||
); |
|
||||
|
export default function RequestSentPage() { |
||||
|
return <RequestSentClient />; |
||||
} |
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue