- OnboardingScreen used min-h-dvh instead of h-dvh, so the scrollable content area never actually clipped/scrolled internally; the page just grew and the primary CTA button scrolled away with it instead of staying visible. Switch to h-dvh and give each step's button a sticky footer (StepFooterButton). - SwipeCard crashed with "Cannot read properties of null" when a candidate had no photos, because the backend could return null instead of an empty array; guard with optional chaining.
دلدل — فرانت PWA اپ دیتینگ (Next.js + Basis Design System)
فرانت موبایلمحور و PWA برای بکاند Go/Gin/GORM که قبلاً ساختیم، با همون Basis Design System (نسخهی شاد و گرد Atlas): قرمز پرانرژی، گوشههای گرد، سایههای نرم، فونت Vazirmatn + Baloo 2.
ویژگیها
- ورود با شماره موبایل + کد OTP (بدون پسورد)
- ۸ مرحلهی آنبوردینگ دقیقاً مطابق API بکاند (با state machine که جلوی پرش از مرحله رو میگیره، ولی اجازهی برگشت و ویرایش میده)
- صفحهی پروفایل کامل با دکمهی ویرایش روی هر بخش (برمیگرده به همون مرحلهی آنبوردینگ، چون بکاند بعد از تکمیل کامل اجازهی ویرایش هر مرحله رو میده)
- شبیهسازی یک اپ سهتبه (کشف/پروفایل/تنظیمات) — تب «کشف» چون بکاند فعلاً matching نداره، حالت «بهزودی» نشون میده
- PWA کامل: قابل نصب روی گوشی (
manifest.webmanifest+ service worker + آیکون)، تمام صفحات موبایلفرست و محدود به عرض یک گوشی
✅ تست شده
قبل از تحویل، کل مسیر کاربر (درخواست OTP → تایید → ۸ مرحلهی آنبوردینگ →
پروفایل نهایی → رفرش توکن) با یک اسکریپت Node که دقیقاً همون درخواستهای
src/lib/api.ts رو میفرسته، روی یک نمونهی واقعی از بکاند گو اجرا و با
موفقیت پاس شد — شامل تستهای منفی (OTP اشتباه، انتخاب ناقص علاقهمندی).
یعنی قرارداد بین این فرانت و بکاندی که قبلاً تحویل گرفتی، تضمینشده همخونه.
راهاندازی
۱) تنظیم آدرس بکاند
cp .env.local.example .env.local
و NEXT_PUBLIC_API_URL رو به آدرس واقعی بکاندت تغییر بده (پیشفرض
http://localhost:8080/api/v1).
۲) نصب و اجرا
npm install
npm run dev
http://localhost:3000 رو باز کن. برای تست موبایل واقعی، از ابزار
device-toolbar مرورگر استفاده کن یا با آیپی لوکال شبکه از گوشی وصل شو.
۳) نصب بهعنوان PWA
- اندروید/کروم: منوی مرورگر → «Add to Home screen»
- iOS/Safari: دکمهی Share → «Add to Home Screen»
بعد از نصب، اپ بدون نوار آدرس مرورگر و با آیکون اختصاصی روی صفحهی اصلی گوشی باز میشه.
ساختار پروژه
src/
├── app/
│ ├── layout.tsx ← فونت، متادیتای PWA، AuthProvider
│ ├── page.tsx ← ریدایرکت اولیه بر اساس وضعیت کاربر
│ ├── login/page.tsx ← ورود با شماره موبایل
│ ├── verify/page.tsx ← تایید کد OTP
│ ├── onboarding/
│ │ ├── [slug]/page.tsx ← صفحهی داینامیک هر ۸ مرحله
│ │ └── done/page.tsx ← صفحهی تبریک پایان آنبوردینگ
│ └── (main)/ ← اپ اصلی بعد از آنبوردینگ (با BottomNav)
│ ├── layout.tsx
│ ├── home/page.tsx ← کشف (placeholder "بهزودی")
│ ├── profile/page.tsx ← پروفایل کامل + دکمهی ویرایش هر بخش
│ └── settings/page.tsx ← خروج از حساب + آیتمهای "بهزودی"
├── components/
│ ├── ui/ ← کامپوننتهای پایهی دیزاینسیستم
│ ├── onboarding/ ← wrapper و ۸ کامپوننت هر مرحله
│ └── BottomNav.tsx
└── lib/
├── api.ts ← کلاینت تایپشدهی کامل API (منطبق با بکاند گو)
├── auth-context.tsx ← مدیریت وضعیت ورود/کاربر/آنبوردینگ
├── token-store.ts ← ذخیرهی توکنها در localStorage
├── onboarding-steps.ts ← ترتیب و متادیتای ۸ مرحله
└── hooks.ts ← useRequireAuth، فرمت خطا
نکات فنی مهم
- رفرش خودکار توکن: اگه access token منقضی بشه،
api.tsخودکار با refresh token یه توکن جدید میگیره و درخواست رو یکبار دوباره میفرسته؛ کاربر چیزی حس نمیکنه. - گارد مراحل آنبوردینگ: هر صفحهی مرحله چک میکنه که کاربر اجازهی
دیدن اون مرحله رو داره یا نه (بر اساس
current_stepاز بکاند)؛ اگه بخواد از روی مرحله بپره، خودکار به مرحلهی درست برمیگرده. - فونت self-hosted: مثل دیزاینسیستم قبلی، فونتها از
@fontsource-variableمیان (نهnext/font/google) تا هیچوقت به گوگل وصل نشه. - CORS: بکاند گو از قبل CORS باز داره، پس این فرانت روی هر پورت/دامنهای بدون تنظیم اضافه بهش وصل میشه.
محدودیت شناختهشده
تب «کشف» (matching/کشف افراد) و بخش چت هنوز در بکاند پیاده نشدن، پس فقط
یک EmptyState با برچسب «بهزودی» نشون داده میشه. هر وقت اون endpoint ها
رو ساختی، فقط کافیه src/app/(main)/home/page.tsx رو با فراخوانی API واقعی
جایگزین کنی.