From d2e090214aafb5b22df1f06fe5e2ed86b675e0bb Mon Sep 17 00:00:00 2001 From: Aravind Date: Thu, 10 Sep 2026 19:25:07 +0530 Subject: [PATCH] update the api --- src/app/(workspace)/commerce/page.tsx | 8 +-- src/app/(workspace)/dashboard/page.tsx | 8 +-- src/app/(workspace)/lyts/page.tsx | 24 ++++----- src/app/(workspace)/settings/profile/page.tsx | 3 +- src/app/(workspace)/staff/page.tsx | 7 +-- src/services/api/reportMapper.ts | 17 +++++-- src/services/api/types.ts | 18 +++++-- .../patterns/FeatureUnavailable.tsx | 50 +++++++++---------- 8 files changed, 65 insertions(+), 70 deletions(-) diff --git a/src/app/(workspace)/commerce/page.tsx b/src/app/(workspace)/commerce/page.tsx index 6a86142..c975ca6 100644 --- a/src/app/(workspace)/commerce/page.tsx +++ b/src/app/(workspace)/commerce/page.tsx @@ -57,13 +57,7 @@ export default function CommercePage() { ); diff --git a/src/app/(workspace)/dashboard/page.tsx b/src/app/(workspace)/dashboard/page.tsx index 02ac35d..7edc1b1 100644 --- a/src/app/(workspace)/dashboard/page.tsx +++ b/src/app/(workspace)/dashboard/page.tsx @@ -121,13 +121,7 @@ export default function DashboardPage() { ); diff --git a/src/app/(workspace)/lyts/page.tsx b/src/app/(workspace)/lyts/page.tsx index 6437dd7..01ceffa 100644 --- a/src/app/(workspace)/lyts/page.tsx +++ b/src/app/(workspace)/lyts/page.tsx @@ -7,31 +7,27 @@ import {FeatureUnavailable} from '@/shared/components/patterns/FeatureUnavailabl /** * LYTs. * - * The entire loyalty programme — reward catalogue, claims, redemptions, - * outstanding LYT liability, expiry windows, accrual rate — has no counterpart - * in the Loyaly platform contract. Every figure this page used to show was - * generated locally, including the "outstanding liability" a merchant would - * reasonably read as money they owe. + * The merchant-app specification (§2.1) states the product direction does NOT + * use loyalty points, LYT balances, redemption or tier calculation — so this + * is not a panel waiting on an endpoint, it is a feature the product dropped. + * The copy says that, rather than implying a reward catalogue is on its way. * - * The page is kept, and states what it needs. Nothing is simulated. + * Every figure this page used to show was generated locally, including an + * "outstanding liability" in rupees that a merchant would reasonably read as + * money they owe. The route is kept so an existing bookmark still lands + * somewhere that explains itself. Nothing is simulated. */ export default function LytsPage() { return ( ); diff --git a/src/app/(workspace)/settings/profile/page.tsx b/src/app/(workspace)/settings/profile/page.tsx index 69df6fc..baa414c 100644 --- a/src/app/(workspace)/settings/profile/page.tsx +++ b/src/app/(workspace)/settings/profile/page.tsx @@ -25,8 +25,7 @@ export default async function MerchantProfilePage() { ) : ( )} diff --git a/src/app/(workspace)/staff/page.tsx b/src/app/(workspace)/staff/page.tsx index b00f7e1..c6c9400 100644 --- a/src/app/(workspace)/staff/page.tsx +++ b/src/app/(workspace)/staff/page.tsx @@ -33,12 +33,7 @@ export default function LeaderboardPage() { ); diff --git a/src/services/api/reportMapper.ts b/src/services/api/reportMapper.ts index d3d7b92..ced5559 100644 --- a/src/services/api/reportMapper.ts +++ b/src/services/api/reportMapper.ts @@ -86,11 +86,18 @@ export function toConversion( revenue: current.revenue ?? 0, conversionPct: current.conversion ?? null, basketSize: current.average_basket ?? null, - // The server's conversion report is a scalar summary with no time series, - // so there is nothing to chart. Empty rather than fabricated. - buckets: [], - // SalesReport carries no timezone either; the footfall report names it. - timezone: null, + buckets: (current.points ?? []).map((p) => ({ + label: p.bucket, + // The conversion series carries no visitor split; those belong to the + // footfall report and are 0 here so the bucket shape stays uniform. + visitors: 0, + newVisitors: 0, + returningVisitors: 0, + purchases: p.baskets ?? 0, + revenue: p.revenue ?? 0, + conversion: 0, + })), + timezone: current.timezone ?? null, previousPurchases: previous?.purchasers ?? null, previousRevenue: previous?.revenue ?? null, }; diff --git a/src/services/api/types.ts b/src/services/api/types.ts index 22a6d05..0c37792 100644 --- a/src/services/api/types.ts +++ b/src/services/api/types.ts @@ -242,10 +242,19 @@ export interface ApiFootfallReport { } /** - * The conversion report is a SCALAR SUMMARY. The server's SalesReport carries - * no time series at all, so there is no `buckets`/`points` field to read and - * anything charting this over time needs a backend change first. + * The conversion report carries both the window totals and a `points` series. + * The totals are NOT the sum of the series: `purchasers` is unique people over + * the whole window, while a per-bucket `purchasers` counts somebody once per + * bucket they bought in. */ +export interface ApiSalesPoint { + bucket: string; + /** Distinct people who bought in THIS bucket. Not summable across buckets. */ + purchasers: number; + baskets: number; + revenue: number; +} + export interface ApiConversionReport { visitors: number; /** People who bought — named `purchasers`, not `purchases`. Reading the @@ -255,6 +264,9 @@ export interface ApiConversionReport { revenue: number; average_basket: number; currency?: string; + /** The time series, named `points` like the footfall report. */ + points?: ApiSalesPoint[]; + timezone?: string; } // --------------------------------------------------------------------------- diff --git a/src/shared/components/patterns/FeatureUnavailable.tsx b/src/shared/components/patterns/FeatureUnavailable.tsx index fa7b733..5c47d2d 100644 --- a/src/shared/components/patterns/FeatureUnavailable.tsx +++ b/src/shared/components/patterns/FeatureUnavailable.tsx @@ -7,33 +7,44 @@ import {Icon} from '@astryxdesign/core/Icon'; import {ICONS} from '@/shared/utils/icons'; /** - * "This needs a backend resource that does not exist yet." + * "This section has nothing to show yet, and here is why." * * ── Why this exists instead of fixture data ────────────────────────────── - * Several screens in this console were built against a loyalty domain — LYT - * balances, reward catalogues, engagement activities, product inventory — that - * the Loyaly platform does not expose. The choice was to keep inventing - * numbers or to say so. Invented numbers are worse than a blank panel: a - * merchant cannot tell them from real ones, and the first time they act on one - * the whole product loses its credibility. + * Several screens were built against a domain the platform does not record. + * The choice was to keep inventing numbers or to say so. Invented numbers are + * worse than a blank panel: a merchant cannot tell them from real ones, and + * the first time they act on one the whole product loses its credibility. * - * So the screen stays, its layout stays, and the panel states plainly what it - * is waiting for. When the endpoint ships, one hook replaces one component. + * ── Why there is no `endpoints` prop any more ──────────────────────────── + * There was. Every panel printed "Required backend resources" and then + * `GET /api/staff — shop-floor roster, distinct from console accounts`, in a + * monospace font, on a screen a shop owner opens to run their business. That + * is an engineering backlog rendered as product copy, and it breaks the same + * rule the merchant-app spec sets for the API itself (§35): expose business + * operations, not implementation details. A merchant cannot act on a route + * name — being shown one only says the product is unfinished. + * + * Gating it on `NODE_ENV` was tried and is NOT sufficient, which is worth + * recording because it looks like it should be: the arrays were passed as + * props from each page, so the literals were still constructed and still + * shipped in the production bundle — verified by grepping `.next/static` after + * a clean build. Not rendering is not the same as not shipping. The prop is + * gone instead, and what each section needs is recorded in the page's own + * doc comment, where the people who can act on it actually work. * * This is NOT an error state. The platform's own vocabulary has a status for * exactly this — 501, "the feature is off for this deployment, not an error" — * and the treatment is deliberately calm: secondary text, no red, no alarm. + * + * `description` is merchant copy. Write it as a sentence a shop owner would + * accept: what is missing, why, and what would change it — never a route. */ export function FeatureUnavailable({ title, description, - endpoints, }: { title: string; description: string; - /** The API resources this section needs. Naming them turns a dead end into - * a work item somebody can pick up. */ - endpoints?: string[]; }) { return ( @@ -46,19 +57,6 @@ export function FeatureUnavailable({ {description} - - {endpoints?.length ? ( - - - Required backend resources - - {endpoints.map((e) => ( - - {e} - - ))} - - ) : null} );