@reeboot/strapi-payment-plugin 0.0.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 (54) hide show
  1. package/README.md +112 -0
  2. package/dist/_chunks/App-BGle38NN.js +1149 -0
  3. package/dist/_chunks/App-DoUUpjp-.mjs +1149 -0
  4. package/dist/_chunks/en-B4KWt_jN.js +4 -0
  5. package/dist/_chunks/en-Byx4XI2L.mjs +4 -0
  6. package/dist/admin/index.js +64 -0
  7. package/dist/admin/index.mjs +65 -0
  8. package/dist/admin/src/components/Header.d.ts +2 -0
  9. package/dist/admin/src/components/Initializer.d.ts +5 -0
  10. package/dist/admin/src/components/NavigationMenu.d.ts +2 -0
  11. package/dist/admin/src/components/PluginIcon.d.ts +2 -0
  12. package/dist/admin/src/components/Sidebar.d.ts +2 -0
  13. package/dist/admin/src/components/TransactionDetailsModal.d.ts +18 -0
  14. package/dist/admin/src/components/TransactionList.d.ts +18 -0
  15. package/dist/admin/src/index.d.ts +10 -0
  16. package/dist/admin/src/pages/App.d.ts +2 -0
  17. package/dist/admin/src/pages/ConfigurationPage.d.ts +2 -0
  18. package/dist/admin/src/pages/DashboardPage.d.ts +2 -0
  19. package/dist/admin/src/pages/HomePage.d.ts +2 -0
  20. package/dist/admin/src/pages/ProductsPage.d.ts +2 -0
  21. package/dist/admin/src/pages/SubscriptionsPage.d.ts +2 -0
  22. package/dist/admin/src/pages/TransactionsPage.d.ts +2 -0
  23. package/dist/admin/src/pluginId.d.ts +1 -0
  24. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  25. package/dist/server/controllers/product.d.ts +12 -0
  26. package/dist/server/controllers/subscription.d.ts +12 -0
  27. package/dist/server/index.js +7287 -0
  28. package/dist/server/index.mjs +7286 -0
  29. package/dist/server/services/product.d.ts +7 -0
  30. package/dist/server/services/subscription.d.ts +7 -0
  31. package/dist/server/src/bootstrap.d.ts +5 -0
  32. package/dist/server/src/config/index.d.ts +13 -0
  33. package/dist/server/src/content-types/index.d.ts +2 -0
  34. package/dist/server/src/controllers/controller.d.ts +10 -0
  35. package/dist/server/src/controllers/index.d.ts +41 -0
  36. package/dist/server/src/controllers/productController.d.ts +9 -0
  37. package/dist/server/src/controllers/subscriptionController.d.ts +9 -0
  38. package/dist/server/src/destroy.d.ts +5 -0
  39. package/dist/server/src/index.d.ts +159 -0
  40. package/dist/server/src/middlewares/index.d.ts +2 -0
  41. package/dist/server/src/policies/index.d.ts +2 -0
  42. package/dist/server/src/register.d.ts +5 -0
  43. package/dist/server/src/routes/admin-routes.d.ts +13 -0
  44. package/dist/server/src/routes/content-api.d.ts +12 -0
  45. package/dist/server/src/routes/index.d.ts +51 -0
  46. package/dist/server/src/routes/product-routes.d.ts +13 -0
  47. package/dist/server/src/routes/refund-routes.d.ts +13 -0
  48. package/dist/server/src/routes/subscription-routes.d.ts +13 -0
  49. package/dist/server/src/services/index.d.ts +41 -0
  50. package/dist/server/src/services/paypalDriver.d.ts +7 -0
  51. package/dist/server/src/services/service.d.ts +33 -0
  52. package/dist/server/src/services/stripeDriver.d.ts +290 -0
  53. package/jest.config.js +13 -0
  54. package/package.json +75 -0
@@ -0,0 +1,1149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const admin = require("@strapi/strapi/admin");
5
+ const reactRouterDom = require("react-router-dom");
6
+ const react = require("react");
7
+ const designSystem = require("@strapi/design-system");
8
+ const formik = require("formik");
9
+ const HomePage = () => {
10
+ const [transactions, setTransactions] = react.useState([]);
11
+ const [loading, setLoading] = react.useState(false);
12
+ const [error, setError] = react.useState(null);
13
+ const [stats, setStats] = react.useState({
14
+ totalRevenue: 0,
15
+ totalTransactions: 0,
16
+ successRate: 0
17
+ });
18
+ const [searchTerm, setSearchTerm] = react.useState("");
19
+ const [filter, setFilter] = react.useState("all");
20
+ const fetchData = async () => {
21
+ setLoading(true);
22
+ setError(null);
23
+ try {
24
+ const response = await fetch("/payment-plugin/transactions");
25
+ if (!response.ok) {
26
+ throw new Error("Failed to fetch transactions");
27
+ }
28
+ const data = await response.json();
29
+ setTransactions(data.data);
30
+ const totalAmount = data.data.reduce(
31
+ (sum, t) => sum + t.amount,
32
+ 0
33
+ );
34
+ const successCount = data.data.filter(
35
+ (t) => t.status === "completed"
36
+ ).length;
37
+ const successRate = data.data.length > 0 ? successCount / data.data.length * 100 : 0;
38
+ setStats({
39
+ totalRevenue: totalAmount,
40
+ totalTransactions: data.data.length,
41
+ successRate
42
+ });
43
+ } catch (err) {
44
+ if (err instanceof Error) {
45
+ setError(err.message);
46
+ } else {
47
+ setError("An unknown error occurred");
48
+ }
49
+ } finally {
50
+ setLoading(false);
51
+ }
52
+ };
53
+ react.useEffect(() => {
54
+ fetchData();
55
+ }, []);
56
+ const handleSearch = (e) => {
57
+ setSearchTerm(e.target.value);
58
+ };
59
+ const handleFilterChange = (e) => {
60
+ setFilter(e.target.value);
61
+ };
62
+ const filteredTransactions = transactions.filter((transaction) => {
63
+ const matchesSearch = [
64
+ transaction.id,
65
+ transaction.customer,
66
+ transaction.amount.toString()
67
+ ].some(
68
+ (field) => field.toLowerCase().includes(searchTerm.toLowerCase())
69
+ );
70
+ const matchesFilter = filter === "all" || transaction.status === filter;
71
+ return matchesSearch && matchesFilter;
72
+ });
73
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
74
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Payment Plugin Home" }),
75
+ /* @__PURE__ */ jsxRuntime.jsxs(
76
+ designSystem.Box,
77
+ {
78
+ padding: 4,
79
+ background: "neutral100",
80
+ borderRadius: "4px",
81
+ border: "1px solid #e0e0e0",
82
+ style: { marginBottom: "2rem" },
83
+ children: [
84
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Payment Statistics" }),
85
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading statistics..." }),
86
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "red" }, children: error }),
87
+ !loading && !error && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
89
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Total Revenue" }),
90
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: [
91
+ "$",
92
+ stats.totalRevenue.toFixed(2)
93
+ ] })
94
+ ] }) }),
95
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
96
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Total Transactions" }),
97
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: stats.totalTransactions })
98
+ ] }) }),
99
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
100
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Successful Payments" }),
101
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: [
102
+ stats.successRate.toFixed(2),
103
+ "%"
104
+ ] })
105
+ ] }) })
106
+ ] })
107
+ ]
108
+ }
109
+ ),
110
+ /* @__PURE__ */ jsxRuntime.jsxs(
111
+ designSystem.Box,
112
+ {
113
+ padding: 4,
114
+ background: "neutral100",
115
+ borderRadius: "4px",
116
+ border: "1px solid #e0e0e0",
117
+ children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Transactions" }),
119
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "1rem", display: "flex", gap: "1rem", alignItems: "center", flexWrap: "wrap" }, children: [
120
+ /* @__PURE__ */ jsxRuntime.jsx(
121
+ designSystem.TextInput,
122
+ {
123
+ label: "Search Transactions",
124
+ value: searchTerm,
125
+ onChange: handleSearch,
126
+ placeholder: "Search by ID, email, or amount",
127
+ style: { flex: 1, minWidth: "200px" }
128
+ }
129
+ ),
130
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { value: filter, onChange: handleFilterChange, style: { minWidth: "150px" }, children: [
131
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "all", children: "All Transactions" }),
132
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "completed", children: "Successful" }),
133
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "failed", children: "Failed" }),
134
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" })
135
+ ] })
136
+ ] }),
137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { overflowX: "auto" }, children: [
138
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading transactions..." }),
139
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "red" }, children: error }),
140
+ !loading && !error && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: filteredTransactions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
141
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "ID" }),
143
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Amount" }),
144
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Currency" }),
145
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Status" }),
146
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Date" }),
147
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Customer" })
148
+ ] }) }),
149
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: filteredTransactions.map((transaction) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
150
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.id }),
151
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Td, { children: [
152
+ "$",
153
+ transaction.amount.toFixed(2)
154
+ ] }),
155
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.currency }),
156
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.status }),
157
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: new Date(transaction.date).toLocaleDateString() }),
158
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.customer })
159
+ ] }, transaction.id)) })
160
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No transactions found" }) })
161
+ ] })
162
+ ]
163
+ }
164
+ )
165
+ ] });
166
+ };
167
+ const ConfigurationPage = () => {
168
+ const [stripeSecretKey, setStripeSecretKey] = react.useState("");
169
+ const [stripePublishableKey, setStripePublishableKey] = react.useState("");
170
+ const [stripeWebhookSecret, setStripeWebhookSecret] = react.useState("");
171
+ const [paypalClientId, setPaypalClientId] = react.useState("");
172
+ const [paypalClientSecret, setPaypalClientSecret] = react.useState("");
173
+ const [paypalWebhookId, setPaypalWebhookId] = react.useState("");
174
+ const [configStatus, setConfigStatus] = react.useState({
175
+ stripe: false,
176
+ paypal: false
177
+ });
178
+ react.useEffect(() => {
179
+ const fetchConfigStatus = async () => {
180
+ try {
181
+ const response = await fetch("/payment-plugin/config-status");
182
+ if (response.ok) {
183
+ const data = await response.json();
184
+ setConfigStatus(data);
185
+ }
186
+ } catch (error) {
187
+ console.error("Failed to fetch config status:", error);
188
+ }
189
+ };
190
+ fetchConfigStatus();
191
+ }, []);
192
+ const handleSave = async () => {
193
+ const response = await fetch("/payment-plugin/config", {
194
+ method: "POST",
195
+ headers: {
196
+ "Content-Type": "application/json"
197
+ },
198
+ body: JSON.stringify({
199
+ stripe: {
200
+ secretKey: stripeSecretKey,
201
+ publishableKey: stripePublishableKey,
202
+ webhookSecret: stripeWebhookSecret
203
+ },
204
+ paypal: {
205
+ clientId: paypalClientId,
206
+ clientSecret: paypalClientSecret,
207
+ webhookId: paypalWebhookId
208
+ }
209
+ })
210
+ });
211
+ if (response.ok) {
212
+ alert("Configuration saved successfully");
213
+ } else {
214
+ alert("Failed to save configuration");
215
+ }
216
+ };
217
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { children: [
218
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { title: "Payment Plugin Configuration" }),
219
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
220
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Payment Configuration" }),
221
+ /* @__PURE__ */ jsxRuntime.jsxs(
222
+ designSystem.Box,
223
+ {
224
+ padding: 4,
225
+ background: "neutral100",
226
+ borderRadius: "4px",
227
+ border: "1px solid #e0e0e0",
228
+ style: { marginBottom: "2rem" },
229
+ children: [
230
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Payment Configuration" }),
231
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, style: { marginBottom: "2rem" }, children: [
232
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
233
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "gamma", as: "h3", textColor: "neutral800", children: "Stripe Status  " }),
234
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", children: [
235
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
236
+ width: "10px",
237
+ height: "10px",
238
+ borderRadius: "50%",
239
+ backgroundColor: configStatus.stripe ? "green" : "red",
240
+ marginRight: "8px"
241
+ } }),
242
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: configStatus.stripe ? "success600" : "danger600", children: configStatus.stripe ? "Connected" : "Not Connected" })
243
+ ] })
244
+ ] }) }),
245
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
246
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "gamma", as: "h3", textColor: "neutral800", children: "PayPal Status  " }),
247
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", children: [
248
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
249
+ width: "10px",
250
+ height: "10px",
251
+ borderRadius: "50%",
252
+ backgroundColor: configStatus.paypal ? "green" : "red",
253
+ marginRight: "8px"
254
+ } }),
255
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: configStatus.paypal ? "success600" : "danger600", children: configStatus.paypal ? "Connected" : "Not Connected" })
256
+ ] })
257
+ ] }) })
258
+ ] }),
259
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, children: [
260
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
261
+ designSystem.Box,
262
+ {
263
+ padding: 6,
264
+ background: "neutral0",
265
+ borderRadius: "4px",
266
+ border: "1px solid #e0e0e0",
267
+ style: { marginBottom: "1rem", width: "100%" },
268
+ children: [
269
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "gamma", as: "h3", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Stripe Configuration" }),
270
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 8, alignItems: "initial", children: [
271
+ /* @__PURE__ */ jsxRuntime.jsx(
272
+ designSystem.TextInput,
273
+ {
274
+ placeholder: "Secret Key",
275
+ name: "stripeSecretKey",
276
+ value: stripeSecretKey,
277
+ onChange: (e) => setStripeSecretKey(e.target.value),
278
+ type: "password",
279
+ disabled: configStatus.stripe,
280
+ style: {
281
+ border: configStatus.stripe ? "2px solid #4CAF50" : ""
282
+ },
283
+ hint: configStatus.stripe ? "This value is controlled by environment variables" : ""
284
+ }
285
+ ),
286
+ /* @__PURE__ */ jsxRuntime.jsx(
287
+ designSystem.TextInput,
288
+ {
289
+ placeholder: "Publishable Key",
290
+ name: "stripePublishableKey",
291
+ value: stripePublishableKey,
292
+ onChange: (e) => setStripePublishableKey(e.target.value),
293
+ disabled: configStatus.stripe,
294
+ style: {
295
+ border: configStatus.stripe ? "2px solid #4CAF50" : ""
296
+ },
297
+ hint: configStatus.stripe ? "This value is controlled by environment variables" : ""
298
+ }
299
+ ),
300
+ /* @__PURE__ */ jsxRuntime.jsx(
301
+ designSystem.TextInput,
302
+ {
303
+ placeholder: "Webhook Secret",
304
+ name: "stripeWebhookSecret",
305
+ value: stripeWebhookSecret,
306
+ onChange: (e) => setStripeWebhookSecret(e.target.value),
307
+ type: "password",
308
+ disabled: configStatus.stripe,
309
+ style: {
310
+ border: configStatus.stripe ? "2px solid #4CAF50" : ""
311
+ },
312
+ hint: configStatus.stripe ? "This value is controlled by environment variables" : ""
313
+ }
314
+ )
315
+ ] })
316
+ ]
317
+ }
318
+ ) }),
319
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
320
+ designSystem.Box,
321
+ {
322
+ padding: 6,
323
+ background: "neutral0",
324
+ borderRadius: "4px",
325
+ border: "1px solid #e0e0e0",
326
+ style: { marginBottom: "1rem", width: "100%" },
327
+ children: [
328
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "gamma", as: "h3", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "PayPal Configuration" }),
329
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 8, alignItems: "initial", children: [
330
+ /* @__PURE__ */ jsxRuntime.jsx(
331
+ designSystem.TextInput,
332
+ {
333
+ placeholder: "Client ID",
334
+ name: "paypalClientId",
335
+ value: paypalClientId,
336
+ onChange: (e) => setPaypalClientId(e.target.value),
337
+ disabled: configStatus.paypal,
338
+ style: {
339
+ border: configStatus.paypal ? "2px solid #4CAF50" : "",
340
+ width: "100%"
341
+ },
342
+ hint: configStatus.paypal ? "This value is controlled by environment variables" : ""
343
+ }
344
+ ),
345
+ /* @__PURE__ */ jsxRuntime.jsx(
346
+ designSystem.TextInput,
347
+ {
348
+ placeholder: "Client Secret",
349
+ name: "paypalClientSecret",
350
+ value: paypalClientSecret,
351
+ onChange: (e) => setPaypalClientSecret(e.target.value),
352
+ type: "password",
353
+ disabled: configStatus.paypal,
354
+ style: {
355
+ border: configStatus.paypal ? "2px solid #4CAF50" : ""
356
+ },
357
+ width: "80%",
358
+ hint: configStatus.paypal ? "This value is controlled by environment variables" : ""
359
+ }
360
+ ),
361
+ /* @__PURE__ */ jsxRuntime.jsx(
362
+ designSystem.TextInput,
363
+ {
364
+ placeholder: "Webhook ID",
365
+ name: "paypalWebhookId",
366
+ value: paypalWebhookId,
367
+ onChange: (e) => setPaypalWebhookId(e.target.value),
368
+ disabled: configStatus.paypal,
369
+ style: {
370
+ border: configStatus.paypal ? "2px solid #4CAF50" : ""
371
+ },
372
+ hint: configStatus.paypal ? "This value is controlled by environment variables" : ""
373
+ }
374
+ )
375
+ ] })
376
+ ]
377
+ }
378
+ ) })
379
+ ] }),
380
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSave, style: { marginTop: "1rem" }, children: "Save Configuration" })
381
+ ]
382
+ }
383
+ )
384
+ ] }) })
385
+ ] });
386
+ };
387
+ const TransactionList = ({ transactions, onViewDetails, onStatusUpdate }) => {
388
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
389
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
390
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "ID" }),
391
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Amount" }),
392
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Currency" }),
393
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Status" }),
394
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Date" }),
395
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Customer" }),
396
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: "Actions" })
397
+ ] }) }),
398
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: transactions.map((transaction) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
399
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.id }),
400
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Td, { children: [
401
+ "$",
402
+ transaction.amount.toFixed(2)
403
+ ] }),
404
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.currency }),
405
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: onStatusUpdate ? /* @__PURE__ */ jsxRuntime.jsxs(
406
+ designSystem.SingleSelect,
407
+ {
408
+ value: transaction.status,
409
+ onChange: (e) => onStatusUpdate(transaction.id, e.target.value),
410
+ style: { minWidth: "120px" },
411
+ children: [
412
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
413
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "completed", children: "Completed" }),
414
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "failed", children: "Failed" }),
415
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "refunded", children: "Refunded" })
416
+ ]
417
+ }
418
+ ) : transaction.status }),
419
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: new Date(transaction.date).toLocaleDateString() }),
420
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: transaction.customer }),
421
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", size: "S", onClick: () => onViewDetails(transaction), children: "View" }) })
422
+ ] }, transaction.id)) })
423
+ ] });
424
+ };
425
+ const TransactionDetailsModal = ({
426
+ isOpen,
427
+ onClose,
428
+ transaction,
429
+ onRefund
430
+ }) => {
431
+ if (!transaction) return null;
432
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { onClick: onClose, children: [
433
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", children: "Transaction Details" }) }),
434
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, children: [
435
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", children: "Details" }),
436
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { marginTop: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
437
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
438
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Amount:" }),
439
+ " $",
440
+ transaction.amount.toFixed(2),
441
+ " ",
442
+ transaction.currency
443
+ ] }),
444
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
445
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Status:" }),
446
+ " ",
447
+ transaction.status
448
+ ] }),
449
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
450
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Date:" }),
451
+ " ",
452
+ new Date(transaction.date).toLocaleString()
453
+ ] }),
454
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
455
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Customer:" }),
456
+ " ",
457
+ transaction.customer
458
+ ] }),
459
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
460
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Payment Method:" }),
461
+ " ",
462
+ transaction.paymentMethod
463
+ ] }),
464
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { children: [
465
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Gateway:" }),
466
+ " ",
467
+ transaction.gateway
468
+ ] })
469
+ ] }) }),
470
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { style: { marginTop: "2rem", gap: "1rem" }, children: [
471
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: onClose, children: "Close" }),
472
+ transaction.status === "completed" && transaction.gateway !== "paypal" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "danger", onClick: onRefund, style: { marginLeft: "auto" }, children: "Refund" })
473
+ ] })
474
+ ] }) })
475
+ ] }) });
476
+ };
477
+ const TransactionsPage = () => {
478
+ const [searchTerm, setSearchTerm] = react.useState("");
479
+ const [filter, setFilter] = react.useState("all");
480
+ const [transactions, setTransactions] = react.useState([]);
481
+ const [loading, setLoading] = react.useState(false);
482
+ const [error, setError] = react.useState(null);
483
+ const [selectedTransaction, setSelectedTransaction] = react.useState(null);
484
+ const [isModalOpen, setIsModalOpen] = react.useState(false);
485
+ const handleSearch = (e) => {
486
+ setSearchTerm(e.target.value);
487
+ };
488
+ const handleFilterChange = (value) => {
489
+ setFilter(value);
490
+ };
491
+ const fetchTransactions = async () => {
492
+ setLoading(true);
493
+ setError(null);
494
+ try {
495
+ const response = await fetch("/payment-plugin/transactions");
496
+ if (!response.ok) {
497
+ throw new Error("Failed to fetch transactions");
498
+ }
499
+ const data = await response.json();
500
+ setTransactions(data.data);
501
+ } catch (err) {
502
+ if (err instanceof Error) {
503
+ setError(err.message);
504
+ } else {
505
+ setError("An unknown error occurred");
506
+ }
507
+ } finally {
508
+ setLoading(false);
509
+ }
510
+ };
511
+ react.useEffect(() => {
512
+ fetchTransactions();
513
+ }, []);
514
+ const filteredTransactions = transactions.filter((transaction) => {
515
+ const matchesSearch = [
516
+ transaction.id,
517
+ transaction.customer,
518
+ transaction.amount.toString()
519
+ ].some(
520
+ (field) => field.toLowerCase().includes(searchTerm.toLowerCase())
521
+ );
522
+ const matchesFilter = filter === "all" || transaction.status === filter;
523
+ return matchesSearch && matchesFilter;
524
+ });
525
+ const handleViewDetails = (transaction) => {
526
+ setSelectedTransaction(transaction);
527
+ setIsModalOpen(true);
528
+ };
529
+ const handleRefund = async () => {
530
+ if (!selectedTransaction) return;
531
+ try {
532
+ const response = await fetch("/payment-plugin/refund", {
533
+ method: "POST",
534
+ headers: {
535
+ "Content-Type": "application/json"
536
+ },
537
+ body: JSON.stringify({
538
+ gateway: selectedTransaction.gateway,
539
+ transactionId: selectedTransaction.id,
540
+ amount: selectedTransaction.amount
541
+ })
542
+ });
543
+ if (!response.ok) {
544
+ throw new Error("Failed to process refund");
545
+ }
546
+ const result = await response.json();
547
+ if (result.success) {
548
+ setTransactions(transactions.map(
549
+ (t) => t.id === selectedTransaction.id ? { ...t, status: "refunded" } : t
550
+ ));
551
+ setIsModalOpen(false);
552
+ } else {
553
+ throw new Error(result.message || "Refund failed");
554
+ }
555
+ } catch (err) {
556
+ if (err instanceof Error) {
557
+ setError(err.message);
558
+ } else {
559
+ setError("An unknown error occurred");
560
+ }
561
+ }
562
+ };
563
+ const handleStatusUpdate = async (transactionId, newStatus) => {
564
+ try {
565
+ setTransactions(transactions.map(
566
+ (t) => t.id === transactionId ? { ...t, status: newStatus } : t
567
+ ));
568
+ } catch (err) {
569
+ if (err instanceof Error) {
570
+ setError(err.message);
571
+ } else {
572
+ setError("An unknown error occurred");
573
+ }
574
+ }
575
+ };
576
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { children: [
577
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { title: "Transactions" }),
578
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
579
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Transactions" }),
580
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "danger", style: { marginBottom: "1rem" }, children: error }),
581
+ /* @__PURE__ */ jsxRuntime.jsxs(
582
+ designSystem.Box,
583
+ {
584
+ padding: 4,
585
+ background: "neutral100",
586
+ borderRadius: "4px",
587
+ border: "1px solid #e0e0e0",
588
+ children: [
589
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Transaction List" }),
590
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "1rem", display: "flex", gap: "1rem", alignItems: "center", flexWrap: "wrap" }, children: [
591
+ /* @__PURE__ */ jsxRuntime.jsx(
592
+ designSystem.TextInput,
593
+ {
594
+ label: "Search Transactions",
595
+ value: searchTerm,
596
+ onChange: handleSearch,
597
+ placeholder: "Search by ID, email, or amount",
598
+ style: { flex: 1, minWidth: "200px" }
599
+ }
600
+ ),
601
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelect, { value: filter, onChange: handleFilterChange, style: { minWidth: "150px" }, children: [
602
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "all", children: "All Transactions" }),
603
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "completed", children: "Successful" }),
604
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "failed", children: "Failed" }),
605
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "pending", children: "Pending" }),
606
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "refunded", children: "Refunded" })
607
+ ] })
608
+ ] }),
609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
610
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading transactions..." }),
611
+ !loading && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: filteredTransactions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
612
+ TransactionList,
613
+ {
614
+ transactions: filteredTransactions,
615
+ onViewDetails: handleViewDetails,
616
+ onStatusUpdate: handleStatusUpdate
617
+ }
618
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No transactions found" }) })
619
+ ] })
620
+ ]
621
+ }
622
+ )
623
+ ] }),
624
+ /* @__PURE__ */ jsxRuntime.jsx(
625
+ TransactionDetailsModal,
626
+ {
627
+ isOpen: isModalOpen,
628
+ onClose: () => setIsModalOpen(false),
629
+ transaction: selectedTransaction,
630
+ onRefund: handleRefund
631
+ }
632
+ )
633
+ ] });
634
+ };
635
+ const DashboardPage = () => {
636
+ const [transactions, setTransactions] = react.useState([]);
637
+ const [loading, setLoading] = react.useState(false);
638
+ const [error, setError] = react.useState(null);
639
+ const [stats, setStats] = react.useState({
640
+ totalRevenue: 0,
641
+ totalTransactions: 0,
642
+ successRate: 0
643
+ });
644
+ const fetchData = async () => {
645
+ setLoading(true);
646
+ setError(null);
647
+ try {
648
+ const response = await fetch("/payment-plugin/transactions");
649
+ if (!response.ok) {
650
+ throw new Error("Failed to fetch transactions");
651
+ }
652
+ const data = await response.json();
653
+ setTransactions(data.data.slice(0, 5));
654
+ const totalAmount = data.data.reduce(
655
+ (sum, t) => sum + t.amount,
656
+ 0
657
+ );
658
+ const successCount = data.data.filter(
659
+ (t) => t.status === "completed"
660
+ ).length;
661
+ const successRate = data.data.length > 0 ? successCount / data.data.length * 100 : 0;
662
+ setStats({
663
+ totalRevenue: totalAmount,
664
+ totalTransactions: data.data.length,
665
+ successRate
666
+ });
667
+ } catch (err) {
668
+ if (err instanceof Error) {
669
+ setError(err.message);
670
+ } else {
671
+ setError("An unknown error occurred");
672
+ }
673
+ } finally {
674
+ setLoading(false);
675
+ }
676
+ };
677
+ react.useEffect(() => {
678
+ fetchData();
679
+ }, []);
680
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { children: [
681
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { title: "Payment Dashboard" }),
682
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
683
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Payment Dashboard" }),
684
+ /* @__PURE__ */ jsxRuntime.jsxs(
685
+ designSystem.Box,
686
+ {
687
+ padding: 4,
688
+ background: "neutral100",
689
+ borderRadius: "4px",
690
+ border: "1px solid #e0e0e0",
691
+ style: { marginBottom: "2rem" },
692
+ children: [
693
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Payment Statistics" }),
694
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading statistics..." }),
695
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "red" }, children: error }),
696
+ !loading && !error && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
697
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Total Revenue" }),
699
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: [
700
+ "$",
701
+ stats.totalRevenue.toFixed(2)
702
+ ] })
703
+ ] }) }),
704
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
705
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Total Transactions" }),
706
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: stats.totalTransactions })
707
+ ] }) }),
708
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "neutral0", borderRadius: "4px", border: "1px solid #e0e0e0", children: [
709
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral800", children: "Successful Payments" }),
710
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "alpha", textColor: "primary600", children: [
711
+ stats.successRate.toFixed(2),
712
+ "%"
713
+ ] })
714
+ ] }) })
715
+ ] })
716
+ ]
717
+ }
718
+ ),
719
+ /* @__PURE__ */ jsxRuntime.jsxs(
720
+ designSystem.Box,
721
+ {
722
+ padding: 4,
723
+ background: "neutral100",
724
+ borderRadius: "4px",
725
+ border: "1px solid #e0e0e0",
726
+ children: [
727
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", style: { marginBottom: "1rem" }, children: "Recent Transactions" }),
728
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading transactions..." }),
729
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "red" }, children: error }),
730
+ !loading && !error && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: transactions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TransactionList, { transactions, onViewDetails: () => {
731
+ } }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No recent transactions" }) })
732
+ ]
733
+ }
734
+ )
735
+ ] })
736
+ ] });
737
+ };
738
+ const ProductsPage = () => {
739
+ const [products, setProducts] = react.useState([]);
740
+ const [loading, setLoading] = react.useState(false);
741
+ const [error, setError] = react.useState(null);
742
+ const [isModalOpen, setIsModalOpen] = react.useState(false);
743
+ const [currentProduct, setCurrentProduct] = react.useState(null);
744
+ const fetchProducts = async () => {
745
+ setLoading(true);
746
+ setError(null);
747
+ try {
748
+ const response = await fetch("/payment-plugin/products");
749
+ if (!response.ok) {
750
+ throw new Error("Failed to fetch products");
751
+ }
752
+ const data = await response.json();
753
+ setProducts(data);
754
+ } catch (err) {
755
+ if (err instanceof Error) {
756
+ setError(err.message);
757
+ } else {
758
+ setError("An unknown error occurred");
759
+ }
760
+ } finally {
761
+ setLoading(false);
762
+ }
763
+ };
764
+ react.useEffect(() => {
765
+ fetchProducts();
766
+ }, []);
767
+ const handleEdit = (product) => {
768
+ setCurrentProduct(product);
769
+ setIsModalOpen(true);
770
+ };
771
+ const handleDelete = async (id) => {
772
+ if (confirm("Are you sure you want to delete this product?")) {
773
+ try {
774
+ const response = await fetch(`/payment-plugin/products/${id}`, {
775
+ method: "DELETE"
776
+ });
777
+ if (!response.ok) {
778
+ throw new Error("Failed to delete product");
779
+ }
780
+ fetchProducts();
781
+ } catch (err) {
782
+ if (err instanceof Error) {
783
+ setError(err.message);
784
+ } else {
785
+ setError("An unknown error occurred");
786
+ }
787
+ }
788
+ }
789
+ };
790
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
791
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Products" }),
792
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "danger", style: { marginBottom: "1rem" }, children: error }),
793
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading products..." }),
794
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Root, { children: [
795
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { children: "Create product" }) }),
796
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
797
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Header, { children: [
798
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: currentProduct ? currentProduct.id ? "Edit Product" : "Create Product" : "Product" }),
799
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.CloseButton, {})
800
+ ] }),
801
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, {})
802
+ ] })
803
+ ] }),
804
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 4, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
805
+ designSystem.Box,
806
+ {
807
+ padding: 4,
808
+ background: "neutral100",
809
+ borderRadius: "4px",
810
+ border: "1px solid #e0e0e0",
811
+ children: [
812
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", children: product.name }),
813
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
814
+ product.price,
815
+ " ",
816
+ product.currency,
817
+ " ",
818
+ product.isSubscription ? `/ ${product.subscriptionInterval}` : ""
819
+ ] }),
820
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", style: { marginTop: "1rem" }, children: product.description }),
821
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { style: { marginTop: "1rem", gap: "1rem" }, children: [
822
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: () => handleEdit(product), children: "Edit" }),
823
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "danger", onClick: () => handleDelete(product.id), children: "Delete" })
824
+ ] })
825
+ ]
826
+ },
827
+ product.id
828
+ ) }, product.id)) })
829
+ ] }) });
830
+ };
831
+ const SubscriptionsPage = () => {
832
+ const [subscriptions, setSubscriptions] = react.useState([]);
833
+ const [products, setProducts] = react.useState([]);
834
+ const [loading, setLoading] = react.useState(false);
835
+ const [error, setError] = react.useState(null);
836
+ const [isModalOpen, setIsModalOpen] = react.useState(false);
837
+ const [currentSubscription, setCurrentSubscription] = react.useState(null);
838
+ const fetchSubscriptions = async () => {
839
+ setLoading(true);
840
+ setError(null);
841
+ try {
842
+ const response = await fetch("/payment-plugin/subscriptions");
843
+ if (!response.ok) {
844
+ throw new Error("Failed to fetch subscriptions");
845
+ }
846
+ const data = await response.json();
847
+ setSubscriptions(data);
848
+ } catch (err) {
849
+ if (err instanceof Error) {
850
+ setError(err.message);
851
+ } else {
852
+ setError("An unknown error occurred");
853
+ }
854
+ } finally {
855
+ setLoading(false);
856
+ }
857
+ };
858
+ const fetchProducts = async () => {
859
+ try {
860
+ const response = await fetch("/payment-plugin/products");
861
+ if (!response.ok) {
862
+ throw new Error("Failed to fetch products");
863
+ }
864
+ const data = await response.json();
865
+ setProducts(data);
866
+ } catch (err) {
867
+ console.error("Failed to fetch products:", err);
868
+ }
869
+ };
870
+ react.useEffect(() => {
871
+ fetchSubscriptions();
872
+ fetchProducts();
873
+ }, []);
874
+ const handleEdit = (subscription) => {
875
+ setCurrentSubscription(subscription);
876
+ setIsModalOpen(true);
877
+ };
878
+ const handleDelete = async (id) => {
879
+ if (confirm("Are you sure you want to delete this subscription?")) {
880
+ try {
881
+ const response = await fetch(`/payment-plugin/subscriptions/${id}`, {
882
+ method: "DELETE"
883
+ });
884
+ if (!response.ok) {
885
+ throw new Error("Failed to delete subscription");
886
+ }
887
+ fetchSubscriptions();
888
+ } catch (err) {
889
+ if (err instanceof Error) {
890
+ setError(err.message);
891
+ } else {
892
+ setError("An unknown error occurred");
893
+ }
894
+ }
895
+ }
896
+ };
897
+ const handleSubmit = async (values) => {
898
+ if (!currentSubscription) return;
899
+ try {
900
+ const method = currentSubscription.id ? "PUT" : "POST";
901
+ const url = currentSubscription.id ? `/payment-plugin/subscriptions/${currentSubscription.id}` : "/payment-plugin/subscriptions";
902
+ const response = await fetch(url, {
903
+ method,
904
+ headers: {
905
+ "Content-Type": "application/json"
906
+ },
907
+ body: JSON.stringify({ data: values })
908
+ });
909
+ if (!response.ok) {
910
+ throw new Error(`Failed to ${currentSubscription.id ? "update" : "create"} subscription`);
911
+ }
912
+ setIsModalOpen(false);
913
+ fetchSubscriptions();
914
+ } catch (err) {
915
+ if (err instanceof Error) {
916
+ setError(err.message);
917
+ } else {
918
+ setError("An unknown error occurred");
919
+ }
920
+ }
921
+ };
922
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 6, background: "neutral0", children: [
923
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", textColor: "primary600", style: { marginBottom: "2rem" }, children: "Subscriptions" }),
924
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "danger", style: { marginBottom: "1rem" }, children: error }),
925
+ loading && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading subscriptions..." }),
926
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Root, { children: [
927
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { children: "Create subscription" }) }),
928
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
929
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: currentSubscription ? currentSubscription.id ? "Edit Subscription" : "Create Subscription" : "Subscription" }) }),
930
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
931
+ formik.Formik,
932
+ {
933
+ initialValues: {
934
+ id: currentSubscription?.id || 0,
935
+ product: currentSubscription?.product || { id: 0, name: "" },
936
+ user: currentSubscription?.user || { id: 0, email: "" },
937
+ status: currentSubscription?.status || "active",
938
+ startDate: currentSubscription?.startDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
939
+ endDate: currentSubscription?.endDate || ""
940
+ },
941
+ onSubmit: handleSubmit,
942
+ children: ({ values, handleChange, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsx(formik.Form, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
943
+ /* @__PURE__ */ jsxRuntime.jsxs(
944
+ designSystem.SingleSelect,
945
+ {
946
+ placeholder: "Product",
947
+ name: "product.id",
948
+ value: values.product.id || "",
949
+ onChange: (e) => {
950
+ const selectedProduct = products.find(
951
+ (p) => p.id === parseInt(e.target.value)
952
+ );
953
+ setFieldValue("product", selectedProduct || { id: 0, name: "" });
954
+ },
955
+ required: true,
956
+ children: [
957
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select a product" }),
958
+ products.map((product) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: product.id, children: product.name }, product.id))
959
+ ]
960
+ }
961
+ ),
962
+ /* @__PURE__ */ jsxRuntime.jsx(
963
+ designSystem.TextInput,
964
+ {
965
+ placeholder: "User Email",
966
+ name: "user.email",
967
+ value: values.user.email,
968
+ onChange: handleChange,
969
+ required: true
970
+ }
971
+ ),
972
+ /* @__PURE__ */ jsxRuntime.jsxs(
973
+ designSystem.SingleSelect,
974
+ {
975
+ placeholder: "Status",
976
+ name: "status",
977
+ value: values.status,
978
+ onChange: handleChange,
979
+ children: [
980
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "active", children: "Active" }),
981
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "canceled", children: "Canceled" }),
982
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "past_due", children: "Past Due" }),
983
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "unpaid", children: "Unpaid" }),
984
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "trialing", children: "Trialing" })
985
+ ]
986
+ }
987
+ ),
988
+ /* @__PURE__ */ jsxRuntime.jsx(
989
+ designSystem.TextInput,
990
+ {
991
+ placeholder: "Start Date",
992
+ name: "startDate",
993
+ type: "date",
994
+ value: values.startDate,
995
+ onChange: handleChange,
996
+ required: true
997
+ }
998
+ ),
999
+ /* @__PURE__ */ jsxRuntime.jsx(
1000
+ designSystem.TextInput,
1001
+ {
1002
+ placeholder: "End Date",
1003
+ name: "endDate",
1004
+ type: "date",
1005
+ value: values.endDate,
1006
+ onChange: handleChange
1007
+ }
1008
+ ),
1009
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", style: { marginTop: "1rem" }, children: currentSubscription?.id ? "Update" : "Create" })
1010
+ ] }) })
1011
+ }
1012
+ ) }) })
1013
+ ] })
1014
+ ] }),
1015
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 4, children: subscriptions.map((subscription) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
1016
+ designSystem.Box,
1017
+ {
1018
+ padding: 4,
1019
+ background: "neutral100",
1020
+ borderRadius: "4px",
1021
+ border: "1px solid #e0e0e0",
1022
+ children: [
1023
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h2", textColor: "neutral800", children: subscription.product.name }),
1024
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
1025
+ "User: ",
1026
+ subscription.user.email
1027
+ ] }),
1028
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
1029
+ "Status: ",
1030
+ subscription.status
1031
+ ] }),
1032
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
1033
+ "Start Date: ",
1034
+ subscription.startDate
1035
+ ] }),
1036
+ subscription.endDate && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
1037
+ "End Date: ",
1038
+ subscription.endDate
1039
+ ] }),
1040
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { style: { marginTop: "1rem", gap: "1rem" }, children: [
1041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: () => handleEdit(subscription), children: "Edit" }),
1042
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "danger", onClick: () => handleDelete(subscription.id), children: "Delete" })
1043
+ ] })
1044
+ ]
1045
+ },
1046
+ subscription.id
1047
+ ) }, subscription.id)) })
1048
+ ] }) });
1049
+ };
1050
+ const NavigationMenu = () => {
1051
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1052
+ designSystem.Box,
1053
+ {
1054
+ background: "neutral100",
1055
+ padding: 4,
1056
+ width: "200px",
1057
+ height: "100vh",
1058
+ position: "fixed",
1059
+ top: 0,
1060
+ left: 100,
1061
+ children: [
1062
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", as: "h1", style: { marginBottom: "2rem" }, children: "Payment Plugin" }),
1063
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { style: { listStyle: "none", padding: 0, fontSize: "14px" }, children: [
1064
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1065
+ reactRouterDom.NavLink,
1066
+ {
1067
+ to: "/plugins/payment-plugin/",
1068
+ style: ({ isActive }) => ({
1069
+ color: isActive ? "#7b79ff" : "inherit",
1070
+ textDecoration: "none"
1071
+ }),
1072
+ children: "Home"
1073
+ }
1074
+ ) }),
1075
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1076
+ reactRouterDom.NavLink,
1077
+ {
1078
+ to: "/plugins/payment-plugin/dashboard",
1079
+ style: ({ isActive }) => ({
1080
+ color: isActive ? "#7b79ff" : "inherit",
1081
+ textDecoration: "none"
1082
+ }),
1083
+ children: "Dashboard"
1084
+ }
1085
+ ) }),
1086
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1087
+ reactRouterDom.NavLink,
1088
+ {
1089
+ to: "/plugins/payment-plugin/transactions",
1090
+ style: ({ isActive }) => ({
1091
+ color: isActive ? "#7b79ff" : "inherit",
1092
+ textDecoration: "none"
1093
+ }),
1094
+ children: "Transactions"
1095
+ }
1096
+ ) }),
1097
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1098
+ reactRouterDom.NavLink,
1099
+ {
1100
+ to: "/plugins/payment-plugin/products",
1101
+ style: ({ isActive }) => ({
1102
+ color: isActive ? "#7b79ff" : "inherit",
1103
+ textDecoration: "none"
1104
+ }),
1105
+ children: "Products"
1106
+ }
1107
+ ) }),
1108
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1109
+ reactRouterDom.NavLink,
1110
+ {
1111
+ to: "/plugins/payment-plugin/subscriptions",
1112
+ style: ({ isActive }) => ({
1113
+ color: isActive ? "#7b79ff" : "inherit",
1114
+ textDecoration: "none"
1115
+ }),
1116
+ children: "Subscriptions"
1117
+ }
1118
+ ) }),
1119
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
1120
+ reactRouterDom.NavLink,
1121
+ {
1122
+ to: "/plugins/payment-plugin/configuration",
1123
+ style: ({ isActive }) => ({
1124
+ color: isActive ? "#7b79ff" : "inherit",
1125
+ textDecoration: "none"
1126
+ }),
1127
+ children: "Configuration"
1128
+ }
1129
+ ) })
1130
+ ] }) })
1131
+ ]
1132
+ }
1133
+ );
1134
+ };
1135
+ const App = () => {
1136
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex" }, children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsx(NavigationMenu, {}),
1138
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginLeft: "200px", flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }),
1140
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/dashboard", element: /* @__PURE__ */ jsxRuntime.jsx(DashboardPage, {}) }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/transactions", element: /* @__PURE__ */ jsxRuntime.jsx(TransactionsPage, {}) }),
1142
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/products", element: /* @__PURE__ */ jsxRuntime.jsx(ProductsPage, {}) }),
1143
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/subscriptions", element: /* @__PURE__ */ jsxRuntime.jsx(SubscriptionsPage, {}) }),
1144
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/configuration", element: /* @__PURE__ */ jsxRuntime.jsx(ConfigurationPage, {}) }),
1145
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "*", element: /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Error, {}) })
1146
+ ] }) })
1147
+ ] });
1148
+ };
1149
+ exports.App = App;