Skip to content

Feature: Add an onboarding page and redirect users to that page if the user is not logged in. Have 3 sample latest question an... - #103

Open
lazydev-issue-resolver[bot] wants to merge 1 commit into
mainfrom
lazydev/feat-102-add-an-onboarding-page-and-redirect-user
Open

Feature: Add an onboarding page and redirect users to that page if the user is not logged in. Have 3 sample latest question an...#103
lazydev-issue-resolver[bot] wants to merge 1 commit into
mainfrom
lazydev/feat-102-add-an-onboarding-page-and-redirect-user

Conversation

@lazydev-issue-resolver

Copy link
Copy Markdown

Resolves #102

Generated autonomously by LazyDev.

Implementation Plan

I have gathered all the context I need. Here's my implementation plan.


Implementation Plan: Onboarding Page + Auth Redirect

Context / Findings

  • Auth is client-side only: AuthProvider (components/auth-provider.tsx) stores a "auth" flag in sessionStorage and exposes isAuthenticated, isAdmin, password, login, logout via useAuth(). Because auth lives in sessionStorage, a Next.js middleware.ts cannot read it — the redirect must be done client-side in a page effect.
  • The main entry point app/page.tsx (HomePage) currently renders for everyone with no auth check. There is no onboarding page today.
  • The home page fetches public questions from GET /api/questions?scope=public&limit=N&page=N (see app/api/questions/route.ts), which supports scope=public and limit — usable to fetch 3 sample questions.
  • QuestionCard (components/question-card.tsx) hides answers behind a "Show Answer" button (useState(false)). For onboarding we want the Q&A visible, so we add an optional prop.
  • The login page (app/login/page.tsx) calls login(password), which pushes to /admin — unchanged by this feature.
  • There is an initial-render race: isAuthenticated starts false and is only set to true in a useEffect in AuthProvider. A naive redirect on !isAuthenticated would bounce logged-in users too. We fix this by exposing an authLoading flag from the provider.

Step 1 — Expose authLoading in components/auth-provider.tsx

Symbols: AuthContextType (interface), AuthProvider (function).

  1. Add authLoading: boolean; to the AuthContextType interface.
  2. In AuthProvider, add state: const [authLoading, setAuthLoading] = React.useState(true);
  3. Modify the existing session-restore useEffect so setAuthLoading(false) runs on every exit path:
    • Change the early return if (!auth) return; to if (!auth) { setAuthLoading(false); return; }
    • Wrap the existing try/catch with a finally { setAuthLoading(false); } (keep the existing sessionStorage.removeItem("auth") calls in the catch/else branches as-is).
  4. Add authLoading to the context value object passed to AuthContext.Provider.

This is the single source of truth for "auth is still being determined" and prevents redirect races.

Step 2 — Redirect unauthenticated users from the home page

File: app/page.tsx — symbol: HomePage (default export function).

  1. Change the existing destructure const { isAdmin, logout } = useAuth(); to also pull isAuthenticated and authLoading: const { isAdmin, logout, isAuthenticated, authLoading } = useAuth(); (the router from useRouter() already exists).
  2. Add a redirect effect (place near the other useEffects, e.g. right after the useEffect that restores the exam type):
    React.useEffect(() => {
      if (authLoading) return;
      if (!isAuthenticated) {
        router.replace("/onboarding");
      }
    }, [authLoading, isAuthenticated, router]);
  3. Optionally add if (authLoading) return null; just before the main return ( JSX to avoid flashing the page content for a frame (all hooks are above it, so this is safe).

Step 3 — Let QuestionCard show the answer initially

File: components/question-card.tsx — symbols: QuestionCardProps (interface), QuestionCard (function).

  1. Add an optional prop to QuestionCardProps: showAnswerInitially?: boolean;
  2. Update the function signature to export function QuestionCard({ question, showAnswerInitially = false }: QuestionCardProps) and change the state initializer to React.useState(showAnswerInitially).
  3. Existing usages (app/page.tsx, components/admin/admin-question-list.tsx uses its own AdminQuestionListItem, not QuestionCard) are unaffected since the prop defaults to false.

Step 4 — Create app/onboarding/page.tsx

New file, "use client", default-exported function OnboardingPage. Follow the existing page patterns (see app/login/page.tsx for the ThemeToggle placement and app/page.tsx for fetch + loading/empty/error rendering).

Structure:

  1. Imports: React, useRouter from next/navigation, QuestionCard, ThemeToggle, Button from @/components/ui/button, useAuth, types Question and PaginatedResponse from @/lib/types, optional lucide icons (e.g. ArrowRight, Sparkles).
  2. State: sampleQuestions: Question[], loading: boolean (init true).
  3. Effects:
    • Redirect already-authenticated users back to / (mirrors Step 2's pattern): if (authLoading) return; if (isAuthenticated) router.replace("/"); with deps [authLoading, isAuthenticated, router].
    • Fetch the 3 latest public questions: fetch("/api/questions?scope=public&limit=3"), parse PaginatedResponse<Question>, setSampleQuestions(data.data); set loading false in finally; use a cancelled flag for cleanup (match the fetch/error-handling pattern in HomePage's fetchQuestions).
  4. Render:
    • Top-right ThemeToggle (match app/login/page.tsx).
    • Hero section: a greeting message (time-of-day based — e.g. "Good morning/afternoon/evening" computed from new Date().getHours()) plus a welcome headline such as "Welcome to AWS Developer Q&A" and a short subheading ("Practice the latest AWS Developer questions and answers."), all with Tailwind classes consistent with the app (text-center, space-y-4, text-muted-foreground, etc.).
    • A primary CTA <Button size="lg" onClick={() => router.push("/login")}>Get Started</Button> linking to the existing /login page.
    • A "Latest Questions" section rendering the fetched questions with <QuestionCard question={q} showAnswerInitially /> (keyed by q._id ?? q.id ?? index, same as home page). Include loading state (Loading sample questions...) and empty state (No questions available yet.), matching the home page's conditional-render pattern.

Step 5 — Sanity / no other changes needed

  • app/admin/page.tsx already gates itself with an inline password form, so no redirect is needed there.
  • app/api/questions/route.ts already supports scope=public + limit=3; no API change required.
  • Login flow stays as-is (login()/admin); the onboarding CTA routes through /login.
  • Run pnpm format (Prettier is checked by pnpm build) after the changes.

Files touched (summary)

File Change
components/auth-provider.tsx Add authLoading state + context field
app/page.tsx Redirect !isAuthenticated/onboarding after authLoading resolves
components/question-card.tsx Add optional showAnswerInitially prop
app/onboarding/page.tsx New onboarding page with greeting + 3 latest Q&A

Generated autonomously by LazyDev.
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-aws-developer-questions Error Error Aug 26, 2026 6:27pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add an onboarding page and redirect users to that page if the user is not logged in. Have 3 sample latest question an...

1 participant