diff --git a/next-env.d.ts b/next-env.d.ts index ce4e94a6..a419cbe4 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,7 +1,7 @@ /// /// -import "./.next/types/routes.d.ts"; -import "./.next/types/root-params.d.ts"; +import "./.next/dev/types/routes.d.ts"; +import "./.next/dev/types/root-params.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/app/(default-locale)/(app)/daily/loading.tsx b/src/app/(default-locale)/(app)/daily/loading.tsx index bb3b63b9..4b79618e 100644 --- a/src/app/(default-locale)/(app)/daily/loading.tsx +++ b/src/app/(default-locale)/(app)/daily/loading.tsx @@ -1,24 +1,4 @@ -import { Box, Container, Skeleton } from "@mui/material"; +import { DailyPageSkeleton } from "#/features/homePage/ui/DailyPageSkeleton"; -/** Instant-nav fallback for `/daily` while the client view hydrates. */ -export default function DailyLoading() { - return ( - - - - - - - ); -} +/** Instant-nav fallback for `/daily` while the page shell and data stream in. */ +export default DailyPageSkeleton; diff --git a/src/app/[lang]/(app)/daily/loading.tsx b/src/app/[lang]/(app)/daily/loading.tsx index bb3b63b9..4b79618e 100644 --- a/src/app/[lang]/(app)/daily/loading.tsx +++ b/src/app/[lang]/(app)/daily/loading.tsx @@ -1,24 +1,4 @@ -import { Box, Container, Skeleton } from "@mui/material"; +import { DailyPageSkeleton } from "#/features/homePage/ui/DailyPageSkeleton"; -/** Instant-nav fallback for `/daily` while the client view hydrates. */ -export default function DailyLoading() { - return ( - - - - - - - ); -} +/** Instant-nav fallback for `/daily` while the page shell and data stream in. */ +export default DailyPageSkeleton; diff --git a/src/features/homePage/ui/DailyPageSkeleton.tsx b/src/features/homePage/ui/DailyPageSkeleton.tsx new file mode 100644 index 00000000..bec4ae94 --- /dev/null +++ b/src/features/homePage/ui/DailyPageSkeleton.tsx @@ -0,0 +1,23 @@ +import { Box, Container, Skeleton } from "@mui/material"; +import React from "react"; + +/** Instant-nav fallback for `/daily` while the page shell and data stream in. */ +export const DailyPageSkeleton: React.FC = () => ( + + + + + + +); diff --git a/src/features/homePage/ui/SessionWidget.tsx b/src/features/homePage/ui/SessionWidget.tsx deleted file mode 100644 index 22b5ec57..00000000 --- a/src/features/homePage/ui/SessionWidget.tsx +++ /dev/null @@ -1,105 +0,0 @@ -"use client"; - -import { Box, Button, CircularProgress, Typography } from "@mui/material"; -import { signIn, signOut, useSession } from "next-auth/react"; -import Image from "next/image"; -import React from "react"; - -const isNextImageOptimizedAvatarUrl = (url: string): boolean => { - try { - const host = new URL(url).hostname; - return ( - host === "avatars.githubusercontent.com" || - host === "lh3.googleusercontent.com" - ); - } catch { - return false; - } -}; - -export const SessionWidget: React.FC = () => { - const { data: session, status } = useSession(); - const loading = status === "loading"; - - if (loading) { - return ( - - - - ); - } - - const handleSignIn: React.MouseEventHandler = async ( - event, - ) => { - event.preventDefault(); - await signIn(); - }; - - const handleSignOut: React.MouseEventHandler = async ( - event, - ) => { - event.preventDefault(); - await signOut(); - }; - - return ( - - {!session?.user ? ( - <> - - You are not signed in - - - - ) : ( - <> - - You are signed in as: - - {session.user.image && ( - user avatar - )} - - {session.user.name}
- {session.user.email}
- {session.user.image}
-
- - - )} -
- ); -}; diff --git a/src/server/daily/getDailyInitialData.ts b/src/server/daily/getDailyInitialData.ts index 81d9bcee..09429469 100644 --- a/src/server/daily/getDailyInitialData.ts +++ b/src/server/daily/getDailyInitialData.ts @@ -6,31 +6,43 @@ import { QuestionOfTodayDocument, } from "#/graphql/generated"; -/** - * Prefetch today's LeetCode daily question for RSC + Apollo cache hydration. - * Returns null when upstream GraphQL is unavailable (client hooks refetch). - */ -export async function getDailyInitialData(): Promise { +const DAILY_PREFETCH_TIMEOUT_MS = 10_000; + +async function fetchDailyInitialData(): Promise { const client = createApolloClient({ ssr: true }); - try { - const todayResult = await client.query({ - query: QuestionOfTodayDocument, + const todayResult = await client.query({ + query: QuestionOfTodayDocument, + fetchPolicy: "no-cache", + }); + + const titleSlug = + todayResult.data.activeDailyCodingChallengeQuestion?.question?.titleSlug; + + if (titleSlug) { + await client.query({ + query: QuestionDataDocument, + variables: { titleSlug }, fetchPolicy: "no-cache", }); + } - const titleSlug = - todayResult.data.activeDailyCodingChallengeQuestion?.question?.titleSlug; - - if (titleSlug) { - await client.query({ - query: QuestionDataDocument, - variables: { titleSlug }, - fetchPolicy: "no-cache", - }); - } + return client.cache.extract(); +} - return client.cache.extract(); +/** + * Prefetch today's LeetCode daily question for RSC + Apollo cache hydration. + * Returns null when upstream GraphQL is unavailable (client hooks refetch). + */ +export async function getDailyInitialData(): Promise { + try { + const result = await Promise.race([ + fetchDailyInitialData(), + new Promise((resolve) => { + setTimeout(() => resolve(null), DAILY_PREFETCH_TIMEOUT_MS); + }), + ]); + return result; } catch (error) { console.warn( "getDailyInitialData: LeetCode GraphQL prefetch failed",