@lodashventure/medusa-membership 0.4.13 → 0.4.15

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.
@@ -0,0 +1,1104 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const adminSdk = require("@medusajs/admin-sdk");
4
+ const ui = require("@medusajs/ui");
5
+ const axios = require("axios");
6
+ const react = require("react");
7
+ const Medusa = require("@medusajs/js-sdk");
8
+ const icons = require("@medusajs/icons");
9
+ require("@medusajs/admin-shared");
10
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
11
+ const axios__default = /* @__PURE__ */ _interopDefault(axios);
12
+ const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
13
+ const useMembershipConfig = (storeId, options) => {
14
+ const [data, setData] = react.useState(void 0);
15
+ const [isLoading, setIsLoading] = react.useState(true);
16
+ const [error, setError] = react.useState(null);
17
+ const fetchConfig = async () => {
18
+ if (!storeId) {
19
+ setError(new Error("No store id found"));
20
+ setIsLoading(false);
21
+ return;
22
+ }
23
+ try {
24
+ setIsLoading(true);
25
+ setError(null);
26
+ const { data: config2 } = await axios__default.default.get(
27
+ `/admin/membership/config/${storeId}`
28
+ );
29
+ setData(config2);
30
+ } catch (err) {
31
+ setError(
32
+ err instanceof Error ? err : new Error("Failed to fetch config")
33
+ );
34
+ } finally {
35
+ setIsLoading(false);
36
+ }
37
+ };
38
+ react.useEffect(() => {
39
+ fetchConfig();
40
+ }, [storeId, options == null ? void 0 : options.enabled]);
41
+ return {
42
+ data,
43
+ isLoading,
44
+ error,
45
+ refetch: fetchConfig
46
+ };
47
+ };
48
+ const sdk = new Medusa__default.default({
49
+ baseUrl: "/",
50
+ debug: false,
51
+ auth: {
52
+ type: "session"
53
+ }
54
+ });
55
+ const useStore = () => {
56
+ const [data, setData] = react.useState(void 0);
57
+ const [isLoading, setIsLoading] = react.useState(true);
58
+ const [error, setError] = react.useState(null);
59
+ const fetchStore = async () => {
60
+ var _a;
61
+ try {
62
+ setIsLoading(true);
63
+ setError(null);
64
+ const response = await sdk.admin.store.list();
65
+ const activeStore = (_a = response.stores) == null ? void 0 : _a[0];
66
+ if (!activeStore) {
67
+ throw new Error("No active store found");
68
+ }
69
+ setData(activeStore);
70
+ } catch (err) {
71
+ setError(err instanceof Error ? err : new Error("Failed to fetch store"));
72
+ } finally {
73
+ setIsLoading(false);
74
+ }
75
+ };
76
+ react.useEffect(() => {
77
+ fetchStore();
78
+ }, []);
79
+ return {
80
+ data,
81
+ isLoading,
82
+ error,
83
+ refetch: fetchStore
84
+ };
85
+ };
86
+ const usePromotionCollectable = (id) => {
87
+ const [data, setData] = react.useState(void 0);
88
+ const [isLoading, setIsLoading] = react.useState(true);
89
+ const [error, setError] = react.useState(null);
90
+ const fetchCollectable = async () => {
91
+ try {
92
+ setIsLoading(true);
93
+ setError(null);
94
+ const response = await axios__default.default.get(
95
+ `/admin/promotions/${id}/update-collectable`
96
+ );
97
+ setData(response);
98
+ } catch (err) {
99
+ setError(
100
+ err instanceof Error ? err : new Error("Failed to fetch collectable")
101
+ );
102
+ } finally {
103
+ setIsLoading(false);
104
+ }
105
+ };
106
+ react.useEffect(() => {
107
+ fetchCollectable();
108
+ }, [id]);
109
+ return {
110
+ data,
111
+ isLoading,
112
+ error,
113
+ refetch: fetchCollectable
114
+ };
115
+ };
116
+ const useUpdatePromotionCollectable = (id) => {
117
+ const [isPending, setIsPending] = react.useState(false);
118
+ const [error, setError] = react.useState(null);
119
+ const mutate = async (data, { onSuccess } = {}) => {
120
+ try {
121
+ setIsPending(true);
122
+ setError(null);
123
+ const response = await axios__default.default.patch(
124
+ `/admin/promotions/${id}/update-collectable`,
125
+ data
126
+ );
127
+ ui.toast.success("Coupon collection updated successfully", {
128
+ dismissable: true,
129
+ duration: 2500
130
+ });
131
+ if (onSuccess) {
132
+ onSuccess();
133
+ }
134
+ return response.data;
135
+ } catch (err) {
136
+ const error2 = err instanceof Error ? err : new Error("Failed to update coupon collection");
137
+ setError(error2);
138
+ ui.toast.error("Failed to update coupon collection", {
139
+ dismissable: true,
140
+ duration: 2500
141
+ });
142
+ throw error2;
143
+ } finally {
144
+ setIsPending(false);
145
+ }
146
+ };
147
+ return {
148
+ mutate,
149
+ isPending,
150
+ error
151
+ };
152
+ };
153
+ const PromotionWidget = ({ data }) => {
154
+ const { id } = data;
155
+ const { data: collectable } = usePromotionCollectable(id);
156
+ const { data: store } = useStore();
157
+ const { data: config2 } = useMembershipConfig(store == null ? void 0 : store.id);
158
+ const { mutate: updateCollectable } = useUpdatePromotionCollectable(id);
159
+ const handleToggleCollectable = async (checked) => {
160
+ try {
161
+ updateCollectable({
162
+ enabled: checked
163
+ });
164
+ ui.toast.success("Coupon collection updated successfully", {
165
+ dismissable: true,
166
+ duration: 2500
167
+ });
168
+ } catch (error) {
169
+ ui.toast.error("Failed to update coupon collection", {
170
+ dismissable: true,
171
+ duration: 2500
172
+ });
173
+ }
174
+ };
175
+ if (!(config2 == null ? void 0 : config2.enable_promotion_collection)) {
176
+ return null;
177
+ }
178
+ if (data.is_automatic) {
179
+ return null;
180
+ }
181
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-6 gap-4", children: [
182
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Coupon Collection" }) }),
183
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-2", children: [
184
+ /* @__PURE__ */ jsxRuntime.jsx(
185
+ ui.Switch,
186
+ {
187
+ checked: collectable == null ? void 0 : collectable.data.enabled,
188
+ onCheckedChange: handleToggleCollectable
189
+ }
190
+ ),
191
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Can be collected by customer" })
192
+ ] })
193
+ ] });
194
+ };
195
+ adminSdk.defineWidgetConfig({
196
+ zone: "promotion.details.side.after"
197
+ });
198
+ const useUpdateMembershipConfig = () => {
199
+ const [isPending, setIsPending] = react.useState(false);
200
+ const [error, setError] = react.useState(null);
201
+ const mutate = async ({ storeId, config: config2 }, {
202
+ onSuccess
203
+ } = {}) => {
204
+ if (!storeId) {
205
+ throw new Error("No store id found");
206
+ }
207
+ try {
208
+ setIsPending(true);
209
+ setError(null);
210
+ const response = await axios__default.default.patch(
211
+ `/admin/membership/config/${storeId}`,
212
+ config2
213
+ );
214
+ if (onSuccess) {
215
+ onSuccess(response.data);
216
+ }
217
+ return response.data;
218
+ } catch (err) {
219
+ const error2 = err instanceof Error ? err : new Error("Failed to update config");
220
+ setError(error2);
221
+ throw error2;
222
+ } finally {
223
+ setIsPending(false);
224
+ }
225
+ };
226
+ return {
227
+ mutate,
228
+ isPending,
229
+ error
230
+ };
231
+ };
232
+ const MembershipPage = () => {
233
+ const { data: store } = useStore();
234
+ const [config2, setConfig] = react.useState({
235
+ enable_membership: false,
236
+ membership_points_multiplier: 1,
237
+ enable_membership_notification: false,
238
+ enable_wishlist: true,
239
+ enable_promotion_collection: true
240
+ });
241
+ const { data: curConfig, error, refetch } = useMembershipConfig(store == null ? void 0 : store.id);
242
+ const { mutate: saveConfig, isPending } = useUpdateMembershipConfig();
243
+ const [spendingAmount, setSpendingAmount] = react.useState(
244
+ 1 / config2.membership_points_multiplier
245
+ );
246
+ react.useEffect(() => {
247
+ if (curConfig) {
248
+ setConfig(curConfig);
249
+ setSpendingAmount(1 / curConfig.membership_points_multiplier);
250
+ }
251
+ }, [curConfig]);
252
+ const handleSave = async () => {
253
+ var _a, _b;
254
+ try {
255
+ await saveConfig({
256
+ storeId: store == null ? void 0 : store.id,
257
+ config: config2
258
+ });
259
+ ui.toast.success("Settings saved successfully", {
260
+ dismissable: true,
261
+ duration: 2500
262
+ });
263
+ await refetch();
264
+ } catch (error2) {
265
+ if (axios__default.default.isAxiosError(error2)) {
266
+ ui.toast.error("Error saving settings", {
267
+ description: (_b = (_a = error2.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
268
+ dismissable: true,
269
+ duration: 2500
270
+ });
271
+ } else {
272
+ ui.toast.error("Error saving settings", {
273
+ dismissable: true,
274
+ duration: 2500
275
+ });
276
+ }
277
+ }
278
+ };
279
+ if (error || !config2) {
280
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
281
+ "Error: ",
282
+ error == null ? void 0 : error.message
283
+ ] });
284
+ }
285
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-8 rounded-lg", children: [
286
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold mb-4", children: "Membership Settings" }),
287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
288
+ /* @__PURE__ */ jsxRuntime.jsx(
289
+ ui.Switch,
290
+ {
291
+ checked: config2.enable_membership,
292
+ onCheckedChange: (checked) => setConfig((prev) => ({ ...prev, enable_membership: checked }))
293
+ }
294
+ ),
295
+ "Enable Membership points"
296
+ ] }),
297
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 mt-4", children: [
298
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Spending" }),
299
+ /* @__PURE__ */ jsxRuntime.jsx(
300
+ ui.Input,
301
+ {
302
+ className: "w-32",
303
+ type: "number",
304
+ value: spendingAmount,
305
+ onChange: (e) => {
306
+ const value = Number(e.target.value) || 0;
307
+ const ratio = 1 / value;
308
+ setConfig((prev) => ({
309
+ ...prev,
310
+ membership_points_multiplier: ratio
311
+ }));
312
+ setSpendingAmount(value);
313
+ }
314
+ }
315
+ ),
316
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "To get 1 point" })
317
+ ] }),
318
+ /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "my-4" }),
319
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 my-2", children: [
320
+ /* @__PURE__ */ jsxRuntime.jsx(
321
+ ui.Switch,
322
+ {
323
+ checked: config2.enable_membership_notification,
324
+ onCheckedChange: (checked) => setConfig((prev) => ({
325
+ ...prev,
326
+ enable_membership_notification: checked
327
+ }))
328
+ }
329
+ ),
330
+ "Enable Membership Notification"
331
+ ] }),
332
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 my-2", children: [
333
+ /* @__PURE__ */ jsxRuntime.jsx(
334
+ ui.Switch,
335
+ {
336
+ checked: config2.enable_wishlist,
337
+ onCheckedChange: (checked) => setConfig((prev) => ({
338
+ ...prev,
339
+ enable_wishlist: checked
340
+ }))
341
+ }
342
+ ),
343
+ "Enable Membership Wishlist"
344
+ ] }),
345
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 my-2", children: [
346
+ /* @__PURE__ */ jsxRuntime.jsx(
347
+ ui.Switch,
348
+ {
349
+ checked: config2.enable_promotion_collection,
350
+ onCheckedChange: (checked) => setConfig((prev) => ({
351
+ ...prev,
352
+ enable_promotion_collection: checked
353
+ }))
354
+ }
355
+ ),
356
+ "Enable Promotion Collection"
357
+ ] }),
358
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: handleSave, disabled: isPending, className: "mt-5", children: isPending ? "Saving..." : "Save Settings" })
359
+ ] });
360
+ };
361
+ const BannerUpload = () => {
362
+ return /* @__PURE__ */ jsxRuntime.jsx(MembershipPage, {});
363
+ };
364
+ const config$2 = adminSdk.defineRouteConfig({
365
+ label: "Membership",
366
+ icon: icons.Users
367
+ });
368
+ const useCreateMembershipConsent = () => {
369
+ const [isPending, setIsPending] = react.useState(false);
370
+ const [error, setError] = react.useState(null);
371
+ const mutate = async (data, { onSuccess } = {}) => {
372
+ try {
373
+ setIsPending(true);
374
+ setError(null);
375
+ const response = await axios__default.default.post("/admin/membership-consents", data);
376
+ if (onSuccess) {
377
+ onSuccess();
378
+ }
379
+ return response.data;
380
+ } catch (err) {
381
+ const error2 = err instanceof Error ? err : new Error("Failed to create consent");
382
+ setError(error2);
383
+ throw error2;
384
+ } finally {
385
+ setIsPending(false);
386
+ }
387
+ };
388
+ return {
389
+ mutate,
390
+ isPending,
391
+ error
392
+ };
393
+ };
394
+ const useDeleteMembershipConsent = () => {
395
+ const [isPending, setIsPending] = react.useState(false);
396
+ const [error, setError] = react.useState(null);
397
+ const mutate = async (id, { onSuccess } = {}) => {
398
+ try {
399
+ setIsPending(true);
400
+ setError(null);
401
+ await axios__default.default.delete(`/admin/membership-consents/${id}`);
402
+ if (onSuccess) {
403
+ onSuccess();
404
+ }
405
+ } catch (err) {
406
+ const error2 = err instanceof Error ? err : new Error("Failed to delete consent");
407
+ setError(error2);
408
+ throw error2;
409
+ } finally {
410
+ setIsPending(false);
411
+ }
412
+ };
413
+ return {
414
+ mutate,
415
+ isPending,
416
+ error
417
+ };
418
+ };
419
+ const useMembershipConsents = () => {
420
+ const [data, setData] = react.useState(void 0);
421
+ const [isLoading, setIsLoading] = react.useState(true);
422
+ const [error, setError] = react.useState(null);
423
+ const fetchConsents = async () => {
424
+ try {
425
+ setIsLoading(true);
426
+ setError(null);
427
+ const response = await axios__default.default.get("/admin/membership-consents");
428
+ setData(
429
+ response.data
430
+ );
431
+ } catch (err) {
432
+ setError(
433
+ err instanceof Error ? err : new Error("Failed to fetch consents")
434
+ );
435
+ } finally {
436
+ setIsLoading(false);
437
+ }
438
+ };
439
+ react.useEffect(() => {
440
+ fetchConsents();
441
+ }, []);
442
+ return {
443
+ data,
444
+ isLoading,
445
+ error,
446
+ refetch: fetchConsents
447
+ };
448
+ };
449
+ const useUpdateMembershipConsent = () => {
450
+ const [isPending, setIsPending] = react.useState(false);
451
+ const [error, setError] = react.useState(null);
452
+ const mutate = async (consentKey, { onSuccess } = {}) => {
453
+ try {
454
+ setIsPending(true);
455
+ setError(null);
456
+ const response = await axios__default.default.patch(
457
+ `/admin/membership-consents/${consentKey.id}`,
458
+ {
459
+ name: consentKey.name,
460
+ description: consentKey.description
461
+ }
462
+ );
463
+ if (onSuccess) {
464
+ onSuccess();
465
+ }
466
+ return response.data;
467
+ } catch (err) {
468
+ const error2 = err instanceof Error ? err : new Error("Failed to update consent");
469
+ setError(error2);
470
+ throw error2;
471
+ } finally {
472
+ setIsPending(false);
473
+ }
474
+ };
475
+ return {
476
+ mutate,
477
+ isPending,
478
+ error
479
+ };
480
+ };
481
+ const columnHelper$1 = ui.createDataTableColumnHelper();
482
+ const columns$1 = [
483
+ columnHelper$1.accessor("name", {
484
+ header: "Name"
485
+ }),
486
+ columnHelper$1.accessor("description", {
487
+ header: "Description",
488
+ maxSize: 250
489
+ })
490
+ ];
491
+ const MembershipConsentsRenderer = () => {
492
+ const dialog = ui.usePrompt();
493
+ const [pagination, setPagination] = react.useState({
494
+ pageSize: 1e3,
495
+ pageIndex: 0
496
+ });
497
+ const [isDrawerOpen, setIsDrawerOpen] = react.useState(false);
498
+ const [editingConsent, setEditingConsent] = react.useState(null);
499
+ const [formData, setFormData] = react.useState({
500
+ name: "",
501
+ description: ""
502
+ });
503
+ const { data, isLoading, refetch } = useMembershipConsents();
504
+ const createConsent = useCreateMembershipConsent();
505
+ const updateConsent = useUpdateMembershipConsent();
506
+ const deleteConsent = useDeleteMembershipConsent();
507
+ const table = ui.useDataTable({
508
+ columns: columns$1,
509
+ data: (data == null ? void 0 : data.consent_keys) || [],
510
+ getRowId: (consent) => consent.id,
511
+ rowCount: (data == null ? void 0 : data.count) || 0,
512
+ isLoading,
513
+ pagination: {
514
+ state: pagination,
515
+ onPaginationChange: setPagination
516
+ },
517
+ onRowClick: (_, row) => {
518
+ openDrawer(row.original);
519
+ }
520
+ });
521
+ const handleInputChange = (e) => {
522
+ const { name, value } = e.target;
523
+ setFormData((prev) => ({
524
+ ...prev,
525
+ [name]: name === "min_points" ? Number(value) : value
526
+ }));
527
+ };
528
+ const handleTextAreaChange = (e) => {
529
+ const { name, value } = e.target;
530
+ setFormData((prev) => ({
531
+ ...prev,
532
+ [name]: value
533
+ }));
534
+ };
535
+ const handleReset = () => {
536
+ setFormData({
537
+ name: "",
538
+ description: ""
539
+ });
540
+ };
541
+ const openDrawer = (consentKey) => {
542
+ if (consentKey) {
543
+ setEditingConsent(consentKey);
544
+ setFormData({
545
+ name: consentKey.name,
546
+ description: consentKey.description
547
+ });
548
+ } else {
549
+ setEditingConsent(null);
550
+ handleReset();
551
+ }
552
+ setIsDrawerOpen(true);
553
+ };
554
+ const closeDrawer = () => {
555
+ setIsDrawerOpen(false);
556
+ setEditingConsent(null);
557
+ handleReset();
558
+ refetch();
559
+ };
560
+ const handleSubmit = async () => {
561
+ var _a, _b;
562
+ try {
563
+ if (!formData.name) {
564
+ ui.toast.error("Name is required", { dismissable: true, duration: 2500 });
565
+ return;
566
+ }
567
+ if (editingConsent) {
568
+ await updateConsent.mutateAsync({ id: editingConsent.id, ...formData });
569
+ ui.toast.success("Consent updated successfully", {
570
+ dismissable: true,
571
+ duration: 2500
572
+ });
573
+ } else {
574
+ await createConsent.mutateAsync(formData);
575
+ ui.toast.success("Consent created successfully", {
576
+ dismissable: true,
577
+ duration: 2500
578
+ });
579
+ }
580
+ closeDrawer();
581
+ } catch (error) {
582
+ if (axios__default.default.isAxiosError(error)) {
583
+ ui.toast.error("Error saving consent", {
584
+ description: (_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
585
+ dismissable: true,
586
+ duration: 2500
587
+ });
588
+ } else {
589
+ ui.toast.error("Error saving consent", {
590
+ dismissable: true,
591
+ duration: 2500
592
+ });
593
+ }
594
+ }
595
+ };
596
+ const handleDelete = async (id) => {
597
+ var _a, _b;
598
+ try {
599
+ const confirmed = await dialog({
600
+ title: "Delete Membership Consent",
601
+ description: `Are you sure you want to delete the \`${editingConsent == null ? void 0 : editingConsent.name}\` consent?`
602
+ });
603
+ if (!confirmed) {
604
+ return;
605
+ }
606
+ await deleteConsent.mutateAsync(id);
607
+ ui.toast.success("Consent deleted successfully", {
608
+ dismissable: true,
609
+ duration: 2500
610
+ });
611
+ closeDrawer();
612
+ } catch (error) {
613
+ if (axios__default.default.isAxiosError(error)) {
614
+ ui.toast.error("Error deleting consent", {
615
+ description: (_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
616
+ dismissable: true,
617
+ duration: 2500
618
+ });
619
+ } else {
620
+ ui.toast.error("Error deleting consent", {
621
+ dismissable: true,
622
+ duration: 2500
623
+ });
624
+ }
625
+ }
626
+ };
627
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
628
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "flex flex-col p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
629
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable.Toolbar, { className: "flex flex-col items-start justify-between gap-2 md:flex-row md:items-center", children: [
630
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Membership Consents" }),
631
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: () => openDrawer(), children: "Add Consent" })
632
+ ] }),
633
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {})
634
+ ] }) }),
635
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: isDrawerOpen, onOpenChange: setIsDrawerOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
636
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: editingConsent ? "Edit Consent" : "Add Consent" }) }),
637
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Body, { "aria-description": "Membership Consent Form", children: [
638
+ /* @__PURE__ */ jsxRuntime.jsxs(
639
+ "div",
640
+ {
641
+ className: "space-y-4",
642
+ "aria-description": "Membership Consent Form",
643
+ children: [
644
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Name" }),
645
+ /* @__PURE__ */ jsxRuntime.jsx(
646
+ ui.Input,
647
+ {
648
+ name: "name",
649
+ value: formData.name,
650
+ onChange: handleInputChange
651
+ }
652
+ ),
653
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Description" }),
654
+ /* @__PURE__ */ jsxRuntime.jsx(
655
+ ui.Textarea,
656
+ {
657
+ className: "truncate",
658
+ name: "description",
659
+ value: formData.description,
660
+ onChange: handleTextAreaChange
661
+ }
662
+ )
663
+ ]
664
+ }
665
+ ),
666
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 mt-6", children: [
667
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: closeDrawer, children: "Cancel" }),
668
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: handleSubmit, children: editingConsent ? "Update" : "Create" })
669
+ ] })
670
+ ] }),
671
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Footer, { className: "flex justify-start", children: editingConsent && /* @__PURE__ */ jsxRuntime.jsx(
672
+ ui.Button,
673
+ {
674
+ variant: "danger",
675
+ onClick: () => {
676
+ handleDelete(editingConsent.id);
677
+ },
678
+ children: "Delete"
679
+ }
680
+ ) })
681
+ ] }) })
682
+ ] });
683
+ };
684
+ const MembershipConsentPage = () => {
685
+ return /* @__PURE__ */ jsxRuntime.jsx(MembershipConsentsRenderer, {});
686
+ };
687
+ const config$1 = adminSdk.defineRouteConfig({
688
+ label: "Membership Consents"
689
+ });
690
+ const useCreateMembershipTier = () => {
691
+ const [isPending, setIsPending] = react.useState(false);
692
+ const [error, setError] = react.useState(null);
693
+ const mutate = async (data, { onSuccess } = {}) => {
694
+ try {
695
+ setIsPending(true);
696
+ setError(null);
697
+ const response = await axios__default.default.post("/admin/member-tiers", data);
698
+ if (onSuccess) {
699
+ onSuccess();
700
+ }
701
+ return response.data;
702
+ } catch (err) {
703
+ const error2 = err instanceof Error ? err : new Error("Failed to create tier");
704
+ setError(error2);
705
+ throw error2;
706
+ } finally {
707
+ setIsPending(false);
708
+ }
709
+ };
710
+ return {
711
+ mutate,
712
+ isPending,
713
+ error
714
+ };
715
+ };
716
+ const useDeleteMembershipTier = () => {
717
+ const [isPending, setIsPending] = react.useState(false);
718
+ const [error, setError] = react.useState(null);
719
+ const mutate = async (id, { onSuccess } = {}) => {
720
+ try {
721
+ setIsPending(true);
722
+ setError(null);
723
+ await axios__default.default.delete(`/admin/member-tiers/${id}`);
724
+ if (onSuccess) {
725
+ onSuccess();
726
+ }
727
+ } catch (err) {
728
+ const error2 = err instanceof Error ? err : new Error("Failed to delete tier");
729
+ setError(error2);
730
+ throw error2;
731
+ } finally {
732
+ setIsPending(false);
733
+ }
734
+ };
735
+ return {
736
+ mutate,
737
+ isPending,
738
+ error
739
+ };
740
+ };
741
+ const useMembershipTiers = (params = {
742
+ limit: 15,
743
+ offset: 0,
744
+ order: {
745
+ min_points: "ASC"
746
+ }
747
+ }) => {
748
+ var _a;
749
+ const [data, setData] = react.useState(void 0);
750
+ const [isLoading, setIsLoading] = react.useState(true);
751
+ const [error, setError] = react.useState(null);
752
+ const fetchTiers = async () => {
753
+ try {
754
+ setIsLoading(true);
755
+ setError(null);
756
+ const response = await axios__default.default.get("/admin/member-tiers", {
757
+ params
758
+ });
759
+ setData(
760
+ response.data
761
+ );
762
+ } catch (err) {
763
+ setError(err instanceof Error ? err : new Error("Failed to fetch tiers"));
764
+ } finally {
765
+ setIsLoading(false);
766
+ }
767
+ };
768
+ react.useEffect(() => {
769
+ fetchTiers();
770
+ }, [params.limit, params.offset, (_a = params.order) == null ? void 0 : _a.min_points]);
771
+ return {
772
+ data,
773
+ isLoading,
774
+ error,
775
+ refetch: fetchTiers
776
+ };
777
+ };
778
+ const useUpdateMembershipTier = () => {
779
+ const [isPending, setIsPending] = react.useState(false);
780
+ const [error, setError] = react.useState(null);
781
+ const mutate = async (tier, { onSuccess } = {}) => {
782
+ try {
783
+ setIsPending(true);
784
+ setError(null);
785
+ const response = await axios__default.default.patch(`/admin/member-tiers/${tier.id}`, {
786
+ name: tier.name,
787
+ description: tier.description,
788
+ privilege_description: tier.privilege_description,
789
+ min_points: tier.min_points
790
+ });
791
+ if (onSuccess) {
792
+ onSuccess();
793
+ }
794
+ return response.data;
795
+ } catch (err) {
796
+ const error2 = err instanceof Error ? err : new Error("Failed to update tier");
797
+ setError(error2);
798
+ throw error2;
799
+ } finally {
800
+ setIsPending(false);
801
+ }
802
+ };
803
+ return {
804
+ mutate,
805
+ isPending,
806
+ error
807
+ };
808
+ };
809
+ const columnHelper = ui.createDataTableColumnHelper();
810
+ const columns = [
811
+ columnHelper.accessor("min_points", {
812
+ header: "Min Points"
813
+ }),
814
+ columnHelper.accessor("name", {
815
+ header: "Name"
816
+ }),
817
+ columnHelper.accessor("description", {
818
+ header: "Description",
819
+ maxSize: 250
820
+ }),
821
+ columnHelper.accessor("privilege_description", {
822
+ header: "Privilege Description",
823
+ maxSize: 250
824
+ })
825
+ ];
826
+ const MembershipTierRenderer = () => {
827
+ const dialog = ui.usePrompt();
828
+ const [pagination, setPagination] = react.useState({
829
+ pageSize: 1e3,
830
+ pageIndex: 0
831
+ });
832
+ const [isDrawerOpen, setIsDrawerOpen] = react.useState(false);
833
+ const [editingTier, setEditingTier] = react.useState(null);
834
+ const [formData, setFormData] = react.useState({
835
+ name: "",
836
+ description: "",
837
+ privilege_description: "",
838
+ min_points: 0
839
+ });
840
+ const { data, isLoading, refetch } = useMembershipTiers({
841
+ limit: pagination.pageSize,
842
+ offset: pagination.pageIndex * pagination.pageSize
843
+ });
844
+ const createTier = useCreateMembershipTier();
845
+ const updateTier = useUpdateMembershipTier();
846
+ const deleteTier = useDeleteMembershipTier();
847
+ const table = ui.useDataTable({
848
+ columns,
849
+ data: (data == null ? void 0 : data.tiers) || [],
850
+ getRowId: (tier) => tier.id,
851
+ rowCount: (data == null ? void 0 : data.count) || 0,
852
+ isLoading,
853
+ pagination: {
854
+ state: pagination,
855
+ onPaginationChange: setPagination
856
+ },
857
+ onRowClick: (_, row) => {
858
+ openDrawer(row.original);
859
+ }
860
+ });
861
+ const handleInputChange = (e) => {
862
+ const { name, value } = e.target;
863
+ setFormData((prev) => ({
864
+ ...prev,
865
+ [name]: name === "min_points" ? Number(value) : value
866
+ }));
867
+ };
868
+ const handleTextAreaChange = (e) => {
869
+ const { name, value } = e.target;
870
+ setFormData((prev) => ({
871
+ ...prev,
872
+ [name]: value
873
+ }));
874
+ };
875
+ const handleReset = () => {
876
+ setFormData({
877
+ name: "",
878
+ description: "",
879
+ privilege_description: "",
880
+ min_points: 0
881
+ });
882
+ };
883
+ const openDrawer = (tier) => {
884
+ if (tier) {
885
+ setEditingTier(tier);
886
+ setFormData({
887
+ name: tier.name,
888
+ description: tier.description,
889
+ privilege_description: tier.privilege_description,
890
+ min_points: tier.min_points
891
+ });
892
+ } else {
893
+ setEditingTier(null);
894
+ handleReset();
895
+ }
896
+ setIsDrawerOpen(true);
897
+ };
898
+ const closeDrawer = () => {
899
+ setIsDrawerOpen(false);
900
+ setEditingTier(null);
901
+ handleReset();
902
+ refetch();
903
+ };
904
+ const handleSubmit = async () => {
905
+ var _a, _b;
906
+ try {
907
+ if (!formData.name) {
908
+ ui.toast.error("Name is required", { dismissable: true, duration: 2500 });
909
+ return;
910
+ }
911
+ if (editingTier) {
912
+ await updateTier.mutateAsync({ id: editingTier.id, ...formData });
913
+ ui.toast.success("Tier updated successfully", {
914
+ dismissable: true,
915
+ duration: 2500
916
+ });
917
+ } else {
918
+ await createTier.mutateAsync(formData);
919
+ ui.toast.success("Tier created successfully", {
920
+ dismissable: true,
921
+ duration: 2500
922
+ });
923
+ }
924
+ closeDrawer();
925
+ } catch (error) {
926
+ if (axios__default.default.isAxiosError(error)) {
927
+ ui.toast.error("Error saving tier", {
928
+ description: (_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
929
+ dismissable: true,
930
+ duration: 2500
931
+ });
932
+ } else {
933
+ ui.toast.error("Error saving tier", {
934
+ dismissable: true,
935
+ duration: 2500
936
+ });
937
+ }
938
+ }
939
+ };
940
+ const handleDelete = async (id) => {
941
+ var _a, _b;
942
+ try {
943
+ const confirmed = await dialog({
944
+ title: "Delete Membership Tier",
945
+ description: `Are you sure you want to delete the \`${editingTier == null ? void 0 : editingTier.name}\` tier?`
946
+ });
947
+ if (!confirmed) {
948
+ return;
949
+ }
950
+ await deleteTier.mutateAsync(id);
951
+ ui.toast.success("Tier deleted successfully", {
952
+ dismissable: true,
953
+ duration: 2500
954
+ });
955
+ closeDrawer();
956
+ } catch (error) {
957
+ if (axios__default.default.isAxiosError(error)) {
958
+ ui.toast.error("Error deleting tier", {
959
+ description: (_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
960
+ dismissable: true,
961
+ duration: 2500
962
+ });
963
+ } else {
964
+ ui.toast.error("Error deleting tier", {
965
+ dismissable: true,
966
+ duration: 2500
967
+ });
968
+ }
969
+ }
970
+ };
971
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
972
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "flex flex-col p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
973
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable.Toolbar, { className: "flex flex-col items-start justify-between gap-2 md:flex-row md:items-center", children: [
974
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Membership Tiers" }),
975
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: () => openDrawer(), children: "Add Tier" })
976
+ ] }),
977
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {})
978
+ ] }) }),
979
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: isDrawerOpen, onOpenChange: setIsDrawerOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
980
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: editingTier ? "Edit Tier" : "Add Tier" }) }),
981
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Body, { "aria-description": "Membership Tier Form", children: [
982
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "aria-description": "Membership Tier Form", children: [
983
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Name" }),
984
+ /* @__PURE__ */ jsxRuntime.jsx(
985
+ ui.Input,
986
+ {
987
+ name: "name",
988
+ value: formData.name,
989
+ onChange: handleInputChange
990
+ }
991
+ ),
992
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Description" }),
993
+ /* @__PURE__ */ jsxRuntime.jsx(
994
+ ui.Textarea,
995
+ {
996
+ className: "truncate",
997
+ name: "description",
998
+ value: formData.description,
999
+ onChange: handleTextAreaChange
1000
+ }
1001
+ ),
1002
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Privilege Description" }),
1003
+ /* @__PURE__ */ jsxRuntime.jsx(
1004
+ ui.Textarea,
1005
+ {
1006
+ className: "truncate",
1007
+ name: "privilege_description",
1008
+ value: formData.privilege_description,
1009
+ onChange: handleTextAreaChange
1010
+ }
1011
+ ),
1012
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Points" }),
1013
+ /* @__PURE__ */ jsxRuntime.jsx(
1014
+ ui.Input,
1015
+ {
1016
+ name: "min_points",
1017
+ type: "number",
1018
+ value: formData.min_points,
1019
+ onChange: handleInputChange
1020
+ }
1021
+ )
1022
+ ] }),
1023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 mt-6", children: [
1024
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: closeDrawer, children: "Cancel" }),
1025
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: handleSubmit, children: editingTier ? "Update" : "Create" })
1026
+ ] })
1027
+ ] }),
1028
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Footer, { className: "flex justify-start", children: editingTier && /* @__PURE__ */ jsxRuntime.jsx(
1029
+ ui.Button,
1030
+ {
1031
+ variant: "danger",
1032
+ onClick: () => {
1033
+ handleDelete(editingTier.id);
1034
+ },
1035
+ children: "Delete"
1036
+ }
1037
+ ) })
1038
+ ] }) })
1039
+ ] });
1040
+ };
1041
+ const MembershipTierPage = () => {
1042
+ return /* @__PURE__ */ jsxRuntime.jsx(MembershipTierRenderer, {});
1043
+ };
1044
+ const config = adminSdk.defineRouteConfig({
1045
+ label: "Membership Tiers"
1046
+ });
1047
+ const widgetModule = { widgets: [
1048
+ {
1049
+ Component: PromotionWidget,
1050
+ zone: ["promotion.details.side.after"]
1051
+ }
1052
+ ] };
1053
+ const routeModule = {
1054
+ routes: [
1055
+ {
1056
+ Component: BannerUpload,
1057
+ path: "/membership"
1058
+ },
1059
+ {
1060
+ Component: MembershipConsentPage,
1061
+ path: "/membership/member-consents"
1062
+ },
1063
+ {
1064
+ Component: MembershipTierPage,
1065
+ path: "/membership/membertier"
1066
+ }
1067
+ ]
1068
+ };
1069
+ const menuItemModule = {
1070
+ menuItems: [
1071
+ {
1072
+ label: config$2.label,
1073
+ icon: config$2.icon,
1074
+ path: "/membership",
1075
+ nested: void 0
1076
+ },
1077
+ {
1078
+ label: config$1.label,
1079
+ icon: void 0,
1080
+ path: "/membership/member-consents",
1081
+ nested: void 0
1082
+ },
1083
+ {
1084
+ label: config.label,
1085
+ icon: void 0,
1086
+ path: "/membership/membertier",
1087
+ nested: void 0
1088
+ }
1089
+ ]
1090
+ };
1091
+ const formModule = { customFields: {} };
1092
+ const displayModule = {
1093
+ displays: {}
1094
+ };
1095
+ const i18nModule = { resources: {} };
1096
+ const plugin = {
1097
+ widgetModule,
1098
+ routeModule,
1099
+ menuItemModule,
1100
+ formModule,
1101
+ displayModule,
1102
+ i18nModule
1103
+ };
1104
+ module.exports = plugin;