@aglyn/plugins-commerce 1.0.0-beta.191 → 1.0.0-beta.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-commerce",
3
- "version": "1.0.0-beta.191",
3
+ "version": "1.0.0-beta.192",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,18 +25,18 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.191",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.191",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.191",
31
- "@aglyn/shared-ui-next": "1.0.0-beta.191",
32
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.191",
33
- "@aglyn/shared-util-email": "1.0.0-beta.191",
34
- "@aglyn/shared-util-http": "1.0.0-beta.191",
35
- "@aglyn/shared-util-timestamp": "1.0.0-beta.191",
36
- "@aglyn/shared-util-tools": "1.0.0-beta.191",
37
- "@aglyn/tenant-data-admin": "1.0.0-beta.191",
38
- "@aglyn/tenant-feature-instance": "1.0.0-beta.191",
39
- "@aglyn/tenant-runtime": "1.0.0-beta.191",
28
+ "@aglyn/aglyn": "1.0.0-beta.192",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.192",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.192",
31
+ "@aglyn/shared-ui-next": "1.0.0-beta.192",
32
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.192",
33
+ "@aglyn/shared-util-email": "1.0.0-beta.192",
34
+ "@aglyn/shared-util-http": "1.0.0-beta.192",
35
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.192",
36
+ "@aglyn/shared-util-tools": "1.0.0-beta.192",
37
+ "@aglyn/tenant-data-admin": "1.0.0-beta.192",
38
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.192",
39
+ "@aglyn/tenant-runtime": "1.0.0-beta.192",
40
40
  "@stripe/react-stripe-js": "^3.10.0",
41
41
  "@stripe/stripe-js": "^5.10.0",
42
42
  "@swc/helpers": "0.5.23",
@@ -303,8 +303,8 @@ const GLANCE_PRODUCT_CEILING = 250;
303
303
  minWidth: 0
304
304
  },
305
305
  children: [
306
- order.orderNumber ? formatOrderNumber(order.orderNumber) : order.$id.slice(0, 8),
307
- order.email ? ` · ${order.email}` : ''
306
+ order.number != null ? formatOrderNumber(order) : order.$id.slice(0, 8),
307
+ order.customerEmail ? ` · ${order.customerEmail}` : ''
308
308
  ]
309
309
  }),
310
310
  /*#__PURE__*/ _jsxs(Stack, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/commerce-glance-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n formatOrderNumber,\n isLowStock,\n liftLegacyProduct,\n orderIsTestMode,\n} from '../../model'\nimport { checkEntitlement, pluginDocsHelp } from '@aglyn/aglyn'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Alert, Button, Chip, Divider, Stack, Typography } from '@mui/material'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useConsoleHostRoute,\n useFirestore,\n useOrgPlan,\n} from '@aglyn/tenant-feature-instance'\nimport { useFirestoreCollection } from '@aglyn/tenant-feature-instance'\n\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000\n\n/**\n * How many orders the 30-day figures may be computed from, and how many\n * products the low-stock count may scan.\n *\n * Both tiles are aggregates, so neither can be paged: a sum over page one is\n * not a sum. What bounds them instead is the window itself — the orders query\n * asks for thirty days rather than for a count, so a store reads what it sold\n * rather than a fixed slab, and only a store selling more than this in a month\n * meets the ceiling at all.\n *\n * A ceiling that bites makes every figure under it an UNDERSTATEMENT, which is\n * why `truncated` is rendered rather than logged. Revenue quietly short is the\n * one failure a reader cannot detect from the number itself.\n */\nconst GLANCE_ORDER_CEILING = 250\nconst GLANCE_PRODUCT_CEILING = 250\n\n/**\n * Commerce at a glance (AGL-353): 30-day revenue, orders, AOV, low-stock\n * count and the five latest orders. Renders nothing for hosts without a\n * catalog so non-commerce dashboards stay clean.\n *\n * The figures are the `commerceAnalytics` entitlement — `/pricing` sells\n * \"Commerce analytics\" as Pro-and-up, and `/product/commerce` calls it \"a\n * built-in commerce analytics dashboard\". Until AGL-1938 the flag was\n * inert: its ONLY occurrence outside `plan-entitlements.ts` was its own\n * type declaration, and this card carried no check, so every commerce org\n * — Starter included — got the Pro surface for free. The store link and\n * card shell stay ungated; only the measured numbers are the paid part.\n */\nexport function CommerceGlanceCard(props: { hostId: string }) {\n const { hostId } = props\n // Console routes are /[orgSlug]/hosts/[subdomain]/… (AGL-673); this\n // component only has a host doc id.\n const consoleRoute = useConsoleHostRoute(hostId)\n const { org, ready: orgReady } = useOrgPlan(hostId)\n const entitled = checkEntitlement(org as never, 'commerceAnalytics')\n const firestore = useFirestore()\n /*\n * Anchored once per mount so the query identity is stable. Recomputing it\n * per render would rebuild the listener on every pass, which re-reads the\n * whole window each time.\n */\n const since = useMemo(() => Date.now() - THIRTY_DAYS_MS, [])\n /**\n * The thirty days the tiles claim, asked for as thirty days.\n *\n * `createdAtMs` is the field every order writer in the plugin stamps — cart,\n * buy-now, draft, POS cash, POS card and subscription cycle — and the one\n * `reconcile-stock` already walks the collection by. `createdAt` is not\n * interchangeable: the orders collection group is indexed on `createdAtMs`\n * alone, and a range on a field a document lacks drops that document rather\n * than mis-placing it.\n *\n * The range and the order are the same field, so this needs no composite\n * index beyond the `createdAtMs` override already declared.\n */\n const { data: orderDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'orders'),\n where('createdAtMs', '>=', since),\n orderBy('createdAtMs', 'desc'),\n limit(GLANCE_ORDER_CEILING + 1),\n ),\n [firestore, hostId, since],\n { idField: '$id' },\n )\n const { data: productDocs } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'products'),\n GLANCE_PRODUCT_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const orderWindow = useMemo(\n () => ceilingedWindow<any>(orderDocs ?? undefined, GLANCE_ORDER_CEILING),\n [orderDocs],\n )\n const productWindow = useMemo(\n () =>\n ceilingedWindow<any>(productDocs ?? undefined, GLANCE_PRODUCT_CEILING),\n [productDocs],\n )\n\n const summary = useMemo(() => {\n // The query returns the window already ordered newest-first; re-sorting a\n // ceilinged read would only restate the order it arrived in.\n const orders = orderWindow.rows\n // ONE DEFINITION OF 30-DAY REVENUE, NOT TWO.\n //\n // This card and `commerce-analytics-card` read the same orders collection\n // over the same window and disagreed three ways, so one dashboard showed a\n // store two different revenues:\n //\n // - `pending` orders, which have taken no money, were counted here as\n // revenue and excluded there.\n // - `cancelled` was tested with the American spelling, which never\n // matches the persisted `OrderStatus`, so every cancelled order was\n // booked. The value is a PERSISTED enum and is not the place to apply\n // the American-spelling rule; the comparison follows the data.\n // - A refund was all-or-nothing: a fully-refunded order was dropped\n // whole while a 99%-refunded one counted in full.\n //\n // The filter and the per-order figure now match that card line for line,\n // so the two cannot drift again without someone editing both.\n const recentWindow = orders.filter(\n (order) =>\n order.status !== 'pending' &&\n order.status !== 'cancelled' &&\n // A rehearsal is not revenue — the same exclusion the\n // analytics card applies, from the same helper.\n !orderIsTestMode(order),\n )\n // Net of what went back, rather than dropping the order. The legacy flat\n // `amountCents` is the fallback, matching every other money reader\n // (AGL-1747): this card had the modern read but not the fallback, so a\n // Commerce Starter order (AGL-90) rendered as $0.00.\n const orderNetCents = (order: any) =>\n Number(order.totals?.totalCents ?? order.amountCents ?? 0) -\n Number(order.refundedCents ?? 0)\n const revenueCents = recentWindow.reduce(\n (sum, order) => sum + orderNetCents(order),\n 0,\n )\n const lowStock = productWindow.rows.filter((product: any) => {\n try {\n return isLowStock(liftLegacyProduct(product))\n } catch {\n return false\n }\n }).length\n return {\n latest: orders.slice(0, 5),\n orders30d: recentWindow.length,\n revenueCents,\n aovCents: recentWindow.length\n ? Math.round(revenueCents / recentWindow.length)\n : 0,\n lowStock,\n }\n }, [orderWindow, productWindow])\n\n // No catalog and nothing sold in the window — this host doesn't sell; stay\n // invisible.\n if (!(productWindow.rows.length || orderWindow.rows.length)) return null\n\n const money = (cents: number) => `$${(cents / 100).toFixed(2)}`\n\n const openStoreAction = (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={consoleRoute.base ? `${consoleRoute.base}/products` : undefined}\n size=\"small\"\n color=\"primary\"\n >\n {'Open store'}\n </Button>\n )\n\n if (!orgReady) {\n // `checkEntitlement(undefined)` resolves the FREE tier rather than\n // \"unknown\" (see `useOrgPlan`), and this card's \"no\" is an upsell —\n // never accuse a paying org of being unentitled while the plan doc is\n // still in flight.\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Checking your plan…'}\n </Typography>\n </CardDisplay>\n )\n }\n\n if (!entitled) {\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Alert\n severity=\"info\"\n action={\n consoleRoute.orgSlug ? (\n <AppLink\n componentVariant=\"button\"\n color=\"inherit\"\n size=\"small\"\n href={`/${consoleRoute.orgSlug}/billing`}\n >\n {'Upgrade'}\n </AppLink>\n ) : undefined\n }\n >\n {'Commerce analytics — revenue, orders and average order value — ' +\n 'is a Pro feature. Every order is still being recorded, so the ' +\n 'numbers are waiting the moment you upgrade.'}\n </Alert>\n </CardDisplay>\n )\n }\n\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Stack spacing={1.5}>\n <Stack direction=\"row\" spacing={3}>\n <Stack>\n <Typography variant=\"h6\">{money(summary.revenueCents)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Revenue · 30d'}\n </Typography>\n </Stack>\n <Stack>\n <Typography variant=\"h6\">{summary.orders30d}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Orders · 30d'}\n </Typography>\n </Stack>\n <Stack>\n <Typography variant=\"h6\">{money(summary.aovCents)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Avg order'}\n </Typography>\n </Stack>\n {summary.lowStock ? (\n <Stack>\n <Typography variant=\"h6\" color=\"warning.main\">\n {summary.lowStock}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Low stock'}\n </Typography>\n </Stack>\n ) : null}\n </Stack>\n {orderWindow.truncated || productWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {orderWindow.truncated\n ? `Counted from the ${GLANCE_ORDER_CEILING} most recent orders of the last 30 days. Open the store for the full figures.`\n : `Low stock counted across ${GLANCE_PRODUCT_CEILING} products. Open the store for the full catalog.`}\n </Typography>\n ) : null}\n {summary.latest.length ? (\n <>\n <Divider />\n <Stack spacing={0.5}>\n {summary.latest.map((order: any) => (\n <Stack\n key={order.$id}\n direction=\"row\"\n spacing={1}\n sx={{\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <Typography variant=\"body2\" noWrap sx={{ minWidth: 0 }}>\n {order.orderNumber\n ? formatOrderNumber(order.orderNumber)\n : order.$id.slice(0, 8)}\n {order.email ? ` · ${order.email}` : ''}\n </Typography>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"caption\">\n {money(\n Number(\n order.totals?.totalCents ?? order.amountCents ?? 0,\n ),\n )}\n </Typography>\n <Chip size=\"small\" label={order.status ?? 'paid'} />\n </Stack>\n </Stack>\n ))}\n </Stack>\n </>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nCommerceGlanceCard.displayName = 'CommerceGlanceCard'\n\nexport default CommerceGlanceCard\n"],"names":["formatOrderNumber","isLowStock","liftLegacyProduct","orderIsTestMode","checkEntitlement","pluginDocsHelp","AppLink","CardDisplay","Alert","Button","Chip","Divider","Stack","Typography","collection","limit","orderBy","query","where","useMemo","ceilingedWindow","collectionCeiling","useConsoleHostRoute","useFirestore","useOrgPlan","useFirestoreCollection","THIRTY_DAYS_MS","GLANCE_ORDER_CEILING","GLANCE_PRODUCT_CEILING","CommerceGlanceCard","props","hostId","consoleRoute","org","ready","orgReady","entitled","firestore","since","Date","now","data","orderDocs","idField","productDocs","orderWindow","undefined","productWindow","summary","orders","rows","recentWindow","filter","order","status","orderNetCents","Number","totals","totalCents","amountCents","refundedCents","revenueCents","reduce","sum","lowStock","product","length","latest","slice","orders30d","aovCents","Math","round","money","cents","toFixed","openStoreAction","component","componentVariant","nativeButton","href","base","size","color","header","help","contentGutterX","contentGutterY","HeaderProps","action","variant","severity","orgSlug","spacing","direction","truncated","map","sx","justifyContent","alignItems","noWrap","minWidth","orderNumber","$id","email","label","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/commerce-glance-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n formatOrderNumber,\n isLowStock,\n liftLegacyProduct,\n orderIsTestMode,\n} from '../../model'\nimport { checkEntitlement, pluginDocsHelp } from '@aglyn/aglyn'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Alert, Button, Chip, Divider, Stack, Typography } from '@mui/material'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useConsoleHostRoute,\n useFirestore,\n useOrgPlan,\n} from '@aglyn/tenant-feature-instance'\nimport { useFirestoreCollection } from '@aglyn/tenant-feature-instance'\n\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000\n\n/**\n * How many orders the 30-day figures may be computed from, and how many\n * products the low-stock count may scan.\n *\n * Both tiles are aggregates, so neither can be paged: a sum over page one is\n * not a sum. What bounds them instead is the window itself — the orders query\n * asks for thirty days rather than for a count, so a store reads what it sold\n * rather than a fixed slab, and only a store selling more than this in a month\n * meets the ceiling at all.\n *\n * A ceiling that bites makes every figure under it an UNDERSTATEMENT, which is\n * why `truncated` is rendered rather than logged. Revenue quietly short is the\n * one failure a reader cannot detect from the number itself.\n */\nconst GLANCE_ORDER_CEILING = 250\nconst GLANCE_PRODUCT_CEILING = 250\n\n/**\n * Commerce at a glance (AGL-353): 30-day revenue, orders, AOV, low-stock\n * count and the five latest orders. Renders nothing for hosts without a\n * catalog so non-commerce dashboards stay clean.\n *\n * The figures are the `commerceAnalytics` entitlement — `/pricing` sells\n * \"Commerce analytics\" as Pro-and-up, and `/product/commerce` calls it \"a\n * built-in commerce analytics dashboard\". Until AGL-1938 the flag was\n * inert: its ONLY occurrence outside `plan-entitlements.ts` was its own\n * type declaration, and this card carried no check, so every commerce org\n * — Starter included — got the Pro surface for free. The store link and\n * card shell stay ungated; only the measured numbers are the paid part.\n */\nexport function CommerceGlanceCard(props: { hostId: string }) {\n const { hostId } = props\n // Console routes are /[orgSlug]/hosts/[subdomain]/… (AGL-673); this\n // component only has a host doc id.\n const consoleRoute = useConsoleHostRoute(hostId)\n const { org, ready: orgReady } = useOrgPlan(hostId)\n const entitled = checkEntitlement(org as never, 'commerceAnalytics')\n const firestore = useFirestore()\n /*\n * Anchored once per mount so the query identity is stable. Recomputing it\n * per render would rebuild the listener on every pass, which re-reads the\n * whole window each time.\n */\n const since = useMemo(() => Date.now() - THIRTY_DAYS_MS, [])\n /**\n * The thirty days the tiles claim, asked for as thirty days.\n *\n * `createdAtMs` is the field every order writer in the plugin stamps — cart,\n * buy-now, draft, POS cash, POS card and subscription cycle — and the one\n * `reconcile-stock` already walks the collection by. `createdAt` is not\n * interchangeable: the orders collection group is indexed on `createdAtMs`\n * alone, and a range on a field a document lacks drops that document rather\n * than mis-placing it.\n *\n * The range and the order are the same field, so this needs no composite\n * index beyond the `createdAtMs` override already declared.\n */\n const { data: orderDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'orders'),\n where('createdAtMs', '>=', since),\n orderBy('createdAtMs', 'desc'),\n limit(GLANCE_ORDER_CEILING + 1),\n ),\n [firestore, hostId, since],\n { idField: '$id' },\n )\n const { data: productDocs } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'products'),\n GLANCE_PRODUCT_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const orderWindow = useMemo(\n () => ceilingedWindow<any>(orderDocs ?? undefined, GLANCE_ORDER_CEILING),\n [orderDocs],\n )\n const productWindow = useMemo(\n () =>\n ceilingedWindow<any>(productDocs ?? undefined, GLANCE_PRODUCT_CEILING),\n [productDocs],\n )\n\n const summary = useMemo(() => {\n // The query returns the window already ordered newest-first; re-sorting a\n // ceilinged read would only restate the order it arrived in.\n const orders = orderWindow.rows\n // ONE DEFINITION OF 30-DAY REVENUE, NOT TWO.\n //\n // This card and `commerce-analytics-card` read the same orders collection\n // over the same window and disagreed three ways, so one dashboard showed a\n // store two different revenues:\n //\n // - `pending` orders, which have taken no money, were counted here as\n // revenue and excluded there.\n // - `cancelled` was tested with the American spelling, which never\n // matches the persisted `OrderStatus`, so every cancelled order was\n // booked. The value is a PERSISTED enum and is not the place to apply\n // the American-spelling rule; the comparison follows the data.\n // - A refund was all-or-nothing: a fully-refunded order was dropped\n // whole while a 99%-refunded one counted in full.\n //\n // The filter and the per-order figure now match that card line for line,\n // so the two cannot drift again without someone editing both.\n const recentWindow = orders.filter(\n (order) =>\n order.status !== 'pending' &&\n order.status !== 'cancelled' &&\n // A rehearsal is not revenue — the same exclusion the\n // analytics card applies, from the same helper.\n !orderIsTestMode(order),\n )\n // Net of what went back, rather than dropping the order. The legacy flat\n // `amountCents` is the fallback, matching every other money reader\n // (AGL-1747): this card had the modern read but not the fallback, so a\n // Commerce Starter order (AGL-90) rendered as $0.00.\n const orderNetCents = (order: any) =>\n Number(order.totals?.totalCents ?? order.amountCents ?? 0) -\n Number(order.refundedCents ?? 0)\n const revenueCents = recentWindow.reduce(\n (sum, order) => sum + orderNetCents(order),\n 0,\n )\n const lowStock = productWindow.rows.filter((product: any) => {\n try {\n return isLowStock(liftLegacyProduct(product))\n } catch {\n return false\n }\n }).length\n return {\n latest: orders.slice(0, 5),\n orders30d: recentWindow.length,\n revenueCents,\n aovCents: recentWindow.length\n ? Math.round(revenueCents / recentWindow.length)\n : 0,\n lowStock,\n }\n }, [orderWindow, productWindow])\n\n // No catalog and nothing sold in the window — this host doesn't sell; stay\n // invisible.\n if (!(productWindow.rows.length || orderWindow.rows.length)) return null\n\n const money = (cents: number) => `$${(cents / 100).toFixed(2)}`\n\n const openStoreAction = (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={consoleRoute.base ? `${consoleRoute.base}/products` : undefined}\n size=\"small\"\n color=\"primary\"\n >\n {'Open store'}\n </Button>\n )\n\n if (!orgReady) {\n // `checkEntitlement(undefined)` resolves the FREE tier rather than\n // \"unknown\" (see `useOrgPlan`), and this card's \"no\" is an upsell —\n // never accuse a paying org of being unentitled while the plan doc is\n // still in flight.\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Checking your plan…'}\n </Typography>\n </CardDisplay>\n )\n }\n\n if (!entitled) {\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Alert\n severity=\"info\"\n action={\n consoleRoute.orgSlug ? (\n <AppLink\n componentVariant=\"button\"\n color=\"inherit\"\n size=\"small\"\n href={`/${consoleRoute.orgSlug}/billing`}\n >\n {'Upgrade'}\n </AppLink>\n ) : undefined\n }\n >\n {'Commerce analytics — revenue, orders and average order value — ' +\n 'is a Pro feature. Every order is still being recorded, so the ' +\n 'numbers are waiting the moment you upgrade.'}\n </Alert>\n </CardDisplay>\n )\n }\n\n return (\n <CardDisplay\n header={'Commerce'}\n help={pluginDocsHelp('commerce')}\n contentGutterX\n contentGutterY\n HeaderProps={{ action: openStoreAction }}\n >\n <Stack spacing={1.5}>\n <Stack direction=\"row\" spacing={3}>\n <Stack>\n <Typography variant=\"h6\">{money(summary.revenueCents)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Revenue · 30d'}\n </Typography>\n </Stack>\n <Stack>\n <Typography variant=\"h6\">{summary.orders30d}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Orders · 30d'}\n </Typography>\n </Stack>\n <Stack>\n <Typography variant=\"h6\">{money(summary.aovCents)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Avg order'}\n </Typography>\n </Stack>\n {summary.lowStock ? (\n <Stack>\n <Typography variant=\"h6\" color=\"warning.main\">\n {summary.lowStock}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Low stock'}\n </Typography>\n </Stack>\n ) : null}\n </Stack>\n {orderWindow.truncated || productWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {orderWindow.truncated\n ? `Counted from the ${GLANCE_ORDER_CEILING} most recent orders of the last 30 days. Open the store for the full figures.`\n : `Low stock counted across ${GLANCE_PRODUCT_CEILING} products. Open the store for the full catalog.`}\n </Typography>\n ) : null}\n {summary.latest.length ? (\n <>\n <Divider />\n <Stack spacing={0.5}>\n {summary.latest.map((order: any) => (\n <Stack\n key={order.$id}\n direction=\"row\"\n spacing={1}\n sx={{\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <Typography variant=\"body2\" noWrap sx={{ minWidth: 0 }}>\n {/* `HostOrder`'s own fields. An order with no number yet\n (a checkout still settling) falls back to its id. */}\n {order.number != null\n ? formatOrderNumber(order)\n : order.$id.slice(0, 8)}\n {order.customerEmail ? ` · ${order.customerEmail}` : ''}\n </Typography>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"caption\">\n {money(\n Number(\n order.totals?.totalCents ?? order.amountCents ?? 0,\n ),\n )}\n </Typography>\n <Chip size=\"small\" label={order.status ?? 'paid'} />\n </Stack>\n </Stack>\n ))}\n </Stack>\n </>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nCommerceGlanceCard.displayName = 'CommerceGlanceCard'\n\nexport default CommerceGlanceCard\n"],"names":["formatOrderNumber","isLowStock","liftLegacyProduct","orderIsTestMode","checkEntitlement","pluginDocsHelp","AppLink","CardDisplay","Alert","Button","Chip","Divider","Stack","Typography","collection","limit","orderBy","query","where","useMemo","ceilingedWindow","collectionCeiling","useConsoleHostRoute","useFirestore","useOrgPlan","useFirestoreCollection","THIRTY_DAYS_MS","GLANCE_ORDER_CEILING","GLANCE_PRODUCT_CEILING","CommerceGlanceCard","props","hostId","consoleRoute","org","ready","orgReady","entitled","firestore","since","Date","now","data","orderDocs","idField","productDocs","orderWindow","undefined","productWindow","summary","orders","rows","recentWindow","filter","order","status","orderNetCents","Number","totals","totalCents","amountCents","refundedCents","revenueCents","reduce","sum","lowStock","product","length","latest","slice","orders30d","aovCents","Math","round","money","cents","toFixed","openStoreAction","component","componentVariant","nativeButton","href","base","size","color","header","help","contentGutterX","contentGutterY","HeaderProps","action","variant","severity","orgSlug","spacing","direction","truncated","map","sx","justifyContent","alignItems","noWrap","minWidth","number","$id","customerEmail","label","displayName"],"mappings":"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"}