Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
162 lines
6.7 KiB
Markdown
162 lines
6.7 KiB
Markdown
# Consumer UI guidelines
|
||
|
||
Hard constraints for the end-user app under `frontend/app/(consumer)/` and
|
||
shared consumer surfaces (`components/consumer/*`, PWA/auth overlays used
|
||
there, event/review/booking flows).
|
||
|
||
Agents must follow the always-on Cursor rules
|
||
`consumer-modals`, `consumer-input`, `consumer-button`, and `consumer-mobile-first`. This doc is the longer
|
||
companion.
|
||
|
||
## 1. Overlays: ConsumerModal only
|
||
|
||
Any modal / dialog in the consumer app must use
|
||
`components/consumer/ConsumerModal`.
|
||
|
||
```tsx
|
||
// ❌ BAD — admin/shared Modal in consumer UI
|
||
import Modal from '@/components/modals/Modal'
|
||
|
||
// ✅ GOOD
|
||
import ConsumerModal from '@/components/consumer/ConsumerModal'
|
||
```
|
||
|
||
Do not use `components/modals/Modal`, HeroUI `Drawer`, or ad-hoc fixed
|
||
banners for consumer dialogs. Admin stays on `components/modals/Modal`
|
||
(see `admin-ui-guidelines.md`).
|
||
|
||
`ConsumerModal` is always a **bottom sheet** (phone and desktop). There is no
|
||
centered / top / auto placement.
|
||
|
||
## 3. Form fields: ConsumerInput only
|
||
|
||
Any text field, select, textarea, OTP, radio, checkbox, switch, or number
|
||
input in the consumer app must use `components/consumer/ConsumerInput`.
|
||
|
||
```tsx
|
||
// ❌ BAD — admin/shared Input in consumer UI
|
||
import Input from '@/components/formElements/Input'
|
||
|
||
// ✅ GOOD
|
||
import ConsumerInput from '@/components/consumer/ConsumerInput'
|
||
```
|
||
|
||
Do not use `components/formElements/Input` in consumer surfaces.
|
||
|
||
**Props:** use `size` (`sm` | `md` | `lg`), `radius`
|
||
(`full` | `control`, 10px), and `tone` (`muted` | `bordered`). `muted` applies
|
||
`#E2E2E280` fill; `bordered` is white surface + border. **Select is always
|
||
`muted`.** Do not pass HeroUI
|
||
`size`, `radius`, or `variant`.
|
||
|
||
**Standalone mode:** when the parent is not wrapped in `react-hook-form`, pass
|
||
`value` and `onValueChange` — `ConsumerInput` creates an internal form bridge.
|
||
|
||
**Custom wrappers:** pass `inputWrapper` to merge classes (auth full-radius
|
||
fields, host contact section).
|
||
|
||
**OTP styling:** pass `otpClassNames={{ segment, segmentWrapper }}` when the
|
||
default consumer OTP look is not enough (e.g. auth gate).
|
||
|
||
**Temporary exception:** `birthDatePicker`, `combobox`, and other admin-only
|
||
field kinds not yet in ConsumerInput v1 may keep `formElements/Input` for that
|
||
single field until support is added.
|
||
|
||
Implementation lives under `components/consumer/input/` (`ConsumerFieldShell`,
|
||
`consumerInputStyles.ts`, per-kind controls). Admin panel and event-create wizard
|
||
stay on `formElements/Input`.
|
||
|
||
## 4. Actions: ConsumerButton only
|
||
|
||
Any button, submit control, or link-styled action in the consumer app must use
|
||
`components/consumer/ConsumerButton`.
|
||
|
||
```tsx
|
||
// ❌ BAD — admin/shared Button in consumer UI
|
||
import Button from '@/components/formElements/Button'
|
||
|
||
// ✅ GOOD
|
||
import ConsumerButton from '@/components/consumer/ConsumerButton'
|
||
```
|
||
|
||
Do not use `components/formElements/Button` in consumer surfaces.
|
||
|
||
**Props:** use `fill` (`orange` | `navy` | `gray` | `none`), `size`
|
||
(`xs` | `sm` | `md` | `lg` | `xl`), `radius` (`full` | `control`), `textColor`,
|
||
`fontSize`, `align`, and icon props (`iconStart` / `iconEnd` / `iconOnly`). Do not
|
||
pass HeroUI `size`, `radius`, `variant`, or `color`.
|
||
|
||
**Size tokens (button heights):**
|
||
|
||
| `size` | height |
|
||
| ------ | ----------------------: |
|
||
| `xs` | 40px |
|
||
| `sm` | 44px |
|
||
| `md` | 48px |
|
||
| `lg` | 52px (default text CTA) |
|
||
| `xl` | 60px |
|
||
|
||
Default: `lg` for text buttons, `sm` for `iconOnly`.
|
||
|
||
**همنام بودن ≠ هماندازه بودن:** `ConsumerButton` `size` and `ConsumerInput`
|
||
`size` reuse labels (`sm`, `md`, `lg`) but map to **different pixel
|
||
heights**. Do not assume a field and a button with the same token name share
|
||
one height.
|
||
|
||
| token | `ConsumerButton` `size` | `ConsumerInput` `size` |
|
||
| ----- | ----------------------: | ---------------------: |
|
||
| `xs` | 40px | — |
|
||
| `sm` | 44px | 32px |
|
||
| `md` | 48px | 48px |
|
||
| `lg` | 52px | 52px |
|
||
| `xl` | 60px | — |
|
||
|
||
**Four button roles (+ icon chrome):**
|
||
|
||
| Role | API | Typical use |
|
||
| ------------------- | ----------------------------------------- | --------------------------------- |
|
||
| Conversion CTA | `fill="orange"` (default) | login, book, continue |
|
||
| Dark primary | `fill="navy"` | modal confirm, host CTAs |
|
||
| Inline / card pill | `fill="gray"` | cancel booking, nav chips, follow |
|
||
| Text / ghost action | `fill="none"` + `textColor` | change mobile, resend code, links |
|
||
| Destructive | `fill="none"` + `textColor="text-fourth-900"` | delete, cancel reservation |
|
||
| Icon-only | `iconOnly` + `size="sm"` | bookmark, share, edit on cards |
|
||
|
||
**Dual cancel/primary rows:** `ConsumerActionButtons` (modal footers,
|
||
`ConsumerFormActionBar`). Do not duplicate that layout.
|
||
|
||
**No ad-hoc visual `className`:** if Figma needs a look this component cannot
|
||
express via `fill`, `size`, `radius`, `textColor`, `fontSize`, or `align`, stop
|
||
and ask the product owner — do not patch with `bg-*`, `text-*`, `rounded-*`, etc.
|
||
Extend `ConsumerButton` only after explicit approval. Layout-only classes
|
||
(`flex-1`, `mt-5`, `shrink-0`, …) are fine.
|
||
|
||
Admin panel stays on `formElements/Button`.
|
||
|
||
## 5. Mobile excellence; desktop does not matter
|
||
|
||
The consumer app is a **mobile product**.
|
||
|
||
- Target phone widths (~360–430px) first and last.
|
||
- No horizontal scroll, clipped content, overlapping BottomNav, or ignored
|
||
safe-area insets.
|
||
- Touch targets ≥ 44px; primary CTAs reachable with one thumb when practical.
|
||
- Fix mobile layout bugs before any other visual work.
|
||
|
||
**Non-goal:** desktop / wide-viewport polish. Do not invest in multi-column
|
||
desktop layouts or large-screen aesthetics unless explicitly requested. A
|
||
correct phone layout always wins over a polished desktop layout.
|
||
|
||
Design tokens and patterns: [`docs/frontend/consumer-design-system.md`](../../docs/frontend/consumer-design-system.md).
|
||
Copy catalog: [`consumer-texts.md`](./consumer-texts.md).
|
||
|
||
## 6. Event cards
|
||
|
||
Use the single medium card `components/consumer/EventCard` everywhere.
|
||
|
||
- Fixed top: poster + date / time / category / location + title.
|
||
- Variable bottom: pass page-specific UI via `children` (inline `div`s).
|
||
- Optional helper: `EventCapacityBadge` for remaining-seat chips in discovery/host footers.
|
||
- Loading state: `EventCardSkeleton` / `EventCardSkeletonList`.
|
||
- Dense lists: `CompactEventCard` or `ConsumerEventThumbRow` when the medium card is too tall.
|