@kb0912/notification-brevo 2.0.2 → 2.0.3
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/.medusa/server/src/admin/index.js +130 -88
- package/.medusa/server/src/admin/index.mjs +130 -88
- package/.medusa/server/src/modules/brevo-settings/migrations/Migration20260307170711.js +14 -0
- package/.medusa/server/src/modules/brevo-settings/migrations/Migration20260308000200.js +14 -0
- package/package.json +1 -1
|
@@ -145,22 +145,104 @@ const config$1 = adminSdk.defineRouteConfig({
|
|
|
145
145
|
label: "Email Analytics",
|
|
146
146
|
icon: icons.ChartBar
|
|
147
147
|
});
|
|
148
|
+
const MultiSelectModal = ({
|
|
149
|
+
title,
|
|
150
|
+
options,
|
|
151
|
+
selected,
|
|
152
|
+
onClose,
|
|
153
|
+
onSave
|
|
154
|
+
}) => {
|
|
155
|
+
const [search, setSearch] = react.useState("");
|
|
156
|
+
const [checked, setChecked] = react.useState(new Set(selected));
|
|
157
|
+
const filtered = options.filter(
|
|
158
|
+
(o) => o.label.toLowerCase().includes(search.toLowerCase()) || o.value.toLowerCase().includes(search.toLowerCase())
|
|
159
|
+
);
|
|
160
|
+
const toggle = (val) => {
|
|
161
|
+
setChecked((prev) => {
|
|
162
|
+
const next = new Set(prev);
|
|
163
|
+
next.has(val) ? next.delete(val) : next.add(val);
|
|
164
|
+
return next;
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-2xl w-[420px] max-h-[520px] flex flex-col", onClick: (e) => e.stopPropagation(), children: [
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-5 py-4 border-b", children: [
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-semibold text-base", children: title }),
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
171
|
+
ui.Input,
|
|
172
|
+
{
|
|
173
|
+
className: "mt-2",
|
|
174
|
+
placeholder: "Search...",
|
|
175
|
+
value: search,
|
|
176
|
+
onChange: (e) => setSearch(e.target.value)
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-3", children: [
|
|
181
|
+
filtered.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: "No results" }),
|
|
182
|
+
filtered.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-3 py-1.5 cursor-pointer hover:bg-ui-bg-base-hover rounded px-2 -mx-2", children: [
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
184
|
+
"input",
|
|
185
|
+
{
|
|
186
|
+
type: "checkbox",
|
|
187
|
+
className: "accent-ui-fg-interactive w-4 h-4",
|
|
188
|
+
checked: checked.has(opt.value),
|
|
189
|
+
onChange: () => toggle(opt.value)
|
|
190
|
+
}
|
|
191
|
+
),
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: opt.label }),
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-ui-fg-subtle font-mono ml-auto", children: opt.value.toUpperCase() })
|
|
194
|
+
] }, opt.value))
|
|
195
|
+
] }),
|
|
196
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-5 py-3 border-t flex items-center justify-between", children: [
|
|
197
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-xs text-ui-fg-subtle", children: [
|
|
198
|
+
checked.size,
|
|
199
|
+
" selected"
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
202
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: onClose, children: "Cancel" }),
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", onClick: () => {
|
|
204
|
+
onSave(Array.from(checked));
|
|
205
|
+
onClose();
|
|
206
|
+
}, children: "Apply" })
|
|
207
|
+
] })
|
|
208
|
+
] })
|
|
209
|
+
] }) });
|
|
210
|
+
};
|
|
148
211
|
const BrevoSettingsPage = () => {
|
|
149
212
|
const [settings, setSettings] = react.useState(null);
|
|
150
213
|
const [loading, setLoading] = react.useState(true);
|
|
151
214
|
const [saving, setSaving] = react.useState(false);
|
|
152
215
|
const [intervalsText, setIntervalsText] = react.useState("");
|
|
153
216
|
const [currencies, setCurrencies] = react.useState([]);
|
|
217
|
+
const [countries, setCountries] = react.useState([]);
|
|
218
|
+
const [modal, setModal] = react.useState(null);
|
|
154
219
|
react.useEffect(() => {
|
|
155
220
|
Promise.all([
|
|
156
221
|
fetch("/admin/brevo-plugin-settings", { credentials: "include" }).then((r) => r.json()),
|
|
157
|
-
fetch("/admin/currencies", { credentials: "include" }).then((r) => r.json()).catch(() => ({ currencies: [] }))
|
|
158
|
-
|
|
222
|
+
fetch("/admin/currencies", { credentials: "include" }).then((r) => r.json()).catch(() => ({ currencies: [] })),
|
|
223
|
+
fetch("/admin/regions", { credentials: "include" }).then((r) => r.json()).catch(() => ({ regions: [] }))
|
|
224
|
+
]).then(([settingsData, currData, regionData]) => {
|
|
159
225
|
setSettings(settingsData.settings);
|
|
160
226
|
const intervals = Array.isArray(settingsData.settings.abandoned_cart_intervals) ? settingsData.settings.abandoned_cart_intervals : [];
|
|
161
227
|
setIntervalsText(intervals.join(", "));
|
|
162
|
-
const
|
|
163
|
-
|
|
228
|
+
const currOpts = (currData.currencies || []).map((c) => ({
|
|
229
|
+
value: c.code,
|
|
230
|
+
label: `${c.name || c.code.toUpperCase()} (${c.code.toUpperCase()})`
|
|
231
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
232
|
+
setCurrencies(currOpts);
|
|
233
|
+
const countryMap = /* @__PURE__ */ new Map();
|
|
234
|
+
for (const region of regionData.regions || []) {
|
|
235
|
+
for (const c of region.countries || []) {
|
|
236
|
+
if (c.iso_2 && !countryMap.has(c.iso_2)) {
|
|
237
|
+
countryMap.set(c.iso_2, c.display_name || c.name || c.iso_2.toUpperCase());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const countryOpts = Array.from(countryMap.entries()).map(([code, name]) => ({
|
|
242
|
+
value: code,
|
|
243
|
+
label: name
|
|
244
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
245
|
+
setCountries(countryOpts);
|
|
164
246
|
setLoading(false);
|
|
165
247
|
}).catch(() => {
|
|
166
248
|
ui.toast.error("Failed to load Brevo settings");
|
|
@@ -347,70 +429,25 @@ const BrevoSettingsPage = () => {
|
|
|
347
429
|
] }),
|
|
348
430
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
|
|
349
431
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Excluded Currencies" }),
|
|
350
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies.
|
|
351
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
{
|
|
358
|
-
type: "button",
|
|
359
|
-
className: `px-2 py-1 rounded text-xs font-mono border transition-colors ${isExcluded ? "bg-red-100 border-red-300 text-red-700" : "bg-ui-bg-base border-ui-border-base text-ui-fg-subtle hover:bg-ui-bg-base-hover"}`,
|
|
360
|
-
onClick: () => {
|
|
361
|
-
const next = isExcluded ? excluded.filter((c) => c !== cur) : [...excluded, cur];
|
|
362
|
-
update("promotion_excluded_currencies", next);
|
|
363
|
-
},
|
|
364
|
-
children: [
|
|
365
|
-
cur.toUpperCase(),
|
|
366
|
-
isExcluded ? " ✕" : ""
|
|
367
|
-
]
|
|
368
|
-
},
|
|
369
|
-
cur
|
|
370
|
-
);
|
|
371
|
-
}),
|
|
372
|
-
currencies.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "No currencies found in store." })
|
|
432
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies." }),
|
|
433
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
434
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_currencies", title: "Select Excluded Currencies", options: currencies }), children: "Select Currencies" }),
|
|
435
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
436
|
+
(settings.promotion_excluded_currencies || []).map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
437
|
+
(settings.promotion_excluded_currencies || []).length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
438
|
+
] })
|
|
373
439
|
] })
|
|
374
440
|
] }),
|
|
375
441
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
|
|
376
442
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Excluded Countries" }),
|
|
377
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a promotion code.
|
|
378
|
-
/* @__PURE__ */ jsxRuntime.
|
|
379
|
-
{
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
{ code: "gb", label: "🇬🇧 GB" },
|
|
386
|
-
{ code: "sg", label: "🇸🇬 SG" },
|
|
387
|
-
{ code: "my", label: "🇲🇾 MY" },
|
|
388
|
-
{ code: "id", label: "🇮🇩 ID" },
|
|
389
|
-
{ code: "ph", label: "🇵🇭 PH" },
|
|
390
|
-
{ code: "au", label: "🇦🇺 AU" },
|
|
391
|
-
{ code: "in", label: "🇮🇳 IN" },
|
|
392
|
-
{ code: "tw", label: "🇹🇼 TW" },
|
|
393
|
-
{ code: "hk", label: "🇭🇰 HK" }
|
|
394
|
-
].map((country) => {
|
|
395
|
-
const excluded = Array.isArray(settings.promotion_excluded_countries) ? settings.promotion_excluded_countries : [];
|
|
396
|
-
const isExcluded = excluded.includes(country.code);
|
|
397
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
398
|
-
"button",
|
|
399
|
-
{
|
|
400
|
-
type: "button",
|
|
401
|
-
className: `px-2 py-1 rounded text-xs border transition-colors ${isExcluded ? "bg-red-100 border-red-300 text-red-700" : "bg-ui-bg-base border-ui-border-base text-ui-fg-subtle hover:bg-ui-bg-base-hover"}`,
|
|
402
|
-
onClick: () => {
|
|
403
|
-
const next = isExcluded ? excluded.filter((c) => c !== country.code) : [...excluded, country.code];
|
|
404
|
-
update("promotion_excluded_countries", next);
|
|
405
|
-
},
|
|
406
|
-
children: [
|
|
407
|
-
country.label,
|
|
408
|
-
isExcluded ? " ✕" : ""
|
|
409
|
-
]
|
|
410
|
-
},
|
|
411
|
-
country.code
|
|
412
|
-
);
|
|
413
|
-
}) })
|
|
443
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a promotion code." }),
|
|
444
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
445
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_countries", title: "Select Excluded Countries", options: countries }), children: "Select Countries" }),
|
|
446
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
447
|
+
(settings.promotion_excluded_countries || []).map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
448
|
+
(settings.promotion_excluded_countries || []).length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
449
|
+
] })
|
|
450
|
+
] })
|
|
414
451
|
] })
|
|
415
452
|
] })
|
|
416
453
|
] }) }),
|
|
@@ -593,29 +630,24 @@ const BrevoSettingsPage = () => {
|
|
|
593
630
|
] }),
|
|
594
631
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
|
|
595
632
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Excluded Currencies" }),
|
|
596
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies.
|
|
597
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
},
|
|
615
|
-
cur
|
|
616
|
-
);
|
|
617
|
-
}),
|
|
618
|
-
currencies.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "No currencies found in store." })
|
|
633
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies." }),
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
635
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "abandoned_cart_discount_excluded_currencies", title: "Select Excluded Currencies", options: currencies }), children: "Select Currencies" }),
|
|
636
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
637
|
+
(settings.abandoned_cart_discount_excluded_currencies || []).map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
638
|
+
(settings.abandoned_cart_discount_excluded_currencies || []).length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
639
|
+
] })
|
|
640
|
+
] })
|
|
641
|
+
] }),
|
|
642
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Excluded Countries" }),
|
|
644
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a discount code." }),
|
|
645
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
646
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_countries", title: "Select Excluded Countries", options: countries }), children: "Select Countries" }),
|
|
647
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
648
|
+
(settings.promotion_excluded_countries || []).map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
649
|
+
(settings.promotion_excluded_countries || []).length === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
650
|
+
] })
|
|
619
651
|
] })
|
|
620
652
|
] })
|
|
621
653
|
] })
|
|
@@ -1007,7 +1039,17 @@ const BrevoSettingsPage = () => {
|
|
|
1007
1039
|
)
|
|
1008
1040
|
] })
|
|
1009
1041
|
] })
|
|
1010
|
-
] }) })
|
|
1042
|
+
] }) }),
|
|
1043
|
+
modal && settings && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1044
|
+
MultiSelectModal,
|
|
1045
|
+
{
|
|
1046
|
+
title: modal.title,
|
|
1047
|
+
options: modal.options,
|
|
1048
|
+
selected: settings[modal.key] || [],
|
|
1049
|
+
onClose: () => setModal(null),
|
|
1050
|
+
onSave: (values) => update(modal.key, values)
|
|
1051
|
+
}
|
|
1052
|
+
)
|
|
1011
1053
|
] });
|
|
1012
1054
|
};
|
|
1013
1055
|
const config = adminSdk.defineRouteConfig({
|
|
@@ -144,22 +144,104 @@ const config$1 = defineRouteConfig({
|
|
|
144
144
|
label: "Email Analytics",
|
|
145
145
|
icon: ChartBar
|
|
146
146
|
});
|
|
147
|
+
const MultiSelectModal = ({
|
|
148
|
+
title,
|
|
149
|
+
options,
|
|
150
|
+
selected,
|
|
151
|
+
onClose,
|
|
152
|
+
onSave
|
|
153
|
+
}) => {
|
|
154
|
+
const [search, setSearch] = useState("");
|
|
155
|
+
const [checked, setChecked] = useState(new Set(selected));
|
|
156
|
+
const filtered = options.filter(
|
|
157
|
+
(o) => o.label.toLowerCase().includes(search.toLowerCase()) || o.value.toLowerCase().includes(search.toLowerCase())
|
|
158
|
+
);
|
|
159
|
+
const toggle = (val) => {
|
|
160
|
+
setChecked((prev) => {
|
|
161
|
+
const next = new Set(prev);
|
|
162
|
+
next.has(val) ? next.delete(val) : next.add(val);
|
|
163
|
+
return next;
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40", onClick: onClose, children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-2xl w-[420px] max-h-[520px] flex flex-col", onClick: (e) => e.stopPropagation(), children: [
|
|
167
|
+
/* @__PURE__ */ jsxs("div", { className: "px-5 py-4 border-b", children: [
|
|
168
|
+
/* @__PURE__ */ jsx(Text, { className: "font-semibold text-base", children: title }),
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
Input,
|
|
171
|
+
{
|
|
172
|
+
className: "mt-2",
|
|
173
|
+
placeholder: "Search...",
|
|
174
|
+
value: search,
|
|
175
|
+
onChange: (e) => setSearch(e.target.value)
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
] }),
|
|
179
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-3", children: [
|
|
180
|
+
filtered.length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm", children: "No results" }),
|
|
181
|
+
filtered.map((opt) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-3 py-1.5 cursor-pointer hover:bg-ui-bg-base-hover rounded px-2 -mx-2", children: [
|
|
182
|
+
/* @__PURE__ */ jsx(
|
|
183
|
+
"input",
|
|
184
|
+
{
|
|
185
|
+
type: "checkbox",
|
|
186
|
+
className: "accent-ui-fg-interactive w-4 h-4",
|
|
187
|
+
checked: checked.has(opt.value),
|
|
188
|
+
onChange: () => toggle(opt.value)
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: opt.label }),
|
|
192
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle font-mono ml-auto", children: opt.value.toUpperCase() })
|
|
193
|
+
] }, opt.value))
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ jsxs("div", { className: "px-5 py-3 border-t flex items-center justify-between", children: [
|
|
196
|
+
/* @__PURE__ */ jsxs(Text, { className: "text-xs text-ui-fg-subtle", children: [
|
|
197
|
+
checked.size,
|
|
198
|
+
" selected"
|
|
199
|
+
] }),
|
|
200
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
201
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onClose, children: "Cancel" }),
|
|
202
|
+
/* @__PURE__ */ jsx(Button, { size: "small", onClick: () => {
|
|
203
|
+
onSave(Array.from(checked));
|
|
204
|
+
onClose();
|
|
205
|
+
}, children: "Apply" })
|
|
206
|
+
] })
|
|
207
|
+
] })
|
|
208
|
+
] }) });
|
|
209
|
+
};
|
|
147
210
|
const BrevoSettingsPage = () => {
|
|
148
211
|
const [settings, setSettings] = useState(null);
|
|
149
212
|
const [loading, setLoading] = useState(true);
|
|
150
213
|
const [saving, setSaving] = useState(false);
|
|
151
214
|
const [intervalsText, setIntervalsText] = useState("");
|
|
152
215
|
const [currencies, setCurrencies] = useState([]);
|
|
216
|
+
const [countries, setCountries] = useState([]);
|
|
217
|
+
const [modal, setModal] = useState(null);
|
|
153
218
|
useEffect(() => {
|
|
154
219
|
Promise.all([
|
|
155
220
|
fetch("/admin/brevo-plugin-settings", { credentials: "include" }).then((r) => r.json()),
|
|
156
|
-
fetch("/admin/currencies", { credentials: "include" }).then((r) => r.json()).catch(() => ({ currencies: [] }))
|
|
157
|
-
|
|
221
|
+
fetch("/admin/currencies", { credentials: "include" }).then((r) => r.json()).catch(() => ({ currencies: [] })),
|
|
222
|
+
fetch("/admin/regions", { credentials: "include" }).then((r) => r.json()).catch(() => ({ regions: [] }))
|
|
223
|
+
]).then(([settingsData, currData, regionData]) => {
|
|
158
224
|
setSettings(settingsData.settings);
|
|
159
225
|
const intervals = Array.isArray(settingsData.settings.abandoned_cart_intervals) ? settingsData.settings.abandoned_cart_intervals : [];
|
|
160
226
|
setIntervalsText(intervals.join(", "));
|
|
161
|
-
const
|
|
162
|
-
|
|
227
|
+
const currOpts = (currData.currencies || []).map((c) => ({
|
|
228
|
+
value: c.code,
|
|
229
|
+
label: `${c.name || c.code.toUpperCase()} (${c.code.toUpperCase()})`
|
|
230
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
231
|
+
setCurrencies(currOpts);
|
|
232
|
+
const countryMap = /* @__PURE__ */ new Map();
|
|
233
|
+
for (const region of regionData.regions || []) {
|
|
234
|
+
for (const c of region.countries || []) {
|
|
235
|
+
if (c.iso_2 && !countryMap.has(c.iso_2)) {
|
|
236
|
+
countryMap.set(c.iso_2, c.display_name || c.name || c.iso_2.toUpperCase());
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const countryOpts = Array.from(countryMap.entries()).map(([code, name]) => ({
|
|
241
|
+
value: code,
|
|
242
|
+
label: name
|
|
243
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
244
|
+
setCountries(countryOpts);
|
|
163
245
|
setLoading(false);
|
|
164
246
|
}).catch(() => {
|
|
165
247
|
toast.error("Failed to load Brevo settings");
|
|
@@ -346,70 +428,25 @@ const BrevoSettingsPage = () => {
|
|
|
346
428
|
] }),
|
|
347
429
|
/* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
|
|
348
430
|
/* @__PURE__ */ jsx(Label, { children: "Excluded Currencies" }),
|
|
349
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies.
|
|
350
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
{
|
|
357
|
-
type: "button",
|
|
358
|
-
className: `px-2 py-1 rounded text-xs font-mono border transition-colors ${isExcluded ? "bg-red-100 border-red-300 text-red-700" : "bg-ui-bg-base border-ui-border-base text-ui-fg-subtle hover:bg-ui-bg-base-hover"}`,
|
|
359
|
-
onClick: () => {
|
|
360
|
-
const next = isExcluded ? excluded.filter((c) => c !== cur) : [...excluded, cur];
|
|
361
|
-
update("promotion_excluded_currencies", next);
|
|
362
|
-
},
|
|
363
|
-
children: [
|
|
364
|
-
cur.toUpperCase(),
|
|
365
|
-
isExcluded ? " ✕" : ""
|
|
366
|
-
]
|
|
367
|
-
},
|
|
368
|
-
cur
|
|
369
|
-
);
|
|
370
|
-
}),
|
|
371
|
-
currencies.length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "No currencies found in store." })
|
|
431
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies." }),
|
|
432
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
433
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_currencies", title: "Select Excluded Currencies", options: currencies }), children: "Select Currencies" }),
|
|
434
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
435
|
+
(settings.promotion_excluded_currencies || []).map((c) => /* @__PURE__ */ jsx(Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
436
|
+
(settings.promotion_excluded_currencies || []).length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
437
|
+
] })
|
|
372
438
|
] })
|
|
373
439
|
] }),
|
|
374
440
|
/* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
|
|
375
441
|
/* @__PURE__ */ jsx(Label, { children: "Excluded Countries" }),
|
|
376
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a promotion code.
|
|
377
|
-
/* @__PURE__ */
|
|
378
|
-
{
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
{ code: "gb", label: "🇬🇧 GB" },
|
|
385
|
-
{ code: "sg", label: "🇸🇬 SG" },
|
|
386
|
-
{ code: "my", label: "🇲🇾 MY" },
|
|
387
|
-
{ code: "id", label: "🇮🇩 ID" },
|
|
388
|
-
{ code: "ph", label: "🇵🇭 PH" },
|
|
389
|
-
{ code: "au", label: "🇦🇺 AU" },
|
|
390
|
-
{ code: "in", label: "🇮🇳 IN" },
|
|
391
|
-
{ code: "tw", label: "🇹🇼 TW" },
|
|
392
|
-
{ code: "hk", label: "🇭🇰 HK" }
|
|
393
|
-
].map((country) => {
|
|
394
|
-
const excluded = Array.isArray(settings.promotion_excluded_countries) ? settings.promotion_excluded_countries : [];
|
|
395
|
-
const isExcluded = excluded.includes(country.code);
|
|
396
|
-
return /* @__PURE__ */ jsxs(
|
|
397
|
-
"button",
|
|
398
|
-
{
|
|
399
|
-
type: "button",
|
|
400
|
-
className: `px-2 py-1 rounded text-xs border transition-colors ${isExcluded ? "bg-red-100 border-red-300 text-red-700" : "bg-ui-bg-base border-ui-border-base text-ui-fg-subtle hover:bg-ui-bg-base-hover"}`,
|
|
401
|
-
onClick: () => {
|
|
402
|
-
const next = isExcluded ? excluded.filter((c) => c !== country.code) : [...excluded, country.code];
|
|
403
|
-
update("promotion_excluded_countries", next);
|
|
404
|
-
},
|
|
405
|
-
children: [
|
|
406
|
-
country.label,
|
|
407
|
-
isExcluded ? " ✕" : ""
|
|
408
|
-
]
|
|
409
|
-
},
|
|
410
|
-
country.code
|
|
411
|
-
);
|
|
412
|
-
}) })
|
|
442
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a promotion code." }),
|
|
443
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
444
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_countries", title: "Select Excluded Countries", options: countries }), children: "Select Countries" }),
|
|
445
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
446
|
+
(settings.promotion_excluded_countries || []).map((c) => /* @__PURE__ */ jsx(Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
447
|
+
(settings.promotion_excluded_countries || []).length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
448
|
+
] })
|
|
449
|
+
] })
|
|
413
450
|
] })
|
|
414
451
|
] })
|
|
415
452
|
] }) }),
|
|
@@ -592,29 +629,24 @@ const BrevoSettingsPage = () => {
|
|
|
592
629
|
] }),
|
|
593
630
|
/* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
|
|
594
631
|
/* @__PURE__ */ jsx(Label, { children: "Excluded Currencies" }),
|
|
595
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies.
|
|
596
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
},
|
|
614
|
-
cur
|
|
615
|
-
);
|
|
616
|
-
}),
|
|
617
|
-
currencies.length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "No currencies found in store." })
|
|
632
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Discount will NOT apply to orders in these currencies." }),
|
|
633
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
634
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "abandoned_cart_discount_excluded_currencies", title: "Select Excluded Currencies", options: currencies }), children: "Select Currencies" }),
|
|
635
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
636
|
+
(settings.abandoned_cart_discount_excluded_currencies || []).map((c) => /* @__PURE__ */ jsx(Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
637
|
+
(settings.abandoned_cart_discount_excluded_currencies || []).length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
638
|
+
] })
|
|
639
|
+
] })
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
|
|
642
|
+
/* @__PURE__ */ jsx(Label, { children: "Excluded Countries" }),
|
|
643
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs mb-2", children: "Customers from these countries will NOT receive a discount code." }),
|
|
644
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
645
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setModal({ key: "promotion_excluded_countries", title: "Select Excluded Countries", options: countries }), children: "Select Countries" }),
|
|
646
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
|
|
647
|
+
(settings.promotion_excluded_countries || []).map((c) => /* @__PURE__ */ jsx(Badge, { color: "red", className: "font-mono text-xs", children: c.toUpperCase() }, c)),
|
|
648
|
+
(settings.promotion_excluded_countries || []).length === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "None" })
|
|
649
|
+
] })
|
|
618
650
|
] })
|
|
619
651
|
] })
|
|
620
652
|
] })
|
|
@@ -1006,7 +1038,17 @@ const BrevoSettingsPage = () => {
|
|
|
1006
1038
|
)
|
|
1007
1039
|
] })
|
|
1008
1040
|
] })
|
|
1009
|
-
] }) })
|
|
1041
|
+
] }) }),
|
|
1042
|
+
modal && settings && /* @__PURE__ */ jsx(
|
|
1043
|
+
MultiSelectModal,
|
|
1044
|
+
{
|
|
1045
|
+
title: modal.title,
|
|
1046
|
+
options: modal.options,
|
|
1047
|
+
selected: settings[modal.key] || [],
|
|
1048
|
+
onClose: () => setModal(null),
|
|
1049
|
+
onSave: (values) => update(modal.key, values)
|
|
1050
|
+
}
|
|
1051
|
+
)
|
|
1010
1052
|
] });
|
|
1011
1053
|
};
|
|
1012
1054
|
const config = defineRouteConfig({
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Migration20260307170711 = void 0;
|
|
4
|
+
const migrations_1 = require("@medusajs/framework/mikro-orm/migrations");
|
|
5
|
+
class Migration20260307170711 extends migrations_1.Migration {
|
|
6
|
+
async up() {
|
|
7
|
+
this.addSql(`alter table if exists "brevo_settings" add column if not exists "promotion_excluded_countries" jsonb null;`);
|
|
8
|
+
}
|
|
9
|
+
async down() {
|
|
10
|
+
this.addSql(`alter table if exists "brevo_settings" drop column if exists "promotion_excluded_countries";`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.Migration20260307170711 = Migration20260307170711;
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uMjAyNjAzMDcxNzA3MTEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9icmV2by1zZXR0aW5ncy9taWdyYXRpb25zL01pZ3JhdGlvbjIwMjYwMzA3MTcwNzExLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlFQUFxRTtBQUVyRSxNQUFhLHVCQUF3QixTQUFRLHNCQUFTO0lBRTNDLEtBQUssQ0FBQyxFQUFFO1FBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyw0R0FBNEcsQ0FBQyxDQUFDO0lBQzVILENBQUM7SUFFUSxLQUFLLENBQUMsSUFBSTtRQUNqQixJQUFJLENBQUMsTUFBTSxDQUFDLDhGQUE4RixDQUFDLENBQUM7SUFDOUcsQ0FBQztDQUVGO0FBVkQsMERBVUMifQ==
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Migration20260308000200 = void 0;
|
|
4
|
+
const migrations_1 = require("@medusajs/framework/mikro-orm/migrations");
|
|
5
|
+
class Migration20260308000200 extends migrations_1.Migration {
|
|
6
|
+
async up() {
|
|
7
|
+
this.addSql(`alter table if exists "brevo_settings" add column if not exists "promotion_excluded_countries" jsonb null;`);
|
|
8
|
+
}
|
|
9
|
+
async down() {
|
|
10
|
+
this.addSql(`alter table if exists "brevo_settings" drop column if exists "promotion_excluded_countries";`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.Migration20260308000200 = Migration20260308000200;
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uMjAyNjAzMDgwMDAyMDAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9icmV2by1zZXR0aW5ncy9taWdyYXRpb25zL01pZ3JhdGlvbjIwMjYwMzA4MDAwMjAwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlFQUFxRTtBQUVyRSxNQUFhLHVCQUF3QixTQUFRLHNCQUFTO0lBRXpDLEtBQUssQ0FBQyxFQUFFO1FBQ2IsSUFBSSxDQUFDLE1BQU0sQ0FBQyw0R0FBNEcsQ0FBQyxDQUFDO0lBQzlILENBQUM7SUFFUSxLQUFLLENBQUMsSUFBSTtRQUNmLElBQUksQ0FBQyxNQUFNLENBQUMsOEZBQThGLENBQUMsQ0FBQztJQUNoSCxDQUFDO0NBRUo7QUFWRCwwREFVQyJ9
|