@burdenoff/microfe-billing 2026.903.1 → 2026.904.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/BillingAdminRoutes.js +81 -68
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useRefunds.js +89 -67
- package/dist/billing/modules/billing/hooks/useRefunds.js.map +1 -1
- package/dist/billing/modules/billing/index.js +2 -1
- package/dist/billing/modules/billing/pages/BillingWebhookLogsPage.js +358 -0
- package/dist/billing/modules/billing/pages/BillingWebhookLogsPage.js.map +1 -0
- package/dist/billing/modules/billing/pages/index.js +1 -0
- package/dist/billing/modules/checkout/hooks/useCheckout.js +49 -47
- package/dist/billing/modules/checkout/hooks/useCheckout.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +5 -3
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/generated/global-operations.js +367 -338
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { AccessDenied as e } from "../../../shared/components/AccessDenied.js";
|
|
2
|
+
import { PageHeader as t } from "../../../shared/components/PageHeader.js";
|
|
3
|
+
import { statusTokens as n } from "../../../shared/utils/tokens.js";
|
|
4
|
+
import { ServerError as r } from "../../../shared/components/ServerError.js";
|
|
5
|
+
import "../../../shared/components/index.js";
|
|
6
|
+
import { formatDateTime as i } from "../../../shared/utils/format.js";
|
|
7
|
+
import { isServerError as a } from "../../../shared/utils/error.js";
|
|
8
|
+
import "../../../shared/utils/index.js";
|
|
9
|
+
import { useBillingPermissions as o } from "../../../hooks/useBillingPermissions.js";
|
|
10
|
+
import { useBillingWebhookLogs as s, useRefundMutations as c } from "../hooks/useRefunds.js";
|
|
11
|
+
import "../hooks/index.js";
|
|
12
|
+
import { useState as l } from "react";
|
|
13
|
+
import { AlertTriangle as u, CheckCircle as d, ChevronLeft as f, ChevronRight as p, DollarSign as m, Eye as h, Loader2 as g, RefreshCw as _, X as v } from "lucide-react";
|
|
14
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
15
|
+
import { IllustratedEmptyState as x, ResponsiveTable as S } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
//#region src/billing/modules/billing/pages/BillingWebhookLogsPage.tsx
|
|
17
|
+
var C = 25, w = ["stripe", "razorpay"], T = (e) => e.processed ? {
|
|
18
|
+
label: "Processed",
|
|
19
|
+
className: `${n.success.bg} ${n.success.text}`,
|
|
20
|
+
icon: d
|
|
21
|
+
} : {
|
|
22
|
+
label: e.error ? "Failed" : "Pending",
|
|
23
|
+
className: `${n.error.bg} ${n.error.text}`,
|
|
24
|
+
icon: u
|
|
25
|
+
}, E = ({ log: e, onClose: t, onCreateRefund: n, isCreatingRefund: r }) => e ? /* @__PURE__ */ y("div", {
|
|
26
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
27
|
+
children: /* @__PURE__ */ b("div", {
|
|
28
|
+
className: "w-full max-w-2xl max-h-[85vh] overflow-y-auto rounded-lg bg-bg-surface border border-border-subtle shadow-[var(--shadow-elevation-2)]",
|
|
29
|
+
children: [/* @__PURE__ */ b("div", {
|
|
30
|
+
className: "flex items-center justify-between p-4 border-b border-border-subtle",
|
|
31
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
32
|
+
className: "text-base font-semibold text-text-primary",
|
|
33
|
+
children: "Webhook log details"
|
|
34
|
+
}), /* @__PURE__ */ y("button", {
|
|
35
|
+
type: "button",
|
|
36
|
+
onClick: t,
|
|
37
|
+
className: "p-1 rounded text-text-muted hover:text-text-primary hover:bg-bg-sunken/50",
|
|
38
|
+
children: /* @__PURE__ */ y(v, { className: "size-4" })
|
|
39
|
+
})]
|
|
40
|
+
}), /* @__PURE__ */ b("div", {
|
|
41
|
+
className: "p-4 space-y-4",
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ b("div", {
|
|
44
|
+
className: "grid grid-cols-2 gap-4 text-sm",
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
47
|
+
className: "text-text-muted",
|
|
48
|
+
children: "Provider"
|
|
49
|
+
}), /* @__PURE__ */ y("p", {
|
|
50
|
+
className: "text-text-primary capitalize",
|
|
51
|
+
children: e.provider
|
|
52
|
+
})] }),
|
|
53
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
54
|
+
className: "text-text-muted",
|
|
55
|
+
children: "Event"
|
|
56
|
+
}), /* @__PURE__ */ y("p", {
|
|
57
|
+
className: "text-text-primary font-mono text-xs",
|
|
58
|
+
children: e.event
|
|
59
|
+
})] }),
|
|
60
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
61
|
+
className: "text-text-muted",
|
|
62
|
+
children: "Received"
|
|
63
|
+
}), /* @__PURE__ */ y("p", {
|
|
64
|
+
className: "text-text-primary",
|
|
65
|
+
children: i(e.createdAt)
|
|
66
|
+
})] }),
|
|
67
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
68
|
+
className: "text-text-muted",
|
|
69
|
+
children: "Processed"
|
|
70
|
+
}), /* @__PURE__ */ y("p", {
|
|
71
|
+
className: "text-text-primary",
|
|
72
|
+
children: e.processed ? "Yes" : "No"
|
|
73
|
+
})] })
|
|
74
|
+
]
|
|
75
|
+
}),
|
|
76
|
+
e.error && /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
77
|
+
className: "text-sm text-text-muted mb-1",
|
|
78
|
+
children: "Error"
|
|
79
|
+
}), /* @__PURE__ */ y("pre", {
|
|
80
|
+
className: "text-xs whitespace-pre-wrap p-3 rounded-md bg-status-error-bg-subtle text-status-error-text border border-status-error-border",
|
|
81
|
+
children: e.error
|
|
82
|
+
})] }),
|
|
83
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
84
|
+
className: "text-sm text-text-muted mb-1",
|
|
85
|
+
children: "Payload"
|
|
86
|
+
}), /* @__PURE__ */ y("pre", {
|
|
87
|
+
className: "text-xs whitespace-pre-wrap p-3 rounded-md bg-bg-sunken/60 text-text-secondary max-h-64 overflow-y-auto",
|
|
88
|
+
children: JSON.stringify(e.payload, null, 2)
|
|
89
|
+
})] }),
|
|
90
|
+
!e.processed && /* @__PURE__ */ b("button", {
|
|
91
|
+
type: "button",
|
|
92
|
+
onClick: () => n(e.id),
|
|
93
|
+
disabled: r,
|
|
94
|
+
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50",
|
|
95
|
+
children: [r ? /* @__PURE__ */ y(g, { className: "size-4 animate-spin" }) : /* @__PURE__ */ y(m, { className: "size-4" }), "Create refund from this webhook"]
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
})]
|
|
99
|
+
})
|
|
100
|
+
}) : null, D = () => {
|
|
101
|
+
let n = o(), [u, d] = l(0), [m, g] = l({}), [v, D] = l(null), { logs: O, totalCount: k, isLoading: A, error: j, refetch: M } = s(m, u, C), { createRefundRecordFromWebhook: N, isCreatingFromWebhook: P } = c();
|
|
102
|
+
if (!n.isBillingAdmin) return /* @__PURE__ */ y(e, { message: "You don't have permission to view billing webhook logs." });
|
|
103
|
+
if (j && a(j)) return /* @__PURE__ */ y("div", {
|
|
104
|
+
className: "p-6",
|
|
105
|
+
children: /* @__PURE__ */ y(r, {
|
|
106
|
+
title: "Server Unavailable",
|
|
107
|
+
message: "Unable to load webhook logs. The server might be down or experiencing issues.",
|
|
108
|
+
onRetry: () => M(),
|
|
109
|
+
showRetry: !0
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
let F = (e, t) => {
|
|
113
|
+
g((n) => ({
|
|
114
|
+
...n,
|
|
115
|
+
[e]: t
|
|
116
|
+
})), d(0);
|
|
117
|
+
}, I = async (e) => {
|
|
118
|
+
await N(e), D(null);
|
|
119
|
+
}, L = [
|
|
120
|
+
{
|
|
121
|
+
key: "date",
|
|
122
|
+
header: "Received",
|
|
123
|
+
priority: "primary",
|
|
124
|
+
cellClassName: "whitespace-nowrap",
|
|
125
|
+
cell: (e) => /* @__PURE__ */ b("div", {
|
|
126
|
+
className: "flex flex-col",
|
|
127
|
+
children: [/* @__PURE__ */ y("span", {
|
|
128
|
+
className: "text-sm text-text-primary",
|
|
129
|
+
children: i(e.createdAt).split(" ")[0]
|
|
130
|
+
}), /* @__PURE__ */ y("span", {
|
|
131
|
+
className: "text-xs text-text-muted",
|
|
132
|
+
children: i(e.createdAt).split(" ")[1]
|
|
133
|
+
})]
|
|
134
|
+
})
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "status",
|
|
138
|
+
header: "Status",
|
|
139
|
+
cellClassName: "whitespace-nowrap",
|
|
140
|
+
cell: (e) => {
|
|
141
|
+
let t = T(e), n = t.icon;
|
|
142
|
+
return /* @__PURE__ */ b("span", {
|
|
143
|
+
className: `inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded ${t.className}`,
|
|
144
|
+
children: [/* @__PURE__ */ y(n, { className: "size-3" }), t.label]
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
key: "provider",
|
|
150
|
+
header: "Provider",
|
|
151
|
+
priority: "hidden-on-mobile",
|
|
152
|
+
cellClassName: "whitespace-nowrap",
|
|
153
|
+
cell: (e) => /* @__PURE__ */ y("span", {
|
|
154
|
+
className: "text-sm text-text-primary capitalize",
|
|
155
|
+
children: e.provider
|
|
156
|
+
})
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: "event",
|
|
160
|
+
header: "Event",
|
|
161
|
+
cellClassName: "whitespace-nowrap max-w-[220px] truncate",
|
|
162
|
+
cell: (e) => /* @__PURE__ */ y("span", {
|
|
163
|
+
className: "text-sm font-mono text-text-muted",
|
|
164
|
+
children: e.event
|
|
165
|
+
})
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
key: "error",
|
|
169
|
+
header: "Error",
|
|
170
|
+
priority: "hidden-on-mobile",
|
|
171
|
+
cellClassName: "max-w-[280px] truncate",
|
|
172
|
+
cell: (e) => /* @__PURE__ */ y("span", {
|
|
173
|
+
className: "text-sm text-status-error-text",
|
|
174
|
+
children: e.error || "-"
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
], R = Math.max(1, Math.ceil(k / C));
|
|
178
|
+
return /* @__PURE__ */ b("div", {
|
|
179
|
+
className: "space-y-6 p-6",
|
|
180
|
+
children: [
|
|
181
|
+
/* @__PURE__ */ y(t, {
|
|
182
|
+
title: "Billing Webhook Logs",
|
|
183
|
+
description: "Every Stripe/Razorpay webhook delivery — investigate processing failures directly.",
|
|
184
|
+
actions: /* @__PURE__ */ b("button", {
|
|
185
|
+
type: "button",
|
|
186
|
+
onClick: () => M(),
|
|
187
|
+
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50",
|
|
188
|
+
children: [/* @__PURE__ */ y(_, { className: "size-4" }), "Refresh"]
|
|
189
|
+
})
|
|
190
|
+
}),
|
|
191
|
+
/* @__PURE__ */ b("div", {
|
|
192
|
+
className: "p-4 border border-border-subtle rounded-lg bg-bg-sunken/30 grid grid-cols-1 sm:grid-cols-3 gap-4",
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
195
|
+
className: "block text-sm font-medium mb-1",
|
|
196
|
+
children: "Processed"
|
|
197
|
+
}), /* @__PURE__ */ b("select", {
|
|
198
|
+
value: m.processed === void 0 ? "" : String(m.processed),
|
|
199
|
+
onChange: (e) => F("processed", e.target.value === "" ? void 0 : e.target.value === "true"),
|
|
200
|
+
className: "w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface",
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ y("option", {
|
|
203
|
+
value: "",
|
|
204
|
+
children: "All"
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ y("option", {
|
|
207
|
+
value: "false",
|
|
208
|
+
children: "Unprocessed / Failed"
|
|
209
|
+
}),
|
|
210
|
+
/* @__PURE__ */ y("option", {
|
|
211
|
+
value: "true",
|
|
212
|
+
children: "Processed"
|
|
213
|
+
})
|
|
214
|
+
]
|
|
215
|
+
})] }),
|
|
216
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
217
|
+
className: "block text-sm font-medium mb-1",
|
|
218
|
+
children: "Provider"
|
|
219
|
+
}), /* @__PURE__ */ b("select", {
|
|
220
|
+
value: m.provider || "",
|
|
221
|
+
onChange: (e) => F("provider", e.target.value || void 0),
|
|
222
|
+
className: "w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface",
|
|
223
|
+
children: [/* @__PURE__ */ y("option", {
|
|
224
|
+
value: "",
|
|
225
|
+
children: "All Providers"
|
|
226
|
+
}), w.map((e) => /* @__PURE__ */ y("option", {
|
|
227
|
+
value: e,
|
|
228
|
+
children: e.charAt(0).toUpperCase() + e.slice(1)
|
|
229
|
+
}, e))]
|
|
230
|
+
})] }),
|
|
231
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
232
|
+
className: "block text-sm font-medium mb-1",
|
|
233
|
+
children: "Has Error"
|
|
234
|
+
}), /* @__PURE__ */ b("select", {
|
|
235
|
+
value: m.hasError === void 0 ? "" : String(m.hasError),
|
|
236
|
+
onChange: (e) => F("hasError", e.target.value === "" ? void 0 : e.target.value === "true"),
|
|
237
|
+
className: "w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface",
|
|
238
|
+
children: [
|
|
239
|
+
/* @__PURE__ */ y("option", {
|
|
240
|
+
value: "",
|
|
241
|
+
children: "All"
|
|
242
|
+
}),
|
|
243
|
+
/* @__PURE__ */ y("option", {
|
|
244
|
+
value: "true",
|
|
245
|
+
children: "Has error"
|
|
246
|
+
}),
|
|
247
|
+
/* @__PURE__ */ y("option", {
|
|
248
|
+
value: "false",
|
|
249
|
+
children: "No error"
|
|
250
|
+
})
|
|
251
|
+
]
|
|
252
|
+
})] })
|
|
253
|
+
]
|
|
254
|
+
}),
|
|
255
|
+
A && O.length === 0 ? /* @__PURE__ */ y("div", {
|
|
256
|
+
className: "space-y-2",
|
|
257
|
+
children: [
|
|
258
|
+
1,
|
|
259
|
+
2,
|
|
260
|
+
3,
|
|
261
|
+
4,
|
|
262
|
+
5
|
|
263
|
+
].map((e) => /* @__PURE__ */ y("div", { className: "h-16 bg-bg-sunken animate-pulse rounded" }, e))
|
|
264
|
+
}) : O.length === 0 ? /* @__PURE__ */ y(x, {
|
|
265
|
+
illustration: "empty-data",
|
|
266
|
+
title: "No webhook logs found",
|
|
267
|
+
description: "Nothing matches these filters — try widening them, or check back after the next payment."
|
|
268
|
+
}) : /* @__PURE__ */ y("div", {
|
|
269
|
+
className: "border border-border-subtle rounded-lg overflow-hidden",
|
|
270
|
+
children: /* @__PURE__ */ y(S, {
|
|
271
|
+
columns: L,
|
|
272
|
+
data: O,
|
|
273
|
+
rowKey: (e) => e.id,
|
|
274
|
+
rowActions: (e) => /* @__PURE__ */ b("button", {
|
|
275
|
+
type: "button",
|
|
276
|
+
onClick: () => D(e),
|
|
277
|
+
className: "inline-flex items-center gap-1.5 px-2 py-1 text-sm font-medium rounded-button text-text-secondary hover:text-text-primary hover:bg-bg-sunken/60 transition-colors",
|
|
278
|
+
children: [/* @__PURE__ */ y(h, { className: "size-4" }), /* @__PURE__ */ y("span", {
|
|
279
|
+
className: "hidden sm:inline",
|
|
280
|
+
children: "View"
|
|
281
|
+
})]
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
}),
|
|
285
|
+
k > 0 && /* @__PURE__ */ b("div", {
|
|
286
|
+
className: "flex flex-col sm:flex-row items-center justify-between gap-4 border-t border-border-subtle pt-4",
|
|
287
|
+
children: [/* @__PURE__ */ b("p", {
|
|
288
|
+
className: "text-sm text-text-muted text-center sm:text-left",
|
|
289
|
+
children: [
|
|
290
|
+
"Showing ",
|
|
291
|
+
u * C + 1,
|
|
292
|
+
" to ",
|
|
293
|
+
Math.min((u + 1) * C, k),
|
|
294
|
+
" of",
|
|
295
|
+
" ",
|
|
296
|
+
k,
|
|
297
|
+
" logs"
|
|
298
|
+
]
|
|
299
|
+
}), /* @__PURE__ */ b("div", {
|
|
300
|
+
className: "flex items-center gap-2",
|
|
301
|
+
children: [
|
|
302
|
+
/* @__PURE__ */ b("button", {
|
|
303
|
+
type: "button",
|
|
304
|
+
onClick: () => d((e) => Math.max(0, e - 1)),
|
|
305
|
+
disabled: u === 0,
|
|
306
|
+
className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
307
|
+
children: [/* @__PURE__ */ y(f, { className: "size-4" }), /* @__PURE__ */ y("span", {
|
|
308
|
+
className: "hidden sm:inline",
|
|
309
|
+
children: "Previous"
|
|
310
|
+
})]
|
|
311
|
+
}),
|
|
312
|
+
/* @__PURE__ */ b("span", {
|
|
313
|
+
className: "text-sm text-text-muted px-2",
|
|
314
|
+
children: [
|
|
315
|
+
/* @__PURE__ */ y("span", {
|
|
316
|
+
className: "hidden sm:inline",
|
|
317
|
+
children: "Page "
|
|
318
|
+
}),
|
|
319
|
+
u + 1,
|
|
320
|
+
" ",
|
|
321
|
+
/* @__PURE__ */ y("span", {
|
|
322
|
+
className: "hidden sm:inline",
|
|
323
|
+
children: "of"
|
|
324
|
+
}),
|
|
325
|
+
/* @__PURE__ */ y("span", {
|
|
326
|
+
className: "sm:hidden",
|
|
327
|
+
children: "/"
|
|
328
|
+
}),
|
|
329
|
+
" ",
|
|
330
|
+
R
|
|
331
|
+
]
|
|
332
|
+
}),
|
|
333
|
+
/* @__PURE__ */ b("button", {
|
|
334
|
+
type: "button",
|
|
335
|
+
onClick: () => d((e) => e + 1 < R ? e + 1 : e),
|
|
336
|
+
disabled: u + 1 >= R,
|
|
337
|
+
className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
338
|
+
children: [/* @__PURE__ */ y("span", {
|
|
339
|
+
className: "hidden sm:inline",
|
|
340
|
+
children: "Next"
|
|
341
|
+
}), /* @__PURE__ */ y(p, { className: "size-4" })]
|
|
342
|
+
})
|
|
343
|
+
]
|
|
344
|
+
})]
|
|
345
|
+
}),
|
|
346
|
+
/* @__PURE__ */ y(E, {
|
|
347
|
+
log: v,
|
|
348
|
+
onClose: () => D(null),
|
|
349
|
+
onCreateRefund: I,
|
|
350
|
+
isCreatingRefund: P
|
|
351
|
+
})
|
|
352
|
+
]
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
//#endregion
|
|
356
|
+
export { D as BillingWebhookLogsPage };
|
|
357
|
+
|
|
358
|
+
//# sourceMappingURL=BillingWebhookLogsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BillingWebhookLogsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/BillingWebhookLogsPage.tsx"],"sourcesContent":["/**\n * Billing Module - Billing Webhook Logs Page\n * Admin visibility into every Stripe/Razorpay webhook processing attempt —\n * not just the payment-succeeded subset eligible for automatic refund\n * creation (see RefundsPage's \"Import Failed Webhooks\" action). Lets whoever\n * owns billing ops see and investigate ANY webhook processing failure\n * without needing direct DB access.\n */\n\nimport { useState, type FC } from 'react';\nimport {\n RefreshCw,\n ChevronLeft,\n ChevronRight,\n CheckCircle,\n AlertTriangle,\n X,\n DollarSign,\n Loader2,\n Eye,\n} from 'lucide-react';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n useBillingWebhookLogs,\n useRefundMutations,\n type BillingWebhookLogFilters,\n type WebhookLog,\n} from '../hooks';\nimport { AccessDenied, PageHeader, ServerError } from '../../../shared/components';\nimport { formatDateTime, isServerError } from '../../../shared/utils';\nimport { statusTokens } from '../../../shared/utils/tokens';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\nconst PAGE_SIZE = 25;\nconst PROVIDER_OPTIONS = ['stripe', 'razorpay'];\n\nconst getBadge = (log: WebhookLog): { label: string; className: string; icon: FC<{ className?: string }> } => {\n if (!log.processed) {\n return {\n label: log.error ? 'Failed' : 'Pending',\n className: `${statusTokens.error.bg} ${statusTokens.error.text}`,\n icon: AlertTriangle,\n };\n }\n return {\n label: 'Processed',\n className: `${statusTokens.success.bg} ${statusTokens.success.text}`,\n icon: CheckCircle,\n };\n};\n\nconst WebhookLogDetailModal: FC<{\n log: WebhookLog | null;\n onClose: () => void;\n onCreateRefund: (id: string) => void;\n isCreatingRefund: boolean;\n}> = ({ log, onClose, onCreateRefund, isCreatingRefund }) => {\n if (!log) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"w-full max-w-2xl max-h-[85vh] overflow-y-auto rounded-lg bg-bg-surface border border-border-subtle shadow-[var(--shadow-elevation-2)]\">\n <div className=\"flex items-center justify-between p-4 border-b border-border-subtle\">\n <h3 className=\"text-base font-semibold text-text-primary\">Webhook log details</h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded text-text-muted hover:text-text-primary hover:bg-bg-sunken/50\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n <div className=\"p-4 space-y-4\">\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-muted\">Provider</p>\n <p className=\"text-text-primary capitalize\">{log.provider}</p>\n </div>\n <div>\n <p className=\"text-text-muted\">Event</p>\n <p className=\"text-text-primary font-mono text-xs\">{log.event}</p>\n </div>\n <div>\n <p className=\"text-text-muted\">Received</p>\n <p className=\"text-text-primary\">{formatDateTime(log.createdAt)}</p>\n </div>\n <div>\n <p className=\"text-text-muted\">Processed</p>\n <p className=\"text-text-primary\">{log.processed ? 'Yes' : 'No'}</p>\n </div>\n </div>\n {log.error && (\n <div>\n <p className=\"text-sm text-text-muted mb-1\">Error</p>\n <pre className=\"text-xs whitespace-pre-wrap p-3 rounded-md bg-status-error-bg-subtle text-status-error-text border border-status-error-border\">\n {log.error}\n </pre>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-muted mb-1\">Payload</p>\n <pre className=\"text-xs whitespace-pre-wrap p-3 rounded-md bg-bg-sunken/60 text-text-secondary max-h-64 overflow-y-auto\">\n {JSON.stringify(log.payload, null, 2)}\n </pre>\n </div>\n {!log.processed && (\n <button\n type=\"button\"\n onClick={() => onCreateRefund(log.id)}\n disabled={isCreatingRefund}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50\"\n >\n {isCreatingRefund ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <DollarSign className=\"size-4\" />\n )}\n Create refund from this webhook\n </button>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport const BillingWebhookLogsPage: FC = () => {\n const permissions = useBillingPermissions();\n const [page, setPage] = useState(0);\n const [filters, setFilters] = useState<BillingWebhookLogFilters>({});\n const [selectedLog, setSelectedLog] = useState<WebhookLog | null>(null);\n\n const { logs, totalCount, isLoading, error, refetch } = useBillingWebhookLogs(\n filters,\n page,\n PAGE_SIZE\n );\n const { createRefundRecordFromWebhook, isCreatingFromWebhook } = useRefundMutations();\n\n if (!permissions.isBillingAdmin) {\n return <AccessDenied message=\"You don't have permission to view billing webhook logs.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <div className=\"p-6\">\n <ServerError\n title=\"Server Unavailable\"\n message=\"Unable to load webhook logs. The server might be down or experiencing issues.\"\n onRetry={() => refetch()}\n showRetry\n />\n </div>\n );\n }\n\n const handleFilterChange = <K extends keyof BillingWebhookLogFilters>(\n key: K,\n value: BillingWebhookLogFilters[K]\n ) => {\n setFilters((prev) => ({ ...prev, [key]: value }));\n setPage(0);\n };\n\n const handleCreateRefund = async (webhookLogId: string) => {\n await createRefundRecordFromWebhook(webhookLogId);\n setSelectedLog(null);\n };\n\n const columns: ResponsiveTableColumn<WebhookLog>[] = [\n {\n key: 'date',\n header: 'Received',\n priority: 'primary',\n cellClassName: 'whitespace-nowrap',\n cell: (log) => (\n <div className=\"flex flex-col\">\n <span className=\"text-sm text-text-primary\">\n {formatDateTime(log.createdAt).split(' ')[0]}\n </span>\n <span className=\"text-xs text-text-muted\">\n {formatDateTime(log.createdAt).split(' ')[1]}\n </span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n cellClassName: 'whitespace-nowrap',\n cell: (log) => {\n const badge = getBadge(log);\n const BadgeIcon = badge.icon;\n return (\n <span\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium rounded ${badge.className}`}\n >\n <BadgeIcon className=\"size-3\" />\n {badge.label}\n </span>\n );\n },\n },\n {\n key: 'provider',\n header: 'Provider',\n priority: 'hidden-on-mobile',\n cellClassName: 'whitespace-nowrap',\n cell: (log) => <span className=\"text-sm text-text-primary capitalize\">{log.provider}</span>,\n },\n {\n key: 'event',\n header: 'Event',\n cellClassName: 'whitespace-nowrap max-w-[220px] truncate',\n cell: (log) => <span className=\"text-sm font-mono text-text-muted\">{log.event}</span>,\n },\n {\n key: 'error',\n header: 'Error',\n priority: 'hidden-on-mobile',\n cellClassName: 'max-w-[280px] truncate',\n cell: (log) => (\n <span className=\"text-sm text-status-error-text\">{log.error || '-'}</span>\n ),\n },\n ];\n\n const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE));\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Billing Webhook Logs\"\n description=\"Every Stripe/Razorpay webhook delivery — investigate processing failures directly.\"\n actions={\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n }\n />\n\n {/* Filters */}\n <div className=\"p-4 border border-border-subtle rounded-lg bg-bg-sunken/30 grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">Processed</label>\n <select\n value={filters.processed === undefined ? '' : String(filters.processed)}\n onChange={(e) =>\n handleFilterChange(\n 'processed',\n e.target.value === '' ? undefined : e.target.value === 'true'\n )\n }\n className=\"w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface\"\n >\n <option value=\"\">All</option>\n <option value=\"false\">Unprocessed / Failed</option>\n <option value=\"true\">Processed</option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">Provider</label>\n <select\n value={filters.provider || ''}\n onChange={(e) => handleFilterChange('provider', e.target.value || undefined)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface\"\n >\n <option value=\"\">All Providers</option>\n {PROVIDER_OPTIONS.map((p) => (\n <option key={p} value={p}>\n {p.charAt(0).toUpperCase() + p.slice(1)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">Has Error</label>\n <select\n value={filters.hasError === undefined ? '' : String(filters.hasError)}\n onChange={(e) =>\n handleFilterChange(\n 'hasError',\n e.target.value === '' ? undefined : e.target.value === 'true'\n )\n }\n className=\"w-full px-3 py-2 border border-border-subtle rounded-md bg-bg-surface\"\n >\n <option value=\"\">All</option>\n <option value=\"true\">Has error</option>\n <option value=\"false\">No error</option>\n </select>\n </div>\n </div>\n\n {/* Table */}\n {isLoading && logs.length === 0 ? (\n <div className=\"space-y-2\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n ) : logs.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No webhook logs found\"\n description=\"Nothing matches these filters — try widening them, or check back after the next payment.\"\n />\n ) : (\n <div className=\"border border-border-subtle rounded-lg overflow-hidden\">\n <ResponsiveTable<WebhookLog>\n columns={columns}\n data={logs}\n rowKey={(log) => log.id}\n rowActions={(log) => (\n <button\n type=\"button\"\n onClick={() => setSelectedLog(log)}\n className=\"inline-flex items-center gap-1.5 px-2 py-1 text-sm font-medium rounded-button text-text-secondary hover:text-text-primary hover:bg-bg-sunken/60 transition-colors\"\n >\n <Eye className=\"size-4\" />\n <span className=\"hidden sm:inline\">View</span>\n </button>\n )}\n />\n </div>\n )}\n\n {/* Pagination */}\n {totalCount > 0 && (\n <div className=\"flex flex-col sm:flex-row items-center justify-between gap-4 border-t border-border-subtle pt-4\">\n <p className=\"text-sm text-text-muted text-center sm:text-left\">\n Showing {page * PAGE_SIZE + 1} to {Math.min((page + 1) * PAGE_SIZE, totalCount)} of{' '}\n {totalCount} logs\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(0, p - 1))}\n disabled={page === 0}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <ChevronLeft className=\"size-4\" />\n <span className=\"hidden sm:inline\">Previous</span>\n </button>\n <span className=\"text-sm text-text-muted px-2\">\n <span className=\"hidden sm:inline\">Page </span>\n {page + 1} <span className=\"hidden sm:inline\">of</span>\n <span className=\"sm:hidden\">/</span> {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setPage((p) => (p + 1 < totalPages ? p + 1 : p))}\n disabled={page + 1 >= totalPages}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <span className=\"hidden sm:inline\">Next</span>\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n\n <WebhookLogDetailModal\n log={selectedLog}\n onClose={() => setSelectedLog(null)}\n onCreateRefund={handleCreateRefund}\n isCreatingRefund={isCreatingFromWebhook}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { useCallback as o, useEffect as s, useMemo as c, useState as l } from "r
|
|
|
5
5
|
//#region src/billing/modules/checkout/hooks/useCheckout.ts
|
|
6
6
|
var te = 100;
|
|
7
7
|
function u(u = {}) {
|
|
8
|
-
let { currentUser: d } = e(), { defaultCurrency: f = "USD", defaultSaveCard: p = !1, upgradeFromSubscriptionId: m, downgradeFromSubscriptionId: h, defaultSubscriptionId: g } = u, [_, v] = l([]), [y, ne] = l(null), [b, re] = l("AUTO"), [x, S] = l(f), [C, w] = l(""), [T, E] = l(0), [ie, D] = l("PERCENTAGE"), [O, k] = l(!1), [A, j] = l(0), [M, N] = l("idle"), [ae, P] = l(null), [F, I] = l(0), [oe, L] = l(0), [se, R] = l("NONE"), [z, ce] = l(null), [B, le] = l(p), [V,
|
|
8
|
+
let { currentUser: d } = e(), { defaultCurrency: f = "USD", defaultSaveCard: p = !1, upgradeFromSubscriptionId: m, downgradeFromSubscriptionId: h, defaultSubscriptionId: g } = u, [_, v] = l([]), [y, ne] = l(null), [b, re] = l("AUTO"), [x, S] = l(f), [C, w] = l(""), [T, E] = l(0), [ie, D] = l("PERCENTAGE"), [O, k] = l(!1), [A, j] = l(0), [M, N] = l("idle"), [ae, P] = l(null), [F, I] = l(0), [oe, L] = l(0), [se, R] = l("NONE"), [z, ce] = l(null), [B, le] = l(p), [V, ue] = l(!1), [H, U] = l(null), [W, G] = l(g ?? null), [de] = r(), [fe] = n(), [pe] = i(), [K, { data: me, loading: he }] = t(), [ge] = a(), q = c(() => _[0]?.currency ?? "USD", [_]), J = c(() => _.reduce((e, t) => e + t.price * t.quantity, 0), [_]), Y = c(() => _.reduce((e, t) => e + (t.priceUSD ?? t.price) * t.quantity, 0), [_]), X = c(() => T ? Math.min(T, J) : 0, [J, T]), Z = c(() => {
|
|
9
9
|
let e = J - X;
|
|
10
10
|
return (O ? Math.max(0, e - A) : e) + F;
|
|
11
11
|
}, [
|
|
@@ -14,24 +14,25 @@ function u(u = {}) {
|
|
|
14
14
|
O,
|
|
15
15
|
A,
|
|
16
16
|
F
|
|
17
|
-
]), Q = y?.creditAmount ?? 0,
|
|
17
|
+
]), Q = y?.creditAmount ?? 0, _e = c(() => Q >= Y * te, [Q, Y]), ve = c(() => !_.some((e) => e.type === "CREDITS") && Q > 0, [_, Q]), ye = me?.convertCurrency?.amount ?? null, be = me?.convertCurrency?.exchangeRate ?? 1, xe = ye ?? Z, Se = M === "loading" || he, Ce = M === "processing";
|
|
18
18
|
s(() => {
|
|
19
|
-
if (b !== "CREDITS" && _.length !== 0 && !_.every((e) => e.currency === x || e.type === "CREDITS") && Z > 0 &&
|
|
19
|
+
if (b !== "CREDITS" && _.length !== 0 && !_.every((e) => e.currency === x || e.type === "CREDITS") && Z > 0 && q !== x) {
|
|
20
20
|
if (x === "INR" && F === 0 && J > 0) return;
|
|
21
|
-
|
|
21
|
+
K({ variables: {
|
|
22
22
|
amount: Z,
|
|
23
23
|
toCurrency: x,
|
|
24
|
-
fromCurrency:
|
|
24
|
+
fromCurrency: q
|
|
25
25
|
} });
|
|
26
26
|
}
|
|
27
27
|
}, [
|
|
28
28
|
Z,
|
|
29
29
|
x,
|
|
30
30
|
b,
|
|
31
|
-
|
|
31
|
+
K,
|
|
32
32
|
F,
|
|
33
33
|
J,
|
|
34
|
-
_
|
|
34
|
+
_,
|
|
35
|
+
q
|
|
35
36
|
]), s(() => {
|
|
36
37
|
if (!y || J <= 0) {
|
|
37
38
|
I(0), L(0), R("NONE");
|
|
@@ -54,7 +55,7 @@ function u(u = {}) {
|
|
|
54
55
|
x,
|
|
55
56
|
b
|
|
56
57
|
]);
|
|
57
|
-
let
|
|
58
|
+
let we = o((e) => {
|
|
58
59
|
v((t) => e.type === "PLAN" ? t.find((e) => e.type === "PLAN") ? t.map((t) => t.type === "PLAN" ? {
|
|
59
60
|
...e,
|
|
60
61
|
quantity: 1
|
|
@@ -67,7 +68,7 @@ function u(u = {}) {
|
|
|
67
68
|
} : t) : [...t, e]);
|
|
68
69
|
}, []), $ = o((e) => {
|
|
69
70
|
v((t) => t.filter((t) => t.id !== e));
|
|
70
|
-
}, []),
|
|
71
|
+
}, []), Te = o((e, t) => {
|
|
71
72
|
if (t <= 0) {
|
|
72
73
|
$(e);
|
|
73
74
|
return;
|
|
@@ -79,7 +80,7 @@ function u(u = {}) {
|
|
|
79
80
|
...n,
|
|
80
81
|
quantity: t
|
|
81
82
|
} : n));
|
|
82
|
-
}, [$]),
|
|
83
|
+
}, [$]), Ee = o((e, t, n) => {
|
|
83
84
|
v((r) => r.map((r) => {
|
|
84
85
|
if (r.id !== e) return r;
|
|
85
86
|
let i = { price: t };
|
|
@@ -88,22 +89,23 @@ function u(u = {}) {
|
|
|
88
89
|
...i
|
|
89
90
|
};
|
|
90
91
|
}));
|
|
91
|
-
}, []),
|
|
92
|
+
}, []), De = o(() => {
|
|
92
93
|
v([]);
|
|
93
|
-
}, []), De = o((e) => {
|
|
94
|
-
ne(e), k(!1), j(0);
|
|
95
94
|
}, []), Oe = o((e) => {
|
|
95
|
+
ne(e), k(!1), j(0);
|
|
96
|
+
}, []), ke = o((e) => {
|
|
96
97
|
S(e);
|
|
97
98
|
let t = _.every((t) => t.currency === e || t.type === "CREDITS");
|
|
98
|
-
Z > 0 &&
|
|
99
|
+
Z > 0 && q !== e && !t && K({ variables: {
|
|
99
100
|
amount: Z,
|
|
100
101
|
toCurrency: e,
|
|
101
|
-
fromCurrency:
|
|
102
|
+
fromCurrency: q
|
|
102
103
|
} });
|
|
103
104
|
}, [
|
|
104
105
|
Z,
|
|
105
|
-
|
|
106
|
-
_
|
|
106
|
+
K,
|
|
107
|
+
_,
|
|
108
|
+
q
|
|
107
109
|
]);
|
|
108
110
|
return {
|
|
109
111
|
items: _,
|
|
@@ -120,8 +122,8 @@ function u(u = {}) {
|
|
|
120
122
|
selectedPaymentMethodId: z,
|
|
121
123
|
saveCard: B,
|
|
122
124
|
autoRenew: V,
|
|
123
|
-
autoRenewPaymentMethodId:
|
|
124
|
-
selectedSubscriptionId:
|
|
125
|
+
autoRenewPaymentMethodId: H,
|
|
126
|
+
selectedSubscriptionId: W,
|
|
125
127
|
subtotal: J,
|
|
126
128
|
subtotalUSD: Y,
|
|
127
129
|
discountAmount: X,
|
|
@@ -129,25 +131,25 @@ function u(u = {}) {
|
|
|
129
131
|
taxRate: oe,
|
|
130
132
|
taxType: se,
|
|
131
133
|
total: Z,
|
|
132
|
-
totalInSelectedCurrency:
|
|
134
|
+
totalInSelectedCurrency: xe,
|
|
133
135
|
availableCredits: Q,
|
|
134
|
-
hasEnoughCredits:
|
|
135
|
-
canPayWithCredits:
|
|
136
|
-
isLoading:
|
|
137
|
-
isProcessing:
|
|
136
|
+
hasEnoughCredits: _e,
|
|
137
|
+
canPayWithCredits: ve,
|
|
138
|
+
isLoading: Se,
|
|
139
|
+
isProcessing: Ce,
|
|
138
140
|
isCalculatingTax: !1,
|
|
139
|
-
conversionRate:
|
|
140
|
-
convertedAmount:
|
|
141
|
-
addItem:
|
|
141
|
+
conversionRate: be,
|
|
142
|
+
convertedAmount: ye,
|
|
143
|
+
addItem: we,
|
|
142
144
|
removeItem: $,
|
|
143
|
-
updateItemQuantity:
|
|
144
|
-
updateItemPrice:
|
|
145
|
-
clearItems:
|
|
146
|
-
setBillingAccount:
|
|
145
|
+
updateItemQuantity: Te,
|
|
146
|
+
updateItemPrice: Ee,
|
|
147
|
+
clearItems: De,
|
|
148
|
+
setBillingAccount: Oe,
|
|
147
149
|
setPaymentProvider: o((e) => {
|
|
148
150
|
re(e), e === "RAZORPAY" && x !== "INR" && S("INR");
|
|
149
151
|
}, [x]),
|
|
150
|
-
setCurrency:
|
|
152
|
+
setCurrency: ke,
|
|
151
153
|
setPromoCode: w,
|
|
152
154
|
validatePromoCode: o(async () => {
|
|
153
155
|
if (!C.trim()) return {
|
|
@@ -159,7 +161,7 @@ function u(u = {}) {
|
|
|
159
161
|
};
|
|
160
162
|
try {
|
|
161
163
|
N("loading");
|
|
162
|
-
let { data: e, error: t } = await
|
|
164
|
+
let { data: e, error: t } = await ge({ variables: { input: {
|
|
163
165
|
code: C.trim().toUpperCase(),
|
|
164
166
|
userId: d?.id ?? "",
|
|
165
167
|
userEmail: d?.email,
|
|
@@ -211,7 +213,7 @@ function u(u = {}) {
|
|
|
211
213
|
C,
|
|
212
214
|
x,
|
|
213
215
|
J,
|
|
214
|
-
|
|
216
|
+
ge
|
|
215
217
|
]),
|
|
216
218
|
clearPromoCode: o(() => {
|
|
217
219
|
w(""), E(0), D("PERCENTAGE");
|
|
@@ -227,9 +229,9 @@ function u(u = {}) {
|
|
|
227
229
|
]),
|
|
228
230
|
setSelectedPaymentMethodId: ce,
|
|
229
231
|
setSaveCard: le,
|
|
230
|
-
setAutoRenew:
|
|
231
|
-
setAutoRenewPaymentMethodId:
|
|
232
|
-
setSelectedSubscriptionId:
|
|
232
|
+
setAutoRenew: ue,
|
|
233
|
+
setAutoRenewPaymentMethodId: U,
|
|
234
|
+
setSelectedSubscriptionId: G,
|
|
233
235
|
initiatePayment: o(async (e) => {
|
|
234
236
|
let t = e?.shippingOverride;
|
|
235
237
|
if (!y) return {
|
|
@@ -291,7 +293,7 @@ function u(u = {}) {
|
|
|
291
293
|
productId: e.metadata?.productId ?? void 0,
|
|
292
294
|
variantId: e.metadata?.variantId ?? void 0
|
|
293
295
|
}
|
|
294
|
-
})), { data: c } = await
|
|
296
|
+
})), { data: c } = await fe({ variables: { input: {
|
|
295
297
|
externalOrderId: r,
|
|
296
298
|
externalService: "STORE",
|
|
297
299
|
currency: x,
|
|
@@ -321,7 +323,7 @@ function u(u = {}) {
|
|
|
321
323
|
}
|
|
322
324
|
}
|
|
323
325
|
if (o === "CREDITS") {
|
|
324
|
-
let e = _.filter((e) => e.type === "ADDON"), t = _.find((e) => e.type === "PLAN"), { data: n } = await
|
|
326
|
+
let e = _.filter((e) => e.type === "ADDON"), t = _.find((e) => e.type === "PLAN"), { data: n } = await pe({ variables: { input: {
|
|
325
327
|
billingAccountId: y.id,
|
|
326
328
|
planId: t ? t.metadata?.planId || t.id : void 0,
|
|
327
329
|
addOnIds: e.length > 0 ? e.map((e) => ({
|
|
@@ -331,7 +333,7 @@ function u(u = {}) {
|
|
|
331
333
|
isAnnual: t?.metadata?.duration === "yearly",
|
|
332
334
|
upgradeFromSubscriptionId: m || void 0,
|
|
333
335
|
downgradeFromSubscriptionId: h || void 0,
|
|
334
|
-
subscriptionId: e.length > 0 ?
|
|
336
|
+
subscriptionId: e.length > 0 ? W : void 0,
|
|
335
337
|
seatCount: t?.metadata?.seatCount
|
|
336
338
|
} } }), r = n?.spendCredits;
|
|
337
339
|
return r?.creditTransactionID ? (N("success"), {
|
|
@@ -358,7 +360,7 @@ function u(u = {}) {
|
|
|
358
360
|
error: "Failed to process credit payment"
|
|
359
361
|
});
|
|
360
362
|
}
|
|
361
|
-
let s = _.filter((e) => e.type === "ADDON"), c = s.length > 0 ? s.map((e) => e.metadata?.addonId || e.id) : void 0, l = s.length > 0 ? s.map((e) => e.quantity) : void 0, te = _.find((e) => e.type === "PLAN")?.metadata?.duration === "yearly", u = n === "PLAN" && V && (
|
|
363
|
+
let s = _.filter((e) => e.type === "ADDON"), c = s.length > 0 ? s.map((e) => e.metadata?.addonId || e.id) : void 0, l = s.length > 0 ? s.map((e) => e.quantity) : void 0, te = _.find((e) => e.type === "PLAN")?.metadata?.duration === "yearly", u = n === "PLAN" && V && (H || z) || void 0, { data: d } = await de({ variables: { input: {
|
|
362
364
|
billingAccountId: y.id,
|
|
363
365
|
amount: a,
|
|
364
366
|
currency: x,
|
|
@@ -371,7 +373,7 @@ function u(u = {}) {
|
|
|
371
373
|
quantity: n === "ADDON" && s.length === 1 && !i ? s[0].quantity : void 0,
|
|
372
374
|
addonIds: n === "ADDON" && s.length > 1 && !i ? c : void 0,
|
|
373
375
|
quantities: n === "ADDON" && s.length > 1 && !i ? l : void 0,
|
|
374
|
-
subscriptionId: n === "ADDON" && !i ?
|
|
376
|
+
subscriptionId: n === "ADDON" && !i ? W : void 0,
|
|
375
377
|
paymentMethodId: z || void 0,
|
|
376
378
|
saveCard: z ? void 0 : B || V,
|
|
377
379
|
upgradeFromSubscriptionId: m || void 0,
|
|
@@ -419,16 +421,16 @@ function u(u = {}) {
|
|
|
419
421
|
z,
|
|
420
422
|
B,
|
|
421
423
|
V,
|
|
422
|
-
|
|
423
|
-
|
|
424
|
+
H,
|
|
425
|
+
W,
|
|
424
426
|
m,
|
|
425
427
|
h,
|
|
426
|
-
ue,
|
|
427
428
|
de,
|
|
428
|
-
fe
|
|
429
|
+
fe,
|
|
430
|
+
pe
|
|
429
431
|
]),
|
|
430
432
|
reset: o(() => {
|
|
431
|
-
v([]), ne(null), re("AUTO"), S(f), w(""), E(0), D("PERCENTAGE"), k(!1), j(0), N("idle"), P(null), I(0), L(0), R("NONE"), ce(null), le(p),
|
|
433
|
+
v([]), ne(null), re("AUTO"), S(f), w(""), E(0), D("PERCENTAGE"), k(!1), j(0), N("idle"), P(null), I(0), L(0), R("NONE"), ce(null), le(p), ue(!1), U(null), G(g ?? null);
|
|
432
434
|
}, [
|
|
433
435
|
f,
|
|
434
436
|
p,
|