Browse Source

ssr 2

master
mortezaei 1 week ago
parent
commit
c6837bb574
  1. 24
      src/app/[lang]/page.tsx
  2. 13
      src/app/page.tsx
  3. 16
      src/lib/ssr-fetch.ts

24
src/app/[lang]/page.tsx

@ -7,6 +7,11 @@ import {
isAuthenticatedToken, isAuthenticatedToken,
MARRIAGE_ENTRY_PATH_COOKIE, MARRIAGE_ENTRY_PATH_COOKIE,
} from "@/lib/entry-route-cache"; } from "@/lib/entry-route-cache";
import {
getSubmitPath,
hasCompletedMarriageProfileBasics,
} from "@/lib/get-submit-path";
import { fetchProfileSSR } from "@/lib/ssr-fetch";
import { localizePath } from "@/translations/config"; import { localizePath } from "@/translations/config";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
@ -21,6 +26,13 @@ export default async function LocaleEntryPage({
cookieStore.get("HABIB_TOKEN")?.value ?? cookieStore.get("HABIB_TOKEN")?.value ??
cookieStore.get("habib_token")?.value; cookieStore.get("habib_token")?.value;
const hasToken = isAuthenticatedToken(token); const hasToken = isAuthenticatedToken(token);
// 1. If not authenticated, render <Intro /> instantly in SSR
if (!hasToken) {
return <Intro />;
}
// 2. Check cached entry path first
const cachedEntryPath = getAuthenticatedCachedEntryPath( const cachedEntryPath = getAuthenticatedCachedEntryPath(
token, token,
cookieStore.get(MARRIAGE_ENTRY_PATH_COOKIE)?.value, cookieStore.get(MARRIAGE_ENTRY_PATH_COOKIE)?.value,
@ -30,12 +42,16 @@ export default async function LocaleEntryPage({
redirect(localizePath(cachedEntryPath, lang)); redirect(localizePath(cachedEntryPath, lang));
} }
// 1. If not authenticated, render <Intro /> instantly in SSR (0ms client delay)
if (!hasToken) {
return <Intro />;
// 3. Deep SSR Profile Resolution: resolve profile & redirect directly on server
const profile = await fetchProfileSSR(token);
if (profile) {
const targetPath = hasCompletedMarriageProfileBasics(profile)
? getSubmitPath(profile)
: "/intro";
redirect(localizePath(targetPath, lang));
} }
// 2. If authenticated without cached route, deliver head/web_ready immediately and resolve in client
// 4. Graceful Fallback if server fetch was unreachable
return ( return (
<> <>
<EntryRouteResolver anonymousEntryVisible={false} /> <EntryRouteResolver anonymousEntryVisible={false} />

13
src/app/page.tsx

@ -5,6 +5,11 @@ import {
isAuthenticatedToken, isAuthenticatedToken,
MARRIAGE_ENTRY_PATH_COOKIE, MARRIAGE_ENTRY_PATH_COOKIE,
} from "@/lib/entry-route-cache"; } from "@/lib/entry-route-cache";
import {
getSubmitPath,
hasCompletedMarriageProfileBasics,
} from "@/lib/get-submit-path";
import { fetchProfileSSR } from "@/lib/ssr-fetch";
import { import {
defaultLocale, defaultLocale,
isLocale, isLocale,
@ -52,5 +57,13 @@ export default async function RootPage() {
redirect(localizePath(cachedEntryPath, targetLocale)); redirect(localizePath(cachedEntryPath, targetLocale));
} }
const profile = await fetchProfileSSR(token);
if (profile) {
const targetPath = hasCompletedMarriageProfileBasics(profile)
? getSubmitPath(profile)
: "/intro";
redirect(localizePath(targetPath, targetLocale));
}
redirect(`/${targetLocale}`); redirect(`/${targetLocale}`);
} }

16
src/lib/ssr-fetch.ts

@ -14,8 +14,14 @@ function getApiBaseUrl(): string {
* @param token - The user authentication token * @param token - The user authentication token
* @returns Profile data or null on failure * @returns Profile data or null on failure
*/ */
export async function fetchProfileSSR(token: string): Promise<any | null> {
if (!token) return null;
export async function fetchProfileSSR(
token: string,
timeoutMs = 1500,
): Promise<any | null> {
if (!token || token === "NO_TOKEN" || token.trim() === "") return null;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
try { try {
const baseUrl = getApiBaseUrl(); const baseUrl = getApiBaseUrl();
@ -24,9 +30,10 @@ export async function fetchProfileSSR(token: string): Promise<any | null> {
const response = await fetch(url, { const response = await fetch(url, {
method: "GET", method: "GET",
cache: "no-store", cache: "no-store",
signal: controller.signal,
headers: { headers: {
Accept: "application/json", Accept: "application/json",
Authorization: `Token ${token}`,
Authorization: `Token ${token.trim()}`,
}, },
}); });
@ -36,7 +43,8 @@ export async function fetchProfileSSR(token: string): Promise<any | null> {
return await response.json(); return await response.json();
} catch (error) { } catch (error) {
console.error("fetchProfileSSR Error:", error);
return null; return null;
} finally {
clearTimeout(timeoutId);
} }
} }
Loading…
Cancel
Save