Admin dashboard for Culturo, a culture & geography quiz platform — manage users, quizzes, categories, countries, player ranks and the leaderboard from a single, polished interface.
A single-page admin application built with React 19 + TypeScript + Vite, styled with TailwindCSS v4 and powered by a separate NestJS REST API. The UI is in French; the codebase and documentation are in English.
| Users | Categories |
|---|---|
![]() |
![]() |
| Quizzes | Countries & Continents |
![]() |
![]() |
| Ranking | Hall of Fame |
![]() |
![]() |
| Settings | Sign in |
![]() |
![]() |
- Dashboard — global platform stats (users, quizzes, categories, countries) with live data and lazy-loaded charts (continent distribution donut + top categories bar chart via Recharts).
- User management — browse, search and sort registered accounts, with admin stats (new sign-ups this week).
- Categories — full CRUD with image/icon upload and per-category quiz counts.
- Quizzes — manage quiz questions and answers.
- Countries & Continents — CRUD with flag upload, grouped by continent.
- Ranking (Classement) — configure player ranks and score thresholds.
- Hall of Fame — top players leaderboard.
- Settings — platform configuration and admin info.
- Authentication — JWT sign-in, protected routes, admin-only guard, and a dedicated unauthorized page.
- ⚡ Code-splitting & route prefetching — pages and the heavy Recharts bundle are lazy-loaded; other routes are prefetched during idle time for instant navigation.
- 🔁 Shared query cache — TanStack Query keys are reused across pages (e.g. the dashboard and categories share
/admin/stats) to avoid duplicate requests. - 🌐 Resilient to cold starts — a keep-alive hook and an offline banner gracefully handle the backend waking up (free-tier hosting).
- 🎨 Custom design system — a reusable UI component library (Button, Card, Modal, Input, Select, Badge, Tooltip, EmptyState, Skeleton…) on a hand-tuned brand palette.
- 🧱 Type-safe forms —
react-hook-form+zodvalidation throughout.
| Area | Technology |
|---|---|
| Framework | React 19, TypeScript |
| Build tool | Vite 8 |
| Styling | TailwindCSS v4 |
| Data fetching | TanStack Query v5, Axios |
| Routing | React Router v7 |
| State | Zustand |
| Forms & validation | React Hook Form, Zod |
| Charts | Recharts |
| Animation | Framer Motion |
| Icons | Lucide React |
| Notifications | React Hot Toast |
| Linting | ESLint (typescript-eslint) |
- Node.js 20+ and npm
# 1. Clone the repository
git clone https://github.com/<your-username>/culturo-admin.git
cd culturo-admin
# 2. Install dependencies
npm install
# 3. Configure the environment
cp .env.example .env
# then edit .env and set VITE_API_URL to your backend URL
# 4. Start the dev server
npm run devThe app runs at http://localhost:5173.
| Variable | Description | Example |
|---|---|---|
VITE_API_URL |
Base URL of the Culturo backend API | http://localhost:3000/api |
VITE_REQUIRE_ADMIN |
Restrict access to admin accounts only | true |
.envis git-ignored. Use.env.exampleas a template.
| Command | Description |
|---|---|
npm run dev |
Start the Vite dev server with HMR |
npm run build |
Type-check and build for production |
npm run preview |
Preview the production build locally |
npm run lint |
Run ESLint over the project |
src/
├── api/ # Axios instance & interceptors
├── assets/ # Static images
├── components/
│ ├── layout/ # Sidebar, Topbar
│ ├── shared/ # StatCard, …
│ └── ui/ # Design-system primitives (Button, Card, Modal, …)
├── hooks/ # useKeepBackendAlive, usePrefetchRoutes, useTheme
├── layouts/ # AdminLayout (persistent shell)
├── pages/ # Route pages (dashboard, users, categories, quizzes, …)
├── routes/ # Router config & ProtectedRoute
├── services/ # Typed API service modules
├── store/ # Zustand stores (auth, ui, activity)
├── types/ # Shared TypeScript types
└── utils/ # Helpers (formatting, csv export, classnames)
This repository contains only the admin front-end. It consumes a separate NestJS REST API (not included here). Point VITE_API_URL at a running instance of that API.
Released under the MIT License.








