Folders under src/components/. Components consume view-models (src/lib/view-models) produced by services (src/lib/services) backed by mock repositories (src/lib/mock/repositories) implementing ports (src/lib/domain/ports).
components/search — the booking heart
| Component | Props (summary) | Consumes |
|---|
ListingSearch | variant hero/compact, initial | composes pickers, pushes /search? query |
DestinationPicker | value, onChange | DESTINATIONS + recent searches + quick suggestions |
DateRangePicker | range, onChange | base-ui Calendar (range) |
GuestSelector | value {adults,children,rooms}, onChange | — |
SearchFiltersPanel | filters, onChange, onReset | SearchFilters, AMENITIES |
recent-searches.ts | get/push helpers | localStorage |
components/listing
| Component | Props | Consumes |
|---|
ListingCard | listing ListingCardVM, layout, priority | ListingCardVM |
ListingGallery | seeds, name | image seeds (lightbox) |
ListingBadges | badges, limit | ListingBadge[] |
UnitRow | unit, action | InventoryUnit |
AmenityList | groups | AmenityGroupVM[] |
PolicyList | policy | ListingPolicy |
ListingHighlights | highlights | string[] |
NearbyList | places | NearbyPlace[] |
ListingFaqList | faqs | ListingFaq[] |
RecommendationRail | listings | ListingCardVM[] |
components/booking
| Component | Props | Consumes |
|---|
ReservationProvider / useReservation | — | carries selection + confirmed across the flow |
ListingBooking | listing | room selection + sticky widget, sets selection |
ReservationFlow | — | reservationService quote/confirm |
ReservationStepper | current | — |
GuestForm | value, coupon handlers | GuestProfile |
PaymentMock | method, onMethodChange | PaymentMethod |
PriceSummary | quote | ReservationQuote |
OrderSummary | selection, quote | ReservationSelection + quote |
components/review
| Component | Props | Consumes |
|---|
RatingBadge | score, count, label | — |
RatingBreakdown | categories | CategoryScores |
ReviewCard | review | Review |
ReviewList | reviews | Review[] |
components/shared
| Component | Notes |
|---|
SiteHeader, SiteFooter, MobileNav | platform chrome |
ThemeToggle | dark/light (next-themes) |
BrandSwitcher | live re-skin across 5 brand themes |
AmenityIcon | key → Phosphor icon registry |
Stars, Price, SectionHeading, EmptyState, MapPlaceholder, Reveal, DestinationCard, PromoCard | reusable primitives |
components/ui
shadcn/ui (base-ui primitives): button, card, badge, input, select, separator, tabs, skeleton, avatar, sonner, accordion, dialog, sheet, popover, label, dropdown-menu, calendar, checkbox, slider, radio-group, tooltip.
Partner phase additions
New reusable primitives (components/admin/, shared by Partner/Admin/Customer/Affiliate)
| Component | Purpose | Notes |
|---|
AppShell | Sidebar + topbar + mobile sheet shell | Generic; takes nav, workspace, toolbar slot. Reuses ThemeToggle, BrandSwitcher, Avatar |
SidebarNav | Vertical nav with active state | usePathname; generic NavItem[] |
PageHeader | Title + description + actions | Server component |
StatCard | KPI tile with delta | Server component |
StatusBadge | Tone-based status pill | Token-based tones (success/warning/info/danger/muted) |
DataTable<T> | Generic typed table | Lightweight, optional row click + empty slot |
BarChart | CSS bar chart | No chart library |
DonutChart | SVG donut + legend | No chart library |
New Partner feature views (features/partner/)
PartnerShell, PartnerWorkspaceProvider/WorkspaceSwitcher, PartnerDashboardView, PartnerBookingsView, PartnerRateCalendarView, PartnerListingsView, PartnerRevenueView.
Reused as-is on Partner
ThemeToggle, BrandSwitcher, EmptyState, formatVnd/formatVndShort, photo() image resolver, ui/* (Card, Sheet, Tabs, Select, Popover, Input, Label, Checkbox, Accordion, Skeleton, Avatar, Button, sonner toast), domain models + partnerService (new) over the same ports->mock-repository seam.
New backend-ready seam (swap repo only)
- Models:
lib/domain/models/partner.ts (BookingRecord, PartnerKpis, RevenuePoint, ChannelRevenue, ListingPerformance, RateDay, ManagedListing + status/channel label & tone maps).
- Port:
lib/domain/ports/partner-repository.ts (PartnerRepository).
- Mock data:
lib/mock/data/reservations.ts (64 deterministic bookings), lib/mock/data/rates.ts (deterministic rate/availability).
- Repo:
lib/mock/repositories/mock-partner.repository.ts; Service: lib/services/partner.service.ts wired in lib/services/index.ts as partnerService.
Platform Admin phase
- Model:
lib/domain/models/platform.ts (PartnerAccount, CustomerAccount, AffiliateAccount, ApprovalItem, PlatformKpis, OversightBooking, CmsEntry, PlatformAnalytics + label/tone maps).
- Port:
lib/domain/ports/platform-repository.ts (PlatformRepository).
- Mock data:
partners.ts (partitions 18 listings -> partner GMV, + pending applicants & listings, approval queue), customers.ts (52), affiliates.ts (12), cms.ts (entries + analytics).
- Repo:
lib/mock/repositories/mock-platform.repository.ts; Service: lib/services/platform.service.ts wired as platformService.
- Features:
features/admin/* (platform-shell + 6 views). NEW shared: none beyond Partner's components/admin (all reused). Modified shared: components/admin/app-shell.tsx gained optional brandName/brandHref props (default to Partner branding) so the same shell serves both portals.
Customer phase
- Model:
lib/domain/models/customer.ts (CustomerProfile, CustomerKpis, CustomerVoucher + VoucherStatus label/tone, PendingReview, PaymentState + paymentStateOf derived from BookingStatus, TimelineStep).
- Port:
lib/domain/ports/customer-repository.ts (CustomerRepository).
- Repo:
lib/mock/repositories/mock-customer.repository.ts (computes CURRENT_CUSTOMER = most-frequent guestName in BOOKINGS; all projections derive from BOOKINGS filtered by it; vouchers from PROMOTIONS; wishlist deterministic LISTINGS subset). Service: lib/services/customer.service.ts wired as customerService.
- NEW generic shared components (reusable by any portal):
components/shared/reservation-timeline.tsx (mount-animated status timeline), components/shared/star-rating-input.tsx (interactive stars), components/shared/voucher-card.tsx (ticket-style voucher).
- Features:
features/customer/* (customer-shell + 7 views). Reuses AppShell/SidebarNav, ListingCard, ReviewCard, PriceSummary, DataTable/StatCard/StatusBadge/PageHeader/EmptyState.
- Routes:
app/(customer)/customer/ (layout + 7 pages incl. dynamic bookings/[id] + loading).
Affiliate Portal — components
- features/affiliate/: affiliate-shell (reuse AppShell+SidebarNav), dashboard-view, links-view, commissions-view, payouts-view, materials-view.
- NEW shared: components/shared/qr-code.tsx (deterministic QR-style module grid, no external lib).
- Seam: lib/domain/models/affiliate.ts, lib/domain/ports/affiliate-repository.ts, lib/mock/repositories/mock-affiliate.repository.ts, lib/services/affiliate.service.ts, lib/mock/data/affiliate-portal.ts.
- Reused: StatCard, DataTable, StatusBadge, BarChart, PageHeader, EmptyState, Tabs/Input/Label/Button/Card/Skeleton, photo(), formatVnd/formatVndShort.