# Shop · Dashboard — Logic & Flows

Demo (canonical): `/private/tmp/Navagoo_MI_dev/navagoo-app/src/portals/shop/Dashboard.tsx`
Ours: `frontend/controllers/SiteController.php` (`actionIndex` + `buildDashboardStats`) → `frontend/views/site/index.php`

> **Headline finding:** The two dashboards are *not the same screen*. The demo is a
> **finance/rail-settlement dashboard** (net-available balance, costs breakdown, subscription
> status, booking link). Ours is a **bookings-analytics dashboard** (status counts, ratings,
> date-range filter, charts). They overlap only on "upcoming bookings" and the two count KPIs.
> Most of the demo's logic has **no equivalent** in our code because the underlying
> models (Subscription, Plan, Charge, Transfer/Settlement, Invoice) do not exist on our side.

---

## 1. Active-shop resolution
- **Demo** `Dashboard.tsx:44` — `shops.find(s => s.id === activeShopId) ?? shops[0]`. Multi-shop store; an active shop is selected.
- **Ours** `SiteController.php:85,132` — single shop bound to the logged-in user (`Yii::$app->user->identity->shop`). No multi-shop switching. Functionally fine for our 1-user-1-shop model.

## 2. KPI computation
- **Demo** `Dashboard.tsx:45-47,166-198`, via `shopKpis()` `selectors.ts:324-374`:
  - `counts.scheduled`, `counts.completed` — status counts over **all** shop bookings (`statusCounts`).
  - `netAvailable` = `availableSettlement.eligibleNet` — withdrawable rail balance after fees, excluding bookings already consumed by a transfer/invoice (`selectors.ts:331-338,365`).
  - `costsTotal` = `cb.subscription + cb.marketing + cb.paymentProcessing + cb.notif` from `costBreakdown()` `selectors.ts:399-409`.
  - `meetsWithdrawalMin` = `eligibleNet >= shop.minWithdrawalAmount` `selectors.ts:367`.
- **Ours** `SiteController.php:347-384` (`buildDashboardStats`):
  - 4 KPIs = **scheduled / completed / in_progress / cancelled** booking counts, each scoped to a **date range** and carrying a **trend %** vs the previous equal-length range (`calculateTrend` `:426-436`).
  - **No** net-available, **no** costs-to-date, **no** withdrawal-minimum KPI.
- **Status:** PARTIAL — only `scheduled` + `completed` counts match. The two financial KPIs (Net Available, Costs to Date) are **missing**. Ours adds `in_progress`, `cancelled`, and trend deltas the demo does not have.

## 3. Subscription banner
- **Demo** `Dashboard.tsx:133-163` — `subscriptionForShop` + `planById`; shows plan name, `free_period` badge, trial-end relative date, monthly price, next-billing date, card last-4; CTA → `/shop/finance`.
- **Ours** — **absent**. No Subscription/Plan model exists (`grep` over `common/models` returns nothing for subscription/plan/free_period). Our shop lifecycle uses `STATUS_AWAITING_CONTRACT`/contract-acceptance (`SiteController.php:103,820-933`), which is a different concept.
- **Status:** MISSING.

## 4. Bookings table (recent/today)
- **Demo** `Dashboard.tsx:51-106,215-220` — last 6 bookings sorted by `appointmentDate` desc; columns: When (date+time), Customer (avatar+name), Service (line names), Specialist, Value (Money), Status (SettlementBadge + BookingBadge). Row click → `/shop/bookings`.
- **Ours** `SiteController.php:438-486` (`getUpcomingBookings`) + view `index.php:66-91` — next **upcoming** (future, scheduled/in-progress) bookings, limit 5 (view re-slices to 6); columns: #, Customer, Appointment time (date+time), Duration, Specialist.
- **Differences:** ours shows *future* bookings only (demo shows recent/most-recent first incl. past); ours has **no Value column**, **no settlement badge**, **no booking-status badge**, no avatar; ours adds a **Duration** column the demo lacks; ours rows are not click-through.
- **Status:** PARTIAL.

## 5. Costs-to-date donut widget
- **Demo** `Dashboard.tsx:224-258` — Donut of total costs + 4 cost lines (Subscription, Marketing fees, Payment-processing fees, Notifications) from `costBreakdown()`; CTA → `/shop/finance`.
- **Ours** — **absent**. No `Charge` model; no cost breakdown. View even notes charts are "not yet ported" (`index.php:108-111`).
- **Status:** MISSING.

## 6. Action cards (booking link / invite / charges)
- **Demo** `Dashboard.tsx:262-291` — 3 cards: copy `deepLinkUrl` to clipboard (toast), invite customer → `/shop/customers`, detailed charges → `/shop/finance`.
- **Ours** — **absent**. No `deepLinkUrl`/booking-link field on Shop (only app-store deep links in `app-redirect.php`, unrelated). No quick-action card row on the dashboard.
- **Status:** MISSING.

## 7. Things ONLY ours has (not in demo dashboard)
- **Date-range filter** (`today`/`7d`/`30d`/`custom`, 30-day cap) `SiteController.php:270-329` + `actionDateRange` `:209-216`.
- **Trend deltas** vs previous period `:426-436`.
- **Store-rating** card (avg + stars + review count) `buildRatingSummary` `:590-625`, view `index.php:94-105`.
- **Specialist hours / occupancy**, **status summary**, **customer new-vs-returning series** computed `:505-693` — but **not rendered** (charts un-ported, `index.php:108-111`).
- **Gating logic**: phone-verification redirect, shop verification/contract status gate, forced logout for unverified shops `SiteController.php:88-141`. The demo has no such gating in this component.

## Date / number formatting
- Demo uses `lib/format.ts` (`money`, `num`, `dateLong`, `relativeDays`, `date`, `timeShort`). Ours uses Yii `formatter->asInteger/asDate/asTime`. Equivalent where features overlap; demo's `relativeDays`/`money(SAR)` have no use on our side because the subscription/costs features are absent.
