A full-featured quiz creation and taking application built with Next.js, TypeScript, and Supabase.
- Quiz Builder — Create quizzes via a visual inline builder (add/reorder/delete questions) or CSV upload
- CSV Import/Export — Upload questions via CSV; download generated CSV templates
- Shareable Links — Generate shareable links for quizzes after creation
- Timed Quizzes — Optional time limit (1–180 min) with countdown, warning toast, and auto-submit
- Take Quiz — Answer questions with navigation, question overview, and progress tracking
- Results & Review — Instant scoring, time tracking, and answer review
- Dashboard — View all quizzes with stats and analytics
- Authentication — Email/password auth via Supabase Auth with protected routes
- Progress Persistence — Quiz progress saved locally to survive refreshes; timer persists via localStorage deadline
- Framework: Next.js 16 (App Router) with TypeScript
- Styling: Tailwind CSS v4
- Database: Supabase (PostgreSQL)
- Auth: Supabase Auth (email/password)
- CSV Parsing: PapaParse
- Icons: Hugeicons
- Notifications: react-hot-toast
- Test Runner: Vitest with jsdom, Testing Library
- Linter: ESLint 9 with typescript-eslint
- Node.js (v20 or higher)
- npm
- Supabase account
git clone <your-repo-url>
cd prepnpm installCreate a .env file in the root directory:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_keynpx supabase login
npx supabase link --project-ref your_project_ref
npx supabase db pushnpm run devThe app will open at http://localhost:3000.
Download the template from the CSV upload tab, or use this format:
Question,Option_A,Option_B,Option_C,Option_D,Correct_Answer,Points
What is 2+2?,2,3,4,5,C,1
Capital of France?,London,Paris,Berlin,Madrid,B,2Rules:
- Headers must match exactly:
Question,Option_A–Option_D,Correct_Answer,Points Correct_Answeris a single letter: A, B, C, or DPointsis a positive integer- Fields with commas or quotes are properly escaped on export
- Go to the landing page and click Get Started, then sign in
- Navigate to Dashboard → Create Quiz
- Enter a title and optional description
- Optionally set a time limit (1–180 minutes)
- Click Create Quiz to persist the quiz
- Add questions using the Build tab (visual builder) or Upload CSV tab
- Click Publish Questions to save them
- Open a shareable link or navigate from the dashboard
- Answer questions using the navigation or overview grid
- The timer (if set) counts down with color-coded warnings
- Click Submit Quiz or let the timer auto-submit
- View your score, time taken, and review answers
prep/
├── app/ # Next.js App Router pages
│ ├── auth/ # Sign-in / sign-up page
│ ├── dashboard/
│ │ ├── create/ # Create quiz page (builder + CSV)
│ │ ├── my-quizzes/ # Quiz list page
│ │ ├── layout.tsx # Dashboard layout (RequireAuth + Sidebar)
│ │ └── page.tsx # Dashboard home (stats)
│ ├── quiz/ # Quiz result pages
│ ├── results/ # Results listing
│ ├── take/ # Quiz-taking page
│ ├── layout.tsx # Root layout (AuthProvider, Toaster)
│ ├── page.tsx # Landing page
│ └── globals.css
├── src/
│ ├── features/
│ │ ├── auth/ # Auth components, context, and hooks
│ │ ├── dashboard/ # Dashboard shell, navigation, stats, and view
│ │ ├── docs/ # Documentation UI
│ │ ├── home/ # Landing-page sections
│ │ ├── quiz-bank/ # Public quiz discovery and ratings
│ │ ├── quiz-management/ # Creation, builder, detail, and owned quizzes
│ │ └── quiz-taking/ # Quiz session, progress, results, and review
│ ├── lib/
│ │ ├── types.ts # Cross-feature TypeScript types
│ │ ├── theme.tsx # Theme provider and hook
│ │ └── supabase.ts # Supabase client
│ └── shared/
│ ├── components/ # Shared feedback and animation components
│ ├── navigation/ # Cross-route navigation
│ ├── providers/ # Application providers
│ └── ui/skeletons/ # Shared skeleton primitives
├── tests/
│ ├── unit/ # Isolated utility, hook, and component tests
│ ├── integration/ # Hook tests with mocked service boundaries
│ └── test-utils/ # Shared test helpers
├── supabase/
│ ├── migrations/ # SQL migrations (managed via Supabase CLI)
│ └── config.toml
├── docs/
│ ├── prt.md # Pull request tracking plan
│ └── VITE_TO_NEXT_MIGRATION.md # Historical framework migration plan
├── vitest.config.ts
├── eslint.config.mjs
└── next.config.ts
| Command | Description |
|---|---|
npm run dev |
Start dev server |
npm run build |
Production build |
npm start |
Start production server |
npm run lint |
Run ESLint |
npm run typecheck |
Run TypeScript check |
npm test |
Run Vitest |
| Variable | Description |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase anonymous key |
The project uses two main tables managed through Supabase migrations:
- quizzes —
id,created_at,title,description,time_limit(nullable, CHECK 1–180) - questions —
id,created_at,quiz_id(FK),question_text,option_a–d,correct_index,points,order
Run npx supabase db push to apply migrations.
MIT
This is a personal study project. Feel free to fork and modify for your own use.