@openrails/billing-ui 0.242.0 → 0.243.0

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 (260) hide show
  1. package/CHANGELOG.md +27 -11
  2. package/README.md +41 -8
  3. package/dist/admin/billing-admin.d.ts +3 -0
  4. package/dist/admin/components/app-sidebar.d.ts +1 -0
  5. package/dist/admin/components/confirm.d.ts +4 -0
  6. package/dist/admin/components/cursor-pager.d.ts +8 -0
  7. package/dist/admin/components/data-table.d.ts +14 -0
  8. package/dist/admin/components/fact-card.d.ts +5 -0
  9. package/dist/admin/components/form-field-errors.d.ts +3 -0
  10. package/dist/admin/components/linked-table-row.d.ts +5 -0
  11. package/dist/admin/components/logo.d.ts +3 -0
  12. package/dist/admin/components/no-access.d.ts +3 -0
  13. package/dist/admin/components/no-merchants.d.ts +1 -0
  14. package/dist/admin/components/notification-bell.d.ts +2 -0
  15. package/dist/admin/components/route-error.d.ts +3 -0
  16. package/dist/admin/components/site-header.d.ts +9 -0
  17. package/dist/admin/components/status-badge.d.ts +3 -0
  18. package/dist/admin/components/typed-confirm-dialog.d.ts +11 -0
  19. package/dist/admin/components/ui/alert-dialog.d.ts +18 -0
  20. package/dist/admin/components/ui/avatar.d.ts +11 -0
  21. package/dist/admin/components/ui/badge.d.ts +7 -0
  22. package/dist/admin/components/ui/breadcrumb.d.ts +10 -0
  23. package/dist/admin/components/ui/button.d.ts +8 -0
  24. package/dist/admin/components/ui/card.d.ts +11 -0
  25. package/dist/admin/components/ui/chart.d.ts +44 -0
  26. package/dist/admin/components/ui/dialog.d.ts +17 -0
  27. package/dist/admin/components/ui/dropdown-menu.d.ts +29 -0
  28. package/dist/admin/components/ui/input.d.ts +3 -0
  29. package/dist/admin/components/ui/label.d.ts +3 -0
  30. package/dist/admin/components/ui/select.d.ts +15 -0
  31. package/dist/admin/components/ui/separator.d.ts +3 -0
  32. package/dist/admin/components/ui/sheet.d.ts +14 -0
  33. package/dist/admin/components/ui/sidebar.d.ts +63 -0
  34. package/dist/admin/components/ui/skeleton.d.ts +2 -0
  35. package/dist/admin/components/ui/sonner.d.ts +3 -0
  36. package/dist/admin/components/ui/switch.d.ts +5 -0
  37. package/dist/admin/components/ui/table.d.ts +10 -0
  38. package/dist/admin/components/ui/tabs.d.ts +10 -0
  39. package/dist/admin/components/ui/textarea.d.ts +3 -0
  40. package/dist/admin/components/ui/tooltip.d.ts +6 -0
  41. package/dist/admin/context.d.ts +1193 -0
  42. package/dist/admin/hooks/use-mobile.d.ts +1 -0
  43. package/dist/admin/index.d.ts +5 -0
  44. package/dist/admin/layouts/app-layout.d.ts +4 -0
  45. package/dist/admin/lib/api/client.d.ts +64 -0
  46. package/dist/admin/lib/api/copilot.d.ts +6 -0
  47. package/dist/admin/lib/api/credit-endpoints.d.ts +8 -0
  48. package/dist/admin/lib/api/credit-types.d.ts +9 -0
  49. package/dist/admin/lib/api/endpoints.d.ts +133 -0
  50. package/dist/admin/lib/api/index.d.ts +89 -0
  51. package/dist/admin/lib/api/invoice-profile-endpoints.d.ts +6 -0
  52. package/dist/admin/lib/api/metrics.d.ts +68 -0
  53. package/dist/admin/lib/api/order-endpoints.d.ts +21 -0
  54. package/dist/admin/lib/api/types.d.ts +122 -0
  55. package/dist/admin/lib/auth.d.ts +6 -0
  56. package/dist/admin/lib/capabilities.d.ts +13 -0
  57. package/dist/admin/lib/chunk-error.d.ts +1 -0
  58. package/dist/admin/lib/confirm.d.ts +11 -0
  59. package/dist/admin/lib/credit-queries.d.ts +23 -0
  60. package/dist/admin/lib/csv.d.ts +3 -0
  61. package/dist/admin/lib/cursor-pages.d.ts +13 -0
  62. package/dist/admin/lib/dialog-width.d.ts +6 -0
  63. package/dist/admin/lib/dom.d.ts +1 -0
  64. package/dist/admin/lib/duration.d.ts +3 -0
  65. package/dist/admin/lib/format.d.ts +23 -0
  66. package/dist/admin/lib/mount.d.ts +6 -0
  67. package/dist/admin/lib/mutations.d.ts +125 -0
  68. package/dist/admin/lib/order-queries.d.ts +29 -0
  69. package/dist/admin/lib/queries.d.ts +369 -0
  70. package/dist/admin/lib/query-client.d.ts +3 -0
  71. package/dist/admin/lib/toast.d.ts +10 -0
  72. package/dist/admin/lib/utils.d.ts +2 -0
  73. package/dist/admin/messages.d.ts +670 -0
  74. package/dist/admin/navigation.d.ts +14 -0
  75. package/dist/admin/pages/catalog/application-dialog.d.ts +2 -0
  76. package/dist/admin/pages/catalog/copilot-panel.d.ts +4 -0
  77. package/dist/admin/pages/catalog/index.d.ts +4 -0
  78. package/dist/admin/pages/catalog/meter-form.d.ts +6 -0
  79. package/dist/admin/pages/catalog/metering-model.d.ts +67 -0
  80. package/dist/admin/pages/catalog/metering.d.ts +3 -0
  81. package/dist/admin/pages/catalog/price-detail.d.ts +2 -0
  82. package/dist/admin/pages/catalog/price-format.d.ts +3 -0
  83. package/dist/admin/pages/catalog/price-wizard-logic.d.ts +20 -0
  84. package/dist/admin/pages/catalog/price-wizard.d.ts +10 -0
  85. package/dist/admin/pages/catalog/psp-links.d.ts +10 -0
  86. package/dist/admin/pages/catalog/rate-card-editor.d.ts +10 -0
  87. package/dist/admin/pages/customers/credit-form.d.ts +14 -0
  88. package/dist/admin/pages/customers/credits.d.ts +5 -0
  89. package/dist/admin/pages/customers/default-card-badges.d.ts +3 -0
  90. package/dist/admin/pages/customers/detail.d.ts +5 -0
  91. package/dist/admin/pages/customers/grant-duration.d.ts +32 -0
  92. package/dist/admin/pages/customers/index.d.ts +2 -0
  93. package/dist/admin/pages/customers/invoice-profile-model.d.ts +18 -0
  94. package/dist/admin/pages/customers/invoice-profile.d.ts +9 -0
  95. package/dist/admin/pages/dashboard/index.d.ts +2 -0
  96. package/dist/admin/pages/dashboard/lib.d.ts +48 -0
  97. package/dist/admin/pages/dashboard/range-picker.d.ts +1 -0
  98. package/dist/admin/pages/dashboard/range.d.ts +34 -0
  99. package/dist/admin/pages/dashboard/reports-model.d.ts +29 -0
  100. package/dist/admin/pages/dashboard/reports.d.ts +2 -0
  101. package/dist/admin/pages/dashboard/use-range.d.ts +5 -0
  102. package/dist/admin/pages/dashboard/widget-editor.d.ts +8 -0
  103. package/dist/admin/pages/dashboard/widget-tile.d.ts +9 -0
  104. package/dist/admin/pages/dashboard/widget-viz.d.ts +12 -0
  105. package/dist/admin/pages/ops/index.d.ts +2 -0
  106. package/dist/admin/pages/orders/detail.d.ts +5 -0
  107. package/dist/admin/pages/orders/index.d.ts +1 -0
  108. package/dist/admin/pages/orders/model.d.ts +7 -0
  109. package/dist/admin/pages/payments/attempts.d.ts +7 -0
  110. package/dist/admin/pages/payments/detail.d.ts +2 -0
  111. package/dist/admin/pages/payments/health-model.d.ts +149 -0
  112. package/dist/admin/pages/payments/health.d.ts +2 -0
  113. package/dist/admin/pages/payments/index.d.ts +2 -0
  114. package/dist/admin/pages/settings/configuration-edit.d.ts +9 -0
  115. package/dist/admin/pages/settings/index.d.ts +9 -0
  116. package/dist/admin/pages/settings/notifications.d.ts +2 -0
  117. package/dist/admin/pages/settings/setting-fields.d.ts +20 -0
  118. package/dist/admin/pages/subscriptions/change-subscription-dialog.d.ts +16 -0
  119. package/dist/admin/pages/subscriptions/detail.d.ts +2 -0
  120. package/dist/admin/pages/subscriptions/dunning.d.ts +2 -0
  121. package/dist/admin/pages/subscriptions/index.d.ts +2 -0
  122. package/dist/admin/pages/subscriptions/subscription-change-options.d.ts +23 -0
  123. package/dist/admin/pages/subscriptions/views.d.ts +15 -0
  124. package/dist/admin/router.d.ts +32 -0
  125. package/dist/admin/routes.d.ts +5 -0
  126. package/dist/admin/summary.d.ts +27 -0
  127. package/dist/admin/theme.d.ts +2 -0
  128. package/dist/admin/types.d.ts +56 -0
  129. package/dist/admin/ui-context.d.ts +14 -0
  130. package/dist/admin-attempts-lAoW-Urd.js +419 -0
  131. package/dist/admin-attempts-lAoW-Urd.js.map +1 -0
  132. package/dist/admin-auth-DQGHtt0j.js +14 -0
  133. package/dist/admin-auth-DQGHtt0j.js.map +1 -0
  134. package/dist/admin-badge-DR5-1qd8.js +31 -0
  135. package/dist/admin-badge-DR5-1qd8.js.map +1 -0
  136. package/dist/admin-button-CTL3DgOt.js +46 -0
  137. package/dist/admin-button-CTL3DgOt.js.map +1 -0
  138. package/dist/admin-capabilities-BuigAgtm.js +59 -0
  139. package/dist/admin-capabilities-BuigAgtm.js.map +1 -0
  140. package/dist/admin-card-bzAks3-3.js +51 -0
  141. package/dist/admin-card-bzAks3-3.js.map +1 -0
  142. package/dist/admin-catalog-CC7I4n0_.js +1189 -0
  143. package/dist/admin-catalog-CC7I4n0_.js.map +1 -0
  144. package/dist/admin-confirm-katGq0Qo.js +12 -0
  145. package/dist/admin-confirm-katGq0Qo.js.map +1 -0
  146. package/dist/admin-csv-CPoNZj2D.js +16 -0
  147. package/dist/admin-csv-CPoNZj2D.js.map +1 -0
  148. package/dist/admin-customers-D8u5gq3M.js +160 -0
  149. package/dist/admin-customers-D8u5gq3M.js.map +1 -0
  150. package/dist/admin-dashboard-DqqFjOzq.js +420 -0
  151. package/dist/admin-dashboard-DqqFjOzq.js.map +1 -0
  152. package/dist/admin-data-table-qfXLOFmN.js +96 -0
  153. package/dist/admin-data-table-qfXLOFmN.js.map +1 -0
  154. package/dist/admin-detail-5aNNvrc0.js +324 -0
  155. package/dist/admin-detail-5aNNvrc0.js.map +1 -0
  156. package/dist/admin-detail-7p684Uyc.js +342 -0
  157. package/dist/admin-detail-7p684Uyc.js.map +1 -0
  158. package/dist/admin-detail-CGOyqs7s.js +1312 -0
  159. package/dist/admin-detail-CGOyqs7s.js.map +1 -0
  160. package/dist/admin-detail-DUAJQg8G.js +710 -0
  161. package/dist/admin-detail-DUAJQg8G.js.map +1 -0
  162. package/dist/admin-dialog-BjuKI5Hp.js +88 -0
  163. package/dist/admin-dialog-BjuKI5Hp.js.map +1 -0
  164. package/dist/admin-dialog-width-BPrgdYlj.js +6 -0
  165. package/dist/admin-dialog-width-BPrgdYlj.js.map +1 -0
  166. package/dist/admin-dom-uMmZzRvU.js +149 -0
  167. package/dist/admin-dom-uMmZzRvU.js.map +1 -0
  168. package/dist/admin-dropdown-menu-BW1D_h6s.js +69 -0
  169. package/dist/admin-dropdown-menu-BW1D_h6s.js.map +1 -0
  170. package/dist/admin-dunning-B2zgtrOo.js +10 -0
  171. package/dist/admin-dunning-B2zgtrOo.js.map +1 -0
  172. package/dist/admin-fact-card-DO_fHosg.js +20 -0
  173. package/dist/admin-fact-card-DO_fHosg.js.map +1 -0
  174. package/dist/admin-form-field-errors-hbUMIriS.js +14 -0
  175. package/dist/admin-form-field-errors-hbUMIriS.js.map +1 -0
  176. package/dist/admin-format-DoohJ7Fg.js +136 -0
  177. package/dist/admin-format-DoohJ7Fg.js.map +1 -0
  178. package/dist/admin-health-B4jN2LwR.js +983 -0
  179. package/dist/admin-health-B4jN2LwR.js.map +1 -0
  180. package/dist/admin-input-CcfQfJFN.js +17 -0
  181. package/dist/admin-input-CcfQfJFN.js.map +1 -0
  182. package/dist/admin-invoice-profile-model-Cgjy3zV8.js +53 -0
  183. package/dist/admin-invoice-profile-model-Cgjy3zV8.js.map +1 -0
  184. package/dist/admin-label-BiEN5cjb.js +15 -0
  185. package/dist/admin-label-BiEN5cjb.js.map +1 -0
  186. package/dist/admin-linked-table-row-BsaUruCN.js +26 -0
  187. package/dist/admin-linked-table-row-BsaUruCN.js.map +1 -0
  188. package/dist/admin-metering-BGAXbT23.js +1702 -0
  189. package/dist/admin-metering-BGAXbT23.js.map +1 -0
  190. package/dist/admin-ops-B3mcr76u.js +217 -0
  191. package/dist/admin-ops-B3mcr76u.js.map +1 -0
  192. package/dist/admin-orders-dxC99Idl.js +192 -0
  193. package/dist/admin-orders-dxC99Idl.js.map +1 -0
  194. package/dist/admin-payments-Bs7HSfP0.js +246 -0
  195. package/dist/admin-payments-Bs7HSfP0.js.map +1 -0
  196. package/dist/admin-price-detail-DRquxpA9.js +482 -0
  197. package/dist/admin-price-detail-DRquxpA9.js.map +1 -0
  198. package/dist/admin-price-format-DM1qORWI.js +44 -0
  199. package/dist/admin-price-format-DM1qORWI.js.map +1 -0
  200. package/dist/admin-price-wizard-CI7K-2Nz.js +357 -0
  201. package/dist/admin-price-wizard-CI7K-2Nz.js.map +1 -0
  202. package/dist/admin-range-picker-Dr2M1EZr.js +192 -0
  203. package/dist/admin-range-picker-Dr2M1EZr.js.map +1 -0
  204. package/dist/admin-reports-CywKLiSA.js +320 -0
  205. package/dist/admin-reports-CywKLiSA.js.map +1 -0
  206. package/dist/admin-select-DBgprVW6.js +81 -0
  207. package/dist/admin-select-DBgprVW6.js.map +1 -0
  208. package/dist/admin-settings-Bmoy95uO.js +1434 -0
  209. package/dist/admin-settings-Bmoy95uO.js.map +1 -0
  210. package/dist/admin-skeleton-DsM7crYi.js +14 -0
  211. package/dist/admin-skeleton-DsM7crYi.js.map +1 -0
  212. package/dist/admin-status-badge-BFPgo71d.js +38 -0
  213. package/dist/admin-status-badge-BFPgo71d.js.map +1 -0
  214. package/dist/admin-subscriptions-CLYc_HEV.js +301 -0
  215. package/dist/admin-subscriptions-CLYc_HEV.js.map +1 -0
  216. package/dist/admin-switch-BJUxLCsa.js +20 -0
  217. package/dist/admin-switch-BJUxLCsa.js.map +1 -0
  218. package/dist/admin-table-CH9TrXJf.js +61 -0
  219. package/dist/admin-table-CH9TrXJf.js.map +1 -0
  220. package/dist/admin-tabs-528FJMjt.js +46 -0
  221. package/dist/admin-tabs-528FJMjt.js.map +1 -0
  222. package/dist/admin-textarea-DEz38RaI.js +15 -0
  223. package/dist/admin-textarea-DEz38RaI.js.map +1 -0
  224. package/dist/admin-typed-confirm-dialog-DU7m9-O7.js +66 -0
  225. package/dist/admin-typed-confirm-dialog-DU7m9-O7.js.map +1 -0
  226. package/dist/admin-utils-BK4Vh1o_.js +1809 -0
  227. package/dist/admin-utils-BK4Vh1o_.js.map +1 -0
  228. package/dist/admin-widget-viz-Da48c-Zf.js +581 -0
  229. package/dist/admin-widget-viz-Da48c-Zf.js.map +1 -0
  230. package/dist/admin.css +3 -0
  231. package/dist/admin.js +2164 -0
  232. package/dist/admin.js.map +1 -0
  233. package/dist/appearance.d.ts +1 -1
  234. package/dist/client/generated/error-codes.d.ts +1 -1
  235. package/dist/client/generated/routes.d.ts +2171 -176
  236. package/dist/client/generated/wire.d.ts +1273 -0
  237. package/dist/{hooks-Uiw-zW3H.js → hooks-Ckd8F2JF.js} +7 -7
  238. package/dist/hooks-Ckd8F2JF.js.map +1 -0
  239. package/dist/index.d.ts +1 -1
  240. package/dist/index.js +11 -11
  241. package/dist/index.js.map +1 -1
  242. package/dist/lib/{offer-label.d.ts → price-label.d.ts} +1 -1
  243. package/dist/locales/de.js +1 -1
  244. package/dist/locales/de.js.map +1 -1
  245. package/dist/locales/en.d.ts +1 -1
  246. package/dist/locales/en.js +1 -1
  247. package/dist/locales/en.js.map +1 -1
  248. package/dist/locales/es.js +1 -1
  249. package/dist/locales/es.js.map +1 -1
  250. package/dist/locales/ja.js +1 -1
  251. package/dist/locales/ja.js.map +1 -1
  252. package/dist/locales/ko.js +1 -1
  253. package/dist/locales/ko.js.map +1 -1
  254. package/dist/locales/zh.js +1 -1
  255. package/dist/locales/zh.js.map +1 -1
  256. package/dist/{offers.d.ts → product-list.d.ts} +5 -5
  257. package/dist/react.js +1 -1
  258. package/dist/styles.css +1 -1
  259. package/package.json +28 -6
  260. package/dist/hooks-Uiw-zW3H.js.map +0 -1
@@ -0,0 +1,357 @@
1
+ import { E as e, p as t, w as n } from "./admin-utils-BK4Vh1o_.js";
2
+ import { t as r } from "./admin-button-CTL3DgOt.js";
3
+ import { t as i } from "./admin-input-CcfQfJFN.js";
4
+ import { c as a, l as o, s } from "./admin-format-DoohJ7Fg.js";
5
+ import { t as c } from "./admin-form-field-errors-hbUMIriS.js";
6
+ import { t as l } from "./admin-badge-DR5-1qd8.js";
7
+ import { a as u, i as d, n as f, o as p, r as m, s as h, t as g } from "./admin-dialog-BjuKI5Hp.js";
8
+ import { t as _ } from "./admin-label-BiEN5cjb.js";
9
+ import { n as v } from "./admin-dialog-width-BPrgdYlj.js";
10
+ import { n as y } from "./admin-price-format-DM1qORWI.js";
11
+ import * as b from "react";
12
+ import { useMutation as x, useQuery as ee, useQueryClient as S } from "@tanstack/react-query";
13
+ import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
14
+ import { useForm as E } from "@tanstack/react-form";
15
+ //#region src/admin/pages/catalog/price-wizard-logic.ts
16
+ function D(e, t) {
17
+ let n = BigInt(e), r = BigInt(t);
18
+ return n > r ? "increase" : n < r ? "decrease" : "unchanged";
19
+ }
20
+ function O(e) {
21
+ return e === "decrease" ? "migrate" : "grandfather";
22
+ }
23
+ function k(e, t, n) {
24
+ if (e !== "increase") return null;
25
+ let r = new Date(t);
26
+ return r.setUTCDate(r.getUTCDate() + n), r;
27
+ }
28
+ function te(e, t, n) {
29
+ return k(e, t, n) ?? t;
30
+ }
31
+ function ne(e, t, n, r) {
32
+ let i = k(e, n, r);
33
+ return !i || t.getTime() >= i.getTime();
34
+ }
35
+ var A = (e) => new Date(e).toLocaleDateString(void 0, {
36
+ month: "short",
37
+ day: "numeric",
38
+ year: "numeric"
39
+ });
40
+ function j(e) {
41
+ let { newAmount: t, currentAmount: n, currency: r, affectedCount: i, plan: a, now: o } = e, c = s(t, r), l = s(n, r), u = `New subscribers pay ${c} immediately.`;
42
+ if (i === 0) return `${u} No existing subscribers are on a prior version of this price.`;
43
+ let d = `${i.toLocaleString()} existing subscriber${i === 1 ? "" : "s"}`;
44
+ return a.mode === "grandfather" ? `${u} ${d} keep ${l} forever (grandfathered).` : new Date(a.effectiveAt).getTime() <= o.getTime() ? `${u} ${d} move to ${c} at their next renewal. Notices go out on confirm.` : `${u} ${d} keep ${l} until ${A(a.effectiveAt)}, then move to ${c} at their next renewal. Notices go out on confirm.`;
45
+ }
46
+ //#endregion
47
+ //#region src/admin/pages/catalog/price-wizard.tsx
48
+ var M = (e) => e.toISOString().slice(0, 10), N = (e, t) => ({
49
+ amountInput: o(t?.new_amount ?? e.unit_amount, e.currency),
50
+ mode: t?.migration ? "migrate" : "grandfather",
51
+ effectiveAt: t?.migration?.effective_at ? M(new Date(t.migration.effective_at)) : ""
52
+ });
53
+ function P({ price: o, productName: A, productKey: P, draft: F, onDone: re }) {
54
+ let { toast: I, toastApiError: L, adminMutations: R, adminQueries: z } = t(), { id: B } = e(), V = S(), [H, U] = b.useState(() => !!F), [W, G] = b.useState(() => F ? 3 : 1), K = x(R.previewPriceChange()), q = x(R.changePrice(V)), J = K.data?.matched ?? F?.affected_count ?? null, { data: Y } = ee({
55
+ ...z.merchantConfiguration(),
56
+ enabled: H
57
+ }), X = Y?.settings.reprice_notice_window_days ?? 30, [Z] = b.useState(() => /* @__PURE__ */ new Date()), Q = E({
58
+ defaultValues: N(o, F),
59
+ onSubmit: async ({ value: e }) => {
60
+ if (!P || o.customer_amount) return;
61
+ let t = a(e.amountInput, o.currency);
62
+ if (!(t === null || BigInt(t) <= 0n)) try {
63
+ let n = await q.mutateAsync({
64
+ price: {
65
+ product_id: o.product_id,
66
+ unit_amount: t,
67
+ currency: o.currency,
68
+ access_duration_hours: o.access_duration_hours ?? void 0,
69
+ billing_interval_hours: o.billing_interval_hours ?? void 0,
70
+ trial_unit_amount: o.trial_unit_amount ?? void 0,
71
+ trial_duration_hours: o.trial_duration_hours ?? void 0,
72
+ key: o.key,
73
+ psps: Object.keys(o.psps ?? {}),
74
+ expected_revision: o.revision
75
+ },
76
+ migration: e.mode === "migrate" ? {
77
+ productKey: P,
78
+ priceKey: o.key,
79
+ effectiveAt: new Date(e.effectiveAt).toISOString()
80
+ } : void 0
81
+ });
82
+ n.pending_manual_actions?.length ? I.warning(`Price updated. One step is left for you: ${n.pending_manual_actions.map((e) => `${e.psp}: ${e.hint}`).join(". ")}`) : I.success(e.mode === "migrate" ? "Price updated and migration scheduled" : "Price updated"), $(!1), re?.();
83
+ } catch (e) {
84
+ L(e, "Change price");
85
+ }
86
+ }
87
+ }), ie = () => {
88
+ G(1), Q.reset(N(o)), K.reset();
89
+ }, $ = (e) => {
90
+ e || ie(), U(e);
91
+ }, ae = () => {
92
+ if (!P || o.customer_amount) return;
93
+ let e = D(a(Q.state.values.amountInput, o.currency) ?? o.unit_amount, o.unit_amount);
94
+ Q.setFieldValue("mode", O(e)), Q.setFieldValue("effectiveAt", M(te(e, Z, X))), G(2), K.reset(), K.mutate({
95
+ productKey: P,
96
+ priceKey: o.key
97
+ }, { onError: (e) => L(e, "Preview affected subscribers") });
98
+ };
99
+ return o.archived || !P || o.customer_amount ? /* @__PURE__ */ w(r, {
100
+ variant: "outline",
101
+ size: "sm",
102
+ disabled: !0,
103
+ title: o.customer_amount ? "This price lets customers choose an amount. Change its limits through a catalog application or the client." : o.archived ? "This is an archived version. Change the current price for this key instead." : "Load the product before changing its price.",
104
+ children: /* @__PURE__ */ w(n, { id: "Change price" })
105
+ }) : /* @__PURE__ */ T(g, {
106
+ open: H,
107
+ onOpenChange: $,
108
+ children: [!F && /* @__PURE__ */ w(h, { render: /* @__PURE__ */ w(r, {
109
+ variant: "outline",
110
+ size: "sm",
111
+ children: /* @__PURE__ */ w(n, { id: "Change price" })
112
+ }) }), /* @__PURE__ */ w(f, {
113
+ className: v,
114
+ children: /* @__PURE__ */ w("form", {
115
+ className: "grid gap-4",
116
+ onSubmit: (e) => {
117
+ e.preventDefault(), e.stopPropagation(), W === 3 && Q.handleSubmit();
118
+ },
119
+ children: /* @__PURE__ */ w(Q.Subscribe, {
120
+ selector: (e) => [e.values, e.isSubmitting],
121
+ children: ([e, t]) => {
122
+ let f = a(e.amountInput, o.currency) ?? o.unit_amount, h = D(f, o.unit_amount), g = k(h, Z, X), v = e.mode !== "migrate" || !!e.effectiveAt && ne(h, new Date(e.effectiveAt), Z, X);
123
+ return /* @__PURE__ */ T(C, { children: [
124
+ /* @__PURE__ */ T(u, { children: [/* @__PURE__ */ T(p, {
125
+ className: "flex items-center gap-2",
126
+ children: [
127
+ /* @__PURE__ */ w(n, { id: "Change price for " }),
128
+ A,
129
+ F && /* @__PURE__ */ w(l, {
130
+ variant: "secondary",
131
+ children: /* @__PURE__ */ w(n, { id: "drafted by copilot" })
132
+ })
133
+ ]
134
+ }), /* @__PURE__ */ T(m, { children: [
135
+ /* @__PURE__ */ w(n, { id: "Step " }),
136
+ W,
137
+ /* @__PURE__ */ w(n, { id: " of 3:" }),
138
+ " ",
139
+ W === 1 ? "new amount" : W === 2 ? "migration plan" : "review"
140
+ ] })] }),
141
+ W === 1 && /* @__PURE__ */ T("div", {
142
+ className: "grid gap-3",
143
+ children: [
144
+ /* @__PURE__ */ T("div", {
145
+ className: "grid grid-cols-2 gap-3 text-sm",
146
+ children: [/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
147
+ className: "text-xs text-muted-foreground uppercase",
148
+ children: /* @__PURE__ */ w(n, { id: "Current amount" })
149
+ }), /* @__PURE__ */ w("p", {
150
+ className: "font-medium",
151
+ children: s(o.unit_amount, o.currency)
152
+ })] }), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
153
+ className: "text-xs text-muted-foreground uppercase",
154
+ children: /* @__PURE__ */ w(n, { id: "Currency · interval" })
155
+ }), /* @__PURE__ */ T("p", {
156
+ className: "font-medium",
157
+ children: [
158
+ o.currency.toUpperCase(),
159
+ " ·",
160
+ " ",
161
+ y(o)
162
+ ]
163
+ })] })]
164
+ }),
165
+ /* @__PURE__ */ w(Q.Field, {
166
+ name: "amountInput",
167
+ validators: { onBlur: ({ value: e }) => {
168
+ let t = a(e, o.currency);
169
+ if (t === null || BigInt(t) <= 0n) return "Enter an amount greater than zero.";
170
+ } },
171
+ children: (e) => /* @__PURE__ */ T("div", {
172
+ className: "grid gap-1.5",
173
+ children: [
174
+ /* @__PURE__ */ w(_, {
175
+ htmlFor: B("wiz-amount"),
176
+ children: /* @__PURE__ */ w(n, { id: "New amount (major units)" })
177
+ }),
178
+ /* @__PURE__ */ w(i, {
179
+ id: B("wiz-amount"),
180
+ type: "number",
181
+ step: "any",
182
+ min: "0",
183
+ value: e.state.value,
184
+ onBlur: e.handleBlur,
185
+ onChange: (t) => e.handleChange(t.target.value),
186
+ autoFocus: !0
187
+ }),
188
+ /* @__PURE__ */ w(c, { errors: e.state.meta.errors })
189
+ ]
190
+ })
191
+ }),
192
+ h !== "unchanged" && /* @__PURE__ */ T("p", {
193
+ className: "text-sm text-muted-foreground",
194
+ children: [
195
+ /* @__PURE__ */ w(n, { id: "This is a price" }),
196
+ " ",
197
+ /* @__PURE__ */ w("span", {
198
+ className: "font-medium text-foreground",
199
+ children: h === "increase" ? "increase" : "decrease"
200
+ }),
201
+ /* @__PURE__ */ w(n, { id: ". Currency and interval stay locked to the current price." })
202
+ ]
203
+ })
204
+ ]
205
+ }),
206
+ W === 2 && /* @__PURE__ */ T("div", {
207
+ className: "grid gap-3",
208
+ children: [
209
+ /* @__PURE__ */ w("p", {
210
+ className: "text-sm",
211
+ children: J === null && K.isPending ? "Checking affected subscribers…" : `${(J ?? 0).toLocaleString()} active subscription${J === 1 ? "" : "s"} on prior versions of ${o.key}.`
212
+ }),
213
+ /* @__PURE__ */ w(Q.Field, {
214
+ name: "mode",
215
+ children: (e) => /* @__PURE__ */ T("div", {
216
+ className: "grid gap-2",
217
+ children: [/* @__PURE__ */ T("label", {
218
+ className: "flex items-start gap-2 rounded-md border p-3 text-sm",
219
+ children: [/* @__PURE__ */ w("input", {
220
+ type: "radio",
221
+ name: e.name,
222
+ className: "mt-1",
223
+ checked: e.state.value === "grandfather",
224
+ onChange: () => e.handleChange("grandfather")
225
+ }), /* @__PURE__ */ T("span", { children: [
226
+ /* @__PURE__ */ w("span", {
227
+ className: "font-medium",
228
+ children: /* @__PURE__ */ w(n, { id: "Grandfather." })
229
+ }),
230
+ " ",
231
+ /* @__PURE__ */ w(n, { id: "Existing subscribers keep the current price." }),
232
+ h === "increase" && /* @__PURE__ */ w(l, {
233
+ variant: "secondary",
234
+ className: "ml-2",
235
+ children: /* @__PURE__ */ w(n, { id: "default" })
236
+ })
237
+ ] })]
238
+ }), /* @__PURE__ */ T("label", {
239
+ className: "flex items-start gap-2 rounded-md border p-3 text-sm",
240
+ children: [/* @__PURE__ */ w("input", {
241
+ type: "radio",
242
+ name: e.name,
243
+ className: "mt-1",
244
+ checked: e.state.value === "migrate",
245
+ onChange: () => e.handleChange("migrate")
246
+ }), /* @__PURE__ */ T("span", { children: [
247
+ /* @__PURE__ */ w("span", {
248
+ className: "font-medium",
249
+ children: /* @__PURE__ */ w(n, { id: "Migrate." })
250
+ }),
251
+ " ",
252
+ /* @__PURE__ */ w(n, { id: "Move everyone to the new price at their first renewal on or after a date you choose." }),
253
+ h === "decrease" && /* @__PURE__ */ w(l, {
254
+ variant: "secondary",
255
+ className: "ml-2",
256
+ children: /* @__PURE__ */ w(n, { id: "default" })
257
+ })
258
+ ] })]
259
+ })]
260
+ })
261
+ }),
262
+ e.mode === "migrate" && /* @__PURE__ */ w(Q.Field, {
263
+ name: "effectiveAt",
264
+ children: (e) => /* @__PURE__ */ T("div", {
265
+ className: "grid gap-1.5",
266
+ children: [
267
+ /* @__PURE__ */ w(_, {
268
+ htmlFor: B("wiz-effective"),
269
+ children: /* @__PURE__ */ w(n, { id: "Effective date" })
270
+ }),
271
+ /* @__PURE__ */ w(i, {
272
+ id: B("wiz-effective"),
273
+ type: "date",
274
+ value: e.state.value,
275
+ min: g ? M(g) : void 0,
276
+ onBlur: e.handleBlur,
277
+ onChange: (t) => e.handleChange(t.target.value)
278
+ }),
279
+ h === "increase" ? /* @__PURE__ */ T("p", {
280
+ className: "text-xs text-muted-foreground",
281
+ children: [
282
+ /* @__PURE__ */ w(n, { id: "Must be at least " }),
283
+ X,
284
+ /* @__PURE__ */ w(n, { id: " days away. Card networks require that much notice before a price goes up. You can change the number in Settings." })
285
+ ]
286
+ }) : /* @__PURE__ */ w("p", {
287
+ className: "text-xs text-muted-foreground",
288
+ children: /* @__PURE__ */ w(n, { id: "A price going down needs no notice, so today is fine." })
289
+ }),
290
+ !v && /* @__PURE__ */ w("p", {
291
+ className: "text-xs text-destructive",
292
+ role: "alert",
293
+ children: /* @__PURE__ */ w(n, { id: "Pick a later date." })
294
+ }),
295
+ /* @__PURE__ */ w("p", {
296
+ className: "text-xs text-muted-foreground",
297
+ children: /* @__PURE__ */ w(n, { id: "A reprice_scheduled notice is queued for every affected subscriber as soon as you confirm." })
298
+ })
299
+ ]
300
+ })
301
+ })
302
+ ]
303
+ }),
304
+ W === 3 && /* @__PURE__ */ w("div", {
305
+ className: "grid gap-3",
306
+ children: /* @__PURE__ */ w("p", {
307
+ className: "rounded-md border bg-muted/40 p-3 text-sm",
308
+ children: j({
309
+ newAmount: f,
310
+ currentAmount: o.unit_amount,
311
+ currency: o.currency,
312
+ affectedCount: J ?? 0,
313
+ plan: {
314
+ mode: e.mode,
315
+ effectiveAt: e.mode === "migrate" ? new Date(e.effectiveAt).toISOString() : ""
316
+ },
317
+ now: Z
318
+ })
319
+ })
320
+ }),
321
+ /* @__PURE__ */ T(d, { children: [
322
+ W > 1 && /* @__PURE__ */ w(r, {
323
+ type: "button",
324
+ variant: "outline",
325
+ disabled: t,
326
+ onClick: () => G((e) => e - 1),
327
+ children: /* @__PURE__ */ w(n, { id: "Back" })
328
+ }),
329
+ W === 1 && /* @__PURE__ */ w(r, {
330
+ type: "button",
331
+ disabled: !e.amountInput || h === "unchanged" || BigInt(f) <= 0n,
332
+ onClick: ae,
333
+ children: /* @__PURE__ */ w(n, { id: "Next" })
334
+ }),
335
+ W === 2 && /* @__PURE__ */ w(r, {
336
+ type: "button",
337
+ disabled: !v || K.isPending,
338
+ onClick: () => G(3),
339
+ children: /* @__PURE__ */ w(n, { id: "Next" })
340
+ }),
341
+ W === 3 && /* @__PURE__ */ w(r, {
342
+ type: "submit",
343
+ disabled: t,
344
+ children: t ? "Working…" : "Confirm"
345
+ })
346
+ ] })
347
+ ] });
348
+ }
349
+ })
350
+ })
351
+ })]
352
+ });
353
+ }
354
+ //#endregion
355
+ export { P as t };
356
+
357
+ //# sourceMappingURL=admin-price-wizard-CI7K-2Nz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-price-wizard-CI7K-2Nz.js","names":[],"sources":["../src/admin/pages/catalog/price-wizard-logic.ts","../src/admin/pages/catalog/price-wizard.tsx"],"sourcesContent":["// Pure logic for the price-change wizard, kept apart from React for unit tests.\nimport { formatNativeAmount } from \"#orck/admin/lib/format\"\n\nexport type PriceDirection = \"increase\" | \"decrease\" | \"unchanged\"\n\nexport function detectDirection(\n newAmount: string,\n currentAmount: string\n): PriceDirection {\n const next = BigInt(newAmount)\n const current = BigInt(currentAmount)\n if (next > current) return \"increase\"\n if (next < current) return \"decrease\"\n return \"unchanged\"\n}\n\nexport type MigrationMode = \"grandfather\" | \"migrate\"\n\n// DEFAULT_NOTICE_WINDOW_DAYS is the fallback until the merchant's\n// reprice_notice_window_days loads; it mirrors\n// subscriptions.DefaultPriceIncreaseNoticeDays so the UI never under-gates.\n// The server enforces the window too (price_increase_notice_too_short).\nexport const DEFAULT_NOTICE_WINDOW_DAYS = 30\n\n// defaultMigrationMode is the direction-aware Step 2 default: an increase\n// grandfathers (no new action), a decrease migrates now (never grandfathered).\nexport function defaultMigrationMode(direction: PriceDirection): MigrationMode {\n return direction === \"decrease\" ? \"migrate\" : \"grandfather\"\n}\n\n// minEffectiveDate is the earliest allowed migration date, or null when there\n// is no minimum (a decrease needs no notice).\nexport function minEffectiveDate(\n direction: PriceDirection,\n now: Date,\n noticeWindowDays: number\n): Date | null {\n if (direction !== \"increase\") return null\n const min = new Date(now)\n min.setUTCDate(min.getUTCDate() + noticeWindowDays)\n return min\n}\n\n// defaultEffectiveDate is Step 2's pre-filled migration date: the notice\n// window's floor for an increase, \"now\" for a decrease.\nexport function defaultEffectiveDate(\n direction: PriceDirection,\n now: Date,\n noticeWindowDays: number\n): Date {\n return minEffectiveDate(direction, now, noticeWindowDays) ?? now\n}\n\n// isEffectiveDateValid enforces the console-side notice-window gate: an\n// increase+migrate plan may not pick a date inside the notice window.\nexport function isEffectiveDateValid(\n direction: PriceDirection,\n effectiveAt: Date,\n now: Date,\n noticeWindowDays: number\n): boolean {\n const min = minEffectiveDate(direction, now, noticeWindowDays)\n return !min || effectiveAt.getTime() >= min.getTime()\n}\n\nexport interface MigrationPlan {\n mode: MigrationMode\n // ISO instant; only meaningful when mode === \"migrate\".\n effectiveAt: string\n}\n\nconst dateLabel = (iso: string) =>\n new Date(iso).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n })\n\n// buildReviewText renders Step 3's plan in words, e.g. \"New subscribers pay $12\n// immediately. 1,204 existing subscribers keep $10 until Sep 1, then move to\n// $12 at their next renewal. Notices go out on confirm.\"\nexport function buildReviewText(params: {\n newAmount: string\n currentAmount: string\n currency: string\n affectedCount: number\n plan: MigrationPlan\n now: Date\n}): string {\n const { newAmount, currentAmount, currency, affectedCount, plan, now } =\n params\n const newLabel = formatNativeAmount(newAmount, currency)\n const oldLabel = formatNativeAmount(currentAmount, currency)\n const lead = `New subscribers pay ${newLabel} immediately.`\n\n if (affectedCount === 0) {\n return `${lead} No existing subscribers are on a prior version of this price.`\n }\n const subj = `${affectedCount.toLocaleString()} existing subscriber${affectedCount === 1 ? \"\" : \"s\"}`\n\n if (plan.mode === \"grandfather\") {\n return `${lead} ${subj} keep ${oldLabel} forever (grandfathered).`\n }\n\n // The engine notifies each affected subscriber at schedule time, however\n // far out effective_at is: always say so.\n const effective = new Date(plan.effectiveAt)\n const immediate = effective.getTime() <= now.getTime()\n if (immediate) {\n return `${lead} ${subj} move to ${newLabel} at their next renewal. Notices go out on confirm.`\n }\n return `${lead} ${subj} keep ${oldLabel} until ${dateLabel(plan.effectiveAt)}, then move to ${newLabel} at their next renewal. Notices go out on confirm.`\n}\n","import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport * as React from \"react\"\n\nimport { useForm } from \"@tanstack/react-form\"\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\"\n\nimport { FormFieldErrors } from \"#orck/admin/components/form-field-errors\"\nimport { Badge } from \"#orck/admin/components/ui/badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"#orck/admin/components/ui/dialog\"\nimport { Input } from \"#orck/admin/components/ui/input\"\nimport { Label } from \"#orck/admin/components/ui/label\"\nimport type { PriceChangeDraft } from \"#orck/admin/lib/api/copilot\"\nimport { DIALOG_FORM } from \"#orck/admin/lib/dialog-width\"\nimport type { Price } from \"#orck/client/generated/wire\"\nimport {\n formatNativeAmount,\n nativeAmountFromInput,\n nativeAmountToInput,\n} from \"#orck/admin/lib/format\"\n\nimport { priceIntervalLabel } from \"#orck/admin/pages/catalog/price-format\"\nimport {\n buildReviewText,\n defaultEffectiveDate,\n defaultMigrationMode,\n DEFAULT_NOTICE_WINDOW_DAYS,\n detectDirection,\n isEffectiveDateValid,\n minEffectiveDate,\n type MigrationMode,\n} from \"#orck/admin/pages/catalog/price-wizard-logic\"\n\nconst toDateInputValue = (d: Date) => d.toISOString().slice(0, 10)\n\nconst priceChangeFormValues = (price: Price, draft?: PriceChangeDraft) => ({\n amountInput: nativeAmountToInput(\n draft?.new_amount ?? price.unit_amount,\n price.currency\n ),\n mode: (draft?.migration ? \"migrate\" : \"grandfather\") as MigrationMode,\n effectiveAt: draft?.migration?.effective_at\n ? toDateInputValue(new Date(draft.migration.effective_at))\n : \"\",\n})\n\n// PriceChangeWizard is the #777 console price-change wizard — the ONLY\n// amount-edit affordance on a price. Three steps: new amount -> migration\n// plan (direction-aware defaults, live affected-count preview, notice-window\n// gate on increase+migrate) -> review in words, then confirm applies the\n// catalog price update followed (if migrating) by the price migration.\n//\n// draft (#779): when the catalog copilot proposed this change, the dialog\n// opens PRE-FILLED straight at Step 3 (review) — the affected count already\n// rode in the draft, so no extra preview call is needed. Confirm behaves\n// EXACTLY as a hand-typed change (the same create-price and price-migration\n// calls).\nexport function PriceChangeWizard({\n price,\n productName,\n productKey,\n draft,\n onDone,\n}: {\n price: Price\n productName: string\n productKey: string | undefined\n draft?: PriceChangeDraft\n onDone?: () => void\n}) {\n const { toast, toastApiError, adminMutations, adminQueries } =\n useAdminServices()\n\n const { id: adminId } = useAdminUI()\n\n const queryClient = useQueryClient()\n const [open, setOpen] = React.useState(() => !!draft)\n const [step, setStep] = React.useState<1 | 2 | 3>(() => (draft ? 3 : 1))\n const previewPriceChange = useMutation(adminMutations.previewPriceChange())\n const changePrice = useMutation(adminMutations.changePrice(queryClient))\n const affectedCount =\n previewPriceChange.data?.matched ?? draft?.affected_count ?? null\n const { data: configuration } = useQuery({\n ...adminQueries.merchantConfiguration(),\n enabled: open,\n })\n const noticeWindowDays =\n configuration?.settings.reprice_notice_window_days ??\n DEFAULT_NOTICE_WINDOW_DAYS\n\n const [now] = React.useState(() => new Date())\n const form = useForm({\n defaultValues: priceChangeFormValues(price, draft),\n onSubmit: async ({ value }) => {\n if (!productKey || price.customer_amount) return\n const newAmount = nativeAmountFromInput(value.amountInput, price.currency)\n if (newAmount === null || BigInt(newAmount) <= 0n) return\n\n try {\n const created = await changePrice.mutateAsync({\n price: {\n product_id: price.product_id,\n unit_amount: newAmount,\n currency: price.currency,\n access_duration_hours: price.access_duration_hours ?? undefined,\n billing_interval_hours: price.billing_interval_hours ?? undefined,\n trial_unit_amount: price.trial_unit_amount ?? undefined,\n trial_duration_hours: price.trial_duration_hours ?? undefined,\n key: price.key,\n psps: Object.keys(price.psps ?? {}),\n expected_revision: price.revision,\n },\n migration:\n value.mode === \"migrate\"\n ? {\n productKey,\n priceKey: price.key,\n effectiveAt: new Date(value.effectiveAt).toISOString(),\n }\n : undefined,\n })\n if (created.pending_manual_actions?.length) {\n toast.warning(\n `Price updated. One step is left for you: ${created.pending_manual_actions.map((action) => `${action.psp}: ${action.hint}`).join(\". \")}`\n )\n } else {\n toast.success(\n value.mode === \"migrate\"\n ? \"Price updated and migration scheduled\"\n : \"Price updated\"\n )\n }\n handleOpenChange(false)\n onDone?.()\n } catch (err) {\n toastApiError(err, \"Change price\")\n }\n },\n })\n\n const reset = () => {\n setStep(1)\n form.reset(priceChangeFormValues(price))\n previewPriceChange.reset()\n }\n\n const handleOpenChange = (next: boolean) => {\n if (!next) {\n reset()\n }\n setOpen(next)\n }\n\n const enterStep2 = () => {\n if (!productKey || price.customer_amount) return\n const amount = nativeAmountFromInput(\n form.state.values.amountInput,\n price.currency\n )\n const direction = detectDirection(\n amount ?? price.unit_amount,\n price.unit_amount\n )\n form.setFieldValue(\"mode\", defaultMigrationMode(direction))\n form.setFieldValue(\n \"effectiveAt\",\n toDateInputValue(defaultEffectiveDate(direction, now, noticeWindowDays))\n )\n setStep(2)\n previewPriceChange.reset()\n previewPriceChange.mutate(\n { productKey, priceKey: price.key },\n { onError: (err) => toastApiError(err, \"Preview affected subscribers\") }\n )\n }\n\n // Archived (prior-version) rows are history, not the editable current\n // price. Each product/key pair has exactly one live edit target.\n // Wait for the product before allowing previews or scheduling a migration.\n if (price.archived || !productKey || price.customer_amount) {\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled\n title={\n price.customer_amount\n ? \"This price lets customers choose an amount. Change its limits through a catalog application or the client.\"\n : price.archived\n ? \"This is an archived version. Change the current price for this key instead.\"\n : \"Load the product before changing its price.\"\n }\n >\n <AdminMessage id={\"Change price\"} />\n </Button>\n )\n }\n\n return (\n <Dialog open={open} onOpenChange={handleOpenChange}>\n {!draft && (\n <DialogTrigger\n render={\n <Button variant=\"outline\" size=\"sm\">\n <AdminMessage id={\"Change price\"} />\n </Button>\n }\n />\n )}\n <DialogContent className={DIALOG_FORM}>\n <form\n className=\"grid gap-4\"\n onSubmit={(event) => {\n event.preventDefault()\n event.stopPropagation()\n if (step !== 3) return\n void form.handleSubmit()\n }}\n >\n <form.Subscribe\n selector={(state) => [state.values, state.isSubmitting] as const}\n >\n {([values, isSubmitting]) => {\n const newAmount =\n nativeAmountFromInput(values.amountInput, price.currency) ??\n price.unit_amount\n const direction = detectDirection(newAmount, price.unit_amount)\n const minDate = minEffectiveDate(direction, now, noticeWindowDays)\n const dateValid =\n values.mode !== \"migrate\" ||\n (!!values.effectiveAt &&\n isEffectiveDateValid(\n direction,\n new Date(values.effectiveAt),\n now,\n noticeWindowDays\n ))\n\n return (\n <>\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <AdminMessage id={\"Change price for \"} />\n {productName}\n {draft && (\n <Badge variant=\"secondary\">\n <AdminMessage id={\"drafted by copilot\"} />\n </Badge>\n )}\n </DialogTitle>\n <DialogDescription>\n <AdminMessage id={\"Step \"} />\n {step}\n <AdminMessage id={\" of 3:\"} />{\" \"}\n {step === 1\n ? \"new amount\"\n : step === 2\n ? \"migration plan\"\n : \"review\"}\n </DialogDescription>\n </DialogHeader>\n\n {step === 1 && (\n <div className=\"grid gap-3\">\n <div className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <p className=\"text-xs text-muted-foreground uppercase\">\n <AdminMessage id={\"Current amount\"} />\n </p>\n <p className=\"font-medium\">\n {formatNativeAmount(\n price.unit_amount,\n price.currency\n )}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground uppercase\">\n <AdminMessage id={\"Currency · interval\"} />\n </p>\n <p className=\"font-medium\">\n {price.currency.toUpperCase()} ·{\" \"}\n {priceIntervalLabel(price)}\n </p>\n </div>\n </div>\n <form.Field\n name=\"amountInput\"\n validators={{\n onBlur: ({ value }) => {\n const amount = nativeAmountFromInput(\n value,\n price.currency\n )\n if (amount === null || BigInt(amount) <= 0n) {\n return \"Enter an amount greater than zero.\"\n }\n return undefined\n },\n }}\n >\n {(field) => (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={adminId(\"wiz-amount\")}>\n <AdminMessage id={\"New amount (major units)\"} />\n </Label>\n <Input\n id={adminId(\"wiz-amount\")}\n type=\"number\"\n step=\"any\"\n min=\"0\"\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(event) =>\n field.handleChange(event.target.value)\n }\n autoFocus\n />\n <FormFieldErrors errors={field.state.meta.errors} />\n </div>\n )}\n </form.Field>\n {direction !== \"unchanged\" && (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"This is a price\"} />{\" \"}\n <span className=\"font-medium text-foreground\">\n {direction === \"increase\" ? \"increase\" : \"decrease\"}\n </span>\n <AdminMessage\n id={\n \". Currency and interval stay locked to the current price.\"\n }\n />\n </p>\n )}\n </div>\n )}\n\n {step === 2 && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm\">\n {affectedCount === null && previewPriceChange.isPending\n ? \"Checking affected subscribers…\"\n : `${(affectedCount ?? 0).toLocaleString()} active subscription${affectedCount === 1 ? \"\" : \"s\"} on prior versions of ${price.key}.`}\n </p>\n <form.Field name=\"mode\">\n {(field) => (\n <div className=\"grid gap-2\">\n <label className=\"flex items-start gap-2 rounded-md border p-3 text-sm\">\n <input\n type=\"radio\"\n name={field.name}\n className=\"mt-1\"\n checked={field.state.value === \"grandfather\"}\n onChange={() =>\n field.handleChange(\"grandfather\")\n }\n />\n <span>\n <span className=\"font-medium\">\n <AdminMessage id={\"Grandfather.\"} />\n </span>{\" \"}\n <AdminMessage\n id={\n \"Existing subscribers keep the current price.\"\n }\n />\n {direction === \"increase\" && (\n <Badge variant=\"secondary\" className=\"ml-2\">\n <AdminMessage id={\"default\"} />\n </Badge>\n )}\n </span>\n </label>\n <label className=\"flex items-start gap-2 rounded-md border p-3 text-sm\">\n <input\n type=\"radio\"\n name={field.name}\n className=\"mt-1\"\n checked={field.state.value === \"migrate\"}\n onChange={() => field.handleChange(\"migrate\")}\n />\n <span>\n <span className=\"font-medium\">\n <AdminMessage id={\"Migrate.\"} />\n </span>{\" \"}\n <AdminMessage\n id={\n \"Move everyone to the new price at their first renewal on or after a date you choose.\"\n }\n />\n {direction === \"decrease\" && (\n <Badge variant=\"secondary\" className=\"ml-2\">\n <AdminMessage id={\"default\"} />\n </Badge>\n )}\n </span>\n </label>\n </div>\n )}\n </form.Field>\n {values.mode === \"migrate\" && (\n <form.Field name=\"effectiveAt\">\n {(field) => (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={adminId(\"wiz-effective\")}>\n <AdminMessage id={\"Effective date\"} />\n </Label>\n <Input\n id={adminId(\"wiz-effective\")}\n type=\"date\"\n value={field.state.value}\n min={\n minDate\n ? toDateInputValue(minDate)\n : undefined\n }\n onBlur={field.handleBlur}\n onChange={(event) =>\n field.handleChange(event.target.value)\n }\n />\n {direction === \"increase\" ? (\n <p className=\"text-xs text-muted-foreground\">\n <AdminMessage id={\"Must be at least \"} />\n {noticeWindowDays}\n <AdminMessage\n id={\n \" days away. Card networks require that much notice before a price goes up. You can change the number in Settings.\"\n }\n />\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n <AdminMessage\n id={\n \"A price going down needs no notice, so today is fine.\"\n }\n />\n </p>\n )}\n {!dateValid && (\n <p\n className=\"text-xs text-destructive\"\n role=\"alert\"\n >\n <AdminMessage id={\"Pick a later date.\"} />\n </p>\n )}\n <p className=\"text-xs text-muted-foreground\">\n <AdminMessage\n id={\n \"A reprice_scheduled notice is queued for every affected subscriber as soon as you confirm.\"\n }\n />\n </p>\n </div>\n )}\n </form.Field>\n )}\n </div>\n )}\n\n {step === 3 && (\n <div className=\"grid gap-3\">\n <p className=\"rounded-md border bg-muted/40 p-3 text-sm\">\n {buildReviewText({\n newAmount,\n currentAmount: price.unit_amount,\n currency: price.currency,\n affectedCount: affectedCount ?? 0,\n plan: {\n mode: values.mode,\n effectiveAt:\n values.mode === \"migrate\"\n ? new Date(values.effectiveAt).toISOString()\n : \"\",\n },\n now,\n })}\n </p>\n </div>\n )}\n\n <DialogFooter>\n {step > 1 && (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={isSubmitting}\n onClick={() => setStep((value) => (value - 1) as 1 | 2)}\n >\n <AdminMessage id={\"Back\"} />\n </Button>\n )}\n {step === 1 && (\n <Button\n type=\"button\"\n disabled={\n !values.amountInput ||\n direction === \"unchanged\" ||\n BigInt(newAmount) <= 0n\n }\n onClick={enterStep2}\n >\n <AdminMessage id={\"Next\"} />\n </Button>\n )}\n {step === 2 && (\n <Button\n type=\"button\"\n disabled={!dateValid || previewPriceChange.isPending}\n onClick={() => setStep(3)}\n >\n <AdminMessage id={\"Next\"} />\n </Button>\n )}\n {step === 3 && (\n <Button type=\"submit\" disabled={isSubmitting}>\n {isSubmitting ? \"Working…\" : \"Confirm\"}\n </Button>\n )}\n </DialogFooter>\n </>\n )\n }}\n </form.Subscribe>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,192 @@
1
+ import { E as e, l as t, w as n } from "./admin-utils-BK4Vh1o_.js";
2
+ import { t as r } from "./admin-button-CTL3DgOt.js";
3
+ import { t as i } from "./admin-input-CcfQfJFN.js";
4
+ import { a, i as o, n as s, r as c, t as l } from "./admin-select-DBgprVW6.js";
5
+ import { useRef as u } from "react";
6
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ //#region src/admin/pages/dashboard/range.ts
8
+ var p = [
9
+ {
10
+ value: "7d",
11
+ label: "Last 7 days"
12
+ },
13
+ {
14
+ value: "30d",
15
+ label: "Last 30 days"
16
+ },
17
+ {
18
+ value: "90d",
19
+ label: "Last 3 months"
20
+ },
21
+ {
22
+ value: "6m",
23
+ label: "Last 6 months"
24
+ },
25
+ {
26
+ value: "1y",
27
+ label: "Last year"
28
+ }
29
+ ], m = /^\d{4}-\d{2}-\d{2}$/, h = (e) => !!e && m.test(e) && !Number.isNaN(Date.parse(`${e}T00:00:00Z`));
30
+ function g(e) {
31
+ let t = e.get("from"), n = e.get("to");
32
+ if (h(t) && h(n)) return t <= n ? {
33
+ from: t,
34
+ to: n
35
+ } : {
36
+ from: n,
37
+ to: t
38
+ };
39
+ let r = e.get("range");
40
+ return { preset: p.some((e) => e.value === r) ? r : "30d" };
41
+ }
42
+ function _(e, t) {
43
+ let n = new URLSearchParams(e);
44
+ return n.delete("range"), n.delete("from"), n.delete("to"), "from" in t ? (n.set("from", t.from), n.set("to", t.to)) : t.preset !== "30d" && n.set("range", t.preset), n;
45
+ }
46
+ function v(e) {
47
+ return "from" in e ? {
48
+ from: e.from,
49
+ to: e.to
50
+ } : { last: e.preset };
51
+ }
52
+ var y = 864e5, b = (e) => e.toISOString().slice(0, 10);
53
+ function x(e, t = /* @__PURE__ */ new Date()) {
54
+ if ("from" in e) return e;
55
+ let [, n, r] = /^(\d+)([dwmy])$/.exec(e.preset) ?? [
56
+ "",
57
+ "30",
58
+ "d"
59
+ ], i = Number(n), a = new Date(Date.UTC(t.getUTCFullYear(), t.getUTCMonth(), t.getUTCDate() + 1));
60
+ return r === "d" && a.setUTCDate(a.getUTCDate() - i), r === "w" && a.setUTCDate(a.getUTCDate() - 7 * i), r === "m" && a.setUTCMonth(a.getUTCMonth() - i), r === "y" && a.setUTCFullYear(a.getUTCFullYear() - i), {
61
+ from: b(a),
62
+ to: b(t)
63
+ };
64
+ }
65
+ function S(e, t = /* @__PURE__ */ new Date()) {
66
+ let { from: n, to: r } = x(e, t), i = (e) => (/* @__PURE__ */ new Date(`${e}T00:00:00Z`)).toLocaleDateString(void 0, {
67
+ month: "short",
68
+ day: "numeric",
69
+ year: e.slice(0, 4) === b(t).slice(0, 4) ? void 0 : "numeric",
70
+ timeZone: "UTC"
71
+ });
72
+ return n === r ? i(n) : `${i(n)} – ${i(r)}`;
73
+ }
74
+ var C = [
75
+ "day",
76
+ "week",
77
+ "month",
78
+ "quarter",
79
+ "year"
80
+ ], w = {
81
+ day: 1,
82
+ week: 7,
83
+ month: 28,
84
+ quarter: 89,
85
+ year: 365
86
+ };
87
+ function T(e, t, n = /* @__PURE__ */ new Date()) {
88
+ let { from: r, to: i } = x(t, n), a = (Date.parse(i) - Date.parse(r)) / y + 1, o = Math.max(C.indexOf(e), 0);
89
+ for (; o < C.length - 1 && a / w[C[o]] > 398;) o++;
90
+ return C[o];
91
+ }
92
+ function E(e, t) {
93
+ if (e.fixed_range) return e.query;
94
+ let n = {
95
+ ...e.query,
96
+ range: v(t)
97
+ };
98
+ return n.grain &&= T(n.grain, t), n;
99
+ }
100
+ //#endregion
101
+ //#region src/admin/pages/dashboard/use-range.ts
102
+ function D() {
103
+ let [e, n] = t();
104
+ return [g(e), (t) => n(_(e, t), { replace: !0 })];
105
+ }
106
+ //#endregion
107
+ //#region src/admin/pages/dashboard/range-picker.tsx
108
+ var O = "custom";
109
+ function k() {
110
+ let { text: t } = e(), [m, h] = D(), g = u(null), _ = u(null), v = "from" in m, y = [...p.map((e) => ({
111
+ value: e.value,
112
+ label: e.label
113
+ })), {
114
+ value: O,
115
+ label: "Custom range"
116
+ }];
117
+ return /* @__PURE__ */ f("div", {
118
+ className: "flex flex-wrap items-center gap-2",
119
+ children: [
120
+ /* @__PURE__ */ d("span", {
121
+ className: "hidden text-sm text-muted-foreground tabular-nums sm:inline",
122
+ "aria-live": "polite",
123
+ children: S(m)
124
+ }),
125
+ /* @__PURE__ */ f(l, {
126
+ items: y,
127
+ value: v ? O : m.preset,
128
+ onValueChange: (e) => {
129
+ e && h(e === O ? x(m) : { preset: e });
130
+ },
131
+ children: [/* @__PURE__ */ d(o, {
132
+ size: "sm",
133
+ className: "w-[150px]",
134
+ "aria-label": t("Date range"),
135
+ children: /* @__PURE__ */ d(a, {})
136
+ }), /* @__PURE__ */ d(s, { children: y.map((e) => /* @__PURE__ */ d(c, {
137
+ value: e.value,
138
+ children: e.label
139
+ }, e.value)) })]
140
+ }),
141
+ v && /* @__PURE__ */ f("div", {
142
+ className: "contents",
143
+ children: [
144
+ /* @__PURE__ */ f("label", {
145
+ className: "flex items-center gap-1.5 text-xs font-medium",
146
+ children: [/* @__PURE__ */ d(n, { id: "Start" }), /* @__PURE__ */ d(i, {
147
+ ref: g,
148
+ type: "date",
149
+ className: "h-8 w-auto",
150
+ defaultValue: m.from,
151
+ max: m.to,
152
+ onChange: (e) => {
153
+ let t = e.target.value, n = _.current?.value || m.to;
154
+ t && h({
155
+ from: t,
156
+ to: t > n ? t : n
157
+ });
158
+ }
159
+ })]
160
+ }),
161
+ /* @__PURE__ */ f("label", {
162
+ className: "flex items-center gap-1.5 text-xs font-medium",
163
+ children: [/* @__PURE__ */ d(n, { id: "End" }), /* @__PURE__ */ d(i, {
164
+ ref: _,
165
+ type: "date",
166
+ className: "h-8 w-auto",
167
+ defaultValue: m.to,
168
+ min: m.from,
169
+ onChange: (e) => {
170
+ let t = e.target.value, n = g.current?.value || m.from;
171
+ t && h({
172
+ from: t < n ? t : n,
173
+ to: t
174
+ });
175
+ }
176
+ })]
177
+ }),
178
+ /* @__PURE__ */ d(r, {
179
+ variant: "ghost",
180
+ size: "sm",
181
+ onClick: () => h({ preset: "30d" }),
182
+ children: /* @__PURE__ */ d(n, { id: "Reset" })
183
+ })
184
+ ]
185
+ }, `${m.from}/${m.to}`)
186
+ ]
187
+ });
188
+ }
189
+ //#endregion
190
+ export { E as a, x as i, D as n, v as r, k as t };
191
+
192
+ //# sourceMappingURL=admin-range-picker-Dr2M1EZr.js.map