@withpotter/pages-admin 0.13.0-next.104 → 0.13.0-next.106

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 (47) hide show
  1. package/dist/admin/_overview/activation-panel.js +6 -6
  2. package/dist/admin/_overview/activation-panel.js.map +1 -1
  3. package/dist/admin/_overview/attention-groups.js +8 -8
  4. package/dist/admin/_overview/attention-groups.js.map +1 -1
  5. package/dist/admin/_overview/attention-panel.js +3 -3
  6. package/dist/admin/_overview/attention-panel.js.map +1 -1
  7. package/dist/admin/_overview/control-room.js +9 -9
  8. package/dist/admin/_overview/control-room.js.map +1 -1
  9. package/dist/admin/_overview/kpi-row.js +7 -7
  10. package/dist/admin/_overview/kpi-row.js.map +1 -1
  11. package/dist/admin/_overview/leaders-panel.js +1 -1
  12. package/dist/admin/_overview/leaders-panel.js.map +1 -1
  13. package/dist/admin/_overview/portfolio-panel.js +5 -5
  14. package/dist/admin/_overview/portfolio-panel.js.map +1 -1
  15. package/dist/admin/_overview/position-panel.js +6 -6
  16. package/dist/admin/_overview/position-panel.js.map +1 -1
  17. package/dist/admin/_ui/data-table.js +1 -1
  18. package/dist/admin/_ui/data-table.js.map +1 -1
  19. package/dist/admin/_ui/list-card.js +1 -1
  20. package/dist/admin/_ui/list-card.js.map +1 -1
  21. package/dist/admin/_ui/trend.js +2 -2
  22. package/dist/admin/_ui/trend.js.map +1 -1
  23. package/dist/admin/page.js +6 -6
  24. package/dist/admin/page.js.map +1 -1
  25. package/dist/admin/payout-tiers/_tier-dialog.js +31 -21
  26. package/dist/admin/payout-tiers/_tier-dialog.js.map +1 -1
  27. package/dist/admin/payout-tiers/requirement-labels.js +70 -0
  28. package/dist/admin/payout-tiers/requirement-labels.js.map +1 -0
  29. package/dist/admin/payout-tiers/tier-preview-result.js +10 -9
  30. package/dist/admin/payout-tiers/tier-preview-result.js.map +1 -1
  31. package/dist/admin/payout-tiers/tiers-table.js +6 -7
  32. package/dist/admin/payout-tiers/tiers-table.js.map +1 -1
  33. package/dist/admin/payout-tiers/tiers-workspace.js +2 -2
  34. package/dist/admin/payout-tiers/tiers-workspace.js.map +1 -1
  35. package/dist/admin/revenue/cohort-panel.js +1 -1
  36. package/dist/admin/revenue/cohort-panel.js.map +1 -1
  37. package/dist/admin/revenue/plan-mix-panel.js +2 -2
  38. package/dist/admin/revenue/plan-mix-panel.js.map +1 -1
  39. package/dist/admin/revenue/revenue-kpis.js +3 -3
  40. package/dist/admin/revenue/revenue-kpis.js.map +1 -1
  41. package/dist/admin/revenue/revenue-overview.js +1 -1
  42. package/dist/admin/revenue/revenue-overview.js.map +1 -1
  43. package/dist/admin/revenue/subscriptions-view.js +3 -3
  44. package/dist/admin/revenue/subscriptions-view.js.map +1 -1
  45. package/dist/admin/revenue/top-tenants-panel.js +3 -3
  46. package/dist/admin/revenue/top-tenants-panel.js.map +1 -1
  47. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_ui/list-card.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentType, ReactNode } from 'react';\nimport { Button, TableShell } from '@withpotter/ui-kit';\nimport { EmptyState } from './empty-state';\nimport { Skeleton } from './skeleton';\nimport styles from './list-card.module.css';\n\n/** What an empty cell shows: an en dash, never a blank. */\nexport const EMPTY = '–';\n\n/**\n * A list table in its own card: title, search and filters in the toolbar,\n * rows scrolling under a sticky header, the pager in the footer. Owns the\n * loading, error and empty rows so each list page only declares columns.\n */\nexport function ListCard({\n title,\n count,\n controls,\n head,\n columns,\n minWidth = 760,\n selection,\n isLoading,\n isError,\n onRetry,\n errorTitle,\n isEmpty,\n emptyIcon,\n emptyTitle,\n emptyDescription,\n footer,\n children,\n}: {\n title: string;\n count?: number;\n controls?: ReactNode;\n /** The header <tr> of <Th> cells. */\n head: ReactNode;\n /** Column count, for skeleton and state rows. */\n columns: number;\n minWidth?: number;\n /** Takes the header row's place while rows are ticked. */\n selection?: ReactNode;\n isLoading?: boolean;\n isError?: boolean;\n onRetry?: () => void;\n errorTitle: string;\n isEmpty?: boolean;\n emptyIcon?: ComponentType<{ size?: number; color?: string }>;\n emptyTitle: string;\n emptyDescription?: string;\n footer?: ReactNode;\n children: ReactNode;\n}) {\n const state = (body: ReactNode) => (\n <tr>\n <td colSpan={columns} className=\"!p-0\">\n {body}\n </td>\n </tr>\n );\n\n return (\n <section\n className={`adm-section ${styles.card}`}\n aria-label={title}\n aria-busy={isLoading || undefined}\n >\n <TableShell\n bare\n minWidth={minWidth}\n head={head}\n selection={selection}\n columnCount={columns}\n toolbar={\n <>\n <h2 className={styles.title}>\n {title}\n {count !== undefined && (\n <span className={styles.count}>{count}</span>\n )}\n </h2>\n {controls}\n </>\n }\n footer={footer}\n >\n {isLoading\n ? Array.from({ length: 8 }, (_, row) => (\n <tr key={`sk-${row}`} aria-hidden>\n {Array.from({ length: columns }, (_, col) => (\n <td key={col}>\n <Skeleton width={`${48 + ((row + col) % 4) * 12}%`} />\n </td>\n ))}\n </tr>\n ))\n : isError\n ? state(\n <EmptyState\n tone=\"error\"\n title={errorTitle}\n description=\"Please retry. If this persists, check the API logs.\"\n action={\n onRetry && (\n <Button size=\"sm\" variant=\"secondary\" onClick={onRetry}>\n Try again\n </Button>\n )\n }\n />,\n )\n : isEmpty\n ? state(\n <EmptyState\n icon={emptyIcon}\n title={emptyTitle}\n description={emptyDescription}\n />,\n )\n : children}\n </TableShell>\n </section>\n );\n}\n\n/** Count on the left, Previous · Page n of m · Next on the right. */\nexport function ListPager({\n page,\n totalPages,\n total,\n noun,\n onPage,\n}: {\n page: number;\n totalPages: number;\n total?: number;\n noun: string;\n onPage: (next: number) => void;\n}) {\n return (\n <div className={styles.footer}>\n <span>\n {total != null\n ? `${new Intl.NumberFormat().format(total)} ${noun}`\n : ''}\n </span>\n <div className={styles.pages}>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => onPage(Math.max(1, page - 1))}\n disabled={page <= 1}\n >\n Previous\n </Button>\n <span>\n Page {page} of {totalPages}\n </span>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => onPage(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n >\n Next\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";AA0DM,SAmBI,UAnBJ,KAoBM,YApBN;AAvDN,SAAS,QAAQ,kBAAkB;AACnC,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,OAAO,YAAY;AAGZ,MAAM,QAAQ;AAOd,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAqBG;AACD,QAAM,QAAQ,CAAC,SACb,oBAAC,QACC,8BAAC,QAAG,SAAS,SAAS,WAAU,QAC7B,gBACH,GACF;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,eAAe,OAAO,IAAI;AAAA,MACrC,cAAY;AAAA,MACZ,aAAW,aAAa;AAAA,MAExB;AAAA,QAAC;AAAA;AAAA,UACC,MAAI;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,SACE,iCACE;AAAA,iCAAC,QAAG,WAAW,OAAO,OACnB;AAAA;AAAA,cACA,UAAU,UACT,oBAAC,UAAK,WAAW,OAAO,OAAQ,iBAAM;AAAA,eAE1C;AAAA,YACC;AAAA,aACH;AAAA,UAEF;AAAA,UAEC,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,QAC5B,oBAAC,QAAqB,eAAW,MAC9B,gBAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAACA,IAAG,QACnC,oBAAC,QACC,8BAAC,YAAS,OAAO,GAAG,MAAO,MAAM,OAAO,IAAK,EAAE,KAAK,KAD7C,GAET,CACD,KALM,MAAM,GAAG,EAMlB,CACD,IACD,UACE;AAAA,YACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,aAAY;AAAA,gBACZ,QACE,WACE,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,SAAS,uBAExD;AAAA;AAAA,YAGN;AAAA,UACF,IACA,UACE;AAAA,YACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,aAAa;AAAA;AAAA,YACf;AAAA,UACF,IACA;AAAA;AAAA,MACV;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,qBAAC,SAAI,WAAW,OAAO,QACrB;AAAA,wBAAC,UACE,mBAAS,OACN,GAAG,IAAI,KAAK,aAAa,EAAE,OAAO,KAAK,CAAC,IAAI,IAAI,KAChD,IACN;AAAA,IACA,qBAAC,SAAI,WAAW,OAAO,OACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,UAC3C,UAAU,QAAQ;AAAA,UACnB;AAAA;AAAA,MAED;AAAA,MACA,qBAAC,UAAK;AAAA;AAAA,QACE;AAAA,QAAK;AAAA,QAAK;AAAA,SAClB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,OAAO,KAAK,IAAI,YAAY,OAAO,CAAC,CAAC;AAAA,UACpD,UAAU,QAAQ;AAAA,UACnB;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;","names":["_"]}
1
+ {"version":3,"sources":["../../../src/admin/_ui/list-card.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentType, ReactNode } from 'react';\nimport { Button, TableShell } from '@withpotter/ui-kit';\nimport { EmptyState } from './empty-state';\nimport { Skeleton } from './skeleton';\nimport styles from './list-card.module.css';\n\n/** What an empty cell shows: an en dash, never a blank. */\nexport const EMPTY = '–';\n\n/**\n * A list table in its own card: title, search and filters in the toolbar,\n * rows scrolling under a sticky header, the pager in the footer. Owns the\n * loading, error and empty rows so each list page only declares columns.\n */\nexport function ListCard({\n title,\n count,\n controls,\n head,\n columns,\n minWidth = 760,\n selection,\n isLoading,\n isError,\n onRetry,\n errorTitle,\n isEmpty,\n emptyIcon,\n emptyTitle,\n emptyDescription,\n footer,\n children,\n}: {\n title: string;\n count?: number;\n controls?: ReactNode;\n /** The header <tr> of <Th> cells. */\n head: ReactNode;\n /** Column count, for skeleton and state rows. */\n columns: number;\n minWidth?: number;\n /** Takes the header row's place while rows are ticked. */\n selection?: ReactNode;\n isLoading?: boolean;\n isError?: boolean;\n onRetry?: () => void;\n errorTitle: string;\n isEmpty?: boolean;\n emptyIcon?: ComponentType<{ size?: number; color?: string }>;\n emptyTitle: string;\n emptyDescription?: string;\n footer?: ReactNode;\n children: ReactNode;\n}) {\n const state = (body: ReactNode) => (\n <tr>\n <td colSpan={columns} className=\"!p-0\">\n {body}\n </td>\n </tr>\n );\n\n return (\n <section\n className={`adm-section ${styles.card}`}\n aria-label={title}\n aria-busy={isLoading || undefined}\n >\n <TableShell\n bare\n minWidth={minWidth}\n head={head}\n selection={selection}\n columnCount={columns}\n toolbar={\n <>\n <h2 className={styles.title}>\n {title}\n {count !== undefined && (\n <span className={styles.count}>{count}</span>\n )}\n </h2>\n {controls}\n </>\n }\n footer={footer}\n >\n {isLoading\n ? Array.from({ length: 8 }, (_, row) => (\n <tr key={`sk-${row}`} aria-hidden>\n {Array.from({ length: columns }, (_, col) => (\n <td key={col}>\n <Skeleton width={`${48 + ((row + col) % 4) * 12}%`} />\n </td>\n ))}\n </tr>\n ))\n : isError\n ? state(\n <EmptyState\n tone=\"error\"\n title={errorTitle}\n description=\"Please try again. If it keeps happening, tell the engineering team.\"\n action={\n onRetry && (\n <Button size=\"sm\" variant=\"secondary\" onClick={onRetry}>\n Try again\n </Button>\n )\n }\n />,\n )\n : isEmpty\n ? state(\n <EmptyState\n icon={emptyIcon}\n title={emptyTitle}\n description={emptyDescription}\n />,\n )\n : children}\n </TableShell>\n </section>\n );\n}\n\n/** Count on the left, Previous · Page n of m · Next on the right. */\nexport function ListPager({\n page,\n totalPages,\n total,\n noun,\n onPage,\n}: {\n page: number;\n totalPages: number;\n total?: number;\n noun: string;\n onPage: (next: number) => void;\n}) {\n return (\n <div className={styles.footer}>\n <span>\n {total != null\n ? `${new Intl.NumberFormat().format(total)} ${noun}`\n : ''}\n </span>\n <div className={styles.pages}>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => onPage(Math.max(1, page - 1))}\n disabled={page <= 1}\n >\n Previous\n </Button>\n <span>\n Page {page} of {totalPages}\n </span>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => onPage(Math.min(totalPages, page + 1))}\n disabled={page >= totalPages}\n >\n Next\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";AA0DM,SAmBI,UAnBJ,KAoBM,YApBN;AAvDN,SAAS,QAAQ,kBAAkB;AACnC,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,OAAO,YAAY;AAGZ,MAAM,QAAQ;AAOd,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAqBG;AACD,QAAM,QAAQ,CAAC,SACb,oBAAC,QACC,8BAAC,QAAG,SAAS,SAAS,WAAU,QAC7B,gBACH,GACF;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,eAAe,OAAO,IAAI;AAAA,MACrC,cAAY;AAAA,MACZ,aAAW,aAAa;AAAA,MAExB;AAAA,QAAC;AAAA;AAAA,UACC,MAAI;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,SACE,iCACE;AAAA,iCAAC,QAAG,WAAW,OAAO,OACnB;AAAA;AAAA,cACA,UAAU,UACT,oBAAC,UAAK,WAAW,OAAO,OAAQ,iBAAM;AAAA,eAE1C;AAAA,YACC;AAAA,aACH;AAAA,UAEF;AAAA,UAEC,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,QAC5B,oBAAC,QAAqB,eAAW,MAC9B,gBAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAACA,IAAG,QACnC,oBAAC,QACC,8BAAC,YAAS,OAAO,GAAG,MAAO,MAAM,OAAO,IAAK,EAAE,KAAK,KAD7C,GAET,CACD,KALM,MAAM,GAAG,EAMlB,CACD,IACD,UACE;AAAA,YACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,aAAY;AAAA,gBACZ,QACE,WACE,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,SAAS,uBAExD;AAAA;AAAA,YAGN;AAAA,UACF,IACA,UACE;AAAA,YACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,aAAa;AAAA;AAAA,YACf;AAAA,UACF,IACA;AAAA;AAAA,MACV;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,qBAAC,SAAI,WAAW,OAAO,QACrB;AAAA,wBAAC,UACE,mBAAS,OACN,GAAG,IAAI,KAAK,aAAa,EAAE,OAAO,KAAK,CAAC,IAAI,IAAI,KAChD,IACN;AAAA,IACA,qBAAC,SAAI,WAAW,OAAO,OACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,UAC3C,UAAU,QAAQ;AAAA,UACnB;AAAA;AAAA,MAED;AAAA,MACA,qBAAC,UAAK;AAAA;AAAA,QACE;AAAA,QAAK;AAAA,QAAK;AAAA,SAClB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,OAAO,KAAK,IAAI,YAAY,OAAO,CAAC,CAAC;AAAA,UACpD,UAAU,QAAQ;AAAA,UACnB;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;","names":["_"]}
@@ -20,9 +20,9 @@ function GmvOrdersChart({
20
20
  data: gmvTrend,
21
21
  compare: compare ? previousGmvTrend : null,
22
22
  compareLabel: `Previous ${span}`,
23
- label: "GMV",
23
+ label: "Sales",
24
24
  formatValue: money,
25
- emptyMessage: "No merchant GMV in this period",
25
+ emptyMessage: "No sales in this period",
26
26
  height: 160
27
27
  }
28
28
  ),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/_ui/trend.tsx"],"sourcesContent":["'use client';\n\nimport { TimeSeriesChart } from '@withpotter/components/charts';\n\n/** A `{date, N}[]` series reshaped into the `{date, value}` TimeSeriesChart wants. */\nexport function toTrend<K extends string>(\n series: Array<{ date: string } & Record<K, number>> | undefined,\n key: K,\n): Array<{ date: string; value: number }> {\n return (series ?? []).map((p) => ({ date: p.date, value: p[key] }));\n}\n\n/**\n * GMV over orders: the two measures share a window but not a scale, so\n * they're two stacked charts rather than one dual-axis one. Used wherever a\n * page shows both for the same range (Overview, Merchants, Commerce).\n */\nexport function GmvOrdersChart({\n gmvTrend,\n ordersTrend,\n previousGmvTrend,\n previousOrdersTrend,\n compare,\n span,\n money,\n}: {\n gmvTrend: Array<{ date: string; value: number }>;\n ordersTrend: Array<{ date: string; value: number }>;\n previousGmvTrend: Array<{ date: string; value: number }>;\n previousOrdersTrend: Array<{ date: string; value: number }>;\n /** False for \"all time\": there is no earlier period to compare with. */\n compare: boolean;\n span: string;\n money: (value: number) => string;\n}) {\n return (\n <>\n <TimeSeriesChart\n data={gmvTrend}\n compare={compare ? previousGmvTrend : null}\n compareLabel={`Previous ${span}`}\n label=\"GMV\"\n formatValue={money}\n emptyMessage=\"No merchant GMV in this period\"\n height={160}\n />\n <div\n style={{\n margin: '20px 0 8px',\n fontSize: 12,\n fontWeight: 600,\n color: 'var(--text-tertiary)',\n }}\n >\n Orders\n </div>\n <TimeSeriesChart\n data={ordersTrend}\n compare={compare ? previousOrdersTrend : null}\n compareLabel={`Previous ${span}`}\n label=\"Orders\"\n emptyMessage=\"No orders in this period\"\n height={100}\n />\n </>\n );\n}\n"],"mappings":";AAoCI,mBACE,KADF;AAlCJ,SAAS,uBAAuB;AAGzB,SAAS,QACd,QACA,KACwC;AACxC,UAAQ,UAAU,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,GAAG,EAAE,EAAE;AACpE;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,UAAU,mBAAmB;AAAA,QACtC,cAAc,YAAY,IAAI;AAAA,QAC9B,OAAM;AAAA,QACN,aAAa;AAAA,QACb,cAAa;AAAA,QACb,QAAQ;AAAA;AAAA,IACV;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,UAAU,sBAAsB;AAAA,QACzC,cAAc,YAAY,IAAI;AAAA,QAC9B,OAAM;AAAA,QACN,cAAa;AAAA,QACb,QAAQ;AAAA;AAAA,IACV;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/_ui/trend.tsx"],"sourcesContent":["'use client';\n\nimport { TimeSeriesChart } from '@withpotter/components/charts';\n\n/** A `{date, N}[]` series reshaped into the `{date, value}` TimeSeriesChart wants. */\nexport function toTrend<K extends string>(\n series: Array<{ date: string } & Record<K, number>> | undefined,\n key: K,\n): Array<{ date: string; value: number }> {\n return (series ?? []).map((p) => ({ date: p.date, value: p[key] }));\n}\n\n/**\n * GMV over orders: the two measures share a window but not a scale, so\n * they're two stacked charts rather than one dual-axis one. Used wherever a\n * page shows both for the same range (Overview, Merchants, Commerce).\n */\nexport function GmvOrdersChart({\n gmvTrend,\n ordersTrend,\n previousGmvTrend,\n previousOrdersTrend,\n compare,\n span,\n money,\n}: {\n gmvTrend: Array<{ date: string; value: number }>;\n ordersTrend: Array<{ date: string; value: number }>;\n previousGmvTrend: Array<{ date: string; value: number }>;\n previousOrdersTrend: Array<{ date: string; value: number }>;\n /** False for \"all time\": there is no earlier period to compare with. */\n compare: boolean;\n span: string;\n money: (value: number) => string;\n}) {\n return (\n <>\n <TimeSeriesChart\n data={gmvTrend}\n compare={compare ? previousGmvTrend : null}\n compareLabel={`Previous ${span}`}\n label=\"Sales\"\n formatValue={money}\n emptyMessage=\"No sales in this period\"\n height={160}\n />\n <div\n style={{\n margin: '20px 0 8px',\n fontSize: 12,\n fontWeight: 600,\n color: 'var(--text-tertiary)',\n }}\n >\n Orders\n </div>\n <TimeSeriesChart\n data={ordersTrend}\n compare={compare ? previousOrdersTrend : null}\n compareLabel={`Previous ${span}`}\n label=\"Orders\"\n emptyMessage=\"No orders in this period\"\n height={100}\n />\n </>\n );\n}\n"],"mappings":";AAoCI,mBACE,KADF;AAlCJ,SAAS,uBAAuB;AAGzB,SAAS,QACd,QACA,KACwC;AACxC,UAAQ,UAAU,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,GAAG,EAAE,EAAE;AACpE;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,UAAU,mBAAmB;AAAA,QACtC,cAAc,YAAY,IAAI;AAAA,QAC9B,OAAM;AAAA,QACN,aAAa;AAAA,QACb,cAAa;AAAA,QACb,QAAQ;AAAA;AAAA,IACV;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,OAAO;AAAA,QACT;AAAA,QACD;AAAA;AAAA,IAED;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,UAAU,sBAAsB;AAAA,QACzC,cAAc,YAAY,IAAI;AAAA,QAC9B,OAAM;AAAA,QACN,cAAa;AAAA,QACb,QAAQ;AAAA;AAAA,IACV;AAAA,KACF;AAEJ;","names":[]}
@@ -62,12 +62,12 @@ function AdminIndexPage() {
62
62
  const gmvTrend = useMemo(() => toTrend(series, "gmv"), [series]);
63
63
  const ordersTrend = useMemo(() => toTrend(series, "orders"), [series]);
64
64
  if (cockpit.isLoading) {
65
- return /* @__PURE__ */ jsx(AdmLoading, { label: "Loading platform operations" });
65
+ return /* @__PURE__ */ jsx(AdmLoading, { label: "Loading overview" });
66
66
  }
67
67
  if (cockpit.isError || !cockpit.data) {
68
68
  return /* @__PURE__ */ jsxs("div", { className: "adm-panel", role: "alert", children: [
69
- /* @__PURE__ */ jsx("strong", { children: "Platform operations could not be loaded." }),
70
- /* @__PURE__ */ jsx("p", { className: "mb-0 mt-2 text-sm text-[var(--text-secondary)]", children: "The range-aware admin API did not return the operating summary." }),
69
+ /* @__PURE__ */ jsx("strong", { children: "We couldn't load the overview." }),
70
+ /* @__PURE__ */ jsx("p", { className: "mb-0 mt-2 text-sm text-[var(--text-secondary)]", children: "Something went wrong while fetching the numbers. Please try again." }),
71
71
  /* @__PURE__ */ jsx(
72
72
  "button",
73
73
  {
@@ -87,8 +87,8 @@ function AdminIndexPage() {
87
87
  /* @__PURE__ */ jsx(
88
88
  PageHeader,
89
89
  {
90
- title: "Platform operations",
91
- description: "Merchant growth, money movement and exceptions to review.",
90
+ title: "Overview",
91
+ description: "How merchants are growing, how much money is moving, and what needs your attention.",
92
92
  actions: /* @__PURE__ */ jsxs("div", { className: "adm-toolbar", children: [
93
93
  /* @__PURE__ */ jsx(
94
94
  CurrencyFilter,
@@ -130,7 +130,7 @@ function AdminIndexPage() {
130
130
  }
131
131
  ),
132
132
  /* @__PURE__ */ jsxs("div", { className: "adm-grid", children: [
133
- /* @__PURE__ */ jsx("div", { className: "adm-span-8", children: /* @__PURE__ */ jsx(Panel, { title: "Processing volume", caption, children: focus ? /* @__PURE__ */ jsx(
133
+ /* @__PURE__ */ jsx("div", { className: "adm-span-8", children: /* @__PURE__ */ jsx(Panel, { title: "Sales over time", caption, children: focus ? /* @__PURE__ */ jsx(
134
134
  GmvOrdersChart,
135
135
  {
136
136
  gmvTrend,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/page.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport {\n AdmLoading,\n CurrencyFilter,\n GmvOrdersChart,\n PICK_CURRENCY,\n PageHeader,\n Panel,\n PeriodSelector,\n periodPhrase,\n customRange,\n focusCurrency,\n moneyIn,\n rangeFromKey,\n rowFor,\n toTrend,\n useCurrencyParam,\n usePersistedDateRange,\n} from './_ui';\nimport { useGatewayChannels, usePlatformCockpit } from './hooks';\nimport { ActivationPanel } from './_overview/activation-panel';\nimport { AttentionPanel } from './_overview/attention-panel';\nimport { ControlRoom } from './_overview/control-room';\nimport { KpiRow } from './_overview/kpi-row';\nimport { LeadersPanel } from './_overview/leaders-panel';\nimport { PortfolioPanel } from './_overview/portfolio-panel';\nimport { PositionPanel } from './_overview/position-panel';\nimport { ChannelPanel } from './revenue/channel-panel';\n\nexport default function AdminIndexPage() {\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n // Money comes back once per currency; `?currency=` narrows it to one.\n const [currency, setCurrency] = useCurrencyParam();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [customEnd, customStart, rangeKey],\n );\n const cockpit = usePlatformCockpit({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const channels = useGatewayChannels({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const currencies = useMemo(\n () => cockpit.data?.currencies ?? [],\n [cockpit.data],\n );\n // A chart can only draw one currency: the filter's, or the only one.\n const focus = focusCurrency(currencies, currency);\n const series = useMemo(\n () =>\n rowFor(cockpit.data?.trend.performanceSeriesByCurrency, focus)?.series,\n [cockpit.data, focus],\n );\n const gmvTrend = useMemo(() => toTrend(series, 'gmv'), [series]);\n const ordersTrend = useMemo(() => toTrend(series, 'orders'), [series]);\n\n if (cockpit.isLoading) {\n return <AdmLoading label=\"Loading platform operations\" />;\n }\n\n if (cockpit.isError || !cockpit.data) {\n return (\n <div className=\"adm-panel\" role=\"alert\">\n <strong>Platform operations could not be loaded.</strong>\n <p className=\"mb-0 mt-2 text-sm text-[var(--text-secondary)]\">\n The range-aware admin API did not return the operating summary.\n </p>\n <button\n type=\"button\"\n className=\"mt-4 text-sm font-semibold text-[var(--accent-primary)]\"\n onClick={() => void cockpit.refetch()}\n >\n Try again\n </button>\n </div>\n );\n }\n\n const data = cockpit.data;\n const span = periodPhrase(range);\n const period = `${span[0].toUpperCase()}${span.slice(1)}`;\n const caption = focus ? `${period} · ${focus}` : period;\n\n return (\n <div>\n <PageHeader\n title=\"Platform operations\"\n description=\"Merchant growth, money movement and exceptions to review.\"\n actions={\n <div className=\"adm-toolbar\">\n <CurrencyFilter\n value={currency}\n onChange={setCurrency}\n currencies={currencies}\n />\n <PeriodSelector\n value={rangeKey}\n onChange={setRangeKey}\n customStart={customStart}\n customEnd={customEnd}\n onCustomChange={onCustomChange}\n />\n </div>\n }\n />\n\n <ControlRoom\n attention={data.attention}\n currency={currency}\n totals={data.totals}\n />\n\n <KpiRow\n data={data}\n currency={currency}\n focus={focus}\n compare={compare}\n caption={caption}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-8\">\n <Panel title=\"Processing volume\" caption={caption}>\n {focus ? (\n <GmvOrdersChart\n gmvTrend={gmvTrend}\n ordersTrend={ordersTrend}\n previousGmvTrend={[]}\n previousOrdersTrend={[]}\n compare={false}\n span={span}\n money={moneyIn(focus)}\n />\n ) : (\n <p className=\"text-sm text-[var(--text-secondary)]\">\n {PICK_CURRENCY}\n </p>\n )}\n </Panel>\n </div>\n <div className=\"adm-span-4\">\n <PositionPanel data={data} currency={currency} />\n </div>\n </div>\n\n {channels.data && channels.data.byChannel.length > 0 && (\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <ChannelPanel\n totals={channels.data.byChannel}\n focus={focus}\n caption={caption}\n />\n </div>\n </div>\n )}\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <ActivationPanel activation={data.activation} />\n </div>\n </div>\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-4\">\n <AttentionPanel attention={data.attention} />\n </div>\n <div className=\"adm-span-4\">\n <LeadersPanel\n tenants={rowFor(data.topTenantsByCurrency, focus)?.tenants ?? []}\n focus={focus}\n caption={focus ? `${span} · ${focus}` : span}\n />\n </div>\n <div className=\"adm-span-4\">\n <PortfolioPanel\n statuses={data.statusBreakdown}\n industries={data.industryBreakdown}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/admin/page.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport {\n AdmLoading,\n CurrencyFilter,\n GmvOrdersChart,\n PICK_CURRENCY,\n PageHeader,\n Panel,\n PeriodSelector,\n periodPhrase,\n customRange,\n focusCurrency,\n moneyIn,\n rangeFromKey,\n rowFor,\n toTrend,\n useCurrencyParam,\n usePersistedDateRange,\n} from './_ui';\nimport { useGatewayChannels, usePlatformCockpit } from './hooks';\nimport { ActivationPanel } from './_overview/activation-panel';\nimport { AttentionPanel } from './_overview/attention-panel';\nimport { ControlRoom } from './_overview/control-room';\nimport { KpiRow } from './_overview/kpi-row';\nimport { LeadersPanel } from './_overview/leaders-panel';\nimport { PortfolioPanel } from './_overview/portfolio-panel';\nimport { PositionPanel } from './_overview/position-panel';\nimport { ChannelPanel } from './revenue/channel-panel';\n\nexport default function AdminIndexPage() {\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n // Money comes back once per currency; `?currency=` narrows it to one.\n const [currency, setCurrency] = useCurrencyParam();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [customEnd, customStart, rangeKey],\n );\n const cockpit = usePlatformCockpit({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const channels = useGatewayChannels({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const currencies = useMemo(\n () => cockpit.data?.currencies ?? [],\n [cockpit.data],\n );\n // A chart can only draw one currency: the filter's, or the only one.\n const focus = focusCurrency(currencies, currency);\n const series = useMemo(\n () =>\n rowFor(cockpit.data?.trend.performanceSeriesByCurrency, focus)?.series,\n [cockpit.data, focus],\n );\n const gmvTrend = useMemo(() => toTrend(series, 'gmv'), [series]);\n const ordersTrend = useMemo(() => toTrend(series, 'orders'), [series]);\n\n if (cockpit.isLoading) {\n return <AdmLoading label=\"Loading overview\" />;\n }\n\n if (cockpit.isError || !cockpit.data) {\n return (\n <div className=\"adm-panel\" role=\"alert\">\n <strong>We couldn&apos;t load the overview.</strong>\n <p className=\"mb-0 mt-2 text-sm text-[var(--text-secondary)]\">\n Something went wrong while fetching the numbers. Please try again.\n </p>\n <button\n type=\"button\"\n className=\"mt-4 text-sm font-semibold text-[var(--accent-primary)]\"\n onClick={() => void cockpit.refetch()}\n >\n Try again\n </button>\n </div>\n );\n }\n\n const data = cockpit.data;\n const span = periodPhrase(range);\n const period = `${span[0].toUpperCase()}${span.slice(1)}`;\n const caption = focus ? `${period} · ${focus}` : period;\n\n return (\n <div>\n <PageHeader\n title=\"Overview\"\n description=\"How merchants are growing, how much money is moving, and what needs your attention.\"\n actions={\n <div className=\"adm-toolbar\">\n <CurrencyFilter\n value={currency}\n onChange={setCurrency}\n currencies={currencies}\n />\n <PeriodSelector\n value={rangeKey}\n onChange={setRangeKey}\n customStart={customStart}\n customEnd={customEnd}\n onCustomChange={onCustomChange}\n />\n </div>\n }\n />\n\n <ControlRoom\n attention={data.attention}\n currency={currency}\n totals={data.totals}\n />\n\n <KpiRow\n data={data}\n currency={currency}\n focus={focus}\n compare={compare}\n caption={caption}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-8\">\n <Panel title=\"Sales over time\" caption={caption}>\n {focus ? (\n <GmvOrdersChart\n gmvTrend={gmvTrend}\n ordersTrend={ordersTrend}\n previousGmvTrend={[]}\n previousOrdersTrend={[]}\n compare={false}\n span={span}\n money={moneyIn(focus)}\n />\n ) : (\n <p className=\"text-sm text-[var(--text-secondary)]\">\n {PICK_CURRENCY}\n </p>\n )}\n </Panel>\n </div>\n <div className=\"adm-span-4\">\n <PositionPanel data={data} currency={currency} />\n </div>\n </div>\n\n {channels.data && channels.data.byChannel.length > 0 && (\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <ChannelPanel\n totals={channels.data.byChannel}\n focus={focus}\n caption={caption}\n />\n </div>\n </div>\n )}\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <ActivationPanel activation={data.activation} />\n </div>\n </div>\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-4\">\n <AttentionPanel attention={data.attention} />\n </div>\n <div className=\"adm-span-4\">\n <LeadersPanel\n tenants={rowFor(data.topTenantsByCurrency, focus)?.tenants ?? []}\n focus={focus}\n caption={focus ? `${span} · ${focus}` : span}\n />\n </div>\n <div className=\"adm-span-4\">\n <PortfolioPanel\n statuses={data.statusBreakdown}\n industries={data.industryBreakdown}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -7,6 +7,7 @@ import { Banner } from "@withpotter/ui-kit/banner";
7
7
  import { Input } from "@withpotter/ui-kit/input";
8
8
  import { Checkbox } from "@withpotter/ui-kit/checkbox";
9
9
  import { Field } from "@withpotter/ui-kit/field";
10
+ import { requirementGroupLabel, requirementLabel } from "./requirement-labels";
10
11
  import { formatMinor, parseMajorToMinor } from "@withpotter/lib/money-minor";
11
12
  import {
12
13
  TIER_REQUIREMENTS
@@ -53,15 +54,15 @@ function TierDialog({
53
54
  const dailyMaximumMinor = parseMajorToMinor(daily, code);
54
55
  const monthlyMaximumMinor = monthly ? parseMajorToMinor(monthly, code) : null;
55
56
  if (!key.trim() || !label.trim())
56
- return setFormError("Key and label are required.");
57
+ return setFormError("Short name and display name are required.");
57
58
  if (!minimumMinor || !maximumMinor || !dailyMaximumMinor)
58
59
  return setFormError(
59
- "Minimum, maximum and daily limit must be valid amounts."
60
+ "The smallest transfer, largest transfer and daily limit must be valid amounts."
60
61
  );
61
62
  if (monthly && !monthlyMaximumMinor)
62
- return setFormError("The monthly limit is not a valid amount.");
63
+ return setFormError("The monthly limit must be a valid amount.");
63
64
  if (!/^\d+$/.test(position))
64
- return setFormError("Position must be a whole number.");
65
+ return setFormError("Priority must be a whole number.");
65
66
  onSave({
66
67
  key: key.trim(),
67
68
  currency: code,
@@ -79,7 +80,7 @@ function TierDialog({
79
80
  FormDialog,
80
81
  {
81
82
  title: tier ? "Edit tier" : "New payout tier",
82
- description: "Limits a business gets once it has passed every listed verification.",
83
+ description: "The sending limits a merchant gets once they have completed every check listed below.",
83
84
  size: "lg",
84
85
  onClose,
85
86
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -89,15 +90,24 @@ function TierDialog({
89
90
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
90
91
  (formError || error) && /* @__PURE__ */ jsx(Banner, { tone: "error", children: formError ?? error }),
91
92
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
92
- /* @__PURE__ */ jsx(Field, { label: "Key", htmlFor: "t-key", required: true, children: /* @__PURE__ */ jsx(
93
- Input,
93
+ /* @__PURE__ */ jsx(
94
+ Field,
94
95
  {
95
- id: "t-key",
96
- value: key,
97
- onChange: (e) => setKey(e.target.value)
96
+ label: "Short name",
97
+ htmlFor: "t-key",
98
+ required: true,
99
+ hint: "A unique code for this level, for example starter.",
100
+ children: /* @__PURE__ */ jsx(
101
+ Input,
102
+ {
103
+ id: "t-key",
104
+ value: key,
105
+ onChange: (e) => setKey(e.target.value)
106
+ }
107
+ )
98
108
  }
99
- ) }),
100
- /* @__PURE__ */ jsx(Field, { label: "Label", htmlFor: "t-label", required: true, children: /* @__PURE__ */ jsx(
109
+ ),
110
+ /* @__PURE__ */ jsx(Field, { label: "Display name", htmlFor: "t-label", required: true, children: /* @__PURE__ */ jsx(
101
111
  Input,
102
112
  {
103
113
  id: "t-label",
@@ -117,9 +127,9 @@ function TierDialog({
117
127
  /* @__PURE__ */ jsx(
118
128
  Field,
119
129
  {
120
- label: "Position",
130
+ label: "Priority",
121
131
  htmlFor: "t-pos",
122
- hint: "Higher tiers are chosen first when a business qualifies for several.",
132
+ hint: "If a merchant qualifies for several levels, the one with the higher number is used.",
123
133
  children: /* @__PURE__ */ jsx(
124
134
  Input,
125
135
  {
@@ -131,7 +141,7 @@ function TierDialog({
131
141
  )
132
142
  }
133
143
  ),
134
- /* @__PURE__ */ jsx(Field, { label: "Per-transfer minimum", htmlFor: "t-min", required: true, children: /* @__PURE__ */ jsx(
144
+ /* @__PURE__ */ jsx(Field, { label: "Smallest single transfer", htmlFor: "t-min", required: true, children: /* @__PURE__ */ jsx(
135
145
  Input,
136
146
  {
137
147
  id: "t-min",
@@ -140,7 +150,7 @@ function TierDialog({
140
150
  onChange: (e) => setMin(e.target.value)
141
151
  }
142
152
  ) }),
143
- /* @__PURE__ */ jsx(Field, { label: "Per-transfer maximum", htmlFor: "t-max", required: true, children: /* @__PURE__ */ jsx(
153
+ /* @__PURE__ */ jsx(Field, { label: "Largest single transfer", htmlFor: "t-max", required: true, children: /* @__PURE__ */ jsx(
144
154
  Input,
145
155
  {
146
156
  id: "t-max",
@@ -149,7 +159,7 @@ function TierDialog({
149
159
  onChange: (e) => setMax(e.target.value)
150
160
  }
151
161
  ) }),
152
- /* @__PURE__ */ jsx(Field, { label: "Daily total", htmlFor: "t-day", required: true, children: /* @__PURE__ */ jsx(
162
+ /* @__PURE__ */ jsx(Field, { label: "Daily limit", htmlFor: "t-day", required: true, children: /* @__PURE__ */ jsx(
153
163
  Input,
154
164
  {
155
165
  id: "t-day",
@@ -158,7 +168,7 @@ function TierDialog({
158
168
  onChange: (e) => setDaily(e.target.value)
159
169
  }
160
170
  ) }),
161
- /* @__PURE__ */ jsx(Field, { label: "Monthly total", htmlFor: "t-mon", hint: "Optional.", children: /* @__PURE__ */ jsx(
171
+ /* @__PURE__ */ jsx(Field, { label: "Monthly limit", htmlFor: "t-mon", hint: "Optional.", children: /* @__PURE__ */ jsx(
162
172
  Input,
163
173
  {
164
174
  id: "t-mon",
@@ -170,16 +180,16 @@ function TierDialog({
170
180
  ] }),
171
181
  /* @__PURE__ */ jsxs("fieldset", { className: "space-y-2", children: [
172
182
  /* @__PURE__ */ jsxs("legend", { className: "text-sm font-medium text-[var(--text-secondary)]", children: [
173
- "Required verifications (",
183
+ "Checks a merchant must complete (",
174
184
  requirements.length,
175
185
  ")"
176
186
  ] }),
177
187
  /* @__PURE__ */ jsx("div", { className: "max-h-56 space-y-3 overflow-y-auto rounded-md border border-[var(--border-default)] p-3", children: Object.entries(TIER_REQUIREMENTS).map(([group, ops]) => /* @__PURE__ */ jsxs("div", { children: [
178
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-medium text-[var(--text-tertiary)]", children: group }),
188
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-medium text-[var(--text-tertiary)]", children: requirementGroupLabel(group) }),
179
189
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-x-4 gap-y-1", children: ops.map((op) => /* @__PURE__ */ jsx(
180
190
  Checkbox,
181
191
  {
182
- label: op,
192
+ label: requirementLabel(op),
183
193
  checked: requirements.includes(op),
184
194
  onChange: () => toggle(op)
185
195
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/payout-tiers/_tier-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { FormDialog } from '@withpotter/ui-kit/form-dialog';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Banner } from '@withpotter/ui-kit/banner';\nimport { Input } from '@withpotter/ui-kit/input';\nimport { Checkbox } from '@withpotter/ui-kit/checkbox';\nimport { Field } from '@withpotter/ui-kit/field';\nimport { formatMinor, parseMajorToMinor } from '@withpotter/lib/money-minor';\nimport {\n TIER_REQUIREMENTS,\n type PayoutTier,\n type PayoutTierInput,\n} from '@withpotter/lib/admin-money-api';\n\n/** Minor units back to what a person types: \"150000\" NGN is \"1500\". */\nfunction toMajor(minor: string, currency: string): string {\n return formatMinor(minor, currency).replace(/[^\\d.]/g, '');\n}\n\nexport function TierDialog({\n tier,\n saving,\n error,\n onSave,\n onClose,\n}: {\n tier: PayoutTier | null;\n saving: boolean;\n error: string | null;\n onSave: (body: PayoutTierInput) => void;\n onClose: () => void;\n}) {\n const [key, setKey] = useState(tier?.key ?? '');\n const [currency, setCurrency] = useState(tier?.currency ?? 'NGN');\n const [label, setLabel] = useState(tier?.label ?? '');\n const [position, setPosition] = useState(String(tier?.position ?? 0));\n const [requirements, setRequirements] = useState<string[]>(\n tier?.requirements ?? [],\n );\n const [min, setMin] = useState(\n tier ? toMajor(tier.minimumMinor, tier.currency) : '',\n );\n const [max, setMax] = useState(\n tier ? toMajor(tier.maximumMinor, tier.currency) : '',\n );\n const [daily, setDaily] = useState(\n tier ? toMajor(tier.dailyMaximumMinor, tier.currency) : '',\n );\n const [monthly, setMonthly] = useState(\n tier?.monthlyMaximumMinor\n ? toMajor(tier.monthlyMaximumMinor, tier.currency)\n : '',\n );\n const [enabled, setEnabled] = useState(tier?.enabled ?? true);\n const [formError, setFormError] = useState<string | null>(null);\n\n const toggle = (r: string) =>\n setRequirements((c) =>\n c.includes(r) ? c.filter((x) => x !== r) : [...c, r],\n );\n\n const submit = () => {\n setFormError(null);\n const code = currency.trim().toUpperCase();\n const minimumMinor = parseMajorToMinor(min, code);\n const maximumMinor = parseMajorToMinor(max, code);\n const dailyMaximumMinor = parseMajorToMinor(daily, code);\n const monthlyMaximumMinor = monthly\n ? parseMajorToMinor(monthly, code)\n : null;\n if (!key.trim() || !label.trim())\n return setFormError('Key and label are required.');\n if (!minimumMinor || !maximumMinor || !dailyMaximumMinor)\n return setFormError(\n 'Minimum, maximum and daily limit must be valid amounts.',\n );\n if (monthly && !monthlyMaximumMinor)\n return setFormError('The monthly limit is not a valid amount.');\n if (!/^\\d+$/.test(position))\n return setFormError('Position must be a whole number.');\n onSave({\n key: key.trim(),\n currency: code,\n label: label.trim(),\n position: Number(position),\n requirements,\n minimumMinor,\n maximumMinor,\n dailyMaximumMinor,\n monthlyMaximumMinor,\n enabled,\n });\n };\n\n return (\n <FormDialog\n title={tier ? 'Edit tier' : 'New payout tier'}\n description=\"Limits a business gets once it has passed every listed verification.\"\n size=\"lg\"\n onClose={onClose}\n footer={\n <>\n <Button variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button onClick={submit} loading={saving}>\n {tier ? 'Save tier' : 'Create tier'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-4\">\n {(formError || error) && (\n <Banner tone=\"error\">{formError ?? error}</Banner>\n )}\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field label=\"Key\" htmlFor=\"t-key\" required>\n <Input\n id=\"t-key\"\n value={key}\n onChange={(e) => setKey(e.target.value)}\n />\n </Field>\n <Field label=\"Label\" htmlFor=\"t-label\" required>\n <Input\n id=\"t-label\"\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n />\n </Field>\n <Field label=\"Currency\" htmlFor=\"t-cur\" required>\n <Input\n id=\"t-cur\"\n value={currency}\n maxLength={3}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </Field>\n <Field\n label=\"Position\"\n htmlFor=\"t-pos\"\n hint=\"Higher tiers are chosen first when a business qualifies for several.\"\n >\n <Input\n id=\"t-pos\"\n inputMode=\"numeric\"\n value={position}\n onChange={(e) => setPosition(e.target.value)}\n />\n </Field>\n <Field label=\"Per-transfer minimum\" htmlFor=\"t-min\" required>\n <Input\n id=\"t-min\"\n inputMode=\"decimal\"\n value={min}\n onChange={(e) => setMin(e.target.value)}\n />\n </Field>\n <Field label=\"Per-transfer maximum\" htmlFor=\"t-max\" required>\n <Input\n id=\"t-max\"\n inputMode=\"decimal\"\n value={max}\n onChange={(e) => setMax(e.target.value)}\n />\n </Field>\n <Field label=\"Daily total\" htmlFor=\"t-day\" required>\n <Input\n id=\"t-day\"\n inputMode=\"decimal\"\n value={daily}\n onChange={(e) => setDaily(e.target.value)}\n />\n </Field>\n <Field label=\"Monthly total\" htmlFor=\"t-mon\" hint=\"Optional.\">\n <Input\n id=\"t-mon\"\n inputMode=\"decimal\"\n value={monthly}\n onChange={(e) => setMonthly(e.target.value)}\n />\n </Field>\n </div>\n\n <fieldset className=\"space-y-2\">\n <legend className=\"text-sm font-medium text-[var(--text-secondary)]\">\n Required verifications ({requirements.length})\n </legend>\n <div className=\"max-h-56 space-y-3 overflow-y-auto rounded-md border border-[var(--border-default)] p-3\">\n {Object.entries(TIER_REQUIREMENTS).map(([group, ops]) => (\n <div key={group}>\n <p className=\"mb-1 text-xs font-medium text-[var(--text-tertiary)]\">\n {group}\n </p>\n <div className=\"flex flex-wrap gap-x-4 gap-y-1\">\n {ops.map((op) => (\n <Checkbox\n key={op}\n label={op}\n checked={requirements.includes(op)}\n onChange={() => toggle(op)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n </fieldset>\n\n <Checkbox\n label=\"Enabled\"\n checked={enabled}\n onChange={(e) => setEnabled(e.target.checked)}\n />\n </div>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/payout-tiers/_tier-dialog.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { FormDialog } from '@withpotter/ui-kit/form-dialog';\nimport { Button } from '@withpotter/ui-kit/button';\nimport { Banner } from '@withpotter/ui-kit/banner';\nimport { Input } from '@withpotter/ui-kit/input';\nimport { Checkbox } from '@withpotter/ui-kit/checkbox';\nimport { Field } from '@withpotter/ui-kit/field';\nimport { requirementGroupLabel, requirementLabel } from './requirement-labels';\nimport { formatMinor, parseMajorToMinor } from '@withpotter/lib/money-minor';\nimport {\n TIER_REQUIREMENTS,\n type PayoutTier,\n type PayoutTierInput,\n} from '@withpotter/lib/admin-money-api';\n\n/** Minor units back to what a person types: \"150000\" NGN is \"1500\". */\nfunction toMajor(minor: string, currency: string): string {\n return formatMinor(minor, currency).replace(/[^\\d.]/g, '');\n}\n\nexport function TierDialog({\n tier,\n saving,\n error,\n onSave,\n onClose,\n}: {\n tier: PayoutTier | null;\n saving: boolean;\n error: string | null;\n onSave: (body: PayoutTierInput) => void;\n onClose: () => void;\n}) {\n const [key, setKey] = useState(tier?.key ?? '');\n const [currency, setCurrency] = useState(tier?.currency ?? 'NGN');\n const [label, setLabel] = useState(tier?.label ?? '');\n const [position, setPosition] = useState(String(tier?.position ?? 0));\n const [requirements, setRequirements] = useState<string[]>(\n tier?.requirements ?? [],\n );\n const [min, setMin] = useState(\n tier ? toMajor(tier.minimumMinor, tier.currency) : '',\n );\n const [max, setMax] = useState(\n tier ? toMajor(tier.maximumMinor, tier.currency) : '',\n );\n const [daily, setDaily] = useState(\n tier ? toMajor(tier.dailyMaximumMinor, tier.currency) : '',\n );\n const [monthly, setMonthly] = useState(\n tier?.monthlyMaximumMinor\n ? toMajor(tier.monthlyMaximumMinor, tier.currency)\n : '',\n );\n const [enabled, setEnabled] = useState(tier?.enabled ?? true);\n const [formError, setFormError] = useState<string | null>(null);\n\n const toggle = (r: string) =>\n setRequirements((c) =>\n c.includes(r) ? c.filter((x) => x !== r) : [...c, r],\n );\n\n const submit = () => {\n setFormError(null);\n const code = currency.trim().toUpperCase();\n const minimumMinor = parseMajorToMinor(min, code);\n const maximumMinor = parseMajorToMinor(max, code);\n const dailyMaximumMinor = parseMajorToMinor(daily, code);\n const monthlyMaximumMinor = monthly\n ? parseMajorToMinor(monthly, code)\n : null;\n if (!key.trim() || !label.trim())\n return setFormError('Short name and display name are required.');\n if (!minimumMinor || !maximumMinor || !dailyMaximumMinor)\n return setFormError(\n 'The smallest transfer, largest transfer and daily limit must be valid amounts.',\n );\n if (monthly && !monthlyMaximumMinor)\n return setFormError('The monthly limit must be a valid amount.');\n if (!/^\\d+$/.test(position))\n return setFormError('Priority must be a whole number.');\n onSave({\n key: key.trim(),\n currency: code,\n label: label.trim(),\n position: Number(position),\n requirements,\n minimumMinor,\n maximumMinor,\n dailyMaximumMinor,\n monthlyMaximumMinor,\n enabled,\n });\n };\n\n return (\n <FormDialog\n title={tier ? 'Edit tier' : 'New payout tier'}\n description=\"The sending limits a merchant gets once they have completed every check listed below.\"\n size=\"lg\"\n onClose={onClose}\n footer={\n <>\n <Button variant=\"secondary\" onClick={onClose}>\n Cancel\n </Button>\n <Button onClick={submit} loading={saving}>\n {tier ? 'Save tier' : 'Create tier'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-4\">\n {(formError || error) && (\n <Banner tone=\"error\">{formError ?? error}</Banner>\n )}\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field\n label=\"Short name\"\n htmlFor=\"t-key\"\n required\n hint=\"A unique code for this level, for example starter.\"\n >\n <Input\n id=\"t-key\"\n value={key}\n onChange={(e) => setKey(e.target.value)}\n />\n </Field>\n <Field label=\"Display name\" htmlFor=\"t-label\" required>\n <Input\n id=\"t-label\"\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n />\n </Field>\n <Field label=\"Currency\" htmlFor=\"t-cur\" required>\n <Input\n id=\"t-cur\"\n value={currency}\n maxLength={3}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </Field>\n <Field\n label=\"Priority\"\n htmlFor=\"t-pos\"\n hint=\"If a merchant qualifies for several levels, the one with the higher number is used.\"\n >\n <Input\n id=\"t-pos\"\n inputMode=\"numeric\"\n value={position}\n onChange={(e) => setPosition(e.target.value)}\n />\n </Field>\n <Field label=\"Smallest single transfer\" htmlFor=\"t-min\" required>\n <Input\n id=\"t-min\"\n inputMode=\"decimal\"\n value={min}\n onChange={(e) => setMin(e.target.value)}\n />\n </Field>\n <Field label=\"Largest single transfer\" htmlFor=\"t-max\" required>\n <Input\n id=\"t-max\"\n inputMode=\"decimal\"\n value={max}\n onChange={(e) => setMax(e.target.value)}\n />\n </Field>\n <Field label=\"Daily limit\" htmlFor=\"t-day\" required>\n <Input\n id=\"t-day\"\n inputMode=\"decimal\"\n value={daily}\n onChange={(e) => setDaily(e.target.value)}\n />\n </Field>\n <Field label=\"Monthly limit\" htmlFor=\"t-mon\" hint=\"Optional.\">\n <Input\n id=\"t-mon\"\n inputMode=\"decimal\"\n value={monthly}\n onChange={(e) => setMonthly(e.target.value)}\n />\n </Field>\n </div>\n\n <fieldset className=\"space-y-2\">\n <legend className=\"text-sm font-medium text-[var(--text-secondary)]\">\n Checks a merchant must complete ({requirements.length})\n </legend>\n <div className=\"max-h-56 space-y-3 overflow-y-auto rounded-md border border-[var(--border-default)] p-3\">\n {Object.entries(TIER_REQUIREMENTS).map(([group, ops]) => (\n <div key={group}>\n <p className=\"mb-1 text-xs font-medium text-[var(--text-tertiary)]\">\n {requirementGroupLabel(group)}\n </p>\n <div className=\"flex flex-wrap gap-x-4 gap-y-1\">\n {ops.map((op) => (\n <Checkbox\n key={op}\n label={requirementLabel(op)}\n checked={requirements.includes(op)}\n onChange={() => toggle(op)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n </fieldset>\n\n <Checkbox\n label=\"Enabled\"\n checked={enabled}\n onChange={(e) => setEnabled(e.target.checked)}\n />\n </div>\n </FormDialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,70 @@
1
+ const LABELS = {
2
+ nin: "National ID number (Nigeria)",
3
+ "nin-slip": "National ID slip (Nigeria)",
4
+ "advanced-nin": "Detailed national ID check (Nigeria)",
5
+ "premium-nin": "Full national ID check with photo (Nigeria)",
6
+ bvn: "Bank verification number (Nigeria)",
7
+ "validate-bvn": "Bank verification number match (Nigeria)",
8
+ "bvn-nin-selfie": "Bank number, national ID and selfie match (Nigeria)",
9
+ "phone-number": "Phone number",
10
+ "age-identity": "Age and identity",
11
+ passport: "Passport",
12
+ "drivers-license": "Driver's licence",
13
+ "voter-id": "Voter's card",
14
+ "ghana-card": "Ghana Card",
15
+ "ghana-passport": "Ghana passport",
16
+ "ghana-digital-address": "Ghana digital address",
17
+ "kenya-national-id": "Kenya national ID",
18
+ "kenya-passport": "Kenya passport",
19
+ "kenya-kra-pin": "Kenya tax number",
20
+ "uganda-nin": "Uganda national ID",
21
+ "uganda-voter-id": "Uganda voter's card",
22
+ "south-africa-national-id": "South Africa national ID",
23
+ "angola-national-id": "Angola national ID",
24
+ "zambia-nrc": "Zambia national registration card",
25
+ "zimbabwe-national-id": "Zimbabwe national ID",
26
+ "zimbabwe-credit-check": "Zimbabwe credit check",
27
+ "canada-ekyc": "Canada identity check",
28
+ "uk-ekyc": "UK identity check",
29
+ liveness: "Live selfie check",
30
+ "face-compare": "Selfie matches photo",
31
+ "face-doc-compare": "Selfie matches ID document",
32
+ "document-analysis": "ID document check",
33
+ "generic-ocr": "Text read from a document",
34
+ "utility-bill": "Utility bill",
35
+ "individual-address": "Home address",
36
+ "aml-screening": "Anti-money-laundering screening",
37
+ "user-screening": "Person screening (sanctions and watchlists)",
38
+ "email-check": "Email address check",
39
+ "ip-screening": "Device location check",
40
+ "phone-check": "Phone number check",
41
+ cac: "Company registration (Nigeria)",
42
+ tin: "Tax number",
43
+ "global-business-search": "Worldwide business search",
44
+ "kenya-business": "Kenya business registration",
45
+ "zambia-business": "Zambia business registration",
46
+ "business-document": "Business documents",
47
+ "business-address": "Business address",
48
+ "business-aml-screening": "Business screening (sanctions and watchlists)",
49
+ "business-owners": "Owners listed",
50
+ "business-profile": "Business profile completed",
51
+ "screening-clear": "Screening came back clear"
52
+ };
53
+ const GROUP_LABELS = {
54
+ Individual: "Checks on a person",
55
+ Business: "Checks on a business",
56
+ Readiness: "Account readiness (worked out automatically)"
57
+ };
58
+ function requirementLabel(code) {
59
+ if (LABELS[code]) return LABELS[code];
60
+ const spaced = code.replace(/[-_]+/g, " ").trim();
61
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
62
+ }
63
+ function requirementGroupLabel(group) {
64
+ return GROUP_LABELS[group] ?? group;
65
+ }
66
+ export {
67
+ requirementGroupLabel,
68
+ requirementLabel
69
+ };
70
+ //# sourceMappingURL=requirement-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/payout-tiers/requirement-labels.ts"],"sourcesContent":["/**\n * Plain-English names for the identity and business checks a payout level can\n * require. The codes are what the API stores; admins should never have to read them.\n */\nconst LABELS: Record<string, string> = {\n nin: 'National ID number (Nigeria)',\n 'nin-slip': 'National ID slip (Nigeria)',\n 'advanced-nin': 'Detailed national ID check (Nigeria)',\n 'premium-nin': 'Full national ID check with photo (Nigeria)',\n bvn: 'Bank verification number (Nigeria)',\n 'validate-bvn': 'Bank verification number match (Nigeria)',\n 'bvn-nin-selfie': 'Bank number, national ID and selfie match (Nigeria)',\n 'phone-number': 'Phone number',\n 'age-identity': 'Age and identity',\n passport: 'Passport',\n 'drivers-license': \"Driver's licence\",\n 'voter-id': \"Voter's card\",\n 'ghana-card': 'Ghana Card',\n 'ghana-passport': 'Ghana passport',\n 'ghana-digital-address': 'Ghana digital address',\n 'kenya-national-id': 'Kenya national ID',\n 'kenya-passport': 'Kenya passport',\n 'kenya-kra-pin': 'Kenya tax number',\n 'uganda-nin': 'Uganda national ID',\n 'uganda-voter-id': \"Uganda voter's card\",\n 'south-africa-national-id': 'South Africa national ID',\n 'angola-national-id': 'Angola national ID',\n 'zambia-nrc': 'Zambia national registration card',\n 'zimbabwe-national-id': 'Zimbabwe national ID',\n 'zimbabwe-credit-check': 'Zimbabwe credit check',\n 'canada-ekyc': 'Canada identity check',\n 'uk-ekyc': 'UK identity check',\n liveness: 'Live selfie check',\n 'face-compare': 'Selfie matches photo',\n 'face-doc-compare': 'Selfie matches ID document',\n 'document-analysis': 'ID document check',\n 'generic-ocr': 'Text read from a document',\n 'utility-bill': 'Utility bill',\n 'individual-address': 'Home address',\n 'aml-screening': 'Anti-money-laundering screening',\n 'user-screening': 'Person screening (sanctions and watchlists)',\n 'email-check': 'Email address check',\n 'ip-screening': 'Device location check',\n 'phone-check': 'Phone number check',\n cac: 'Company registration (Nigeria)',\n tin: 'Tax number',\n 'global-business-search': 'Worldwide business search',\n 'kenya-business': 'Kenya business registration',\n 'zambia-business': 'Zambia business registration',\n 'business-document': 'Business documents',\n 'business-address': 'Business address',\n 'business-aml-screening': 'Business screening (sanctions and watchlists)',\n 'business-owners': 'Owners listed',\n 'business-profile': 'Business profile completed',\n 'screening-clear': 'Screening came back clear',\n};\n\nconst GROUP_LABELS: Record<string, string> = {\n Individual: 'Checks on a person',\n Business: 'Checks on a business',\n Readiness: 'Account readiness (worked out automatically)',\n};\n\n/** \"bvn\" → \"Bank verification number (Nigeria)\". Unknown codes stay readable. */\nexport function requirementLabel(code: string): string {\n if (LABELS[code]) return LABELS[code];\n const spaced = code.replace(/[-_]+/g, ' ').trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nexport function requirementGroupLabel(group: string): string {\n return GROUP_LABELS[group] ?? group;\n}\n"],"mappings":"AAIA,MAAM,SAAiC;AAAA,EACrC,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,KAAK;AAAA,EACL,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,4BAA4B;AAAA,EAC5B,sBAAsB;AAAA,EACtB,cAAc;AAAA,EACd,wBAAwB;AAAA,EACxB,yBAAyB;AAAA,EACzB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,KAAK;AAAA,EACL,KAAK;AAAA,EACL,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AACrB;AAEA,MAAM,eAAuC;AAAA,EAC3C,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AACb;AAGO,SAAS,iBAAiB,MAAsB;AACrD,MAAI,OAAO,IAAI,EAAG,QAAO,OAAO,IAAI;AACpC,QAAM,SAAS,KAAK,QAAQ,UAAU,GAAG,EAAE,KAAK;AAChD,SAAO,OAAO,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,MAAM,CAAC;AACxD;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,SAAO,aAAa,KAAK,KAAK;AAChC;","names":[]}
@@ -11,15 +11,16 @@ import {
11
11
  import { StatusBadge } from "@withpotter/components/shared/status-badge";
12
12
  import { limitLines, requirementRows } from "./tier-preview";
13
13
  import styles from "../_money/ledger.module.css";
14
+ import { requirementLabel } from "./requirement-labels";
14
15
  function TierPreviewResult({ preview }) {
15
16
  const { tier } = preview;
16
17
  const rows = requirementRows(preview);
17
18
  return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 16 }, children: [
18
19
  /* @__PURE__ */ jsxs(Card, { children: [
19
- /* @__PURE__ */ jsx("h3", { className: styles.chosenName, children: tier ? `Lands on ${tier.label} in ${preview.currency}` : `No ${preview.currency} tier qualifies yet` }),
20
+ /* @__PURE__ */ jsx("h3", { className: styles.chosenName, children: tier ? `Gets the ${tier.label} level in ${preview.currency}` : `No ${preview.currency} level fits yet` }),
20
21
  tier ? /* @__PURE__ */ jsxs(FactList, { className: "mt-4", children: [
21
- /* @__PURE__ */ jsx(Fact, { label: "Tier", value: `${tier.label} (${tier.key})` }),
22
- /* @__PURE__ */ jsx(Fact, { label: "Position", value: String(tier.position) }),
22
+ /* @__PURE__ */ jsx(Fact, { label: "Level", value: tier.label }),
23
+ /* @__PURE__ */ jsx(Fact, { label: "Priority", value: String(tier.position) }),
23
24
  limitLines(tier).map(([label, value]) => /* @__PURE__ */ jsx(Fact, { label, value }, label)),
24
25
  /* @__PURE__ */ jsx(
25
26
  Fact,
@@ -28,23 +29,23 @@ function TierPreviewResult({ preview }) {
28
29
  value: tier.enabled ? "Enabled" : "Disabled"
29
30
  }
30
31
  )
31
- ] }) : /* @__PURE__ */ jsx("p", { className: styles.quiet, children: "With no tier, this business resolves to verification required." })
32
+ ] }) : /* @__PURE__ */ jsx("p", { className: styles.quiet, children: "This merchant has to verify their identity before they can send money out." })
32
33
  ] }),
33
34
  /* @__PURE__ */ jsx(
34
35
  TableShell,
35
36
  {
36
37
  minWidth: 0,
37
38
  head: /* @__PURE__ */ jsxs("tr", { children: [
38
- /* @__PURE__ */ jsx(Th, { children: "Requirement" }),
39
- /* @__PURE__ */ jsx(Th, { children: "State" })
39
+ /* @__PURE__ */ jsx(Th, { children: "Check" }),
40
+ /* @__PURE__ */ jsx(Th, { children: "Result" })
40
41
  ] }),
41
42
  children: rows.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 2, className: styles.quiet, children: "Nothing verified and nothing required." }) }) : rows.map((r) => /* @__PURE__ */ jsxs(TableRow, { children: [
42
- /* @__PURE__ */ jsx("td", { children: r.name }),
43
- /* @__PURE__ */ jsx("td", { children: r.met ? /* @__PURE__ */ jsx(StatusBadge, { status: "completed", label: "Met" }) : /* @__PURE__ */ jsx(
43
+ /* @__PURE__ */ jsx("td", { children: requirementLabel(r.name) }),
44
+ /* @__PURE__ */ jsx("td", { children: r.met ? /* @__PURE__ */ jsx(StatusBadge, { status: "completed", label: "Done" }) : /* @__PURE__ */ jsx(
44
45
  StatusBadge,
45
46
  {
46
47
  status: "action_required",
47
- label: "Missing for the next tier"
48
+ label: "Still needed for the next level"
48
49
  }
49
50
  ) })
50
51
  ] }, r.name))
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/payout-tiers/tier-preview-result.tsx"],"sourcesContent":["'use client';\n\nimport {\n Card,\n Fact,\n FactList,\n TableRow,\n TableShell,\n Th,\n} from '@withpotter/ui-kit';\nimport { StatusBadge } from '@withpotter/components/shared/status-badge';\nimport type { PayoutTierPreview } from '@withpotter/lib/admin-money-api';\nimport { limitLines, requirementRows } from './tier-preview';\nimport styles from '../_money/ledger.module.css';\n\n/**\n * What the preview answered: the tier the business lands on with its\n * limits, then every requirement it names, met or still missing.\n */\nexport function TierPreviewResult({ preview }: { preview: PayoutTierPreview }) {\n const { tier } = preview;\n const rows = requirementRows(preview);\n\n return (\n <div style={{ display: 'grid', gap: 16 }}>\n <Card>\n <h3 className={styles.chosenName}>\n {tier\n ? `Lands on ${tier.label} in ${preview.currency}`\n : `No ${preview.currency} tier qualifies yet`}\n </h3>\n {tier ? (\n <FactList className=\"mt-4\">\n <Fact label=\"Tier\" value={`${tier.label} (${tier.key})`} />\n <Fact label=\"Position\" value={String(tier.position)} />\n {limitLines(tier).map(([label, value]) => (\n <Fact key={label} label={label} value={value} />\n ))}\n <Fact\n label=\"Status\"\n value={tier.enabled ? 'Enabled' : 'Disabled'}\n />\n </FactList>\n ) : (\n <p className={styles.quiet}>\n With no tier, this business resolves to verification required.\n </p>\n )}\n </Card>\n <TableShell\n minWidth={0}\n head={\n <tr>\n <Th>Requirement</Th>\n <Th>State</Th>\n </tr>\n }\n >\n {rows.length === 0 ? (\n <tr>\n <td colSpan={2} className={styles.quiet}>\n Nothing verified and nothing required.\n </td>\n </tr>\n ) : (\n rows.map((r) => (\n <TableRow key={r.name}>\n <td>{r.name}</td>\n <td>\n {r.met ? (\n <StatusBadge status=\"completed\" label=\"Met\" />\n ) : (\n <StatusBadge\n status=\"action_required\"\n label=\"Missing for the next tier\"\n />\n )}\n </td>\n </TableRow>\n ))\n )}\n </TableShell>\n </div>\n );\n}\n"],"mappings":";AA0BQ,cAME,YANF;AAxBR;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAAmB;AAE5B,SAAS,YAAY,uBAAuB;AAC5C,OAAO,YAAY;AAMZ,SAAS,kBAAkB,EAAE,QAAQ,GAAmC;AAC7E,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,OAAO,gBAAgB,OAAO;AAEpC,SACE,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,GACrC;AAAA,yBAAC,QACC;AAAA,0BAAC,QAAG,WAAW,OAAO,YACnB,iBACG,YAAY,KAAK,KAAK,OAAO,QAAQ,QAAQ,KAC7C,MAAM,QAAQ,QAAQ,uBAC5B;AAAA,MACC,OACC,qBAAC,YAAS,WAAU,QAClB;AAAA,4BAAC,QAAK,OAAM,QAAO,OAAO,GAAG,KAAK,KAAK,KAAK,KAAK,GAAG,KAAK;AAAA,QACzD,oBAAC,QAAK,OAAM,YAAW,OAAO,OAAO,KAAK,QAAQ,GAAG;AAAA,QACpD,WAAW,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,KAAK,MAClC,oBAAC,QAAiB,OAAc,SAArB,KAAmC,CAC/C;AAAA,QACD;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,OAAO,KAAK,UAAU,YAAY;AAAA;AAAA,QACpC;AAAA,SACF,IAEA,oBAAC,OAAE,WAAW,OAAO,OAAO,4EAE5B;AAAA,OAEJ;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,MACE,qBAAC,QACC;AAAA,8BAAC,MAAG,yBAAW;AAAA,UACf,oBAAC,MAAG,mBAAK;AAAA,WACX;AAAA,QAGD,eAAK,WAAW,IACf,oBAAC,QACC,8BAAC,QAAG,SAAS,GAAG,WAAW,OAAO,OAAO,oDAEzC,GACF,IAEA,KAAK,IAAI,CAAC,MACR,qBAAC,YACC;AAAA,8BAAC,QAAI,YAAE,MAAK;AAAA,UACZ,oBAAC,QACE,YAAE,MACD,oBAAC,eAAY,QAAO,aAAY,OAAM,OAAM,IAE5C;AAAA,YAAC;AAAA;AAAA,cACC,QAAO;AAAA,cACP,OAAM;AAAA;AAAA,UACR,GAEJ;AAAA,aAXa,EAAE,IAYjB,CACD;AAAA;AAAA,IAEL;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/payout-tiers/tier-preview-result.tsx"],"sourcesContent":["'use client';\n\nimport {\n Card,\n Fact,\n FactList,\n TableRow,\n TableShell,\n Th,\n} from '@withpotter/ui-kit';\nimport { StatusBadge } from '@withpotter/components/shared/status-badge';\nimport type { PayoutTierPreview } from '@withpotter/lib/admin-money-api';\nimport { limitLines, requirementRows } from './tier-preview';\nimport styles from '../_money/ledger.module.css';\nimport { requirementLabel } from './requirement-labels';\n\n/**\n * What the preview answered: the tier the business lands on with its\n * limits, then every requirement it names, met or still missing.\n */\nexport function TierPreviewResult({ preview }: { preview: PayoutTierPreview }) {\n const { tier } = preview;\n const rows = requirementRows(preview);\n\n return (\n <div style={{ display: 'grid', gap: 16 }}>\n <Card>\n <h3 className={styles.chosenName}>\n {tier\n ? `Gets the ${tier.label} level in ${preview.currency}`\n : `No ${preview.currency} level fits yet`}\n </h3>\n {tier ? (\n <FactList className=\"mt-4\">\n <Fact label=\"Level\" value={tier.label} />\n <Fact label=\"Priority\" value={String(tier.position)} />\n {limitLines(tier).map(([label, value]) => (\n <Fact key={label} label={label} value={value} />\n ))}\n <Fact\n label=\"Status\"\n value={tier.enabled ? 'Enabled' : 'Disabled'}\n />\n </FactList>\n ) : (\n <p className={styles.quiet}>\n This merchant has to verify their identity before they can send money out.\n </p>\n )}\n </Card>\n <TableShell\n minWidth={0}\n head={\n <tr>\n <Th>Check</Th>\n <Th>Result</Th>\n </tr>\n }\n >\n {rows.length === 0 ? (\n <tr>\n <td colSpan={2} className={styles.quiet}>\n Nothing verified and nothing required.\n </td>\n </tr>\n ) : (\n rows.map((r) => (\n <TableRow key={r.name}>\n <td>{requirementLabel(r.name)}</td>\n <td>\n {r.met ? (\n <StatusBadge status=\"completed\" label=\"Done\" />\n ) : (\n <StatusBadge\n status=\"action_required\"\n label=\"Still needed for the next level\"\n />\n )}\n </td>\n </TableRow>\n ))\n )}\n </TableShell>\n </div>\n );\n}\n"],"mappings":";AA2BQ,cAME,YANF;AAzBR;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAAmB;AAE5B,SAAS,YAAY,uBAAuB;AAC5C,OAAO,YAAY;AACnB,SAAS,wBAAwB;AAM1B,SAAS,kBAAkB,EAAE,QAAQ,GAAmC;AAC7E,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,OAAO,gBAAgB,OAAO;AAEpC,SACE,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,GACrC;AAAA,yBAAC,QACC;AAAA,0BAAC,QAAG,WAAW,OAAO,YACnB,iBACG,YAAY,KAAK,KAAK,aAAa,QAAQ,QAAQ,KACnD,MAAM,QAAQ,QAAQ,mBAC5B;AAAA,MACC,OACC,qBAAC,YAAS,WAAU,QAClB;AAAA,4BAAC,QAAK,OAAM,SAAQ,OAAO,KAAK,OAAO;AAAA,QACvC,oBAAC,QAAK,OAAM,YAAW,OAAO,OAAO,KAAK,QAAQ,GAAG;AAAA,QACpD,WAAW,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,KAAK,MAClC,oBAAC,QAAiB,OAAc,SAArB,KAAmC,CAC/C;AAAA,QACD;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,OAAO,KAAK,UAAU,YAAY;AAAA;AAAA,QACpC;AAAA,SACF,IAEA,oBAAC,OAAE,WAAW,OAAO,OAAO,wFAE5B;AAAA,OAEJ;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,MACE,qBAAC,QACC;AAAA,8BAAC,MAAG,mBAAK;AAAA,UACT,oBAAC,MAAG,oBAAM;AAAA,WACZ;AAAA,QAGD,eAAK,WAAW,IACf,oBAAC,QACC,8BAAC,QAAG,SAAS,GAAG,WAAW,OAAO,OAAO,oDAEzC,GACF,IAEA,KAAK,IAAI,CAAC,MACR,qBAAC,YACC;AAAA,8BAAC,QAAI,2BAAiB,EAAE,IAAI,GAAE;AAAA,UAC9B,oBAAC,QACE,YAAE,MACD,oBAAC,eAAY,QAAO,aAAY,OAAM,QAAO,IAE7C;AAAA,YAAC;AAAA;AAAA,cACC,QAAO;AAAA,cACP,OAAM;AAAA;AAAA,UACR,GAEJ;AAAA,aAXa,EAAE,IAYjB,CACD;AAAA;AAAA,IAEL;AAAA,KACF;AAEJ;","names":[]}
@@ -14,6 +14,7 @@ import {
14
14
  dangerRowBtn
15
15
  } from "../_ui";
16
16
  import { TierDialog } from "./_tier-dialog";
17
+ import { requirementLabel } from "./requirement-labels";
17
18
  import { TIERS_KEY, useTiers } from "./use-tiers";
18
19
  const TAG = {
19
20
  padding: "2px 8px",
@@ -50,7 +51,7 @@ function TiersTable({
50
51
  const columns = [
51
52
  {
52
53
  key: "label",
53
- header: "Tier",
54
+ header: "Level",
54
55
  render: (t) => /* @__PURE__ */ jsxs("span", { children: [
55
56
  /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: t.label }),
56
57
  !t.enabled && /* @__PURE__ */ jsx("span", { style: { ...TAG, marginLeft: 8 }, children: "Disabled" }),
@@ -64,10 +65,8 @@ function TiersTable({
64
65
  fontFamily: "var(--font-mono, monospace)"
65
66
  },
66
67
  children: [
67
- t.key,
68
- " \xB7 ",
69
68
  t.currency,
70
- " \xB7 position ",
69
+ " \xB7 priority ",
71
70
  t.position
72
71
  ]
73
72
  }
@@ -76,8 +75,8 @@ function TiersTable({
76
75
  },
77
76
  {
78
77
  key: "requirements",
79
- header: "Needs",
80
- render: (t) => t.requirements.length === 0 ? "\u2013" : /* @__PURE__ */ jsx("span", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: t.requirements.map((r) => /* @__PURE__ */ jsx("span", { style: TAG, children: r }, r)) })
78
+ header: "Must complete",
79
+ render: (t) => t.requirements.length === 0 ? "\u2013" : /* @__PURE__ */ jsx("span", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: t.requirements.map((r) => /* @__PURE__ */ jsx("span", { style: TAG, children: requirementLabel(r) }, r)) })
81
80
  },
82
81
  {
83
82
  key: "transfer",
@@ -130,7 +129,7 @@ function TiersTable({
130
129
  isLoading,
131
130
  isError,
132
131
  emptyTitle: currency && data?.length ? `No ${currency} levels` : "No levels yet",
133
- emptyDescription: `With no tier, every business resolves to verification required${currency ? ` in ${currency}` : ""}.`
132
+ emptyDescription: `Until you add one, every merchant has to verify their identity before they can send money out${currency ? ` in ${currency}` : ""}.`
134
133
  }
135
134
  ),
136
135
  editing && /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/payout-tiers/tiers-table.tsx"],"sourcesContent":["'use client';\n\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { Banner } from '@withpotter/ui-kit/banner';\nimport { useConfirm } from '@withpotter/ui-kit/confirm-dialog';\nimport { formatMinor } from '@withpotter/lib/money-minor';\nimport {\n adminMoneyApi,\n type PayoutTier,\n type PayoutTierInput,\n} from '@withpotter/lib/admin-money-api';\nimport {\n DataTable,\n byCurrency,\n rowBtn,\n dangerRowBtn,\n type Column,\n} from '../_ui';\nimport { TierDialog } from './_tier-dialog';\nimport { TIERS_KEY, useTiers } from './use-tiers';\n\nconst TAG = {\n padding: '2px 8px',\n borderRadius: 999,\n border: '1px solid var(--border-default)',\n fontSize: 12,\n color: 'var(--text-secondary)',\n} as const;\n\ntype Editing = PayoutTier | 'new' | null;\n\n/** The tiers, with edit and remove on each row and the tier dialog. */\nexport function TiersTable({\n editing,\n onEdit,\n currency = '',\n}: {\n editing: Editing;\n onEdit: (next: Editing) => void;\n /** The currency filter's choice; '' lists every currency. */\n currency?: string;\n}) {\n const qc = useQueryClient();\n const confirm = useConfirm();\n const { data, isLoading, isError } = useTiers();\n\n const refresh = () => qc.invalidateQueries({ queryKey: TIERS_KEY });\n const save = useMutation({\n mutationFn: (body: PayoutTierInput) =>\n editing && editing !== 'new'\n ? adminMoneyApi.updateTier(editing.id, body)\n : adminMoneyApi.createTier(body),\n onSuccess: () => {\n close();\n refresh();\n },\n });\n const remove = useMutation({\n mutationFn: (id: string) => adminMoneyApi.removeTier(id),\n onSuccess: refresh,\n });\n // Closing the dialog clears both errors, as opening a fresh one should.\n function close() {\n onEdit(null);\n save.reset();\n remove.reset();\n }\n\n const columns: Column<PayoutTier>[] = [\n {\n key: 'label',\n header: 'Tier',\n render: (t) => (\n <span>\n <span style={{ fontWeight: 500 }}>{t.label}</span>\n {!t.enabled && (\n <span style={{ ...TAG, marginLeft: 8 }}>Disabled</span>\n )}\n <span\n style={{\n display: 'block',\n fontSize: 12,\n color: 'var(--text-tertiary)',\n fontFamily: 'var(--font-mono, monospace)',\n }}\n >\n {t.key} · {t.currency} · position {t.position}\n </span>\n </span>\n ),\n },\n {\n key: 'requirements',\n header: 'Needs',\n render: (t) =>\n t.requirements.length === 0 ? (\n '–'\n ) : (\n <span style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {t.requirements.map((r) => (\n <span key={r} style={TAG}>\n {r}\n </span>\n ))}\n </span>\n ),\n },\n {\n key: 'transfer',\n header: 'Per transfer',\n render: (t) =>\n `${formatMinor(t.minimumMinor, t.currency)} to ${formatMinor(t.maximumMinor, t.currency)}`,\n },\n {\n key: 'daily',\n header: 'Per day',\n render: (t) => formatMinor(t.dailyMaximumMinor, t.currency),\n },\n {\n key: 'monthly',\n header: 'Per month',\n render: (t) =>\n t.monthlyMaximumMinor\n ? formatMinor(t.monthlyMaximumMinor, t.currency)\n : 'No cap',\n },\n {\n key: 'actions',\n header: '',\n render: (t) => (\n <span style={{ display: 'flex', gap: 6 }}>\n <button type=\"button\" style={rowBtn} onClick={() => onEdit(t)}>\n Edit\n </button>\n <button\n type=\"button\"\n style={dangerRowBtn}\n onClick={async () => {\n const ok = await confirm({\n title: `Remove ${t.label}?`,\n description:\n 'Businesses on this tier fall back to the next tier they qualify for.',\n confirmLabel: 'Remove',\n tone: 'danger',\n });\n if (ok) remove.mutate(t.id);\n }}\n >\n Remove\n </button>\n </span>\n ),\n },\n ];\n\n return (\n <>\n {remove.error && !editing && (\n <Banner tone=\"error\">{remove.error.message}</Banner>\n )}\n <DataTable\n columns={columns}\n rows={data && byCurrency(data, currency, (t) => t.currency)}\n getRowKey={(t) => t.id}\n isLoading={isLoading}\n isError={isError}\n emptyTitle={\n currency && data?.length ? `No ${currency} levels` : 'No levels yet'\n }\n emptyDescription={`With no tier, every business resolves to verification required${currency ? ` in ${currency}` : ''}.`}\n />\n {editing && (\n <TierDialog\n tier={editing === 'new' ? null : editing}\n saving={save.isPending}\n error={save.error?.message ?? null}\n onSave={(b) => save.mutate(b)}\n onClose={close}\n />\n )}\n </>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/payout-tiers/tiers-table.tsx"],"sourcesContent":["'use client';\n\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { Banner } from '@withpotter/ui-kit/banner';\nimport { useConfirm } from '@withpotter/ui-kit/confirm-dialog';\nimport { formatMinor } from '@withpotter/lib/money-minor';\nimport {\n adminMoneyApi,\n type PayoutTier,\n type PayoutTierInput,\n} from '@withpotter/lib/admin-money-api';\nimport {\n DataTable,\n byCurrency,\n rowBtn,\n dangerRowBtn,\n type Column,\n} from '../_ui';\nimport { TierDialog } from './_tier-dialog';\nimport { requirementLabel } from './requirement-labels';\nimport { TIERS_KEY, useTiers } from './use-tiers';\n\nconst TAG = {\n padding: '2px 8px',\n borderRadius: 999,\n border: '1px solid var(--border-default)',\n fontSize: 12,\n color: 'var(--text-secondary)',\n} as const;\n\ntype Editing = PayoutTier | 'new' | null;\n\n/** The tiers, with edit and remove on each row and the tier dialog. */\nexport function TiersTable({\n editing,\n onEdit,\n currency = '',\n}: {\n editing: Editing;\n onEdit: (next: Editing) => void;\n /** The currency filter's choice; '' lists every currency. */\n currency?: string;\n}) {\n const qc = useQueryClient();\n const confirm = useConfirm();\n const { data, isLoading, isError } = useTiers();\n\n const refresh = () => qc.invalidateQueries({ queryKey: TIERS_KEY });\n const save = useMutation({\n mutationFn: (body: PayoutTierInput) =>\n editing && editing !== 'new'\n ? adminMoneyApi.updateTier(editing.id, body)\n : adminMoneyApi.createTier(body),\n onSuccess: () => {\n close();\n refresh();\n },\n });\n const remove = useMutation({\n mutationFn: (id: string) => adminMoneyApi.removeTier(id),\n onSuccess: refresh,\n });\n // Closing the dialog clears both errors, as opening a fresh one should.\n function close() {\n onEdit(null);\n save.reset();\n remove.reset();\n }\n\n const columns: Column<PayoutTier>[] = [\n {\n key: 'label',\n header: 'Level',\n render: (t) => (\n <span>\n <span style={{ fontWeight: 500 }}>{t.label}</span>\n {!t.enabled && (\n <span style={{ ...TAG, marginLeft: 8 }}>Disabled</span>\n )}\n <span\n style={{\n display: 'block',\n fontSize: 12,\n color: 'var(--text-tertiary)',\n fontFamily: 'var(--font-mono, monospace)',\n }}\n >\n {t.currency} · priority {t.position}\n </span>\n </span>\n ),\n },\n {\n key: 'requirements',\n header: 'Must complete',\n render: (t) =>\n t.requirements.length === 0 ? (\n '–'\n ) : (\n <span style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {t.requirements.map((r) => (\n <span key={r} style={TAG}>\n {requirementLabel(r)}\n </span>\n ))}\n </span>\n ),\n },\n {\n key: 'transfer',\n header: 'Per transfer',\n render: (t) =>\n `${formatMinor(t.minimumMinor, t.currency)} to ${formatMinor(t.maximumMinor, t.currency)}`,\n },\n {\n key: 'daily',\n header: 'Per day',\n render: (t) => formatMinor(t.dailyMaximumMinor, t.currency),\n },\n {\n key: 'monthly',\n header: 'Per month',\n render: (t) =>\n t.monthlyMaximumMinor\n ? formatMinor(t.monthlyMaximumMinor, t.currency)\n : 'No cap',\n },\n {\n key: 'actions',\n header: '',\n render: (t) => (\n <span style={{ display: 'flex', gap: 6 }}>\n <button type=\"button\" style={rowBtn} onClick={() => onEdit(t)}>\n Edit\n </button>\n <button\n type=\"button\"\n style={dangerRowBtn}\n onClick={async () => {\n const ok = await confirm({\n title: `Remove ${t.label}?`,\n description:\n 'Businesses on this tier fall back to the next tier they qualify for.',\n confirmLabel: 'Remove',\n tone: 'danger',\n });\n if (ok) remove.mutate(t.id);\n }}\n >\n Remove\n </button>\n </span>\n ),\n },\n ];\n\n return (\n <>\n {remove.error && !editing && (\n <Banner tone=\"error\">{remove.error.message}</Banner>\n )}\n <DataTable\n columns={columns}\n rows={data && byCurrency(data, currency, (t) => t.currency)}\n getRowKey={(t) => t.id}\n isLoading={isLoading}\n isError={isError}\n emptyTitle={\n currency && data?.length ? `No ${currency} levels` : 'No levels yet'\n }\n emptyDescription={`Until you add one, every merchant has to verify their identity before they can send money out${currency ? ` in ${currency}` : ''}.`}\n />\n {editing && (\n <TierDialog\n tier={editing === 'new' ? null : editing}\n saving={save.isPending}\n error={save.error?.message ?? null}\n onSave={(b) => save.mutate(b)}\n onClose={close}\n />\n )}\n </>\n );\n}\n"],"mappings":"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","names":[]}