@withpotter/pages-admin 0.13.0-next.62 → 0.13.0-next.63

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.
@@ -14,39 +14,43 @@ function AttentionPanel({
14
14
  const total = groups.reduce((sum, g) => sum + g.count, 0);
15
15
  const [picked, setPicked] = useState(null);
16
16
  const active = groups.find((g) => g.key === picked) ?? [...groups].sort((a, b) => b.count - a.count)[0];
17
- return /* @__PURE__ */ jsx(Panel, { title: "Needs attention", count: total, flush: true, children: !active ? /* @__PURE__ */ jsx("div", { className: styles.clear, children: /* @__PURE__ */ jsx(EmptyNote, { children: "No exceptions in this period." }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
18
- /* @__PURE__ */ jsx(
19
- "div",
20
- {
21
- className: styles.filters,
22
- role: "group",
23
- "aria-label": "Show exceptions of one kind",
24
- children: groups.map((g) => /* @__PURE__ */ jsxs(
25
- "button",
26
- {
27
- type: "button",
28
- "aria-pressed": g.key === active.key,
29
- className: styles.filter,
30
- onClick: () => setPicked(g.key),
31
- children: [
32
- g.title,
33
- /* @__PURE__ */ jsx("span", { children: g.count })
34
- ]
35
- },
36
- g.key
37
- ))
38
- }
39
- ),
40
- active.note && /* @__PURE__ */ jsx("p", { className: styles.note, children: active.note }),
41
- /* @__PURE__ */ jsx("ul", { className: styles.rows, children: active.items.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, { href: item.href, className: styles.row, children: [
42
- item.logo && /* @__PURE__ */ jsx(EntityAvatar, { name: item.title, src: item.logo, size: 32 }),
43
- /* @__PURE__ */ jsxs("span", { className: styles.rowMain, children: [
44
- /* @__PURE__ */ jsx("strong", { children: item.title }),
45
- /* @__PURE__ */ jsx("small", { children: item.detail })
46
- ] }),
47
- /* @__PURE__ */ jsx("span", { className: styles.rowValue, children: item.value })
48
- ] }) }, item.id)) })
49
- ] }) });
17
+ const unknown = attention.unavailable ?? [];
18
+ return /* @__PURE__ */ jsxs(Panel, { title: "Needs attention", count: total, flush: true, children: [
19
+ unknown.length > 0 && /* @__PURE__ */ jsx("p", { className: styles.note, children: "Some exceptions could not be loaded, so this list may be incomplete." }),
20
+ !active ? /* @__PURE__ */ jsx("div", { className: styles.clear, children: /* @__PURE__ */ jsx(EmptyNote, { children: unknown.length > 0 ? "Nothing to show right now." : "No exceptions in this period." }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
21
+ /* @__PURE__ */ jsx(
22
+ "div",
23
+ {
24
+ className: styles.filters,
25
+ role: "group",
26
+ "aria-label": "Show exceptions of one kind",
27
+ children: groups.map((g) => /* @__PURE__ */ jsxs(
28
+ "button",
29
+ {
30
+ type: "button",
31
+ "aria-pressed": g.key === active.key,
32
+ className: styles.filter,
33
+ onClick: () => setPicked(g.key),
34
+ children: [
35
+ g.title,
36
+ /* @__PURE__ */ jsx("span", { children: g.count })
37
+ ]
38
+ },
39
+ g.key
40
+ ))
41
+ }
42
+ ),
43
+ active.note && /* @__PURE__ */ jsx("p", { className: styles.note, children: active.note }),
44
+ /* @__PURE__ */ jsx("ul", { className: styles.rows, children: active.items.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, { href: item.href, className: styles.row, children: [
45
+ item.logo && /* @__PURE__ */ jsx(EntityAvatar, { name: item.title, src: item.logo, size: 32 }),
46
+ /* @__PURE__ */ jsxs("span", { className: styles.rowMain, children: [
47
+ /* @__PURE__ */ jsx("strong", { children: item.title }),
48
+ /* @__PURE__ */ jsx("small", { children: item.detail })
49
+ ] }),
50
+ /* @__PURE__ */ jsx("span", { className: styles.rowValue, children: item.value })
51
+ ] }) }, item.id)) })
52
+ ] })
53
+ ] });
50
54
  }
51
55
  export {
52
56
  AttentionPanel
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_overview/attention-panel.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { EmptyNote } from '@withpotter/ui-kit';\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { Panel } from '../_ui';\nimport { attentionGroups } from './attention-groups';\nimport styles from './attention.module.css';\n\n/**\n * Every exception in one card: a filter per kind, the rows scrolling inside.\n * The busiest kind is open first; empty kinds are not offered at all.\n */\nexport function AttentionPanel({\n attention,\n}: {\n attention: PlatformCockpit['attention'];\n}) {\n const groups = attentionGroups(attention).filter((g) => g.count);\n const total = groups.reduce((sum, g) => sum + g.count, 0);\n const [picked, setPicked] = useState<string | null>(null);\n const active =\n groups.find((g) => g.key === picked) ??\n [...groups].sort((a, b) => b.count - a.count)[0];\n\n return (\n <Panel title=\"Needs attention\" count={total} flush>\n {!active ? (\n <div className={styles.clear}>\n <EmptyNote>No exceptions in this period.</EmptyNote>\n </div>\n ) : (\n <>\n <div\n className={styles.filters}\n role=\"group\"\n aria-label=\"Show exceptions of one kind\"\n >\n {groups.map((g) => (\n <button\n key={g.key}\n type=\"button\"\n aria-pressed={g.key === active.key}\n className={styles.filter}\n onClick={() => setPicked(g.key)}\n >\n {g.title}\n <span>{g.count}</span>\n </button>\n ))}\n </div>\n {active.note && <p className={styles.note}>{active.note}</p>}\n <ul className={styles.rows}>\n {active.items.map((item) => (\n <li key={item.id}>\n <Link href={item.href} className={styles.row}>\n {item.logo && (\n <EntityAvatar name={item.title} src={item.logo} size={32} />\n )}\n <span className={styles.rowMain}>\n <strong>{item.title}</strong>\n <small>{item.detail}</small>\n </span>\n <span className={styles.rowValue}>{item.value}</span>\n </Link>\n </li>\n ))}\n </ul>\n </>\n )}\n </Panel>\n );\n}\n"],"mappings":";AA+BU,SAGF,UAHE,KAUI,YAVJ;AA7BV,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,OAAO,YAAY;AAMZ,SAAS,eAAe;AAAA,EAC7B;AACF,GAEG;AACD,QAAM,SAAS,gBAAgB,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK;AAC/D,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACxD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AACxD,QAAM,SACJ,OAAO,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,KACnC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAEjD,SACE,oBAAC,SAAM,OAAM,mBAAkB,OAAO,OAAO,OAAK,MAC/C,WAAC,SACA,oBAAC,SAAI,WAAW,OAAO,OACrB,8BAAC,aAAU,2CAA6B,GAC1C,IAEA,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,OAAO;AAAA,QAClB,MAAK;AAAA,QACL,cAAW;AAAA,QAEV,iBAAO,IAAI,CAAC,MACX;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,gBAAc,EAAE,QAAQ,OAAO;AAAA,YAC/B,WAAW,OAAO;AAAA,YAClB,SAAS,MAAM,UAAU,EAAE,GAAG;AAAA,YAE7B;AAAA,gBAAE;AAAA,cACH,oBAAC,UAAM,YAAE,OAAM;AAAA;AAAA;AAAA,UAPV,EAAE;AAAA,QAQT,CACD;AAAA;AAAA,IACH;AAAA,IACC,OAAO,QAAQ,oBAAC,OAAE,WAAW,OAAO,MAAO,iBAAO,MAAK;AAAA,IACxD,oBAAC,QAAG,WAAW,OAAO,MACnB,iBAAO,MAAM,IAAI,CAAC,SACjB,oBAAC,QACC,+BAAC,QAAK,MAAM,KAAK,MAAM,WAAW,OAAO,KACtC;AAAA,WAAK,QACJ,oBAAC,gBAAa,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,MAAM,IAAI;AAAA,MAE5D,qBAAC,UAAK,WAAW,OAAO,SACtB;AAAA,4BAAC,YAAQ,eAAK,OAAM;AAAA,QACpB,oBAAC,WAAO,eAAK,QAAO;AAAA,SACtB;AAAA,MACA,oBAAC,UAAK,WAAW,OAAO,UAAW,eAAK,OAAM;AAAA,OAChD,KAVO,KAAK,EAWd,CACD,GACH;AAAA,KACF,GAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/_overview/attention-panel.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { EmptyNote } from '@withpotter/ui-kit';\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { Panel } from '../_ui';\nimport { attentionGroups } from './attention-groups';\nimport styles from './attention.module.css';\n\n/**\n * Every exception in one card: a filter per kind, the rows scrolling inside.\n * The busiest kind is open first; empty kinds are not offered at all.\n */\nexport function AttentionPanel({\n attention,\n}: {\n attention: PlatformCockpit['attention'];\n}) {\n const groups = attentionGroups(attention).filter((g) => g.count);\n const total = groups.reduce((sum, g) => sum + g.count, 0);\n const [picked, setPicked] = useState<string | null>(null);\n const active =\n groups.find((g) => g.key === picked) ??\n [...groups].sort((a, b) => b.count - a.count)[0];\n\n const unknown = attention.unavailable ?? [];\n\n return (\n <Panel title=\"Needs attention\" count={total} flush>\n {unknown.length > 0 && (\n <p className={styles.note}>\n Some exceptions could not be loaded, so this list may be incomplete.\n </p>\n )}\n {!active ? (\n <div className={styles.clear}>\n <EmptyNote>\n {unknown.length > 0\n ? 'Nothing to show right now.'\n : 'No exceptions in this period.'}\n </EmptyNote>\n </div>\n ) : (\n <>\n <div\n className={styles.filters}\n role=\"group\"\n aria-label=\"Show exceptions of one kind\"\n >\n {groups.map((g) => (\n <button\n key={g.key}\n type=\"button\"\n aria-pressed={g.key === active.key}\n className={styles.filter}\n onClick={() => setPicked(g.key)}\n >\n {g.title}\n <span>{g.count}</span>\n </button>\n ))}\n </div>\n {active.note && <p className={styles.note}>{active.note}</p>}\n <ul className={styles.rows}>\n {active.items.map((item) => (\n <li key={item.id}>\n <Link href={item.href} className={styles.row}>\n {item.logo && (\n <EntityAvatar name={item.title} src={item.logo} size={32} />\n )}\n <span className={styles.rowMain}>\n <strong>{item.title}</strong>\n <small>{item.detail}</small>\n </span>\n <span className={styles.rowValue}>{item.value}</span>\n </Link>\n </li>\n ))}\n </ul>\n </>\n )}\n </Panel>\n );\n}\n"],"mappings":";AAgCQ,SAaA,UAbA,KAoBM,YApBN;AA9BR,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,OAAO,YAAY;AAMZ,SAAS,eAAe;AAAA,EAC7B;AACF,GAEG;AACD,QAAM,SAAS,gBAAgB,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK;AAC/D,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACxD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AACxD,QAAM,SACJ,OAAO,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,KACnC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAEjD,QAAM,UAAU,UAAU,eAAe,CAAC;AAE1C,SACE,qBAAC,SAAM,OAAM,mBAAkB,OAAO,OAAO,OAAK,MAC/C;AAAA,YAAQ,SAAS,KAChB,oBAAC,OAAE,WAAW,OAAO,MAAM,kFAE3B;AAAA,IAED,CAAC,SACA,oBAAC,SAAI,WAAW,OAAO,OACrB,8BAAC,aACE,kBAAQ,SAAS,IACd,+BACA,iCACN,GACF,IAEA,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,MAAK;AAAA,UACL,cAAW;AAAA,UAEV,iBAAO,IAAI,CAAC,MACX;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,gBAAc,EAAE,QAAQ,OAAO;AAAA,cAC/B,WAAW,OAAO;AAAA,cAClB,SAAS,MAAM,UAAU,EAAE,GAAG;AAAA,cAE7B;AAAA,kBAAE;AAAA,gBACH,oBAAC,UAAM,YAAE,OAAM;AAAA;AAAA;AAAA,YAPV,EAAE;AAAA,UAQT,CACD;AAAA;AAAA,MACH;AAAA,MACC,OAAO,QAAQ,oBAAC,OAAE,WAAW,OAAO,MAAO,iBAAO,MAAK;AAAA,MACxD,oBAAC,QAAG,WAAW,OAAO,MACnB,iBAAO,MAAM,IAAI,CAAC,SACjB,oBAAC,QACC,+BAAC,QAAK,MAAM,KAAK,MAAM,WAAW,OAAO,KACtC;AAAA,aAAK,QACJ,oBAAC,gBAAa,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,MAAM,IAAI;AAAA,QAE5D,qBAAC,UAAK,WAAW,OAAO,SACtB;AAAA,8BAAC,YAAQ,eAAK,OAAM;AAAA,UACpB,oBAAC,WAAO,eAAK,QAAO;AAAA,WACtB;AAAA,QACA,oBAAC,UAAK,WAAW,OAAO,UAAW,eAAK,OAAM;AAAA,SAChD,KAVO,KAAK,EAWd,CACD,GACH;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":[]}
@@ -26,6 +26,8 @@ function ControlRoom({
26
26
  }) {
27
27
  const failed = attention.failedSettlements.count;
28
28
  const overdue = attention.overdueInvoices.count;
29
+ const failedUnknown = !!attention.unavailable?.includes("failedSettlements");
30
+ const overdueUnknown = !!attention.unavailable?.includes("overdueInvoices");
29
31
  const withdrawals = useModuleOn("withdrawals");
30
32
  const verification = useModuleOn("verification");
31
33
  return /* @__PURE__ */ jsxs("section", { className: styles.room, "aria-label": "Control room", children: [
@@ -34,10 +36,10 @@ function ControlRoom({
34
36
  {
35
37
  compact: true,
36
38
  label: "Failed payouts",
37
- value: /* @__PURE__ */ jsx(CountUp, { value: failed }),
38
- sub: "Settlements that did not land",
39
+ value: failedUnknown ? "\u2013" : /* @__PURE__ */ jsx(CountUp, { value: failed }),
40
+ sub: failedUnknown ? "Could not be loaded" : "Settlements that did not land",
39
41
  href: withdrawals ? "/admin/withdrawals?tab=failed" : void 0,
40
- alert: failed > 0
42
+ alert: failedUnknown || failed > 0
41
43
  }
42
44
  ),
43
45
  /* @__PURE__ */ jsx(
@@ -45,10 +47,10 @@ function ControlRoom({
45
47
  {
46
48
  compact: true,
47
49
  label: "Overdue invoices",
48
- value: /* @__PURE__ */ jsx(CountUp, { value: overdue }),
49
- sub: overdueOutstanding(attention.overdueInvoices, currency) ?? "Invoices past their due date",
50
+ value: overdueUnknown ? "\u2013" : /* @__PURE__ */ jsx(CountUp, { value: overdue }),
51
+ sub: overdueUnknown ? "Could not be loaded" : overdueOutstanding(attention.overdueInvoices, currency) ?? "Invoices past their due date",
50
52
  href: "/admin/revenue",
51
- alert: overdue > 0
53
+ alert: overdueUnknown || overdue > 0
52
54
  }
53
55
  ),
54
56
  verification && /* @__PURE__ */ jsx(VerificationCard, {})
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_overview/control-room.tsx"],"sourcesContent":["'use client';\n\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { CountUp } from '../_fx';\nimport { StatCard } from '../_ui';\nimport { useModuleOn } from '../_shell/modules-context';\nimport styles from './control-room.module.css';\nimport { useWaitingCases } from './use-waiting-cases';\nimport { overdueOutstanding } from './overdue-outstanding';\n\n/** KYC / KYB waiting count; mounted only where Verification is served. */\nfunction VerificationCard() {\n const waiting = useWaitingCases().data;\n\n return (\n <StatCard\n compact\n label=\"KYC / KYB decisions\"\n value={waiting === undefined ? '–' : <CountUp value={waiting} />}\n sub=\"Businesses waiting for review\"\n href=\"/admin/verification\"\n alert={!!waiting}\n />\n );\n}\n\n/**\n * The control room: every queue that needs a decision, as one row of\n * identical metric cards that wraps. A card opens its screen when this Box\n * serves that screen; a queue whose module is off is not shown.\n */\nexport function ControlRoom({\n attention,\n currency = '',\n}: {\n attention: PlatformCockpit['attention'];\n /** The currency filter's choice; narrows what overdue invoices owe. */\n currency?: string;\n}) {\n const failed = attention.failedSettlements.count;\n const overdue = attention.overdueInvoices.count;\n const withdrawals = useModuleOn('withdrawals');\n const verification = useModuleOn('verification');\n\n return (\n <section className={styles.room} aria-label=\"Control room\">\n <StatCard\n compact\n label=\"Failed payouts\"\n value={<CountUp value={failed} />}\n sub=\"Settlements that did not land\"\n href={withdrawals ? '/admin/withdrawals?tab=failed' : undefined}\n alert={failed > 0}\n />\n <StatCard\n compact\n label=\"Overdue invoices\"\n value={<CountUp value={overdue} />}\n sub={\n overdueOutstanding(attention.overdueInvoices, currency) ??\n 'Invoices past their due date'\n }\n href=\"/admin/revenue\"\n alert={overdue > 0}\n />\n {verification && <VerificationCard />}\n </section>\n );\n}\n"],"mappings":";AAkB2C,cA2BvC,YA3BuC;AAf3C,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,OAAO,YAAY;AACnB,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AAGnC,SAAS,mBAAmB;AAC1B,QAAM,UAAU,gBAAgB,EAAE;AAElC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAO;AAAA,MACP,OAAM;AAAA,MACN,OAAO,YAAY,SAAY,WAAM,oBAAC,WAAQ,OAAO,SAAS;AAAA,MAC9D,KAAI;AAAA,MACJ,MAAK;AAAA,MACL,OAAO,CAAC,CAAC;AAAA;AAAA,EACX;AAEJ;AAOO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,WAAW;AACb,GAIG;AACD,QAAM,SAAS,UAAU,kBAAkB;AAC3C,QAAM,UAAU,UAAU,gBAAgB;AAC1C,QAAM,cAAc,YAAY,aAAa;AAC7C,QAAM,eAAe,YAAY,cAAc;AAE/C,SACE,qBAAC,aAAQ,WAAW,OAAO,MAAM,cAAW,gBAC1C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,OAAM;AAAA,QACN,OAAO,oBAAC,WAAQ,OAAO,QAAQ;AAAA,QAC/B,KAAI;AAAA,QACJ,MAAM,cAAc,kCAAkC;AAAA,QACtD,OAAO,SAAS;AAAA;AAAA,IAClB;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,OAAM;AAAA,QACN,OAAO,oBAAC,WAAQ,OAAO,SAAS;AAAA,QAChC,KACE,mBAAmB,UAAU,iBAAiB,QAAQ,KACtD;AAAA,QAEF,MAAK;AAAA,QACL,OAAO,UAAU;AAAA;AAAA,IACnB;AAAA,IACC,gBAAgB,oBAAC,oBAAiB;AAAA,KACrC;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/_overview/control-room.tsx"],"sourcesContent":["'use client';\n\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { CountUp } from '../_fx';\nimport { StatCard } from '../_ui';\nimport { useModuleOn } from '../_shell/modules-context';\nimport styles from './control-room.module.css';\nimport { useWaitingCases } from './use-waiting-cases';\nimport { overdueOutstanding } from './overdue-outstanding';\n\n/** KYC / KYB waiting count; mounted only where Verification is served. */\nfunction VerificationCard() {\n const waiting = useWaitingCases().data;\n\n return (\n <StatCard\n compact\n label=\"KYC / KYB decisions\"\n value={waiting === undefined ? '–' : <CountUp value={waiting} />}\n sub=\"Businesses waiting for review\"\n href=\"/admin/verification\"\n alert={!!waiting}\n />\n );\n}\n\n/**\n * The control room: every queue that needs a decision, as one row of\n * identical metric cards that wraps. A card opens its screen when this Box\n * serves that screen; a queue whose module is off is not shown.\n */\nexport function ControlRoom({\n attention,\n currency = '',\n}: {\n attention: PlatformCockpit['attention'];\n /** The currency filter's choice; narrows what overdue invoices owe. */\n currency?: string;\n}) {\n const failed = attention.failedSettlements.count;\n const overdue = attention.overdueInvoices.count;\n // A feed that failed to load is unknown, not zero.\n const failedUnknown = !!attention.unavailable?.includes('failedSettlements');\n const overdueUnknown = !!attention.unavailable?.includes('overdueInvoices');\n const withdrawals = useModuleOn('withdrawals');\n const verification = useModuleOn('verification');\n\n return (\n <section className={styles.room} aria-label=\"Control room\">\n <StatCard\n compact\n label=\"Failed payouts\"\n value={failedUnknown ? '–' : <CountUp value={failed} />}\n sub={\n failedUnknown\n ? 'Could not be loaded'\n : 'Settlements that did not land'\n }\n href={withdrawals ? '/admin/withdrawals?tab=failed' : undefined}\n alert={failedUnknown || failed > 0}\n />\n <StatCard\n compact\n label=\"Overdue invoices\"\n value={overdueUnknown ? '–' : <CountUp value={overdue} />}\n sub={\n overdueUnknown\n ? 'Could not be loaded'\n : (overdueOutstanding(attention.overdueInvoices, currency) ??\n 'Invoices past their due date')\n }\n href=\"/admin/revenue\"\n alert={overdueUnknown || overdue > 0}\n />\n {verification && <VerificationCard />}\n </section>\n );\n}\n"],"mappings":";AAkB2C,cA8BvC,YA9BuC;AAf3C,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,OAAO,YAAY;AACnB,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AAGnC,SAAS,mBAAmB;AAC1B,QAAM,UAAU,gBAAgB,EAAE;AAElC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAO;AAAA,MACP,OAAM;AAAA,MACN,OAAO,YAAY,SAAY,WAAM,oBAAC,WAAQ,OAAO,SAAS;AAAA,MAC9D,KAAI;AAAA,MACJ,MAAK;AAAA,MACL,OAAO,CAAC,CAAC;AAAA;AAAA,EACX;AAEJ;AAOO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,WAAW;AACb,GAIG;AACD,QAAM,SAAS,UAAU,kBAAkB;AAC3C,QAAM,UAAU,UAAU,gBAAgB;AAE1C,QAAM,gBAAgB,CAAC,CAAC,UAAU,aAAa,SAAS,mBAAmB;AAC3E,QAAM,iBAAiB,CAAC,CAAC,UAAU,aAAa,SAAS,iBAAiB;AAC1E,QAAM,cAAc,YAAY,aAAa;AAC7C,QAAM,eAAe,YAAY,cAAc;AAE/C,SACE,qBAAC,aAAQ,WAAW,OAAO,MAAM,cAAW,gBAC1C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,OAAM;AAAA,QACN,OAAO,gBAAgB,WAAM,oBAAC,WAAQ,OAAO,QAAQ;AAAA,QACrD,KACE,gBACI,wBACA;AAAA,QAEN,MAAM,cAAc,kCAAkC;AAAA,QACtD,OAAO,iBAAiB,SAAS;AAAA;AAAA,IACnC;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,OAAM;AAAA,QACN,OAAO,iBAAiB,WAAM,oBAAC,WAAQ,OAAO,SAAS;AAAA,QACvD,KACE,iBACI,wBACC,mBAAmB,UAAU,iBAAiB,QAAQ,KACvD;AAAA,QAEN,MAAK;AAAA,QACL,OAAO,kBAAkB,UAAU;AAAA;AAAA,IACrC;AAAA,IACC,gBAAgB,oBAAC,oBAAiB;AAAA,KACrC;AAEJ;","names":[]}
@@ -11,12 +11,13 @@ function PositionPanel({
11
11
  [
12
12
  "Active workspaces",
13
13
  integer.format(data.totals.activeTenants),
14
- `of ${integer.format(data.totals.totalTenants)}`
14
+ `of ${integer.format(data.totals.totalTenants)} \xB7 status active`
15
15
  ],
16
16
  [
17
17
  "Merchants with sales",
18
18
  perf ? integer.format(perf.transactingTenants) : "\u2014",
19
- perf ? `${perf.transactingTenantRatePct}% of active` : void 0
19
+ // The API divides by every workspace, not only the active ones.
20
+ perf ? `${perf.transactingTenantRatePct}% of all workspaces, this period` : void 0
20
21
  ],
21
22
  [
22
23
  "Lifetime GMV",
@@ -45,15 +46,10 @@ function PositionPanel({
45
46
  ),
46
47
  "this period, scaled to a year"
47
48
  ],
48
- [
49
- "Active subscriptions",
50
- integer.format(data.totals.activeSubscriptions),
51
- `${integer.format(data.totals.trialingSubscriptions)} trialing`
52
- ],
53
49
  [
54
50
  "Accounts",
55
51
  integer.format(data.totals.totalAccounts),
56
- data.accounts ? `${integer.format(data.accounts.active)} active` : void 0
52
+ data.accounts ? `${integer.format(data.accounts.active)} active and verified` : void 0
57
53
  ]
58
54
  ];
59
55
  return /* @__PURE__ */ jsx(Panel, { title: "Platform position", caption: "Today", children: /* @__PURE__ */ jsx("dl", { className: styles.position, children: rows.map(([label, value, hint]) => /* @__PURE__ */ jsxs("div", { children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_overview/position-panel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { MoneyLines, Panel } from '../_ui';\nimport styles from './position.module.css';\n\nconst integer = new Intl.NumberFormat();\n\n/** The platform's standing figures — not tied to the selected window. */\nexport function PositionPanel({\n data,\n currency,\n}: {\n data: PlatformCockpit;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n}) {\n const perf = data.performance;\n const rows: Array<[string, ReactNode, string?]> = [\n [\n 'Active workspaces',\n integer.format(data.totals.activeTenants),\n `of ${integer.format(data.totals.totalTenants)}`,\n ],\n [\n 'Merchants with sales',\n perf ? integer.format(perf.transactingTenants) : '—',\n perf ? `${perf.transactingTenantRatePct}% of active` : undefined,\n ],\n [\n 'Lifetime GMV',\n <MoneyLines\n key=\"gmv\"\n rows={data.totals.lifetimeGmvByCurrency}\n currency={currency}\n amount={(r) => r.amount}\n empty=\"No sales yet\"\n />,\n ],\n [\n 'Yearly sales pace',\n <MoneyLines\n key=\"run\"\n rows={perf?.byCurrency}\n currency={currency}\n amount={(r) => r.annualizedGmvRunRate}\n empty=\"—\"\n />,\n 'this period, scaled to a year',\n ],\n [\n 'Active subscriptions',\n integer.format(data.totals.activeSubscriptions),\n `${integer.format(data.totals.trialingSubscriptions)} trialing`,\n ],\n [\n 'Accounts',\n integer.format(data.totals.totalAccounts),\n data.accounts\n ? `${integer.format(data.accounts.active)} active`\n : undefined,\n ],\n ];\n\n return (\n <Panel title=\"Platform position\" caption=\"Today\">\n <dl className={styles.position}>\n {rows.map(([label, value, hint]) => (\n <div key={label}>\n <dt>{label}</dt>\n <dd>\n <strong>{value}</strong>\n {hint && <small>{hint}</small>}\n </dd>\n </div>\n ))}\n </dl>\n </Panel>\n );\n}\n"],"mappings":"AA8BM,cAuCM,YAvCN;AA5BN,SAAS,YAAY,aAAa;AAClC,OAAO,YAAY;AAEnB,MAAM,UAAU,IAAI,KAAK,aAAa;AAG/B,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,KAAK;AAClB,QAAM,OAA4C;AAAA,IAChD;AAAA,MACE;AAAA,MACA,QAAQ,OAAO,KAAK,OAAO,aAAa;AAAA,MACxC,MAAM,QAAQ,OAAO,KAAK,OAAO,YAAY,CAAC;AAAA,IAChD;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO,QAAQ,OAAO,KAAK,kBAAkB,IAAI;AAAA,MACjD,OAAO,GAAG,KAAK,wBAAwB,gBAAgB;AAAA,IACzD;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,KAAK,OAAO;AAAA,UAClB;AAAA,UACA,QAAQ,CAAC,MAAM,EAAE;AAAA,UACjB,OAAM;AAAA;AAAA,QAJF;AAAA,MAKN;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,MAAM;AAAA,UACZ;AAAA,UACA,QAAQ,CAAC,MAAM,EAAE;AAAA,UACjB,OAAM;AAAA;AAAA,QAJF;AAAA,MAKN;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA,QAAQ,OAAO,KAAK,OAAO,mBAAmB;AAAA,MAC9C,GAAG,QAAQ,OAAO,KAAK,OAAO,qBAAqB,CAAC;AAAA,IACtD;AAAA,IACA;AAAA,MACE;AAAA,MACA,QAAQ,OAAO,KAAK,OAAO,aAAa;AAAA,MACxC,KAAK,WACD,GAAG,QAAQ,OAAO,KAAK,SAAS,MAAM,CAAC,YACvC;AAAA,IACN;AAAA,EACF;AAEA,SACE,oBAAC,SAAM,OAAM,qBAAoB,SAAQ,SACvC,8BAAC,QAAG,WAAW,OAAO,UACnB,eAAK,IAAI,CAAC,CAAC,OAAO,OAAO,IAAI,MAC5B,qBAAC,SACC;AAAA,wBAAC,QAAI,iBAAM;AAAA,IACX,qBAAC,QACC;AAAA,0BAAC,YAAQ,iBAAM;AAAA,MACd,QAAQ,oBAAC,WAAO,gBAAK;AAAA,OACxB;AAAA,OALQ,KAMV,CACD,GACH,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/_overview/position-panel.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { PlatformCockpit } from '@withpotter/lib/admin-api';\nimport { MoneyLines, Panel } from '../_ui';\nimport styles from './position.module.css';\n\nconst integer = new Intl.NumberFormat();\n\n/** The platform's standing figures — not tied to the selected window. */\nexport function PositionPanel({\n data,\n currency,\n}: {\n data: PlatformCockpit;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n}) {\n const perf = data.performance;\n const rows: Array<[string, ReactNode, string?]> = [\n [\n 'Active workspaces',\n integer.format(data.totals.activeTenants),\n `of ${integer.format(data.totals.totalTenants)} · status active`,\n ],\n [\n 'Merchants with sales',\n perf ? integer.format(perf.transactingTenants) : '—',\n // The API divides by every workspace, not only the active ones.\n perf\n ? `${perf.transactingTenantRatePct}% of all workspaces, this period`\n : undefined,\n ],\n [\n 'Lifetime GMV',\n <MoneyLines\n key=\"gmv\"\n rows={data.totals.lifetimeGmvByCurrency}\n currency={currency}\n amount={(r) => r.amount}\n empty=\"No sales yet\"\n />,\n ],\n [\n 'Yearly sales pace',\n <MoneyLines\n key=\"run\"\n rows={perf?.byCurrency}\n currency={currency}\n amount={(r) => r.annualizedGmvRunRate}\n empty=\"—\"\n />,\n 'this period, scaled to a year',\n ],\n [\n 'Accounts',\n integer.format(data.totals.totalAccounts),\n data.accounts\n ? `${integer.format(data.accounts.active)} active and verified`\n : undefined,\n ],\n ];\n\n return (\n <Panel title=\"Platform position\" caption=\"Today\">\n <dl className={styles.position}>\n {rows.map(([label, value, hint]) => (\n <div key={label}>\n <dt>{label}</dt>\n <dd>\n <strong>{value}</strong>\n {hint && <small>{hint}</small>}\n </dd>\n </div>\n ))}\n </dl>\n </Panel>\n );\n}\n"],"mappings":"AAiCM,cAkCM,YAlCN;AA/BN,SAAS,YAAY,aAAa;AAClC,OAAO,YAAY;AAEnB,MAAM,UAAU,IAAI,KAAK,aAAa;AAG/B,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,KAAK;AAClB,QAAM,OAA4C;AAAA,IAChD;AAAA,MACE;AAAA,MACA,QAAQ,OAAO,KAAK,OAAO,aAAa;AAAA,MACxC,MAAM,QAAQ,OAAO,KAAK,OAAO,YAAY,CAAC;AAAA,IAChD;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO,QAAQ,OAAO,KAAK,kBAAkB,IAAI;AAAA;AAAA,MAEjD,OACI,GAAG,KAAK,wBAAwB,qCAChC;AAAA,IACN;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,KAAK,OAAO;AAAA,UAClB;AAAA,UACA,QAAQ,CAAC,MAAM,EAAE;AAAA,UACjB,OAAM;AAAA;AAAA,QAJF;AAAA,MAKN;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,MAAM;AAAA,UACZ;AAAA,UACA,QAAQ,CAAC,MAAM,EAAE;AAAA,UACjB,OAAM;AAAA;AAAA,QAJF;AAAA,MAKN;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA,QAAQ,OAAO,KAAK,OAAO,aAAa;AAAA,MACxC,KAAK,WACD,GAAG,QAAQ,OAAO,KAAK,SAAS,MAAM,CAAC,yBACvC;AAAA,IACN;AAAA,EACF;AAEA,SACE,oBAAC,SAAM,OAAM,qBAAoB,SAAQ,SACvC,8BAAC,QAAG,WAAW,OAAO,UACnB,eAAK,IAAI,CAAC,CAAC,OAAO,OAAO,IAAI,MAC5B,qBAAC,SACC;AAAA,wBAAC,QAAI,iBAAM;AAAA,IACX,qBAAC,QACC;AAAA,0BAAC,YAAQ,iBAAM;AAAA,MACd,QAAQ,oBAAC,WAAO,gBAAK;AAAA,OACxB;AAAA,OALQ,KAMV,CACD,GACH,GACF;AAEJ;","names":[]}
@@ -12,6 +12,9 @@ function RevenueKpis({
12
12
  gmvSpark
13
13
  }) {
14
14
  const { recurring } = data;
15
+ const tracked = recurring.tracked !== false;
16
+ const notTracked = "Not tracked";
17
+ const noSource = "No billing source connected";
15
18
  const gmv = rowFor(data.gmvByCurrency, focus);
16
19
  const lifetimeShare = gmv && gmv.lifetime > 0 ? `${Math.round(gmv.inRange / gmv.lifetime * 100)}% of lifetime` : void 0;
17
20
  return /* @__PURE__ */ jsxs("section", { "aria-label": "Revenue indicators", className: "adm-grid", children: [
@@ -19,27 +22,27 @@ function RevenueKpis({
19
22
  StatCard,
20
23
  {
21
24
  label: "Monthly recurring revenue (MRR)",
22
- value: /* @__PURE__ */ jsx(CountUp, { value: recurring.mrr, format: money }),
25
+ value: tracked ? /* @__PURE__ */ jsx(CountUp, { value: recurring.mrr, format: money }) : notTracked,
23
26
  hint: `Monthly recurring revenue from active merchant billing subscriptions, in ${data.currency || "USD"}. Yearly plans are divided by 12.`,
24
- sub: `${integer.format(recurring.activeSubscriptions)} paying`
27
+ sub: tracked ? `${integer.format(recurring.activeSubscriptions)} paying` : noSource
25
28
  }
26
29
  ) }),
27
30
  /* @__PURE__ */ jsx(Reveal, { index: 1, className: "adm-span-3", children: /* @__PURE__ */ jsx(
28
31
  StatCard,
29
32
  {
30
33
  label: "Annual recurring revenue (ARR)",
31
- value: /* @__PURE__ */ jsx(CountUp, { value: recurring.arr, format: money }),
34
+ value: tracked ? /* @__PURE__ */ jsx(CountUp, { value: recurring.arr, format: money }) : notTracked,
32
35
  hint: "Annual recurring revenue: what the monthly recurring revenue adds up to over a year if nothing changes (MRR \xD7 12).",
33
- sub: "MRR \xD7 12"
36
+ sub: tracked ? "MRR \xD7 12" : noSource
34
37
  }
35
38
  ) }),
36
39
  /* @__PURE__ */ jsx(Reveal, { index: 2, className: "adm-span-3", children: /* @__PURE__ */ jsx(
37
40
  StatCard,
38
41
  {
39
42
  label: "Average revenue per account (ARPA)",
40
- value: /* @__PURE__ */ jsx(CountUp, { value: recurring.arpa, format: money2 }),
43
+ value: tracked ? /* @__PURE__ */ jsx(CountUp, { value: recurring.arpa, format: money2 }) : notTracked,
41
44
  hint: "What the average paying merchant pays each month: monthly recurring revenue divided by the number of paying merchants.",
42
- sub: "Per paying account"
45
+ sub: tracked ? "Per paying account" : noSource
43
46
  }
44
47
  ) }),
45
48
  /* @__PURE__ */ jsx(Reveal, { index: 3, className: "adm-span-3", children: /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/revenue/revenue-kpis.tsx"],"sourcesContent":["import { ADMIN_NAME } from '../_shell/admin-brand';\nimport type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { CountUp, Reveal, TONE } from '../_fx';\nimport { MoneyLines, StatCard, rowFor } from '../_ui';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/** The four headline figures: recurring revenue first, then merchant GMV. */\nexport function RevenueKpis({\n data,\n money,\n money2,\n currency,\n focus,\n gmvSpark,\n}: {\n data: PlatformRevenue;\n /** Formats recurring revenue, in the currency the API names for it. */\n money: (value: number) => string;\n money2: (value: number) => string;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n /** The one currency the share and sparkline follow, or null. */\n focus: string | null;\n gmvSpark: number[];\n}) {\n const { recurring } = data;\n const gmv = rowFor(data.gmvByCurrency, focus);\n const lifetimeShare =\n gmv && gmv.lifetime > 0\n ? `${Math.round((gmv.inRange / gmv.lifetime) * 100)}% of lifetime`\n : undefined;\n\n return (\n <section aria-label=\"Revenue indicators\" className=\"adm-grid\">\n <Reveal index={0} className=\"adm-span-3\">\n <StatCard\n label=\"Monthly recurring revenue (MRR)\"\n value={<CountUp value={recurring.mrr} format={money} />}\n hint={`Monthly recurring revenue from active merchant billing subscriptions, in ${data.currency || 'USD'}. Yearly plans are divided by 12.`}\n sub={`${integer.format(recurring.activeSubscriptions)} paying`}\n />\n </Reveal>\n <Reveal index={1} className=\"adm-span-3\">\n <StatCard\n label=\"Annual recurring revenue (ARR)\"\n value={<CountUp value={recurring.arr} format={money} />}\n hint=\"Annual recurring revenue: what the monthly recurring revenue adds up to over a year if nothing changes (MRR × 12).\"\n sub=\"MRR × 12\"\n />\n </Reveal>\n <Reveal index={2} className=\"adm-span-3\">\n <StatCard\n label=\"Average revenue per account (ARPA)\"\n value={<CountUp value={recurring.arpa} format={money2} />}\n hint=\"What the average paying merchant pays each month: monthly recurring revenue divided by the number of paying merchants.\"\n sub=\"Per paying account\"\n />\n </Reveal>\n <Reveal index={3} className=\"adm-span-3\">\n <StatCard\n label=\"Merchant sales (GMV)\"\n value={\n <MoneyLines\n rows={data.gmvByCurrency}\n currency={currency}\n amount={(g) => g.inRange}\n empty=\"No sales yet\"\n />\n }\n href=\"/admin/tenants\"\n sub={lifetimeShare}\n hint={`The merchant sales ${ADMIN_NAME}'s recurring revenue sits on, not ${ADMIN_NAME}'s own income (that's MRR). One line per currency; currencies are never added together or converted.`}\n spark={focus ? gmvSpark : undefined}\n sparkColor={TONE.money.fg}\n />\n </Reveal>\n </section>\n );\n}\n"],"mappings":"AAkCI,SAIa,KAJb;AAlCJ,SAAS,kBAAkB;AAE3B,SAAS,SAAS,QAAQ,YAAY;AACtC,SAAS,YAAY,UAAU,cAAc;AAE7C,MAAM,UAAU,IAAI,KAAK,aAAa,OAAO;AAGtC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,EAAE,UAAU,IAAI;AACtB,QAAM,MAAM,OAAO,KAAK,eAAe,KAAK;AAC5C,QAAM,gBACJ,OAAO,IAAI,WAAW,IAClB,GAAG,KAAK,MAAO,IAAI,UAAU,IAAI,WAAY,GAAG,CAAC,kBACjD;AAEN,SACE,qBAAC,aAAQ,cAAW,sBAAqB,WAAU,YACjD;AAAA,wBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,oBAAC,WAAQ,OAAO,UAAU,KAAK,QAAQ,OAAO;AAAA,QACrD,MAAM,4EAA4E,KAAK,YAAY,KAAK;AAAA,QACxG,KAAK,GAAG,QAAQ,OAAO,UAAU,mBAAmB,CAAC;AAAA;AAAA,IACvD,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,oBAAC,WAAQ,OAAO,UAAU,KAAK,QAAQ,OAAO;AAAA,QACrD,MAAK;AAAA,QACL,KAAI;AAAA;AAAA,IACN,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,oBAAC,WAAQ,OAAO,UAAU,MAAM,QAAQ,QAAQ;AAAA,QACvD,MAAK;AAAA,QACL,KAAI;AAAA;AAAA,IACN,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OACE;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,KAAK;AAAA,YACX;AAAA,YACA,QAAQ,CAAC,MAAM,EAAE;AAAA,YACjB,OAAM;AAAA;AAAA,QACR;AAAA,QAEF,MAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM,sBAAsB,UAAU,qCAAqC,UAAU;AAAA,QACrF,OAAO,QAAQ,WAAW;AAAA,QAC1B,YAAY,KAAK,MAAM;AAAA;AAAA,IACzB,GACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/revenue/revenue-kpis.tsx"],"sourcesContent":["import { ADMIN_NAME } from '../_shell/admin-brand';\nimport type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { CountUp, Reveal, TONE } from '../_fx';\nimport { MoneyLines, StatCard, rowFor } from '../_ui';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/** The four headline figures: recurring revenue first, then merchant GMV. */\nexport function RevenueKpis({\n data,\n money,\n money2,\n currency,\n focus,\n gmvSpark,\n}: {\n data: PlatformRevenue;\n /** Formats recurring revenue, in the currency the API names for it. */\n money: (value: number) => string;\n money2: (value: number) => string;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n /** The one currency the share and sparkline follow, or null. */\n focus: string | null;\n gmvSpark: number[];\n}) {\n const { recurring } = data;\n // Without a billing source the API sends 0s; show that nothing is measured.\n const tracked = recurring.tracked !== false;\n const notTracked = 'Not tracked';\n const noSource = 'No billing source connected';\n const gmv = rowFor(data.gmvByCurrency, focus);\n const lifetimeShare =\n gmv && gmv.lifetime > 0\n ? `${Math.round((gmv.inRange / gmv.lifetime) * 100)}% of lifetime`\n : undefined;\n\n return (\n <section aria-label=\"Revenue indicators\" className=\"adm-grid\">\n <Reveal index={0} className=\"adm-span-3\">\n <StatCard\n label=\"Monthly recurring revenue (MRR)\"\n value={\n tracked ? (\n <CountUp value={recurring.mrr} format={money} />\n ) : (\n notTracked\n )\n }\n hint={`Monthly recurring revenue from active merchant billing subscriptions, in ${data.currency || 'USD'}. Yearly plans are divided by 12.`}\n sub={\n tracked\n ? `${integer.format(recurring.activeSubscriptions)} paying`\n : noSource\n }\n />\n </Reveal>\n <Reveal index={1} className=\"adm-span-3\">\n <StatCard\n label=\"Annual recurring revenue (ARR)\"\n value={\n tracked ? (\n <CountUp value={recurring.arr} format={money} />\n ) : (\n notTracked\n )\n }\n hint=\"Annual recurring revenue: what the monthly recurring revenue adds up to over a year if nothing changes (MRR × 12).\"\n sub={tracked ? 'MRR × 12' : noSource}\n />\n </Reveal>\n <Reveal index={2} className=\"adm-span-3\">\n <StatCard\n label=\"Average revenue per account (ARPA)\"\n value={\n tracked ? (\n <CountUp value={recurring.arpa} format={money2} />\n ) : (\n notTracked\n )\n }\n hint=\"What the average paying merchant pays each month: monthly recurring revenue divided by the number of paying merchants.\"\n sub={tracked ? 'Per paying account' : noSource}\n />\n </Reveal>\n <Reveal index={3} className=\"adm-span-3\">\n <StatCard\n label=\"Merchant sales (GMV)\"\n value={\n <MoneyLines\n rows={data.gmvByCurrency}\n currency={currency}\n amount={(g) => g.inRange}\n empty=\"No sales yet\"\n />\n }\n href=\"/admin/tenants\"\n sub={lifetimeShare}\n hint={`The merchant sales ${ADMIN_NAME}'s recurring revenue sits on, not ${ADMIN_NAME}'s own income (that's MRR). One line per currency; currencies are never added together or converted.`}\n spark={focus ? gmvSpark : undefined}\n sparkColor={TONE.money.fg}\n />\n </Reveal>\n </section>\n );\n}\n"],"mappings":"AAsCI,SAMU,KANV;AAtCJ,SAAS,kBAAkB;AAE3B,SAAS,SAAS,QAAQ,YAAY;AACtC,SAAS,YAAY,UAAU,cAAc;AAE7C,MAAM,UAAU,IAAI,KAAK,aAAa,OAAO;AAGtC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,EAAE,UAAU,IAAI;AAEtB,QAAM,UAAU,UAAU,YAAY;AACtC,QAAM,aAAa;AACnB,QAAM,WAAW;AACjB,QAAM,MAAM,OAAO,KAAK,eAAe,KAAK;AAC5C,QAAM,gBACJ,OAAO,IAAI,WAAW,IAClB,GAAG,KAAK,MAAO,IAAI,UAAU,IAAI,WAAY,GAAG,CAAC,kBACjD;AAEN,SACE,qBAAC,aAAQ,cAAW,sBAAqB,WAAU,YACjD;AAAA,wBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OACE,UACE,oBAAC,WAAQ,OAAO,UAAU,KAAK,QAAQ,OAAO,IAE9C;AAAA,QAGJ,MAAM,4EAA4E,KAAK,YAAY,KAAK;AAAA,QACxG,KACE,UACI,GAAG,QAAQ,OAAO,UAAU,mBAAmB,CAAC,YAChD;AAAA;AAAA,IAER,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OACE,UACE,oBAAC,WAAQ,OAAO,UAAU,KAAK,QAAQ,OAAO,IAE9C;AAAA,QAGJ,MAAK;AAAA,QACL,KAAK,UAAU,gBAAa;AAAA;AAAA,IAC9B,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OACE,UACE,oBAAC,WAAQ,OAAO,UAAU,MAAM,QAAQ,QAAQ,IAEhD;AAAA,QAGJ,MAAK;AAAA,QACL,KAAK,UAAU,uBAAuB;AAAA;AAAA,IACxC,GACF;AAAA,IACA,oBAAC,UAAO,OAAO,GAAG,WAAU,cAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OACE;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,KAAK;AAAA,YACX;AAAA,YACA,QAAQ,CAAC,MAAM,EAAE;AAAA,YACjB,OAAM;AAAA;AAAA,QACR;AAAA,QAEF,MAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM,sBAAsB,UAAU,qCAAqC,UAAU;AAAA,QACrF,OAAO,QAAQ,WAAW;AAAA,QAC1B,YAAY,KAAK,MAAM;AAAA;AAAA,IACzB,GACF;AAAA,KACF;AAEJ;","names":[]}
@@ -24,6 +24,7 @@ function RevenueOverview({
24
24
  const gmv = rowFor(data.gmvByCurrency, focus);
25
25
  const gmvSeries = useMemo(() => toTrend(gmv?.series, "gmv"), [gmv]);
26
26
  const gmvCaption = focus ? `${period} \xB7 ${focus}` : period;
27
+ const recurringTracked = data.recurring.tracked !== false;
27
28
  return /* @__PURE__ */ jsxs(Fragment, { children: [
28
29
  /* @__PURE__ */ jsx(
29
30
  RevenueKpis,
@@ -55,8 +56,15 @@ function RevenueOverview({
55
56
  ) }) }) : /* @__PURE__ */ jsx("p", { className: styles.empty, children: PICK_CURRENCY })
56
57
  }
57
58
  ) }) }),
58
- /* @__PURE__ */ jsxs("div", { className: "adm-grid", children: [
59
- /* @__PURE__ */ jsx("div", { className: "adm-span-7", children: /* @__PURE__ */ jsx(HealthPanel, { health, money, caption: recurringCaption }) }),
59
+ recurringTracked && /* @__PURE__ */ jsxs("div", { className: "adm-grid", children: [
60
+ /* @__PURE__ */ jsx("div", { className: "adm-span-7", children: /* @__PURE__ */ jsx(
61
+ HealthPanel,
62
+ {
63
+ health,
64
+ money,
65
+ caption: recurringCaption
66
+ }
67
+ ) }),
60
68
  /* @__PURE__ */ jsx("div", { className: "adm-span-5", children: /* @__PURE__ */ jsx(
61
69
  PlanMixPanel,
62
70
  {
@@ -67,7 +75,7 @@ function RevenueOverview({
67
75
  ) })
68
76
  ] }),
69
77
  /* @__PURE__ */ jsxs("div", { className: "adm-grid", children: [
70
- /* @__PURE__ */ jsx("div", { className: "adm-span-8", children: /* @__PURE__ */ jsx(
78
+ /* @__PURE__ */ jsx("div", { className: recurringTracked ? "adm-span-8" : "adm-span-12", children: /* @__PURE__ */ jsx(
71
79
  TopTenantsPanel,
72
80
  {
73
81
  tenants: gmv?.topTenants ?? [],
@@ -75,7 +83,7 @@ function RevenueOverview({
75
83
  focus
76
84
  }
77
85
  ) }),
78
- /* @__PURE__ */ jsx("div", { className: "adm-span-4", children: /* @__PURE__ */ jsx(SubscriptionsPanel, { recurring: data.recurring, span }) })
86
+ recurringTracked && /* @__PURE__ */ jsx("div", { className: "adm-span-4", children: /* @__PURE__ */ jsx(SubscriptionsPanel, { recurring: data.recurring, span }) })
79
87
  ] })
80
88
  ] });
81
89
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/revenue/revenue-overview.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport { TimeSeriesChart } from '@withpotter/components/charts';\nimport type { PlatformCockpit, PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { PICK_CURRENCY, Panel, moneyIn, rowFor, toTrend } from '../_ui';\nimport { Tinted } from '../audit/tinted';\nimport { HealthPanel } from './health-panel';\nimport { PlanMixPanel } from './plan-mix-panel';\nimport { RevenueKpis } from './revenue-kpis';\nimport { SubscriptionsPanel } from './subscriptions-panel';\nimport { TopTenantsPanel } from './top-tenants-panel';\nimport styles from './revenue.module.css';\n\n/**\n * Overview tab: the four headline figures, then the GMV trend as the one\n * full-width primary chart, then revenue health, plan mix, top merchants\n * and subscriptions beneath it. Merchant GMV is per currency: the chart and\n * the leaderboard follow one currency (`focus`), never a mix.\n */\nexport function RevenueOverview({\n data,\n health,\n money,\n money2,\n currency,\n focus,\n period,\n span,\n recurringCaption,\n}: {\n data: PlatformRevenue;\n health: PlatformCockpit['health'] | undefined;\n /** Formats recurring revenue, in the currency the API names for it. */\n money: (value: number) => string;\n money2: (value: number) => string;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n /** The one currency the chart and leaderboard show, or null. */\n focus: string | null;\n period: string;\n span: string;\n recurringCaption: string;\n}) {\n const gmv = rowFor(data.gmvByCurrency, focus);\n const gmvSeries = useMemo(() => toTrend(gmv?.series, 'gmv'), [gmv]);\n const gmvCaption = focus ? `${period} · ${focus}` : period;\n\n return (\n <>\n <RevenueKpis\n data={data}\n money={money}\n money2={money2}\n currency={currency}\n focus={focus}\n gmvSpark={gmvSeries.map((p) => p.value)}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <Panel\n title=\"GMV trend\"\n caption={gmvCaption}\n height=\"calc(var(--adm-panel-h) + 32px)\"\n >\n {focus ? (\n <div className={styles.flatChart}>\n <Tinted tone=\"money\">\n <TimeSeriesChart\n data={gmvSeries}\n compare={null}\n compareLabel={`Previous ${span}`}\n formatValue={moneyIn(focus)}\n emptyMessage={`No paid ${focus} orders in this window yet`}\n height={240}\n />\n </Tinted>\n </div>\n ) : (\n <p className={styles.empty}>{PICK_CURRENCY}</p>\n )}\n </Panel>\n </div>\n </div>\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-7\">\n <HealthPanel health={health} money={money} caption={recurringCaption} />\n </div>\n <div className=\"adm-span-5\">\n <PlanMixPanel\n planBreakdown={data.recurring.planBreakdown}\n money={money}\n caption={recurringCaption}\n />\n </div>\n </div>\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-8\">\n <TopTenantsPanel\n tenants={gmv?.topTenants ?? []}\n lifetime={gmv?.lifetime ?? 0}\n focus={focus}\n />\n </div>\n <div className=\"adm-span-4\">\n <SubscriptionsPanel recurring={data.recurring} span={span} />\n </div>\n </div>\n </>\n );\n}\n"],"mappings":";AAiDI,mBACE,KAoCA,YArCF;AA/CJ,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAEhC,SAAS,eAAe,OAAO,SAAS,QAAQ,eAAe;AAC/D,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,OAAO,YAAY;AAQZ,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAaG;AACD,QAAM,MAAM,OAAO,KAAK,eAAe,KAAK;AAC5C,QAAM,YAAY,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,GAAG,CAAC,GAAG,CAAC;AAClE,QAAM,aAAa,QAAQ,GAAG,MAAM,SAAM,KAAK,KAAK;AAEpD,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA;AAAA,IACxC;AAAA,IAEA,oBAAC,SAAI,WAAU,YACb,8BAAC,SAAI,WAAU,eACb;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAO;AAAA,QAEN,kBACC,oBAAC,SAAI,WAAW,OAAO,WACrB,8BAAC,UAAO,MAAK,SACX;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,cAAc,YAAY,IAAI;AAAA,YAC9B,aAAa,QAAQ,KAAK;AAAA,YAC1B,cAAc,WAAW,KAAK;AAAA,YAC9B,QAAQ;AAAA;AAAA,QACV,GACF,GACF,IAEA,oBAAC,OAAE,WAAW,OAAO,OAAQ,yBAAc;AAAA;AAAA,IAE/C,GACF,GACF;AAAA,IAEA,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAI,WAAU,cACb,8BAAC,eAAY,QAAgB,OAAc,SAAS,kBAAkB,GACxE;AAAA,MACA,oBAAC,SAAI,WAAU,cACb;AAAA,QAAC;AAAA;AAAA,UACC,eAAe,KAAK,UAAU;AAAA,UAC9B;AAAA,UACA,SAAS;AAAA;AAAA,MACX,GACF;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAI,WAAU,cACb;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,KAAK,cAAc,CAAC;AAAA,UAC7B,UAAU,KAAK,YAAY;AAAA,UAC3B;AAAA;AAAA,MACF,GACF;AAAA,MACA,oBAAC,SAAI,WAAU,cACb,8BAAC,sBAAmB,WAAW,KAAK,WAAW,MAAY,GAC7D;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/revenue/revenue-overview.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport { TimeSeriesChart } from '@withpotter/components/charts';\nimport type { PlatformCockpit, PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { PICK_CURRENCY, Panel, moneyIn, rowFor, toTrend } from '../_ui';\nimport { Tinted } from '../audit/tinted';\nimport { HealthPanel } from './health-panel';\nimport { PlanMixPanel } from './plan-mix-panel';\nimport { RevenueKpis } from './revenue-kpis';\nimport { SubscriptionsPanel } from './subscriptions-panel';\nimport { TopTenantsPanel } from './top-tenants-panel';\nimport styles from './revenue.module.css';\n\n/**\n * Overview tab: the four headline figures, then the GMV trend as the one\n * full-width primary chart, then revenue health, plan mix, top merchants\n * and subscriptions beneath it. Merchant GMV is per currency: the chart and\n * the leaderboard follow one currency (`focus`), never a mix.\n */\nexport function RevenueOverview({\n data,\n health,\n money,\n money2,\n currency,\n focus,\n period,\n span,\n recurringCaption,\n}: {\n data: PlatformRevenue;\n health: PlatformCockpit['health'] | undefined;\n /** Formats recurring revenue, in the currency the API names for it. */\n money: (value: number) => string;\n money2: (value: number) => string;\n /** The currency filter's choice; empty shows a line per currency. */\n currency: string;\n /** The one currency the chart and leaderboard show, or null. */\n focus: string | null;\n period: string;\n span: string;\n recurringCaption: string;\n}) {\n const gmv = rowFor(data.gmvByCurrency, focus);\n const gmvSeries = useMemo(() => toTrend(gmv?.series, 'gmv'), [gmv]);\n const gmvCaption = focus ? `${period} · ${focus}` : period;\n const recurringTracked = data.recurring.tracked !== false;\n\n return (\n <>\n <RevenueKpis\n data={data}\n money={money}\n money2={money2}\n currency={currency}\n focus={focus}\n gmvSpark={gmvSeries.map((p) => p.value)}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <Panel\n title=\"GMV trend\"\n caption={gmvCaption}\n height=\"calc(var(--adm-panel-h) + 32px)\"\n >\n {focus ? (\n <div className={styles.flatChart}>\n <Tinted tone=\"money\">\n <TimeSeriesChart\n data={gmvSeries}\n compare={null}\n compareLabel={`Previous ${span}`}\n formatValue={moneyIn(focus)}\n emptyMessage={`No paid ${focus} orders in this window yet`}\n height={240}\n />\n </Tinted>\n </div>\n ) : (\n <p className={styles.empty}>{PICK_CURRENCY}</p>\n )}\n </Panel>\n </div>\n </div>\n\n {recurringTracked && (\n <div className=\"adm-grid\">\n <div className=\"adm-span-7\">\n <HealthPanel\n health={health}\n money={money}\n caption={recurringCaption}\n />\n </div>\n <div className=\"adm-span-5\">\n <PlanMixPanel\n planBreakdown={data.recurring.planBreakdown}\n money={money}\n caption={recurringCaption}\n />\n </div>\n </div>\n )}\n\n <div className=\"adm-grid\">\n <div className={recurringTracked ? 'adm-span-8' : 'adm-span-12'}>\n <TopTenantsPanel\n tenants={gmv?.topTenants ?? []}\n lifetime={gmv?.lifetime ?? 0}\n focus={focus}\n />\n </div>\n {recurringTracked && (\n <div className=\"adm-span-4\">\n <SubscriptionsPanel recurring={data.recurring} span={span} />\n </div>\n )}\n </div>\n </>\n );\n}\n"],"mappings":";AAkDI,mBACE,KAqCE,YAtCJ;AAhDJ,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAEhC,SAAS,eAAe,OAAO,SAAS,QAAQ,eAAe;AAC/D,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,OAAO,YAAY;AAQZ,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAaG;AACD,QAAM,MAAM,OAAO,KAAK,eAAe,KAAK;AAC5C,QAAM,YAAY,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,GAAG,CAAC,GAAG,CAAC;AAClE,QAAM,aAAa,QAAQ,GAAG,MAAM,SAAM,KAAK,KAAK;AACpD,QAAM,mBAAmB,KAAK,UAAU,YAAY;AAEpD,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA;AAAA,IACxC;AAAA,IAEA,oBAAC,SAAI,WAAU,YACb,8BAAC,SAAI,WAAU,eACb;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAS;AAAA,QACT,QAAO;AAAA,QAEN,kBACC,oBAAC,SAAI,WAAW,OAAO,WACrB,8BAAC,UAAO,MAAK,SACX;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,cAAc,YAAY,IAAI;AAAA,YAC9B,aAAa,QAAQ,KAAK;AAAA,YAC1B,cAAc,WAAW,KAAK;AAAA,YAC9B,QAAQ;AAAA;AAAA,QACV,GACF,GACF,IAEA,oBAAC,OAAE,WAAW,OAAO,OAAQ,yBAAc;AAAA;AAAA,IAE/C,GACF,GACF;AAAA,IAEC,oBACC,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAI,WAAU,cACb;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,SAAS;AAAA;AAAA,MACX,GACF;AAAA,MACA,oBAAC,SAAI,WAAU,cACb;AAAA,QAAC;AAAA;AAAA,UACC,eAAe,KAAK,UAAU;AAAA,UAC9B;AAAA,UACA,SAAS;AAAA;AAAA,MACX,GACF;AAAA,OACF;AAAA,IAGF,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAI,WAAW,mBAAmB,eAAe,eAChD;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,KAAK,cAAc,CAAC;AAAA,UAC7B,UAAU,KAAK,YAAY;AAAA,UAC3B;AAAA;AAAA,MACF,GACF;AAAA,MACC,oBACC,oBAAC,SAAI,WAAU,cACb,8BAAC,sBAAmB,WAAW,KAAK,WAAW,MAAY,GAC7D;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withpotter/pages-admin",
3
- "version": "0.13.0-next.62",
3
+ "version": "0.13.0-next.63",
4
4
  "description": "Box console platform-admin routes: overview, revenue, accounts, tenants, admins, roles, audit.",
5
5
  "license": "UNLICENSED",
6
6
  "sideEffects": false,
@@ -31,9 +31,9 @@
31
31
  "dependencies": {
32
32
  "@radix-ui/react-popover": "^1.1.23",
33
33
  "@tanstack/react-query": "^5.90.20",
34
- "@withpotter/lib": "^0.13.0-next.62",
35
- "@withpotter/platform-admin": "^0.13.0-next.62",
36
- "@withpotter/ui-kit": "^0.13.0-next.62",
34
+ "@withpotter/lib": "^0.13.0-next.63",
35
+ "@withpotter/platform-admin": "^0.13.0-next.63",
36
+ "@withpotter/ui-kit": "^0.13.0-next.63",
37
37
  "lucide-react": "^0.562.0",
38
38
  "motion": "^12.42.2"
39
39
  },
@@ -50,7 +50,7 @@
50
50
  "typescript": "^5"
51
51
  },
52
52
  "publishConfig": {
53
- "registry": "https://registry.npmjs.org",
53
+ "registry": "https://registry.npmjs.org/",
54
54
  "access": "restricted"
55
55
  }
56
56
  }