TorbatYar/frontend/docs/shared-components-report.md
Mortezakoohjani 6f4a484051 Migrate Beauty, Healthcare, and Accounting frontend to modular src/modules architecture.
Move business logic out of App Router into module packages, add boundary validation scripts, and keep all routes as thin re-exports without changing URLs or API behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 22:28:27 +03:30

328 lines
12 KiB
Markdown

# TorbatYar Frontend — Shared Components Report
**Date:** 2026-07-26
**Scope:** `components/` inventory, design system analysis, duplication mapping
---
## 1. Component Layer Overview
The frontend operates a **three-tier component hierarchy**:
```
Tier 1 — Platform DS components/ds/ (primary, ~90+ consumers)
Tier 2 — Marketing DS components/ui/ (legacy, ~10 consumers)
Tier 3 — Module DS components/{module}/design-system|ui/
Module pages components/{module}/pages/
Module shells components/{module}/*Shell.tsx
```
---
## 2. Primary Design System (`components/ds/`)
### File inventory
| File | Exports | Role |
|------|---------|------|
| `index.ts` | Barrel | Public API |
| `Button.tsx` | `Button` | CVA variants, ref forwarding |
| `Input.tsx` | `Input` | Text input |
| `Card.tsx` | `Card`, subcomponents | Surface container |
| `Badge.tsx` | `Badge` | Semantic tones (success/warning/danger/info) |
| `Dialog.tsx` | `Dialog`, `ConfirmDialog` | Modal dialogs |
| `Drawer.tsx` | `Drawer` | Side panel |
| `DatePicker.tsx` | `DatePicker` | Jalali calendar |
| `FormControls.tsx` | `FormField`, `Select`, `Checkbox`, `MoneyInput`, `Tabs` | Form primitives |
| `NavChrome.tsx` | `TableToolbar`, `Pagination`, `Breadcrumbs`, `Skeleton` | Navigation/table chrome |
| `Page.tsx` | `PageHeader`, `EmptyState`, `LoadingState`, `ErrorState`, `DataTable`, `StatCard` | Page scaffolding |
### DS export surface (from `index.ts`)
```typescript
Button, Input, Card, Badge, Dialog, ConfirmDialog,
PageHeader, EmptyState, LoadingState, ErrorState,
DataTable, StatCard, DatePicker, Drawer, Select,
FormField, Checkbox, MoneyInput, Tabs,
TableToolbar, Breadcrumbs, Skeleton, Pagination
```
### Adoption by module
| Consumer | Approx. import sites |
|----------|---------------------:|
| Accounting | 40+ |
| Beauty | 30+ |
| Healthcare | 25+ |
| Platform (admin, auth, settings) | 10+ |
**Boundary compliance:**`components/ds/` imports nothing from domain modules.
### Known DS gap
`components/ds/Button.tsx` does **not** expose a `loading` prop, but accounting routes use `<Button loading={...}>` — causing the current build failure. The legacy `components/ui/Button.tsx` **does** support `loading`.
---
## 3. Legacy Marketing UI (`components/ui/`)
### File inventory
| File | Exports |
|------|---------|
| `Button.tsx` | `Button` (with `loading` prop) |
| `Badge.tsx` | `Badge` (variant-based) |
| `Container.tsx` | `Container` |
| `SectionTitle.tsx` | `SectionTitle` |
| `AppTile.tsx` | `AppTile` |
| `index.ts` | Barrel |
### Consumers (~10 files)
- `app/page.tsx` (platform home)
- `app/login/page.tsx`, `app/register/page.tsx`, `app/onboarding/page.tsx`
- `app/dashboard/page.tsx`
- `components/auth/AuthPanel.tsx`
- `components/AppStoreGrid.tsx`
- `components/TenantSitePage.tsx`
### Duplicate components: DS vs UI
| Component | DS path | UI path | Key difference |
|-----------|---------|---------|----------------|
| **Button** | `ds/Button.tsx` | `ui/Button.tsx` | UI has `loading` prop; DS uses CVA + ref |
| **Badge** | `ds/Badge.tsx` | `ui/Badge.tsx` | DS uses `tone`; UI uses `variant` |
**Recommendation:** Deprecate `components/ui/Button` and `Badge`; add `loading` to DS Button; migrate 10 consumer files.
---
## 4. Platform Shared Components (root `components/`)
| Component | Role | Used by |
|-----------|------|---------|
| `AuthGuard.tsx` | Redirect unauthenticated users | All module layouts |
| `AdminAuthGuard.tsx` | Admin-specific auth | Admin layout |
| `ThemeProvider.tsx` | White-label theme loader | Root layout |
| `SiteHeader.tsx` | Global navigation bar | Root layout (all routes) |
| `TenantSwitcher.tsx` | Workspace selector | SiteHeader |
| `RouteProgress.tsx` | Navigation progress bar | Accounting layout |
| `AppStoreGrid.tsx` | SuperApp module launcher | Dashboard |
| `TenantSitePage.tsx` | Tenant subdomain landing | Platform home |
| `HealthStatus.tsx` | Service health display | **UNUSED (dead code)** |
---
## 5. Providers (`components/providers/`)
| Provider | Context? | Responsibility |
|----------|----------|----------------|
| `AppProviders.tsx` | No (QueryClient only) | TanStack Query + Sonner toaster |
| `ColorModeProvider.tsx` | Yes | Light/dark mode, `localStorage` persistence |
**Provider stack in root layout:**
```
ThemeProvider → ColorModeProvider → AppProviders → SiteHeader + main
```
No auth context — auth state accessed via `useMe()` hook hitting TanStack Query cache.
---
## 6. Module Shells
### Side-by-side comparison
| Feature | AccountingShell | BeautyPortalShell | HealthcarePortalShell |
|---------|-----------------|-------------------|----------------------|
| Sidebar nav | ✅ | ✅ | ✅ |
| Collapsible groups | ✅ | ✅ | ✅ |
| Mobile drawer | ✅ | ✅ | ✅ |
| Tenant display | ✅ | ✅ | ✅ |
| Nav source | `lib/accounting-nav.ts` | `lib/beauty-portals.ts` | `lib/healthcare-portals.ts` |
| Portal ID param | N/A | ✅ | ✅ |
| Lines of code | ~200 | ~220 | ~220 |
| Similarity | — | ~90% identical structure | ~90% identical structure |
### Portal layout factory
| Module | File | Portal IDs |
|--------|------|------------|
| Beauty | `components/beauty/createPortalLayout.tsx` | customer, owner, reception, staff, admin |
| Healthcare | `components/healthcare/createPortalLayout.tsx` | patient, doctor, reception, clinic, hospital, pharmacy, admin |
Both factories implement identical gate logic:
1. `AuthGuard`
2. `useMe()` loading/error/onboarding check
3. Tenant ID validation
4. Render domain portal shell
**Duplication estimate:** ~95% code overlap between the two factory files.
---
## 7. Module Design Systems
### Beauty (`components/beauty/design-system/`)
| File | Exports |
|------|---------|
| `tokens.ts` | Status tone maps, accent constants |
| `BeautyStatusChip.tsx` | Domain status badges |
| `BeautyCards.tsx` | CardShell, SalonCard, ServiceCard, TimelineItem, StatWidget |
| `BeautyPrimitives.tsx` | StatWidget, SearchResultRow |
| `BeautyTablePage.tsx` | Searchable DataTable wrapper |
| `index.ts` | Barrel |
### Healthcare (`components/healthcare/ui/`)
| File | Exports |
|------|---------|
| `tokens.ts` | Status tone maps (+ prescriptionStatusTone) |
| `MedicalStatusChip.tsx` | Domain status badges |
| `HealthcareCards.tsx` | CardShell, ClinicCard, DoctorCard, TimelineItem, StatWidget |
| `index.ts` | Barrel |
**Naming inconsistency:** Beauty uses `design-system/` folder; healthcare uses `ui/` folder for the same concept.
### Duplicated module DS components
| Concept | Beauty | Healthcare | Similarity |
|---------|--------|------------|------------|
| Status chip | `BeautyStatusChip` | `MedicalStatusChip` | ~85% |
| Card shell | `CardShell` in BeautyCards | `CardShell` in HealthcareCards | ~95% |
| Stat widget | `StatWidget` in BeautyPrimitives | `StatWidget` in HealthcareCards | ~98% |
| Timeline item | `TimelineItem` in BeautyCards | `TimelineItem` in HealthcareCards | ~90% |
| Search result row | `SearchResultRow` in BeautyPrimitives | (inline in public pages) | ~80% |
| Table page wrapper | `BeautyTablePage` | None | — |
| Tokens | `design-system/tokens.ts` | `ui/tokens.ts` | ~90% |
---
## 8. Page Bundles
Large co-located page component files serving multiple routes:
| File | Lines | Routes served |
|------|------:|---------------|
| `beauty/pages/public.tsx` | 753 | ~20 site routes |
| `beauty/pages/owner.tsx` | ~400+ | ~6 owner re-export routes |
| `beauty/pages/customer.tsx` | 442 | ~20 customer routes |
| `beauty/pages/reception.tsx` | ~350+ | ~10 reception routes |
| `healthcare/pages/patient.tsx` | 552 | ~18 patient routes |
| `healthcare/pages/doctor.tsx` | 537 | ~16 doctor routes |
| `healthcare/pages/public.tsx` | 467 | ~15 site routes |
### Shared page helpers
| File | Exports |
|------|---------|
| `beauty/pages/shared.tsx` | PageLoader, PageError, ServiceMetaBadges, MetricsGrid, audit helpers |
| `healthcare/pages/shared.tsx` | Same pattern — near copy-paste |
---
## 9. Accounting Screen Aggregators
Large reusable components (not route pages):
| File | Lines | Purpose |
|------|------:|---------|
| `BusinessDocsPage.tsx` | 1,328 | Document management screens |
| `WorkflowScreens.tsx` | 1,132 | Workflow UI (approvals, compliance) |
| `OperationalDocumentPage.tsx` | 996 | Voucher/document editing |
| `DomainScreens.tsx` | 652 | Domain-specific list screens |
| `SpecializedOpsPage.tsx` | ~400+ | Specialized operations |
| `EntityCombobox.tsx` | ~200+ | Entity picker |
| `CompletionScoreboard.tsx` | ~150+ | Setup progress |
These are shared **within accounting only** — correct boundary, but files are too large.
---
## 10. Public Site Layouts
| Component | Module | Unique elements |
|-----------|--------|-----------------|
| `PublicBeautyLayout.tsx` | Beauty | `--beauty-accent`, beauty branding |
| `PublicHealthcareLayout.tsx` | Healthcare | `--health-accent`, healthcare branding |
Both provide: hero header, footer, mobile nav, booking CTA. Structure ~90% identical.
---
## 11. Deprecated / Dead Components
| Component | Status | Action |
|-----------|--------|--------|
| `BeautyBusinessShell.tsx` | `@deprecated` in source | Remove after confirming zero imports |
| `HealthStatus.tsx` | Zero imports | Delete |
| `beauty/pages/mobile.tsx` (`MobilePortalFrame`) | Zero imports | Delete |
---
## 12. Component Usage Matrix
| Component category | Accounting | Beauty | Healthcare | Platform |
|--------------------|:----------:|:------:|:----------:|:--------:|
| `ds/Button` | ✅ | ✅ | ✅ | ❌ (uses ui) |
| `ds/DataTable` | ✅ | ✅ | ✅ | ❌ |
| `ds/FormField` | ✅ | ✅ | ❌ | ❌ |
| `ds/DatePicker` | ✅ | ❌ | ❌ | ❌ |
| `ds/MoneyInput` | ✅ | ❌ | ❌ | ❌ |
| `ui/Button` | ❌ | ❌ | ❌ | ✅ |
| Module status chip | ❌ | ✅ | ✅ | ❌ |
| Module CardShell | ❌ | ✅ | ✅ | ❌ |
| Portal shell | AccountingShell | BeautyPortalShell | HealthcarePortalShell | AdminShell |
---
## 13. Consolidation Roadmap
### Priority 1 — Unify Button/Badge (Phase 0)
Add `loading` prop to `ds/Button`; migrate `ui/` consumers; deprecate `ui/Button` and `ui/Badge`.
### Priority 2 — Extract portal infrastructure (Phase 2)
```
components/portals/
├── PortalShell.tsx # Base sidebar shell (parametric nav)
├── createPortalLayout.tsx # Single factory
├── PublicSiteLayout.tsx # Parametric public layout
├── PageHelpers.tsx # Merged shared.tsx helpers
├── DomainCardShell.tsx # Parametric CardShell + StatWidget
└── DomainStatusChip.tsx # Parametric status chip
```
### Priority 3 — Split large files (Phase 4)
- Accounting screen aggregators → one file per screen domain
- Page bundles → one file per route group (e.g. `customer/wallet.tsx`)
---
## 14. Summary
| Metric | Value |
|--------|------:|
| DS component files | 11 |
| UI (legacy) component files | 6 |
| Duplicate Button implementations | 2 |
| Duplicate Badge implementations | 2 |
| Duplicate portal factories | 2 |
| Duplicate portal shells | 3 (90% similar) |
| Duplicate shared page helpers | 2 (near copy-paste) |
| Dead components | 3 |
| Largest component file | 1,328 lines (`BusinessDocsPage.tsx`) |
The shared design system (`components/ds/`) is the correct foundation. The primary issue is **parallel implementations** at the module layer (beauty vs healthcare) and **legacy UI coexistence** at the platform layer.
---
## Related Documents
- [frontend-architecture-audit.md](./frontend-architecture-audit.md)
- [frontend-migration-plan.md](./frontend-migration-plan.md)
- [dependency-report.md](./dependency-report.md)