PWA Fitness App — Developer Documentation
Fitova is a production-ready, mobile-first fitness PWA built on Next.js 16 App Router with TypeScript, Tailwind CSS v4, and React 19. It ships as a complete frontend template — every screen designed, every form validated, every user flow connected.
It covers the full fitness app lifecycle: onboarding, authentication, workout discovery, food scanning, nutrition tracking, progress statistics, trainer profiles, subscriptions, and settings — 44 pages total, zero placeholders.
44
Pages
25+
UI Components
25
JSON Data Files
100%
TypeScript
📱
Installable on iOS and Android. Offline fallback via plain service worker, manifest.json included — no extra package required.
🔐
Login, signup, forgot password, OTP verification, and new password — all validated with React Hook Form + Zod v4.
🏋️
48 workouts across levels, categories, trainers. Filter, search, favorite, schedule, and play.
📷
Camera access with animated scan line. Upload or capture — shows apple result by default. Ready for backend integration.
📊
Chart.js weekly bar chart, circular progress rings, weight journey line chart, heart rate sparkline.
💳
Three plan tiers, saved cards, add-card with live preview, confirmation with tax breakdown.
🎨
CSS split into globals.css, components.css, images.css, animations.css. @theme tokens — no tailwind.config.js.
🔒
Next.js middleware reads fitzen-token cookie. Unauthenticated users redirected to /options.
💾
Context API + localStorage — no Zustand. UserProfile, notifications, favorites, food log, language all persisted.
♿
Semantic HTML, aria-labels, role attributes, sr-only labels, keyboard navigable throughout.
# 1. Install dependencies
npm install
# 2. Start development server
npm run dev
# 3. Open in browser
http://localhost:3000
| Script | Description |
|---|---|
npm run dev | Start Next.js dev server with HMR |
npm run build | Production build — outputs to .next/ |
npm run start | Serve the production build |
npm run lint | ESLint check across all .ts/.tsx files |
npm run format | Prettier format all source files |
npm run format:fix | Auto-fix formatting with Prettier |
| Route | Description |
|---|---|
/splash | Animated splash screen, auto-redirects to /onboarding |
/onboarding | 3-slide fullscreen carousel with swipe + dot indicators |
| Route | Description |
|---|---|
/options | Login method selector — Email, Google, Apple |
/login | Email + password form with validation |
/signup | Registration form — name, email, password |
/forgot-password | Email input to send reset link |
/check-email | Confirmation screen — check your inbox |
/reset-password | 6-digit OTP verification |
/new-password | Set new password with strength rules |
| Route | Description |
|---|---|
/setup/gender | Step 1/5 — gender card selection |
/setup/birthday | Step 2/5 — drum-roll date of birth picker |
/setup/weight | Step 3/5 — weight with kg ↔ lbs live toggle |
/setup/sports | Step 4/5 — multi-select sports emoji grid |
/setup/goal | Step 5/5 — fitness goal cards → saves full profile to context |
/setup/done | Success screen, 3s countdown auto-redirects to /home |
| Route | Description |
|---|---|
/home | Dashboard — categories, popular workouts, trainers, search, bell |
/search | Search idle — recent searches + filter modal |
/search/results | Filtered results by URL params (q, level, category) |
/notifications | Unread/read split, mark read, delete, clear all — localStorage |
/favorites | Bookmarked workouts — date grouped, search, toggle bookmark |
| Route | Description |
|---|---|
/statistics | Weekly bar chart, circular rings, heart rate sparkline |
/statistics/weight-journey | Running stats, route map, health metrics today |
| Route | Description |
|---|---|
/workouts | Workout listing with Beginner / Medium / Progressive tabs |
/workouts/[id] | Detail — hero video, share modal, exercise sections |
/workouts/[id]/play | Video player + rep-by-rep exercise list |
/workouts/[id]/sets | Section slider + weekly schedule |
/workouts/[id]/reviews | Rating bar chart + review cards with star rows |
/workouts/todays-best | Top of the day — filter tabs, lock/unlock grid, search modal |
| Route | Description |
|---|---|
/scan | Camera scanner — animated scan line, file upload, View Result button |
/scan/result | Scanned food — macros grid, save to log, scan again |
| Route | Description |
|---|---|
/trainers | Trainer listing with rating and specialty |
/trainers/[id] | Trainer profile — bio, workouts list, follow toggle |
| Route | Description |
|---|---|
/profile | User profile — stats, subscription badge, settings links |
/profile/edit | Edit name, email, gender, DOB, weight — RHF + Zod validated |
/schedule | Weekly workout schedule view |
/schedule/new | Create a new scheduled workout session |
| Route | Description |
|---|---|
/subscription | Plan selector — Monthly / Yearly / Lifetime with feature list |
/payment/method | Select saved card or add new — radio selection |
/payment/add-card | Live card preview, brand detection, masked number formatting |
/payment/confirmation | Order summary — price + tax + fee, animated success modal |
| Route | Description |
|---|---|
/settings/security | Password change, biometric toggle, 2FA |
/settings/language | Language picker — persists to localStorage, sets html[lang] |
/settings/help | FAQ accordion + contact support |
/settings/privacy | Privacy policy + data controls |
/splash → /onboarding (3 slides) → /options → /signup → /setup/gender → … → /setup/goal → /setup/done → /home
/splash → middleware reads fitzen-token cookie → /home (skips onboarding + setup)
/login → /forgot-password → /check-email → /reset-password (OTP) → /new-password → /login
/home → /workouts → /workouts/[id] → /workouts/[id]/play
or → /workouts/[id]/reviews
or → /workouts/[id]/sets
/scan (camera or upload) → 2.5s animation → View Result → /scan/result?food=fs1 → Save to Log
/subscription → /payment/method → /payment/add-card (optional) → /payment/confirmation → success modal → /home
Primary
Poppins
Weights 400, 500, 600, 700. Used for all body text, headings, and UI labels.
var(--font-sans)Brand / Logo
Anek Bangla
Used exclusively for the FITOVA logotype in the navigation header.
var(--font-brand)next/font/google in lib/fonts.ts — zero layout shift, automatic font subsetting, self-hosted by Next.js.| Use | Size |
|---|---|
| Page title | text-xl / 20px |
| Section header | text-base / 16px |
| Body | text-sm / 14px |
| Caption / meta | text-xs / 12px |
| Micro label | text-[10px] |
One change in styles/globals.css recolours the entire app:
Styles are split into four files, all imported by globals.css:
globals.css
@theme tokens, base reset, utility classes
components.css
All reusable UI component classes (btn, input, card…)
images.css
All background-image utility classes
animations.css
All @keyframes and animation classes
app/(main)/your-page/page.tsx<AppLayout> or use <div className="px-5 pt-5">HIDDEN_EXACT in BottomNavBar.tsx if nav should be hiddenlib/types.ts and mock data to data/data/ are drop-in mocks. To connect a real backend, create lib/api.ts with typed fetch wrappers and replace the JSON imports in each page — the component structure stays identical.src/lib/utils/constants.ts under STORAGE_KEYS, COOKIE_KEYS, and SESSION_KEYS. Never hardcode key strings.| Key | Type | Purpose |
|---|---|---|
fitzen-user-profile | JSON | Full UserProfile object — name, avatar, weight, goal, sports |
fitzen-token | string | Auth token copy in localStorage (cookie is the authoritative version) |
fitzen-setup-done | "1" | Flag — set after setup/goal step completes |
fitzen-favorites | JSON[] | Array of { workoutId, savedAt } — used by /favorites |
fitzen_notifications | JSON[] | NotificationItem[] — shared by home bell + /notifications |
fitzen_language | string | BCP-47 locale code e.g. 'en', 'ar' — applied to html[lang] |
fitzen-food-log | JSON[] | FoodLogEntry[] — written by /scan/result save button |
| Key | Type | Purpose |
|---|---|---|
fitzen-token | string | Auth cookie — set on login via document.cookie, read by middleware to protect routes |
| Key | Type | Purpose |
|---|---|---|
fitzen-pwa-dismissed | "1" | Hides PWA install banner for the current session |
fitzen-setup-gender | "1" | Guards /setup/birthday — must complete gender step first |
fitzen-setup-dob | "1" | Guards /setup/weight — must complete birthday step first |
fitzen-setup-weight | "1" | Guards /setup/sports — must complete weight step first |
fitzen-setup-sports | "1" | Guards /setup/goal — must complete sports step first |
AuthContext
Stores token + isLoggedIn. Writes fitzen-token cookie via document.cookie for middleware.
UserProfileContext
Full profile — name, avatar, weight, goal, sports. Persists to localStorage.
ScanContext
Camera stream state and last scan result.
public/manifest.json
App name, icons (7 sizes), theme colour, shortcuts
public/sw.js
Plain JS — cache-first for assets, network-first for pages. No build package needed.
public/offline.html
Self-contained HTML shown when user is offline and page is not cached
app/layout.tsx via a useEffect — no extra package required.iPhone notch and home indicator are handled with CSS env(safe-area-inset-*) via utility classes .safe-top, .safe-bottom, and .safe-x defined in styles/globals.css.
| Library / Resource | Version | Used For |
|---|---|---|
| Next.js 16 | 16.1.6 | App Router, RSC, file-based routing, image optimisation |
| React 19 | 19.2.3 | Concurrent features, Server Components, Actions |
| TypeScript | ^5 | Strict mode — all domain types in lib/types.ts |
| Tailwind CSS v4 | ^4 | @theme tokens in globals.css — no tailwind.config.js |
| React Hook Form | ^7.71 | All forms — auth, setup, edit profile, add card |
| Zod | ^4.3 | Schema validation, colocated with RHF resolvers |
| Sonner | ^2.0 | Toast notifications throughout the app |
| Chart.js + react-chartjs-2 | ^4.5 / ^5.3 | Weekly bar chart + weight journey line chart |
| Framer Motion | ^12 | Page transitions, bottom sheet animations |
| Lucide React | ^0.576 | All UI icons — consistent stroke-based set |
| date-fns | ^4.1 | Date formatting across schedule and statistics pages |
| Google Fonts — Poppins | — | Primary typeface across all screens |
| Google Fonts — Anek Bangla | — | FITZEN logotype on nav header |
If you have questions beyond the scope of this documentation, please contact via the ThemeForest item page. Typical response time is 24–48 hours.
Before reaching out, please:
npm run dev — not opening files directly.npm install completed without errors.NEXT_PUBLIC_ variables are set in .env.local before running the build.