diff --git a/next.config.ts b/next.config.ts index 0d9f95f..cc3a473 100644 --- a/next.config.ts +++ b/next.config.ts @@ -82,16 +82,12 @@ const nextConfig: NextConfig = { ], }, { - // Application HTML pages – no-store to prevent HTML/shell caching in WebView + // Application HTML shell – App Shell + Stale-While-Revalidate pattern for instant WebView rendering source: "/:path((?!api/|_next/|fonts/|assets/).*)", headers: [ { key: "Cache-Control", - value: "no-store, no-cache, must-revalidate, max-age=0", - }, - { - key: "Pragma", - value: "no-cache", + value: "public, max-age=0, stale-while-revalidate=86400", }, ], }, @@ -115,6 +111,16 @@ const nextConfig: NextConfig = { }, ], }, + { + // Static fonts inside assets directory are immutable + source: "/assets/fonts/:path*", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=31536000, immutable", + }, + ], + }, ]; }, }; diff --git a/public/assets/fonts/ArabicYekanXRegular.woff2 b/public/assets/fonts/ArabicYekanXRegular.woff2 new file mode 100644 index 0000000..1d4f3c1 Binary files /dev/null and b/public/assets/fonts/ArabicYekanXRegular.woff2 differ diff --git a/public/assets/fonts/Faminela.woff2 b/public/assets/fonts/Faminela.woff2 new file mode 100644 index 0000000..9b4d7f6 Binary files /dev/null and b/public/assets/fonts/Faminela.woff2 differ diff --git a/public/assets/fonts/NotoNastaliqUrdu.woff2 b/public/assets/fonts/NotoNastaliqUrdu.woff2 new file mode 100644 index 0000000..194e2c3 Binary files /dev/null and b/public/assets/fonts/NotoNastaliqUrdu.woff2 differ diff --git a/public/assets/fonts/SegoeUIBold.woff2 b/public/assets/fonts/SegoeUIBold.woff2 new file mode 100644 index 0000000..be59e22 Binary files /dev/null and b/public/assets/fonts/SegoeUIBold.woff2 differ diff --git a/public/assets/fonts/YekanXFaNum-R.woff2 b/public/assets/fonts/YekanXFaNum-R.woff2 new file mode 100644 index 0000000..c7df6f8 Binary files /dev/null and b/public/assets/fonts/YekanXFaNum-R.woff2 differ diff --git a/public/assets/fonts/faminela.woff2 b/public/assets/fonts/faminela.woff2 new file mode 100644 index 0000000..66b924f Binary files /dev/null and b/public/assets/fonts/faminela.woff2 differ diff --git a/public/assets/fonts/segoeui.woff2 b/public/assets/fonts/segoeui.woff2 new file mode 100644 index 0000000..68d4918 Binary files /dev/null and b/public/assets/fonts/segoeui.woff2 differ diff --git a/public/fonts/Amiri/Amiri-Bold.woff2 b/public/fonts/Amiri/Amiri-Bold.woff2 new file mode 100644 index 0000000..20a7398 Binary files /dev/null and b/public/fonts/Amiri/Amiri-Bold.woff2 differ diff --git a/public/fonts/Amiri/Amiri-BoldItalic.woff2 b/public/fonts/Amiri/Amiri-BoldItalic.woff2 new file mode 100644 index 0000000..62f0a69 Binary files /dev/null and b/public/fonts/Amiri/Amiri-BoldItalic.woff2 differ diff --git a/public/fonts/Amiri/Amiri-Italic.woff2 b/public/fonts/Amiri/Amiri-Italic.woff2 new file mode 100644 index 0000000..1fcdfce Binary files /dev/null and b/public/fonts/Amiri/Amiri-Italic.woff2 differ diff --git a/public/fonts/Amiri/Amiri-Regular.woff2 b/public/fonts/Amiri/Amiri-Regular.woff2 new file mode 100644 index 0000000..f2732df Binary files /dev/null and b/public/fonts/Amiri/Amiri-Regular.woff2 differ diff --git a/public/fonts/Faminela/Faminela.woff2 b/public/fonts/Faminela/Faminela.woff2 new file mode 100644 index 0000000..9b4d7f6 Binary files /dev/null and b/public/fonts/Faminela/Faminela.woff2 differ diff --git a/public/fonts/segoeui/SegoeUIBold.woff2 b/public/fonts/segoeui/SegoeUIBold.woff2 new file mode 100644 index 0000000..be59e22 Binary files /dev/null and b/public/fonts/segoeui/SegoeUIBold.woff2 differ diff --git a/public/fonts/segoeui/segoeui.woff2 b/public/fonts/segoeui/segoeui.woff2 new file mode 100644 index 0000000..68d4918 Binary files /dev/null and b/public/fonts/segoeui/segoeui.woff2 differ diff --git a/public/fonts/urdu/NotoNastaliqUrdu.woff2 b/public/fonts/urdu/NotoNastaliqUrdu.woff2 new file mode 100644 index 0000000..194e2c3 Binary files /dev/null and b/public/fonts/urdu/NotoNastaliqUrdu.woff2 differ diff --git a/public/fonts/yekanx-arabic/ArabicYekanXRegular.woff2 b/public/fonts/yekanx-arabic/ArabicYekanXRegular.woff2 new file mode 100644 index 0000000..1d4f3c1 Binary files /dev/null and b/public/fonts/yekanx-arabic/ArabicYekanXRegular.woff2 differ diff --git a/public/fonts/yekanx/YekanXFaNum-R.woff2 b/public/fonts/yekanx/YekanXFaNum-R.woff2 new file mode 100644 index 0000000..c7df6f8 Binary files /dev/null and b/public/fonts/yekanx/YekanXFaNum-R.woff2 differ diff --git a/src/app/globals.css b/src/app/globals.css index fd3e457..3a00c75 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,7 +3,9 @@ /* ─── App fonts matching Flutter Najm & Hosseinieh ─── */ @font-face { font-family: 'Faminela'; - src: url('/fonts/Faminela/Faminela.otf') format('opentype'), + src: url('/fonts/Faminela/Faminela.woff2') format('woff2'), + url('/assets/fonts/Faminela.woff2') format('woff2'), + url('/fonts/Faminela/Faminela.otf') format('opentype'), url('/assets/fonts/Faminela.otf') format('opentype'), url('/assets/fonts/faminela.ttf') format('truetype'); font-weight: 400 900; @@ -12,35 +14,40 @@ } @font-face { font-family: 'YekanX'; - src: url('/assets/fonts/YekanXFaNum-R.ttf') format('truetype'); + src: url('/assets/fonts/YekanXFaNum-R.woff2') format('woff2'), + url('/assets/fonts/YekanXFaNum-R.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'YekanXArabic'; - src: url('/assets/fonts/ArabicYekanXRegular.ttf') format('truetype'); + src: url('/assets/fonts/ArabicYekanXRegular.woff2') format('woff2'), + url('/assets/fonts/ArabicYekanXRegular.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'NastaliqUrdu'; - src: url('/assets/fonts/NotoNastaliqUrdu.ttf') format('truetype'); + src: url('/assets/fonts/NotoNastaliqUrdu.woff2') format('woff2'), + url('/assets/fonts/NotoNastaliqUrdu.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'Segoeui'; - src: url('/assets/fonts/segoeui.ttf') format('truetype'); + src: url('/assets/fonts/segoeui.woff2') format('woff2'), + url('/assets/fonts/segoeui.ttf') format('truetype'); font-weight: 400 500; font-style: normal; font-display: swap; } @font-face { font-family: 'Segoeui'; - src: url('/assets/fonts/SegoeUIBold.ttf') format('truetype'); + src: url('/assets/fonts/SegoeUIBold.woff2') format('woff2'), + url('/assets/fonts/SegoeUIBold.ttf') format('truetype'); font-weight: 600 900; font-style: normal; font-display: swap; diff --git a/src/app/questions-list/[slug]/question-detail-client.tsx b/src/app/questions-list/[slug]/question-detail-client.tsx index c610f37..04e28e9 100644 --- a/src/app/questions-list/[slug]/question-detail-client.tsx +++ b/src/app/questions-list/[slug]/question-detail-client.tsx @@ -349,13 +349,18 @@ export default function QuestionDetailClient({ } catch {} return false; }, [isAssessment, overview, itemSlug, profileId]); - const { data: sectionResponse, isLoading: isSectionLoading, isError: isSectionError, refetch: refetchSection } = - useFormSectionQuery( - "profile", - itemSlug, - locale, - Boolean(itemSlug) && !isAssessment, - ); + const { + data: sectionResponse, + isLoading: isSectionLoading, + isPending: isSectionPending, + isError: isSectionError, + refetch: refetchSection, + } = useFormSectionQuery( + "profile", + itemSlug, + locale, + Boolean(itemSlug) && !isAssessment, + ); const items = useMemo( () => convertOverviewToFrontendItems(overview), [overview], @@ -368,14 +373,17 @@ export default function QuestionDetailClient({ sectionResponse.section_progress.completion_percent, ); } - return overviewItem; + if (isAssessment) { + return overviewItem; + } + return null; }, [isAssessment, overviewItem, sectionResponse]); const isSchemaError = isAssessment ? isOverviewError : (isOverviewError || isSectionError) && !sectionResponse; const isSchemaLoading = isAssessment ? isOverviewLoading - : !sectionResponse && (isOverviewLoading || isSectionLoading); + : !sectionResponse && !isSchemaError && (isOverviewLoading || isSectionLoading || isSectionPending); const cattellQuery = useCattellQuestionsQuery(locale, { enabled: isCattellSlug && isTestStarted, @@ -395,13 +403,13 @@ export default function QuestionDetailClient({ void queryClient.prefetchQuery({ queryKey: marriageQueryKeys.cattellQuestions(locale), queryFn: () => getCattellQuestions(locale), - staleTime: 30 * 1000, + staleTime: 3 * 60 * 1000, }); } else if (isGlasserSlug) { void queryClient.prefetchQuery({ queryKey: marriageQueryKeys.glasserQuestions(locale), queryFn: () => getGlasserQuestions(locale), - staleTime: 30 * 1000, + staleTime: 3 * 60 * 1000, }); } }, [ @@ -534,7 +542,7 @@ export default function QuestionDetailClient({