@withpotter/pages-admin 0.13.0-next.120 → 0.13.0-next.123

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.
Files changed (35) hide show
  1. package/dist/admin/_ui/admin.css +7 -0
  2. package/dist/admin/_ui/stat-card.js +11 -2
  3. package/dist/admin/_ui/stat-card.js.map +1 -1
  4. package/dist/admin/admins/access-dialog.js +2 -7
  5. package/dist/admin/admins/access-dialog.js.map +1 -1
  6. package/dist/admin/admins/invite-dialog.js +0 -6
  7. package/dist/admin/admins/invite-dialog.js.map +1 -1
  8. package/dist/admin/hooks.js +0 -7
  9. package/dist/admin/hooks.js.map +1 -1
  10. package/dist/admin/revenue/earnings/earnings-colors.js +25 -0
  11. package/dist/admin/revenue/earnings/earnings-colors.js.map +1 -0
  12. package/dist/admin/revenue/earnings/earnings-legend.js +75 -0
  13. package/dist/admin/revenue/earnings/earnings-legend.js.map +1 -0
  14. package/dist/admin/revenue/earnings/earnings-summary.js +296 -0
  15. package/dist/admin/revenue/earnings/earnings-summary.js.map +1 -0
  16. package/dist/admin/revenue/earnings/earnings-table.js +143 -0
  17. package/dist/admin/revenue/earnings/earnings-table.js.map +1 -0
  18. package/dist/admin/revenue/earnings/earnings.module.css +201 -0
  19. package/dist/admin/revenue/earnings/use-earnings.js +27 -0
  20. package/dist/admin/revenue/earnings/use-earnings.js.map +1 -0
  21. package/dist/admin/revenue/health-panel.js +5 -4
  22. package/dist/admin/revenue/health-panel.js.map +1 -1
  23. package/dist/admin/revenue/revenue-kpis.js +1 -1
  24. package/dist/admin/revenue/revenue-kpis.js.map +1 -1
  25. package/dist/admin/revenue/revenue-overview.js +20 -118
  26. package/dist/admin/revenue/revenue-overview.js.map +1 -1
  27. package/dist/admin/revenue/revenue-workspace.js +4 -10
  28. package/dist/admin/revenue/revenue-workspace.js.map +1 -1
  29. package/dist/admin/roles/page.js +4 -14
  30. package/dist/admin/roles/page.js.map +1 -1
  31. package/dist/admin/roles/role-dialog.js +1 -2
  32. package/dist/admin/roles/role-dialog.js.map +1 -1
  33. package/package.json +4 -4
  34. package/dist/admin/roles/role-requests.js +0 -80
  35. package/dist/admin/roles/role-requests.js.map +0 -1
@@ -209,6 +209,13 @@
209
209
  min-width: 0;
210
210
  }
211
211
 
212
+ /* A colour key along the top edge, matching the chart slice the card stands for. */
213
+ .adm-stat[data-accent] {
214
+ box-shadow:
215
+ inset 0 3px 0 var(--adm-stat-accent),
216
+ var(--adm-card-shadow);
217
+ }
218
+
212
219
  .adm-stat-head {
213
220
  display: grid;
214
221
  gap: 2px;
@@ -14,7 +14,8 @@ function StatCard({
14
14
  href,
15
15
  compact,
16
16
  note,
17
- alert
17
+ alert,
18
+ accent
18
19
  }) {
19
20
  const body = /* @__PURE__ */ jsxs(Fragment, { children: [
20
21
  /* @__PURE__ */ jsxs("div", { className: "adm-stat-head", children: [
@@ -60,7 +61,15 @@ function StatCard({
60
61
  }
61
62
  );
62
63
  }
63
- return /* @__PURE__ */ jsx("div", { className: `adm-stat${compact ? " adm-stat--compact" : ""}`, children: body });
64
+ return /* @__PURE__ */ jsx(
65
+ "div",
66
+ {
67
+ className: `adm-stat${compact ? " adm-stat--compact" : ""}`,
68
+ "data-accent": accent ? "" : void 0,
69
+ style: accent ? { "--adm-stat-accent": accent } : void 0,
70
+ children: body
71
+ }
72
+ );
64
73
  }
65
74
  const isWord = (value) => typeof value === "string" && !/\d/.test(value) && value.length > 10;
66
75
  function DeltaPill({ delta }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_ui/stat-card.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\nimport Link from 'next/link';\nimport { Skeleton } from './skeleton';\nimport { Sparkline } from './sparkline';\n\nexport interface StatCardDelta {\n /** Period-over-period change. `null` = no prior baseline to compare against. */\n pct: number | null;\n /** When false, an increase is rendered red and a decrease green. Default true. */\n positiveIsGood?: boolean;\n /** Optional caption, e.g. \"vs prev 30d\". */\n caption?: string;\n}\n\n/**\n * KPI stat card: label, value (weight 500), optional sub-line or plain-text\n * delta, and an optional sparkline. No icon chip. Becomes a link with `href`.\n */\nexport function StatCard({\n label,\n value,\n sub,\n hint,\n isLoading,\n delta,\n spark,\n sparkColor,\n href,\n compact,\n note,\n alert,\n}: {\n label: string;\n value: ReactNode;\n sub?: string;\n /** Accepted for older callers; KPI cards no longer draw an icon chip. */\n icon?: ComponentType<{ size?: number; color?: string }>;\n hint?: string;\n isLoading?: boolean;\n delta?: StatCardDelta;\n spark?: number[];\n sparkColor?: string;\n href?: string;\n compact?: boolean;\n /** Quiet secondary text under the label. */\n note?: string;\n /** Paint the value red: a queue that needs someone now. */\n alert?: boolean;\n}) {\n const body = (\n <>\n <div className=\"adm-stat-head\">\n {hint ? (\n <span\n className=\"adm-stat-label adm-hint\"\n tabIndex={0}\n role=\"note\"\n aria-label={hint}\n >\n {label}\n <span className=\"adm-hint-bubble\" role=\"tooltip\">\n {hint}\n </span>\n </span>\n ) : (\n <span className=\"adm-stat-label\" title={label}>\n {label}\n </span>\n )}\n {note && <span className=\"adm-stat-note\">{note}</span>}\n </div>\n {isLoading ? (\n <Skeleton width={96} height={30} />\n ) : (\n <div\n className={`adm-stat-value${isWord(value) ? ' adm-stat-value--text' : ''}`}\n data-alert={alert || undefined}\n title={typeof value === 'string' ? value : undefined}\n >\n {value}\n </div>\n )}\n {!isLoading && (delta || sub || (spark && spark.length > 0)) && (\n <div className=\"adm-stat-foot\">\n <div className=\"adm-stat-foot-meta\">\n {delta ? (\n <DeltaPill delta={delta} />\n ) : sub ? (\n <span className=\"adm-stat-sub\" title={sub}>\n {sub}\n </span>\n ) : null}\n {delta?.caption && (\n <span className=\"adm-stat-caption\">{delta.caption}</span>\n )}\n </div>\n {spark && spark.length > 0 && (\n <Sparkline values={spark} color={sparkColor} />\n )}\n </div>\n )}\n </>\n );\n\n if (href) {\n return (\n <Link\n href={href}\n className={`adm-stat adm-stat-link${\n compact ? ' adm-stat--compact' : ''\n }`}\n >\n {body}\n </Link>\n );\n }\n return (\n <div className={`adm-stat${compact ? ' adm-stat--compact' : ''}`}>\n {body}\n </div>\n );\n}\n\n/** A label rather than a number: set at body size so it never shouts. */\nconst isWord = (value: ReactNode) =>\n typeof value === 'string' && !/\\d/.test(value) && value.length > 10;\n\nfunction DeltaPill({ delta }: { delta: StatCardDelta }) {\n const positiveIsGood = delta.positiveIsGood ?? true;\n if (delta.pct === null) {\n return <span className=\"adm-delta adm-delta--flat\">New</span>;\n }\n const up = delta.pct > 0;\n const flat = delta.pct === 0;\n const good = flat ? false : up === positiveIsGood;\n const tone = flat ? 'flat' : good ? 'good' : 'bad';\n // The sign carries the direction in words, so no arrow glyph is needed.\n const sign = flat ? '' : up ? '+' : '\\u2212';\n return (\n <span className={`adm-delta adm-delta--${tone}`}>\n {sign}\n {Math.abs(delta.pct)}%\n </span>\n );\n}\n"],"mappings":"AAkDI,mBAUQ,KAPF,YAHN;AAjDJ,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAenB,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAiBG;AACD,QAAM,OACJ,iCACE;AAAA,yBAAC,SAAI,WAAU,iBACZ;AAAA,aACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,UAAU;AAAA,UACV,MAAK;AAAA,UACL,cAAY;AAAA,UAEX;AAAA;AAAA,YACD,oBAAC,UAAK,WAAU,mBAAkB,MAAK,WACpC,gBACH;AAAA;AAAA;AAAA,MACF,IAEA,oBAAC,UAAK,WAAU,kBAAiB,OAAO,OACrC,iBACH;AAAA,MAED,QAAQ,oBAAC,UAAK,WAAU,iBAAiB,gBAAK;AAAA,OACjD;AAAA,IACC,YACC,oBAAC,YAAS,OAAO,IAAI,QAAQ,IAAI,IAEjC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,iBAAiB,OAAO,KAAK,IAAI,0BAA0B,EAAE;AAAA,QACxE,cAAY,SAAS;AAAA,QACrB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,QAE1C;AAAA;AAAA,IACH;AAAA,IAED,CAAC,cAAc,SAAS,OAAQ,SAAS,MAAM,SAAS,MACvD,qBAAC,SAAI,WAAU,iBACb;AAAA,2BAAC,SAAI,WAAU,sBACZ;AAAA,gBACC,oBAAC,aAAU,OAAc,IACvB,MACF,oBAAC,UAAK,WAAU,gBAAe,OAAO,KACnC,eACH,IACE;AAAA,QACH,OAAO,WACN,oBAAC,UAAK,WAAU,oBAAoB,gBAAM,SAAQ;AAAA,SAEtD;AAAA,MACC,SAAS,MAAM,SAAS,KACvB,oBAAC,aAAU,QAAQ,OAAO,OAAO,YAAY;AAAA,OAEjD;AAAA,KAEJ;AAGF,MAAI,MAAM;AACR,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,yBACT,UAAU,uBAAuB,EACnC;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AACA,SACE,oBAAC,SAAI,WAAW,WAAW,UAAU,uBAAuB,EAAE,IAC3D,gBACH;AAEJ;AAGA,MAAM,SAAS,CAAC,UACd,OAAO,UAAU,YAAY,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,SAAS;AAEnE,SAAS,UAAU,EAAE,MAAM,GAA6B;AACtD,QAAM,iBAAiB,MAAM,kBAAkB;AAC/C,MAAI,MAAM,QAAQ,MAAM;AACtB,WAAO,oBAAC,UAAK,WAAU,6BAA4B,iBAAG;AAAA,EACxD;AACA,QAAM,KAAK,MAAM,MAAM;AACvB,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,OAAO,QAAQ,OAAO;AACnC,QAAM,OAAO,OAAO,SAAS,OAAO,SAAS;AAE7C,QAAM,OAAO,OAAO,KAAK,KAAK,MAAM;AACpC,SACE,qBAAC,UAAK,WAAW,wBAAwB,IAAI,IAC1C;AAAA;AAAA,IACA,KAAK,IAAI,MAAM,GAAG;AAAA,IAAE;AAAA,KACvB;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/_ui/stat-card.tsx"],"sourcesContent":["import type { ComponentType, CSSProperties, ReactNode } from 'react';\nimport Link from 'next/link';\nimport { Skeleton } from './skeleton';\nimport { Sparkline } from './sparkline';\n\nexport interface StatCardDelta {\n /** Period-over-period change. `null` = no prior baseline to compare against. */\n pct: number | null;\n /** When false, an increase is rendered red and a decrease green. Default true. */\n positiveIsGood?: boolean;\n /** Optional caption, e.g. \"vs prev 30d\". */\n caption?: string;\n}\n\n/**\n * KPI stat card: label, value (weight 500), optional sub-line or plain-text\n * delta, and an optional sparkline. No icon chip. Becomes a link with `href`.\n */\nexport function StatCard({\n label,\n value,\n sub,\n hint,\n isLoading,\n delta,\n spark,\n sparkColor,\n href,\n compact,\n note,\n alert,\n accent,\n}: {\n label: string;\n value: ReactNode;\n sub?: string;\n /** Accepted for older callers; KPI cards no longer draw an icon chip. */\n icon?: ComponentType<{ size?: number; color?: string }>;\n hint?: string;\n isLoading?: boolean;\n delta?: StatCardDelta;\n spark?: number[];\n sparkColor?: string;\n href?: string;\n compact?: boolean;\n /** Quiet secondary text under the label. */\n note?: string;\n /** Paint the value red: a queue that needs someone now. */\n alert?: boolean;\n /** A colour key for the card: a bar along its top edge, so it can match a chart slice. */\n accent?: string;\n}) {\n const body = (\n <>\n <div className=\"adm-stat-head\">\n {hint ? (\n <span\n className=\"adm-stat-label adm-hint\"\n tabIndex={0}\n role=\"note\"\n aria-label={hint}\n >\n {label}\n <span className=\"adm-hint-bubble\" role=\"tooltip\">\n {hint}\n </span>\n </span>\n ) : (\n <span className=\"adm-stat-label\" title={label}>\n {label}\n </span>\n )}\n {note && <span className=\"adm-stat-note\">{note}</span>}\n </div>\n {isLoading ? (\n <Skeleton width={96} height={30} />\n ) : (\n <div\n className={`adm-stat-value${isWord(value) ? ' adm-stat-value--text' : ''}`}\n data-alert={alert || undefined}\n title={typeof value === 'string' ? value : undefined}\n >\n {value}\n </div>\n )}\n {!isLoading && (delta || sub || (spark && spark.length > 0)) && (\n <div className=\"adm-stat-foot\">\n <div className=\"adm-stat-foot-meta\">\n {delta ? (\n <DeltaPill delta={delta} />\n ) : sub ? (\n <span className=\"adm-stat-sub\" title={sub}>\n {sub}\n </span>\n ) : null}\n {delta?.caption && (\n <span className=\"adm-stat-caption\">{delta.caption}</span>\n )}\n </div>\n {spark && spark.length > 0 && (\n <Sparkline values={spark} color={sparkColor} />\n )}\n </div>\n )}\n </>\n );\n\n if (href) {\n return (\n <Link\n href={href}\n className={`adm-stat adm-stat-link${\n compact ? ' adm-stat--compact' : ''\n }`}\n >\n {body}\n </Link>\n );\n }\n return (\n <div\n className={`adm-stat${compact ? ' adm-stat--compact' : ''}`}\n data-accent={accent ? '' : undefined}\n style={accent ? ({ '--adm-stat-accent': accent } as CSSProperties) : undefined}\n >\n {body}\n </div>\n );\n}\n\n/** A label rather than a number: set at body size so it never shouts. */\nconst isWord = (value: ReactNode) =>\n typeof value === 'string' && !/\\d/.test(value) && value.length > 10;\n\nfunction DeltaPill({ delta }: { delta: StatCardDelta }) {\n const positiveIsGood = delta.positiveIsGood ?? true;\n if (delta.pct === null) {\n return <span className=\"adm-delta adm-delta--flat\">New</span>;\n }\n const up = delta.pct > 0;\n const flat = delta.pct === 0;\n const good = flat ? false : up === positiveIsGood;\n const tone = flat ? 'flat' : good ? 'good' : 'bad';\n // The sign carries the direction in words, so no arrow glyph is needed.\n const sign = flat ? '' : up ? '+' : '\\u2212';\n return (\n <span className={`adm-delta adm-delta--${tone}`}>\n {sign}\n {Math.abs(delta.pct)}%\n </span>\n );\n}\n"],"mappings":"AAqDI,mBAUQ,KAPF,YAHN;AApDJ,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAenB,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAmBG;AACD,QAAM,OACJ,iCACE;AAAA,yBAAC,SAAI,WAAU,iBACZ;AAAA,aACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,UAAU;AAAA,UACV,MAAK;AAAA,UACL,cAAY;AAAA,UAEX;AAAA;AAAA,YACD,oBAAC,UAAK,WAAU,mBAAkB,MAAK,WACpC,gBACH;AAAA;AAAA;AAAA,MACF,IAEA,oBAAC,UAAK,WAAU,kBAAiB,OAAO,OACrC,iBACH;AAAA,MAED,QAAQ,oBAAC,UAAK,WAAU,iBAAiB,gBAAK;AAAA,OACjD;AAAA,IACC,YACC,oBAAC,YAAS,OAAO,IAAI,QAAQ,IAAI,IAEjC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,iBAAiB,OAAO,KAAK,IAAI,0BAA0B,EAAE;AAAA,QACxE,cAAY,SAAS;AAAA,QACrB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,QAE1C;AAAA;AAAA,IACH;AAAA,IAED,CAAC,cAAc,SAAS,OAAQ,SAAS,MAAM,SAAS,MACvD,qBAAC,SAAI,WAAU,iBACb;AAAA,2BAAC,SAAI,WAAU,sBACZ;AAAA,gBACC,oBAAC,aAAU,OAAc,IACvB,MACF,oBAAC,UAAK,WAAU,gBAAe,OAAO,KACnC,eACH,IACE;AAAA,QACH,OAAO,WACN,oBAAC,UAAK,WAAU,oBAAoB,gBAAM,SAAQ;AAAA,SAEtD;AAAA,MACC,SAAS,MAAM,SAAS,KACvB,oBAAC,aAAU,QAAQ,OAAO,OAAO,YAAY;AAAA,OAEjD;AAAA,KAEJ;AAGF,MAAI,MAAM;AACR,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,yBACT,UAAU,uBAAuB,EACnC;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,WAAW,UAAU,uBAAuB,EAAE;AAAA,MACzD,eAAa,SAAS,KAAK;AAAA,MAC3B,OAAO,SAAU,EAAE,qBAAqB,OAAO,IAAsB;AAAA,MAEpE;AAAA;AAAA,EACH;AAEJ;AAGA,MAAM,SAAS,CAAC,UACd,OAAO,UAAU,YAAY,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,SAAS;AAEnE,SAAS,UAAU,EAAE,MAAM,GAA6B;AACtD,QAAM,iBAAiB,MAAM,kBAAkB;AAC/C,MAAI,MAAM,QAAQ,MAAM;AACtB,WAAO,oBAAC,UAAK,WAAU,6BAA4B,iBAAG;AAAA,EACxD;AACA,QAAM,KAAK,MAAM,MAAM;AACvB,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,OAAO,QAAQ,OAAO;AACnC,QAAM,OAAO,OAAO,SAAS,OAAO,SAAS;AAE7C,QAAM,OAAO,OAAO,KAAK,KAAK,MAAM;AACpC,SACE,qBAAC,UAAK,WAAW,wBAAwB,IAAI,IAC1C;AAAA;AAAA,IACA,KAAK,IAAI,MAAM,GAAG;AAAA,IAAE;AAAA,KACvB;AAEJ;","names":[]}
@@ -53,14 +53,9 @@ function AccessForm({
53
53
  () => kind === "roles" ? (a.roleIds ?? []).filter((id) => roles.some((r) => r.id === id)) : a.permissions ?? []
54
54
  );
55
55
  const save = useMutation({
56
- mutationFn: async () => kind === "roles" ? platformAdminApi.setAdminRoles(a.id, draft) : platformAdminApi.setAdminPermissions(a.id, draft),
56
+ mutationFn: () => kind === "roles" ? platformAdminApi.setAdminRoles(a.id, draft) : platformAdminApi.setAdminPermissions(a.id, draft),
57
57
  onSuccess: () => {
58
- toast(
59
- kind === "roles" ? {
60
- title: "Sent for approval",
61
- description: `Another super admin has to approve the roles for ${a.name ?? a.email}.`
62
- } : { title: `Access updated for ${a.name ?? a.email}` }
63
- );
58
+ toast({ title: `Access updated for ${a.name ?? a.email}` });
64
59
  onSaved();
65
60
  onClose();
66
61
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/admins/access-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useMutation } from '@tanstack/react-query';\nimport { Button, FormDialog, useToast } from '@withpotter/ui-kit';\nimport {\n platformAdminApi,\n type AdminRow as Admin,\n type RoleRow,\n} from '@withpotter/lib/admin-api';\nimport { PermissionPicker, toggleIn } from '../roles/permission-picker';\nimport { RoleChoices } from './role-choices';\nimport styles from './admins.module.css';\n\nexport type AccessEdit = { admin: Admin; kind: 'roles' | 'permissions' };\nconst FORM_ID = 'admin-access-form';\n\n/** Change one admin's roles or direct permissions. */\nexport function AccessDialog({\n edit,\n catalog,\n roles,\n onClose,\n onSaved,\n}: {\n edit: AccessEdit | null;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onSaved: () => void;\n}) {\n // Count each opening so a cancelled edit never reappears on the next open.\n const [last, setLast] = useState(edit);\n const [opens, setOpens] = useState(0);\n const [wasOpen, setWasOpen] = useState(false);\n if (edit && edit !== last) setLast(edit);\n if (Boolean(edit) !== wasOpen) {\n setWasOpen(Boolean(edit));\n if (edit) setOpens((n) => n + 1);\n }\n const shown = edit ?? last;\n if (!shown) return null;\n return (\n <AccessForm\n key={`${opens}-${shown.admin.id}-${shown.kind}`}\n open={edit !== null}\n edit={shown}\n catalog={catalog}\n roles={roles}\n onClose={onClose}\n onSaved={onSaved}\n />\n );\n}\n\nfunction AccessForm({\n open,\n edit: { admin: a, kind },\n catalog,\n roles,\n onClose,\n onSaved,\n}: {\n open: boolean;\n edit: AccessEdit;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onSaved: () => void;\n}) {\n const { toast } = useToast();\n // Deleted roles linger in an admin's roleIds (the API keeps them); drop\n // them so the count is honest and Save does not send dead ids back.\n const [draft, setDraft] = useState<string[]>(() =>\n kind === 'roles'\n ? (a.roleIds ?? []).filter((id) => roles.some((r) => r.id === id))\n : (a.permissions ?? []),\n );\n const save = useMutation({\n mutationFn: async (): Promise<unknown> =>\n kind === 'roles'\n ? platformAdminApi.setAdminRoles(a.id, draft)\n : platformAdminApi.setAdminPermissions(a.id, draft),\n onSuccess: () => {\n toast(\n kind === 'roles'\n ? {\n title: 'Sent for approval',\n description: `Another super admin has to approve the roles for ${a.name ?? a.email}.`,\n }\n : { title: `Access updated for ${a.name ?? a.email}` },\n );\n onSaved();\n onClose();\n },\n onError: (error) =>\n toast({\n title: 'Access was not updated',\n description: error.message,\n variant: 'destructive',\n }),\n });\n\n return (\n <FormDialog\n open={open}\n size={kind === 'roles' ? 'md' : 'lg'}\n title={kind === 'roles' ? 'Roles' : 'Direct permissions'}\n description={a.email}\n onClose={onClose}\n footer={\n <>\n <span className={styles.footNote}>{draft.length} selected</span>\n <div className={styles.footActions}>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={save.isPending}\n loading={save.isPending}\n >\n Save\n </Button>\n </div>\n </>\n }\n >\n <form\n id={FORM_ID}\n onSubmit={(e) => {\n e.preventDefault();\n if (!save.isPending) save.mutate();\n }}\n >\n {kind === 'roles' ? (\n <RoleChoices\n legend=\"Their access is the union of every role ticked here.\"\n roles={roles}\n value={draft}\n onToggle={(id) => setDraft(toggleIn(id))}\n emptyLabel=\"No roles available.\"\n />\n ) : (\n <PermissionPicker\n legend=\"Granted on top of their roles\"\n keys={catalog}\n value={draft}\n onToggle={(key) => setDraft(toggleIn(key))}\n onSet={setDraft}\n />\n )}\n </form>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/admins/access-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useMutation } from '@tanstack/react-query';\nimport { Button, FormDialog, useToast } from '@withpotter/ui-kit';\nimport {\n platformAdminApi,\n type AdminRow as Admin,\n type RoleRow,\n} from '@withpotter/lib/admin-api';\nimport { PermissionPicker, toggleIn } from '../roles/permission-picker';\nimport { RoleChoices } from './role-choices';\nimport styles from './admins.module.css';\n\nexport type AccessEdit = { admin: Admin; kind: 'roles' | 'permissions' };\nconst FORM_ID = 'admin-access-form';\n\n/** Change one admin's roles or direct permissions. */\nexport function AccessDialog({\n edit,\n catalog,\n roles,\n onClose,\n onSaved,\n}: {\n edit: AccessEdit | null;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onSaved: () => void;\n}) {\n // Count each opening so a cancelled edit never reappears on the next open.\n const [last, setLast] = useState(edit);\n const [opens, setOpens] = useState(0);\n const [wasOpen, setWasOpen] = useState(false);\n if (edit && edit !== last) setLast(edit);\n if (Boolean(edit) !== wasOpen) {\n setWasOpen(Boolean(edit));\n if (edit) setOpens((n) => n + 1);\n }\n const shown = edit ?? last;\n if (!shown) return null;\n return (\n <AccessForm\n key={`${opens}-${shown.admin.id}-${shown.kind}`}\n open={edit !== null}\n edit={shown}\n catalog={catalog}\n roles={roles}\n onClose={onClose}\n onSaved={onSaved}\n />\n );\n}\n\nfunction AccessForm({\n open,\n edit: { admin: a, kind },\n catalog,\n roles,\n onClose,\n onSaved,\n}: {\n open: boolean;\n edit: AccessEdit;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onSaved: () => void;\n}) {\n const { toast } = useToast();\n // Deleted roles linger in an admin's roleIds (the API keeps them); drop\n // them so the count is honest and Save does not send dead ids back.\n const [draft, setDraft] = useState<string[]>(() =>\n kind === 'roles'\n ? (a.roleIds ?? []).filter((id) => roles.some((r) => r.id === id))\n : (a.permissions ?? []),\n );\n const save = useMutation({\n mutationFn: () =>\n kind === 'roles'\n ? platformAdminApi.setAdminRoles(a.id, draft)\n : platformAdminApi.setAdminPermissions(a.id, draft),\n onSuccess: () => {\n toast({ title: `Access updated for ${a.name ?? a.email}` });\n onSaved();\n onClose();\n },\n onError: (error) =>\n toast({\n title: 'Access was not updated',\n description: error.message,\n variant: 'destructive',\n }),\n });\n\n return (\n <FormDialog\n open={open}\n size={kind === 'roles' ? 'md' : 'lg'}\n title={kind === 'roles' ? 'Roles' : 'Direct permissions'}\n description={a.email}\n onClose={onClose}\n footer={\n <>\n <span className={styles.footNote}>{draft.length} selected</span>\n <div className={styles.footActions}>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={save.isPending}\n loading={save.isPending}\n >\n Save\n </Button>\n </div>\n </>\n }\n >\n <form\n id={FORM_ID}\n onSubmit={(e) => {\n e.preventDefault();\n if (!save.isPending) save.mutate();\n }}\n >\n {kind === 'roles' ? (\n <RoleChoices\n legend=\"Their access is the union of every role ticked here.\"\n roles={roles}\n value={draft}\n onToggle={(id) => setDraft(toggleIn(id))}\n emptyLabel=\"No roles available.\"\n />\n ) : (\n <PermissionPicker\n legend=\"Granted on top of their roles\"\n keys={catalog}\n value={draft}\n onToggle={(key) => setDraft(toggleIn(key))}\n onSet={setDraft}\n />\n )}\n </form>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -25,12 +25,6 @@ function InviteDialog({
25
25
  const invite = useMutation({
26
26
  mutationFn: () => platformAdminApi.inviteAdmin(email, role, perms, roleIds),
27
27
  onSuccess: (r) => {
28
- if (r.pendingRoles) {
29
- toast({
30
- title: "Roles sent for approval",
31
- description: "Another super admin has to approve them before this admin holds them."
32
- });
33
- }
34
28
  onInvited(r);
35
29
  setEmail("");
36
30
  setRole("admin");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/admins/invite-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState } from 'react';\nimport { useMutation } from '@tanstack/react-query';\nimport { Button, FormDialog, Input, useToast } from '@withpotter/ui-kit';\nimport { Select } from '@withpotter/ui-kit/select';\nimport { platformAdminApi, type RoleRow } from '@withpotter/lib/admin-api';\nimport { PermissionPicker, toggleIn } from '../roles/permission-picker';\nimport { RoleChoices } from './role-choices';\nimport styles from './admins.module.css';\n\ntype AdminRole = 'admin' | 'superadmin';\nconst FORM_ID = 'invite-admin-form';\n\n/** Email and access level, then roles and any direct grants. */\nexport function InviteDialog({\n open,\n catalog,\n roles,\n onClose,\n onInvited,\n}: {\n open: boolean;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onInvited: (temp: { email: string; tempPassword: string }) => void;\n}) {\n const { toast } = useToast();\n const roleFieldId = useId();\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<AdminRole>('admin');\n const [perms, setPerms] = useState<string[]>([]);\n const [roleIds, setRoleIds] = useState<string[]>([]);\n\n const invite = useMutation({\n mutationFn: () => platformAdminApi.inviteAdmin(email, role, perms, roleIds),\n onSuccess: (r) => {\n if (r.pendingRoles) {\n toast({\n title: 'Roles sent for approval',\n description:\n 'Another super admin has to approve them before this admin holds them.',\n });\n }\n onInvited(r);\n setEmail('');\n setRole('admin');\n setPerms([]);\n setRoleIds([]);\n },\n onError: (error) =>\n toast({\n title: 'The invite was not sent',\n description: error.message,\n variant: 'destructive',\n }),\n });\n const canSend = email.trim().length > 0 && !invite.isPending;\n\n return (\n <FormDialog\n open={open}\n size=\"lg\"\n title=\"Invite admin\"\n description=\"They get a temporary password and choose their own on first sign-in.\"\n onClose={onClose}\n footer={\n <>\n <span className={styles.footNote}>\n {role === 'superadmin'\n ? 'Full access'\n : `${roleIds.length} role${roleIds.length === 1 ? '' : 's'} · ${perms.length} direct`}\n </span>\n <div className={styles.footActions}>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={!canSend}\n loading={invite.isPending}\n >\n Send invite\n </Button>\n </div>\n </>\n }\n >\n <form\n id={FORM_ID}\n className={styles.form}\n onSubmit={(e) => {\n e.preventDefault();\n if (canSend) invite.mutate();\n }}\n >\n <div className={styles.formRow}>\n <Input\n label=\"Email\"\n type=\"email\"\n placeholder=\"name@company.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoFocus\n />\n <div className={styles.field}>\n <label htmlFor={roleFieldId} className={styles.fieldLabel}>\n Access level\n </label>\n <Select\n id={roleFieldId}\n value={role}\n onChange={(v) => setRole(v as AdminRole)}\n options={[\n { value: 'admin', label: 'Admin' },\n { value: 'superadmin', label: 'Superadmin' },\n ]}\n />\n </div>\n </div>\n\n {role === 'admin' ? (\n <>\n <RoleChoices\n legend=\"Roles (permissions stack as a union)\"\n roles={roles}\n value={roleIds}\n onToggle={(id) => setRoleIds(toggleIn(id))}\n emptyLabel=\"No roles yet — create one on the Roles page.\"\n />\n <PermissionPicker\n legend=\"Extra permissions (optional)\"\n keys={catalog}\n value={perms}\n onToggle={(key) => setPerms(toggleIn(key))}\n onSet={setPerms}\n />\n </>\n ) : (\n <p className={styles.note}>\n Superadmins have full access, so no roles or permissions are needed.\n </p>\n )}\n </form>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/admins/invite-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState } from 'react';\nimport { useMutation } from '@tanstack/react-query';\nimport { Button, FormDialog, Input, useToast } from '@withpotter/ui-kit';\nimport { Select } from '@withpotter/ui-kit/select';\nimport { platformAdminApi, type RoleRow } from '@withpotter/lib/admin-api';\nimport { PermissionPicker, toggleIn } from '../roles/permission-picker';\nimport { RoleChoices } from './role-choices';\nimport styles from './admins.module.css';\n\ntype AdminRole = 'admin' | 'superadmin';\nconst FORM_ID = 'invite-admin-form';\n\n/** Email and access level, then roles and any direct grants. */\nexport function InviteDialog({\n open,\n catalog,\n roles,\n onClose,\n onInvited,\n}: {\n open: boolean;\n catalog: string[];\n roles: RoleRow[];\n onClose: () => void;\n onInvited: (temp: { email: string; tempPassword: string }) => void;\n}) {\n const { toast } = useToast();\n const roleFieldId = useId();\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<AdminRole>('admin');\n const [perms, setPerms] = useState<string[]>([]);\n const [roleIds, setRoleIds] = useState<string[]>([]);\n\n const invite = useMutation({\n mutationFn: () => platformAdminApi.inviteAdmin(email, role, perms, roleIds),\n onSuccess: (r) => {\n onInvited(r);\n setEmail('');\n setRole('admin');\n setPerms([]);\n setRoleIds([]);\n },\n onError: (error) =>\n toast({\n title: 'The invite was not sent',\n description: error.message,\n variant: 'destructive',\n }),\n });\n const canSend = email.trim().length > 0 && !invite.isPending;\n\n return (\n <FormDialog\n open={open}\n size=\"lg\"\n title=\"Invite admin\"\n description=\"They get a temporary password and choose their own on first sign-in.\"\n onClose={onClose}\n footer={\n <>\n <span className={styles.footNote}>\n {role === 'superadmin'\n ? 'Full access'\n : `${roleIds.length} role${roleIds.length === 1 ? '' : 's'} · ${perms.length} direct`}\n </span>\n <div className={styles.footActions}>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={FORM_ID}\n disabled={!canSend}\n loading={invite.isPending}\n >\n Send invite\n </Button>\n </div>\n </>\n }\n >\n <form\n id={FORM_ID}\n className={styles.form}\n onSubmit={(e) => {\n e.preventDefault();\n if (canSend) invite.mutate();\n }}\n >\n <div className={styles.formRow}>\n <Input\n label=\"Email\"\n type=\"email\"\n placeholder=\"name@company.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoFocus\n />\n <div className={styles.field}>\n <label htmlFor={roleFieldId} className={styles.fieldLabel}>\n Access level\n </label>\n <Select\n id={roleFieldId}\n value={role}\n onChange={(v) => setRole(v as AdminRole)}\n options={[\n { value: 'admin', label: 'Admin' },\n { value: 'superadmin', label: 'Superadmin' },\n ]}\n />\n </div>\n </div>\n\n {role === 'admin' ? (\n <>\n <RoleChoices\n legend=\"Roles (permissions stack as a union)\"\n roles={roles}\n value={roleIds}\n onToggle={(id) => setRoleIds(toggleIn(id))}\n emptyLabel=\"No roles yet — create one on the Roles page.\"\n />\n <PermissionPicker\n legend=\"Extra permissions (optional)\"\n keys={catalog}\n value={perms}\n onToggle={(key) => setPerms(toggleIn(key))}\n onSet={setPerms}\n />\n </>\n ) : (\n <p className={styles.note}>\n Superadmins have full access, so no roles or permissions are needed.\n </p>\n )}\n </form>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -211,12 +211,6 @@ function useAdminRoles() {
211
211
  queryFn: () => platformAdminApi.roles()
212
212
  });
213
213
  }
214
- function useRoleChangeRequests() {
215
- return useQuery({
216
- queryKey: ["platform-admin", "roles", "requests"],
217
- queryFn: () => platformAdminApi.roleRequests()
218
- });
219
- }
220
214
  function useAccountSessions(id) {
221
215
  return useQuery({
222
216
  queryKey: ["platform-admin", "account-sessions", id],
@@ -265,7 +259,6 @@ export {
265
259
  usePlatformTenant,
266
260
  usePlatformTenants,
267
261
  usePlatformTenantsAnalytics,
268
- useRoleChangeRequests,
269
262
  useSubscriptionPayments,
270
263
  useTenantAnalytics,
271
264
  useTenantCustomerInsights,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/hooks.ts"],"sourcesContent":["'use client';\n\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport { platformAdminApi, type LedgerFilters } from '@withpotter/lib/admin-api';\nimport type { TenantListParams } from '@withpotter/lib/admin-tenants-query';\nimport type { AccountStage } from '@withpotter/lib/admin-account-types';\n\nexport function useAdminSession(enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'session'],\n queryFn: () => platformAdminApi.me(),\n enabled,\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformOverview() {\n return useQuery({\n queryKey: ['platform-admin', 'overview'],\n queryFn: () => platformAdminApi.overview(),\n });\n}\n\nexport function usePlatformCockpit(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'cockpit', range],\n queryFn: () => platformAdminApi.cockpit(range),\n });\n}\n\nexport function usePlatformRevenue(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', range],\n queryFn: () => platformAdminApi.revenue(range),\n });\n}\n\n/**\n * How customers paid, per channel. Not every box can say: where the route is\n * absent the query fails once (no retry) and `data` stays undefined, which the\n * panels read as \"nothing to show\".\n */\nexport function useGatewayChannels(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'gateway-channels', range],\n queryFn: () => platformAdminApi.gatewayChannels(range),\n retry: false,\n staleTime: 60_000,\n });\n}\n\n/**\n * Revenue's Merchant payments view. A box without the route answers 404; the\n * view reads that as \"not available here\", never as a failure to retry.\n */\nexport function useMerchantPayments(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchant-payments', filters],\n queryFn: () => platformAdminApi.merchantPayments(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** Revenue's Subscriptions view: every plan payment merchants made to Olive. */\nexport function useSubscriptionPayments(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'subscription-payments', filters],\n queryFn: () => platformAdminApi.subscriptionPayments(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** Revenue's Merchants view: what each merchant received and how customers paid them. */\nexport function useMerchantRevenue(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchants', filters],\n queryFn: () => platformAdminApi.merchantRevenue(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** The merchants that took payments in the window, for the merchant picker. */\nexport function useMerchantOptions(range: { startDate?: string; endDate?: string }) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchant-options', range],\n queryFn: () => platformAdminApi.merchantOptions(range),\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformTenantsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants-analytics', range],\n queryFn: () => platformAdminApi.tenantsAnalytics(range),\n });\n}\n\nexport function usePlatformTenants(params: TenantListParams) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants', params],\n queryFn: () => platformAdminApi.tenants(params),\n });\n}\n\nexport function usePlatformTenant(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant', id, range],\n queryFn: () => platformAdminApi.tenant(id, range),\n enabled: !!id,\n });\n}\n\nexport function useTenantAnalytics(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-analytics', id, range],\n queryFn: () => platformAdminApi.tenantAnalytics(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantFinance(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-finance', id, range],\n queryFn: () => platformAdminApi.tenantFinance(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantTransactions(\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-transactions', id, params],\n queryFn: () => platformAdminApi.tenantTransactions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomers(\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customers', id, params],\n queryFn: () => platformAdminApi.tenantCustomers(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProducts(\n id: string,\n params: { type?: string; search?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-products', id, params],\n queryFn: () => platformAdminApi.tenantProducts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProductInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-product-insights', id, range],\n queryFn: () => platformAdminApi.tenantProductInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomerInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customer-insights', id, range],\n queryFn: () => platformAdminApi.tenantCustomerInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantInvoices(\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-invoices', id, params],\n queryFn: () => platformAdminApi.tenantInvoices(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantLoyalty(id: string, enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-loyalty', id],\n queryFn: () => platformAdminApi.tenantLoyalty(id),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantDiscounts(\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-discounts', id, params],\n queryFn: () => platformAdminApi.tenantDiscounts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSettlements(\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-settlements', id, params],\n queryFn: () => platformAdminApi.tenantSettlements(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSubscriptions(\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-subscriptions', id, params],\n queryFn: () => platformAdminApi.tenantSubscriptions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function usePlatformAccounts(params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n stage?: AccountStage;\n}) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts', params],\n queryFn: () => platformAdminApi.accounts(params),\n });\n}\n\nexport function usePlatformAccountsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts-analytics', range],\n queryFn: () => platformAdminApi.accountsAnalytics(range),\n });\n}\n\nexport function usePlatformAdmins() {\n return useQuery({\n queryKey: ['platform-admin', 'admins'],\n queryFn: () => platformAdminApi.admins(),\n });\n}\n\nexport function usePlatformAdminsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'admins-analytics', range],\n queryFn: () => platformAdminApi.adminsAnalytics(range),\n });\n}\n\nexport function useAdminPermissions() {\n return useQuery({\n queryKey: ['platform-admin', 'admin-permissions'],\n queryFn: () => platformAdminApi.adminPermissions(),\n staleTime: 5 * 60_000,\n });\n}\n\nexport function useAdminRoles() {\n return useQuery({\n queryKey: ['platform-admin', 'roles'],\n queryFn: () => platformAdminApi.roles(),\n });\n}\n\nexport function useRoleChangeRequests() {\n return useQuery({\n queryKey: ['platform-admin', 'roles', 'requests'],\n queryFn: () => platformAdminApi.roleRequests(),\n });\n}\n\nexport function useAccountSessions(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-sessions', id],\n queryFn: () => platformAdminApi.accountSessions(id!),\n enabled: !!id,\n });\n}\n\nexport function useAccountTenants(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-tenants', id],\n queryFn: () => platformAdminApi.accountTenants(id!),\n enabled: !!id,\n });\n}\n\nexport function usePlatformAudit(\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit', params],\n queryFn: () => platformAdminApi.audit(params),\n });\n}\n\nexport function usePlatformAuditAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit-analytics', range],\n queryFn: () => platformAdminApi.auditAnalytics(range),\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/admin/hooks.ts"],"sourcesContent":["'use client';\n\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport { platformAdminApi, type LedgerFilters } from '@withpotter/lib/admin-api';\nimport type { TenantListParams } from '@withpotter/lib/admin-tenants-query';\nimport type { AccountStage } from '@withpotter/lib/admin-account-types';\n\nexport function useAdminSession(enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'session'],\n queryFn: () => platformAdminApi.me(),\n enabled,\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformOverview() {\n return useQuery({\n queryKey: ['platform-admin', 'overview'],\n queryFn: () => platformAdminApi.overview(),\n });\n}\n\nexport function usePlatformCockpit(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'cockpit', range],\n queryFn: () => platformAdminApi.cockpit(range),\n });\n}\n\nexport function usePlatformRevenue(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', range],\n queryFn: () => platformAdminApi.revenue(range),\n });\n}\n\n/**\n * How customers paid, per channel. Not every box can say: where the route is\n * absent the query fails once (no retry) and `data` stays undefined, which the\n * panels read as \"nothing to show\".\n */\nexport function useGatewayChannels(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'gateway-channels', range],\n queryFn: () => platformAdminApi.gatewayChannels(range),\n retry: false,\n staleTime: 60_000,\n });\n}\n\n/**\n * Revenue's Merchant payments view. A box without the route answers 404; the\n * view reads that as \"not available here\", never as a failure to retry.\n */\nexport function useMerchantPayments(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchant-payments', filters],\n queryFn: () => platformAdminApi.merchantPayments(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** Revenue's Subscriptions view: every plan payment merchants made to Olive. */\nexport function useSubscriptionPayments(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'subscription-payments', filters],\n queryFn: () => platformAdminApi.subscriptionPayments(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** Revenue's Merchants view: what each merchant received and how customers paid them. */\nexport function useMerchantRevenue(filters: LedgerFilters) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchants', filters],\n queryFn: () => platformAdminApi.merchantRevenue(filters),\n retry: false,\n staleTime: 30_000,\n placeholderData: keepPreviousData,\n });\n}\n\n/** The merchants that took payments in the window, for the merchant picker. */\nexport function useMerchantOptions(range: { startDate?: string; endDate?: string }) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', 'merchant-options', range],\n queryFn: () => platformAdminApi.merchantOptions(range),\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformTenantsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants-analytics', range],\n queryFn: () => platformAdminApi.tenantsAnalytics(range),\n });\n}\n\nexport function usePlatformTenants(params: TenantListParams) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants', params],\n queryFn: () => platformAdminApi.tenants(params),\n });\n}\n\nexport function usePlatformTenant(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant', id, range],\n queryFn: () => platformAdminApi.tenant(id, range),\n enabled: !!id,\n });\n}\n\nexport function useTenantAnalytics(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-analytics', id, range],\n queryFn: () => platformAdminApi.tenantAnalytics(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantFinance(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-finance', id, range],\n queryFn: () => platformAdminApi.tenantFinance(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantTransactions(\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-transactions', id, params],\n queryFn: () => platformAdminApi.tenantTransactions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomers(\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customers', id, params],\n queryFn: () => platformAdminApi.tenantCustomers(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProducts(\n id: string,\n params: { type?: string; search?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-products', id, params],\n queryFn: () => platformAdminApi.tenantProducts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProductInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-product-insights', id, range],\n queryFn: () => platformAdminApi.tenantProductInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomerInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customer-insights', id, range],\n queryFn: () => platformAdminApi.tenantCustomerInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantInvoices(\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-invoices', id, params],\n queryFn: () => platformAdminApi.tenantInvoices(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantLoyalty(id: string, enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-loyalty', id],\n queryFn: () => platformAdminApi.tenantLoyalty(id),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantDiscounts(\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-discounts', id, params],\n queryFn: () => platformAdminApi.tenantDiscounts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSettlements(\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-settlements', id, params],\n queryFn: () => platformAdminApi.tenantSettlements(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSubscriptions(\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-subscriptions', id, params],\n queryFn: () => platformAdminApi.tenantSubscriptions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function usePlatformAccounts(params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n stage?: AccountStage;\n}) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts', params],\n queryFn: () => platformAdminApi.accounts(params),\n });\n}\n\nexport function usePlatformAccountsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts-analytics', range],\n queryFn: () => platformAdminApi.accountsAnalytics(range),\n });\n}\n\nexport function usePlatformAdmins() {\n return useQuery({\n queryKey: ['platform-admin', 'admins'],\n queryFn: () => platformAdminApi.admins(),\n });\n}\n\nexport function usePlatformAdminsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'admins-analytics', range],\n queryFn: () => platformAdminApi.adminsAnalytics(range),\n });\n}\n\nexport function useAdminPermissions() {\n return useQuery({\n queryKey: ['platform-admin', 'admin-permissions'],\n queryFn: () => platformAdminApi.adminPermissions(),\n staleTime: 5 * 60_000,\n });\n}\n\nexport function useAdminRoles() {\n return useQuery({\n queryKey: ['platform-admin', 'roles'],\n queryFn: () => platformAdminApi.roles(),\n });\n}\n\nexport function useAccountSessions(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-sessions', id],\n queryFn: () => platformAdminApi.accountSessions(id!),\n enabled: !!id,\n });\n}\n\nexport function useAccountTenants(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-tenants', id],\n queryFn: () => platformAdminApi.accountTenants(id!),\n enabled: !!id,\n });\n}\n\nexport function usePlatformAudit(\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit', params],\n queryFn: () => platformAdminApi.audit(params),\n });\n}\n\nexport function usePlatformAuditAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit-analytics', range],\n queryFn: () => platformAdminApi.auditAnalytics(range),\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { useChartTheme } from "@withpotter/components/charts";
3
+ const ORDER = [
4
+ "online",
5
+ "pos",
6
+ "payments",
7
+ "payouts",
8
+ "plans",
9
+ "settlements",
10
+ "cash",
11
+ "transfers",
12
+ "fx",
13
+ "lending"
14
+ ];
15
+ function useSourceColors() {
16
+ const { series } = useChartTheme();
17
+ const colors = Object.fromEntries(
18
+ ORDER.map((source, i) => [source, series[i % series.length]])
19
+ );
20
+ return { ...colors, other: "var(--text-tertiary)", series };
21
+ }
22
+ export {
23
+ useSourceColors
24
+ };
25
+ //# sourceMappingURL=earnings-colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/admin/revenue/earnings/earnings-colors.ts"],"sourcesContent":["'use client';\n\nimport { useChartTheme } from '@withpotter/components/charts';\nimport type { EarningsSource } from '@withpotter/lib/admin-earnings-api';\n\n/**\n * One colour per source, the same on its card, its pie slice and its legend row. They come from the chart system's\n * validated palette (fixed order, checked in light and dark), never picked here; the palette has eight slots, so\n * \"other\" takes a neutral rather than a ninth hue. The most important sources take the first slots.\n */\nconst ORDER: readonly EarningsSource[] = [\n 'online',\n 'pos',\n 'payments',\n 'payouts',\n 'plans',\n 'settlements',\n 'cash',\n 'transfers',\n 'fx',\n 'lending',\n];\n\nexport function useSourceColors(): Record<EarningsSource, string> & {\n /** Colours for things that are not sources (payment methods, kept / cost), in palette order. */\n series: readonly string[];\n} {\n const { series } = useChartTheme();\n const colors = Object.fromEntries(\n ORDER.map((source, i) => [source, series[i % series.length]]),\n ) as Record<EarningsSource, string>;\n\n return { ...colors, other: 'var(--text-tertiary)', series };\n}\n"],"mappings":";AAEA,SAAS,qBAAqB;AAQ9B,MAAM,QAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,kBAGd;AACA,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,SAAS,OAAO;AAAA,IACpB,MAAM,IAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,OAAO,IAAI,OAAO,MAAM,CAAC,CAAC;AAAA,EAC9D;AAEA,SAAO,EAAE,GAAG,QAAQ,OAAO,wBAAwB,OAAO;AAC5D;","names":[]}
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { DonutChart } from "@withpotter/components/charts";
4
+ import { pctChange } from "@withpotter/lib/admin-earnings-model";
5
+ import styles from "./earnings.module.css";
6
+ function PieWithDetails({
7
+ slices,
8
+ money,
9
+ centerLabel
10
+ }) {
11
+ const shown = slices.filter((s) => s.value > 0);
12
+ const total = shown.reduce((a, s) => a + s.value, 0);
13
+ return /* @__PURE__ */ jsxs("div", { className: styles.pie, children: [
14
+ /* @__PURE__ */ jsx(
15
+ DonutChart,
16
+ {
17
+ data: shown.map((s) => ({ label: s.label, value: s.value, color: s.color })),
18
+ format: money,
19
+ centerLabel,
20
+ size: 170
21
+ }
22
+ ),
23
+ /* @__PURE__ */ jsx("ul", { className: styles.legend, children: shown.map((s) => /* @__PURE__ */ jsxs("li", { className: styles.legendRow, children: [
24
+ /* @__PURE__ */ jsx("span", { className: styles.swatch, style: { background: s.color }, "aria-hidden": true }),
25
+ /* @__PURE__ */ jsxs("span", { className: styles.legendText, children: [
26
+ /* @__PURE__ */ jsx("span", { className: styles.legendLabel, children: s.label }),
27
+ s.detail ? /* @__PURE__ */ jsx("span", { className: styles.legendDetail, children: s.detail }) : null
28
+ ] }),
29
+ /* @__PURE__ */ jsxs("span", { className: styles.legendNumbers, children: [
30
+ /* @__PURE__ */ jsx("strong", { children: money(s.value) }),
31
+ /* @__PURE__ */ jsx("span", { children: total > 0 ? `${Math.round(s.value / total * 100)}%` : "\u2013" })
32
+ ] })
33
+ ] }, s.key)) })
34
+ ] });
35
+ }
36
+ function CompareBars({
37
+ rows,
38
+ money
39
+ }) {
40
+ const widest = Math.max(1, ...rows.flatMap((r) => [r.value, r.previous]));
41
+ return /* @__PURE__ */ jsx("ul", { className: styles.cmp, children: rows.map((r) => {
42
+ const change = pctChange(r.value, r.previous);
43
+ const tone = change === null || change === 0 ? "" : change > 0 ? styles.up : styles.down;
44
+ return /* @__PURE__ */ jsxs("li", { className: styles.cmpRow, children: [
45
+ /* @__PURE__ */ jsxs("span", { className: styles.cmpHead, children: [
46
+ /* @__PURE__ */ jsx("span", { className: styles.swatch, style: { background: r.color }, "aria-hidden": true }),
47
+ /* @__PURE__ */ jsx("span", { className: styles.legendLabel, children: r.label }),
48
+ /* @__PURE__ */ jsx("span", { className: `${styles.cmpDelta} ${tone}`, children: change === null ? r.value > 0 ? "New" : "\u2013" : `${change > 0 ? "+" : change < 0 ? "\u2212" : ""}${Math.abs(change)}%` })
49
+ ] }),
50
+ /* @__PURE__ */ jsx("span", { className: styles.cmpTrack, "aria-hidden": true, children: /* @__PURE__ */ jsx(
51
+ "span",
52
+ {
53
+ className: styles.cmpPrev,
54
+ style: { width: `${r.previous / widest * 100}%`, background: r.color }
55
+ }
56
+ ) }),
57
+ /* @__PURE__ */ jsx("span", { className: styles.cmpTrack, "aria-hidden": true, children: /* @__PURE__ */ jsx(
58
+ "span",
59
+ {
60
+ className: styles.cmpNow,
61
+ style: { width: `${r.value / widest * 100}%`, background: r.color }
62
+ }
63
+ ) }),
64
+ /* @__PURE__ */ jsxs("span", { className: styles.cmpNums, children: [
65
+ /* @__PURE__ */ jsx("strong", { children: money(r.value) }),
66
+ /* @__PURE__ */ jsx("span", { children: `before ${money(r.previous)}` })
67
+ ] })
68
+ ] }, r.key);
69
+ }) });
70
+ }
71
+ export {
72
+ CompareBars,
73
+ PieWithDetails
74
+ };
75
+ //# sourceMappingURL=earnings-legend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/admin/revenue/earnings/earnings-legend.tsx"],"sourcesContent":["'use client';\n\nimport { DonutChart } from '@withpotter/components/charts';\nimport { pctChange } from '@withpotter/lib/admin-earnings-model';\nimport styles from './earnings.module.css';\n\nexport interface LegendSlice {\n key: string;\n label: string;\n value: number;\n color: string;\n /** A second line: \"12 transactions\". */\n detail?: string;\n}\n\n/**\n * A pie with its key beside it: every slice named in its own colour with its amount and share, so the chart can be\n * read without hovering. Slices of nothing are left out.\n */\nexport function PieWithDetails({\n slices,\n money,\n centerLabel,\n}: {\n slices: LegendSlice[];\n money: (value: number) => string;\n centerLabel: string;\n}) {\n const shown = slices.filter((s) => s.value > 0);\n const total = shown.reduce((a, s) => a + s.value, 0);\n\n return (\n <div className={styles.pie}>\n <DonutChart\n data={shown.map((s) => ({ label: s.label, value: s.value, color: s.color }))}\n format={money}\n centerLabel={centerLabel}\n size={170}\n />\n <ul className={styles.legend}>\n {shown.map((s) => (\n <li key={s.key} className={styles.legendRow}>\n <span className={styles.swatch} style={{ background: s.color }} aria-hidden />\n <span className={styles.legendText}>\n <span className={styles.legendLabel}>{s.label}</span>\n {s.detail ? <span className={styles.legendDetail}>{s.detail}</span> : null}\n </span>\n <span className={styles.legendNumbers}>\n <strong>{money(s.value)}</strong>\n <span>{total > 0 ? `${Math.round((s.value / total) * 100)}%` : '–'}</span>\n </span>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\nexport interface CompareRow {\n key: string;\n label: string;\n color: string;\n value: number;\n previous: number;\n}\n\n/**\n * Each stream this period against the period before, as paired bars in the stream's own colour: the faded bar is\n * before, the solid bar is now, and the change is said in words beside them.\n */\nexport function CompareBars({\n rows,\n money,\n}: {\n rows: CompareRow[];\n money: (value: number) => string;\n}) {\n const widest = Math.max(1, ...rows.flatMap((r) => [r.value, r.previous]));\n\n return (\n <ul className={styles.cmp}>\n {rows.map((r) => {\n const change = pctChange(r.value, r.previous);\n const tone =\n change === null || change === 0 ? '' : change > 0 ? styles.up : styles.down;\n\n return (\n <li key={r.key} className={styles.cmpRow}>\n <span className={styles.cmpHead}>\n <span className={styles.swatch} style={{ background: r.color }} aria-hidden />\n <span className={styles.legendLabel}>{r.label}</span>\n <span className={`${styles.cmpDelta} ${tone}`}>\n {change === null\n ? r.value > 0\n ? 'New'\n : '–'\n : `${change > 0 ? '+' : change < 0 ? '\\u2212' : ''}${Math.abs(change)}%`}\n </span>\n </span>\n <span className={styles.cmpTrack} aria-hidden>\n <span\n className={styles.cmpPrev}\n style={{ width: `${(r.previous / widest) * 100}%`, background: r.color }}\n />\n </span>\n <span className={styles.cmpTrack} aria-hidden>\n <span\n className={styles.cmpNow}\n style={{ width: `${(r.value / widest) * 100}%`, background: r.color }}\n />\n </span>\n <span className={styles.cmpNums}>\n <strong>{money(r.value)}</strong>\n <span>{`before ${money(r.previous)}`}</span>\n </span>\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":";AAiCM,cAUM,YAVN;AA/BN,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,OAAO,YAAY;AAeZ,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;AAC9C,QAAM,QAAQ,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC;AAEnD,SACE,qBAAC,SAAI,WAAW,OAAO,KACrB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,OAAO,OAAO,EAAE,MAAM,EAAE;AAAA,QAC3E,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA;AAAA,IACR;AAAA,IACA,oBAAC,QAAG,WAAW,OAAO,QACnB,gBAAM,IAAI,CAAC,MACV,qBAAC,QAAe,WAAW,OAAO,WAChC;AAAA,0BAAC,UAAK,WAAW,OAAO,QAAQ,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,eAAW,MAAC;AAAA,MAC5E,qBAAC,UAAK,WAAW,OAAO,YACtB;AAAA,4BAAC,UAAK,WAAW,OAAO,aAAc,YAAE,OAAM;AAAA,QAC7C,EAAE,SAAS,oBAAC,UAAK,WAAW,OAAO,cAAe,YAAE,QAAO,IAAU;AAAA,SACxE;AAAA,MACA,qBAAC,UAAK,WAAW,OAAO,eACtB;AAAA,4BAAC,YAAQ,gBAAM,EAAE,KAAK,GAAE;AAAA,QACxB,oBAAC,UAAM,kBAAQ,IAAI,GAAG,KAAK,MAAO,EAAE,QAAQ,QAAS,GAAG,CAAC,MAAM,UAAI;AAAA,SACrE;AAAA,SATO,EAAE,GAUX,CACD,GACH;AAAA,KACF;AAEJ;AAcO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,QAAM,SAAS,KAAK,IAAI,GAAG,GAAG,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAExE,SACE,oBAAC,QAAG,WAAW,OAAO,KACnB,eAAK,IAAI,CAAC,MAAM;AACf,UAAM,SAAS,UAAU,EAAE,OAAO,EAAE,QAAQ;AAC5C,UAAM,OACJ,WAAW,QAAQ,WAAW,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,OAAO;AAEzE,WACE,qBAAC,QAAe,WAAW,OAAO,QAChC;AAAA,2BAAC,UAAK,WAAW,OAAO,SACtB;AAAA,4BAAC,UAAK,WAAW,OAAO,QAAQ,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,eAAW,MAAC;AAAA,QAC5E,oBAAC,UAAK,WAAW,OAAO,aAAc,YAAE,OAAM;AAAA,QAC9C,oBAAC,UAAK,WAAW,GAAG,OAAO,QAAQ,IAAI,IAAI,IACxC,qBAAW,OACR,EAAE,QAAQ,IACR,QACA,WACF,GAAG,SAAS,IAAI,MAAM,SAAS,IAAI,WAAW,EAAE,GAAG,KAAK,IAAI,MAAM,CAAC,KACzE;AAAA,SACF;AAAA,MACA,oBAAC,UAAK,WAAW,OAAO,UAAU,eAAW,MAC3C;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,OAAO,EAAE,OAAO,GAAI,EAAE,WAAW,SAAU,GAAG,KAAK,YAAY,EAAE,MAAM;AAAA;AAAA,MACzE,GACF;AAAA,MACA,oBAAC,UAAK,WAAW,OAAO,UAAU,eAAW,MAC3C;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,OAAO,EAAE,OAAO,GAAI,EAAE,QAAQ,SAAU,GAAG,KAAK,YAAY,EAAE,MAAM;AAAA;AAAA,MACtE,GACF;AAAA,MACA,qBAAC,UAAK,WAAW,OAAO,SACtB;AAAA,4BAAC,YAAQ,gBAAM,EAAE,KAAK,GAAE;AAAA,QACxB,oBAAC,UAAM,oBAAU,MAAM,EAAE,QAAQ,CAAC,IAAG;AAAA,SACvC;AAAA,SA3BO,EAAE,GA4BX;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}