@vicacha-devs/strapi-plugin-inbox 0.0.0-stage → 1.1.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 (90) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +17 -2
  3. package/dist/admin/InboxHomePage-B5xUPD7Y.mjs +2153 -0
  4. package/dist/admin/InboxHomePage-BCHbPE2t.js +2171 -0
  5. package/dist/admin/LocalizationRoutingTab-CEXbHNe4.mjs +282 -0
  6. package/dist/admin/LocalizationRoutingTab-Dt6U-kXn.js +281 -0
  7. package/dist/admin/SettingsPage-Dif7Cq7I.mjs +819 -0
  8. package/dist/admin/SettingsPage-qB_efKCl.js +837 -0
  9. package/dist/admin/ar-CbjX4o07.mjs +268 -0
  10. package/dist/admin/ar-KedDMvsH.js +268 -0
  11. package/dist/admin/de-BrJIGJEV.mjs +268 -0
  12. package/dist/admin/de-rj5pqQ0S.js +268 -0
  13. package/dist/admin/en-BE8TARw0.mjs +268 -0
  14. package/dist/admin/en-CuTmgXZL.js +268 -0
  15. package/dist/admin/es-Berf1dRb.js +268 -0
  16. package/dist/admin/es-Ce4nMwC7.mjs +268 -0
  17. package/dist/admin/fr-CfdjWCiu.js +268 -0
  18. package/dist/admin/fr-Y3GKi6mQ.mjs +268 -0
  19. package/dist/admin/index-5e9dAMBs.mjs +822 -0
  20. package/dist/admin/index-DLfoIVZP.js +839 -0
  21. package/dist/admin/index.js +5 -0
  22. package/dist/admin/index.mjs +5 -0
  23. package/dist/admin/it-DXXnvX5J.mjs +268 -0
  24. package/dist/admin/it-DkJ3WwLA.js +268 -0
  25. package/dist/admin/pt-D7WKv-MR.js +268 -0
  26. package/dist/admin/pt-QDCJ6lOH.mjs +268 -0
  27. package/dist/admin/ru-DgYTw9aE.js +268 -0
  28. package/dist/admin/ru-DzP0H4fh.mjs +268 -0
  29. package/dist/admin/src/components/Initializer.d.ts +6 -0
  30. package/dist/admin/src/components/PluginIcon.d.ts +3 -0
  31. package/dist/admin/src/components/inbox/AlertBannersTab.d.ts +10 -0
  32. package/dist/admin/src/components/inbox/CaseworkDetailPanel.d.ts +15 -0
  33. package/dist/admin/src/components/inbox/CaseworkPayloadChecklistColumn.d.ts +12 -0
  34. package/dist/admin/src/components/inbox/CaseworkSubmissionsTab.d.ts +12 -0
  35. package/dist/admin/src/components/inbox/FormBuilderTab.d.ts +17 -0
  36. package/dist/admin/src/components/inbox/FormChecklistAndLocalePanels.d.ts +17 -0
  37. package/dist/admin/src/components/inbox/FormRoutingDrawer.d.ts +15 -0
  38. package/dist/admin/src/components/inbox/SubscribersTab.d.ts +10 -0
  39. package/dist/admin/src/components/settings/AntiSpamCaptchaTab.d.ts +9 -0
  40. package/dist/admin/src/components/settings/BridgesNotificationsTab.d.ts +8 -0
  41. package/dist/admin/src/components/settings/CaptchaProviderCard.d.ts +21 -0
  42. package/dist/admin/src/components/settings/LocalizationRoutingTab.d.ts +16 -0
  43. package/dist/admin/src/index.d.ts +21 -0
  44. package/dist/admin/src/pages/InboxHomePage.d.ts +3 -0
  45. package/dist/admin/src/pages/SettingsPage.d.ts +3 -0
  46. package/dist/admin/src/pluginId.d.ts +3 -0
  47. package/dist/admin/src/translations/cmLabels.d.ts +1 -0
  48. package/dist/admin/src/translations/cmPlaceholders.d.ts +1 -0
  49. package/dist/admin/src/utils/getTranslation.d.ts +3 -0
  50. package/dist/admin/tr-5q4NwTgF.mjs +268 -0
  51. package/dist/admin/tr-CT-24fLA.js +268 -0
  52. package/dist/admin/zh-CYhWM5Qr.mjs +268 -0
  53. package/dist/admin/zh-CmCHcNcd.js +268 -0
  54. package/dist/server/index.js +3108 -0
  55. package/dist/server/index.mjs +3108 -0
  56. package/dist/server/src/bootstrap.d.ts +5 -0
  57. package/dist/server/src/config/index.d.ts +5 -0
  58. package/dist/server/src/content-types/alert-banner/index.d.ts +73 -0
  59. package/dist/server/src/content-types/alert-banner/schema.json.d.ts +73 -0
  60. package/dist/server/src/content-types/index.d.ts +253 -0
  61. package/dist/server/src/content-types/submission/index.d.ts +111 -0
  62. package/dist/server/src/content-types/submission/schema.json.d.ts +126 -0
  63. package/dist/server/src/content-types/subscriber/index.d.ts +69 -0
  64. package/dist/server/src/content-types/subscriber/schema.json.d.ts +69 -0
  65. package/dist/server/src/controllers/caseworkHandlers.d.ts +10 -0
  66. package/dist/server/src/controllers/communityHandlers.d.ts +10 -0
  67. package/dist/server/src/controllers/formHandlers.d.ts +14 -0
  68. package/dist/server/src/controllers/inboxController.d.ts +40 -0
  69. package/dist/server/src/controllers/index.d.ts +2 -0
  70. package/dist/server/src/destroy.d.ts +5 -0
  71. package/dist/server/src/index.d.ts +2 -0
  72. package/dist/server/src/register.d.ts +5 -0
  73. package/dist/server/src/routes/admin.d.ts +12 -0
  74. package/dist/server/src/routes/content-api.d.ts +13 -0
  75. package/dist/server/src/routes/index.d.ts +26 -0
  76. package/dist/server/src/services/alertService.d.ts +16 -0
  77. package/dist/server/src/services/docHelper.d.ts +28 -0
  78. package/dist/server/src/services/formBuilderMapper.d.ts +22 -0
  79. package/dist/server/src/services/formBuilderSync.d.ts +13 -0
  80. package/dist/server/src/services/formService.d.ts +40 -0
  81. package/dist/server/src/services/index.d.ts +2 -0
  82. package/dist/server/src/services/settings.d.ts +9 -0
  83. package/dist/server/src/services/submissionEcosystemBridges.d.ts +21 -0
  84. package/dist/server/src/services/submissionFormBuilderBridge.d.ts +23 -0
  85. package/dist/server/src/services/submissionService.d.ts +58 -0
  86. package/dist/server/src/services/subscriberService.d.ts +22 -0
  87. package/dist/shared/index.d.ts +1 -0
  88. package/dist/shared/index.js +917 -0
  89. package/dist/shared/index.mjs +917 -0
  90. package/package.json +125 -3
@@ -0,0 +1,837 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const designSystem = require("@strapi/design-system");
5
+ const admin = require("@strapi/strapi/admin");
6
+ const React = require("react");
7
+ const reactIntl = require("react-intl");
8
+ const index = require("./index-DLfoIVZP.js");
9
+ const LocalizationRoutingTab = require("./LocalizationRoutingTab-Dt6U-kXn.js");
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
13
+ if (e) {
14
+ for (const k in e) {
15
+ if (k !== "default") {
16
+ const d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: () => e[k]
20
+ });
21
+ }
22
+ }
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
28
+ const subCardStyle$1 = {
29
+ border: "1px solid rgba(128, 128, 128, 0.2)",
30
+ display: "flex",
31
+ flexDirection: "column",
32
+ justifyContent: "space-between"
33
+ };
34
+ const CaptchaProviderCard = ({
35
+ t,
36
+ title,
37
+ isDefaultActive,
38
+ testButtonLabel,
39
+ onTestSecret,
40
+ siteKeyName,
41
+ siteKeyLabel,
42
+ siteKeyPlaceholder,
43
+ siteKeyValue,
44
+ siteKeyHint,
45
+ onSiteKeyChange,
46
+ secretKeyName,
47
+ secretKeyLabel,
48
+ secretKeyPlaceholder,
49
+ secretKeyValue,
50
+ secretKeyHint,
51
+ onSecretKeyChange
52
+ }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", hasRadius: true, style: subCardStyle$1, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
53
+ /* @__PURE__ */ jsxRuntime.jsxs(
54
+ designSystem.Flex,
55
+ {
56
+ justifyContent: "space-between",
57
+ alignItems: "center",
58
+ paddingBottom: 3,
59
+ wrap: "wrap",
60
+ gap: 2,
61
+ children: [
62
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
63
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h3", fontWeight: "bold", children: title }),
64
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: isDefaultActive ? t("settings.ui.default_active", "Default Active") : t("settings.ui.standby", "Standby") })
65
+ ] }),
66
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", size: "S", onClick: onTestSecret, children: testButtonLabel })
67
+ ]
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
71
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: siteKeyName, hint: siteKeyHint, children: [
72
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: siteKeyLabel }),
73
+ /* @__PURE__ */ jsxRuntime.jsx(
74
+ designSystem.TextInput,
75
+ {
76
+ name: siteKeyName,
77
+ placeholder: siteKeyPlaceholder,
78
+ value: siteKeyValue,
79
+ onChange: (e) => onSiteKeyChange(e.target.value)
80
+ }
81
+ ),
82
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
83
+ ] }),
84
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: secretKeyName, hint: secretKeyHint, children: [
85
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: secretKeyLabel }),
86
+ /* @__PURE__ */ jsxRuntime.jsx(
87
+ designSystem.TextInput,
88
+ {
89
+ name: secretKeyName,
90
+ type: "password",
91
+ placeholder: secretKeyPlaceholder,
92
+ value: secretKeyValue,
93
+ onChange: (e) => onSecretKeyChange(e.target.value)
94
+ }
95
+ ),
96
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
97
+ ] })
98
+ ] })
99
+ ] }) });
100
+ const CAPTCHA_PROVIDER_OPTIONS = [
101
+ { value: "none", label: "None (Honeypot + IP Rate Limiting only)" },
102
+ { value: "turnstile", label: "Cloudflare Turnstile (Recommended)" },
103
+ { value: "recaptcha", label: "Google reCAPTCHA v2" }
104
+ ];
105
+ const AntiSpamCaptchaTab = ({
106
+ t,
107
+ settings,
108
+ setSettings,
109
+ onTestCaptcha
110
+ }) => {
111
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "antispam", children: /* @__PURE__ */ jsxRuntime.jsxs(
112
+ designSystem.Box,
113
+ {
114
+ padding: 6,
115
+ background: "neutral0",
116
+ hasRadius: true,
117
+ shadow: "filterShadow",
118
+ style: { borderTopLeftRadius: 0, borderTopRightRadius: 0 },
119
+ children: [
120
+ /* @__PURE__ */ jsxRuntime.jsxs(
121
+ designSystem.Flex,
122
+ {
123
+ justifyContent: "space-between",
124
+ alignItems: "center",
125
+ paddingBottom: 2,
126
+ wrap: "wrap",
127
+ gap: 2,
128
+ children: [
129
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", tag: "h2", children: t(
131
+ "settings.ui.2_anti_spam_guard_honeypot_rate_limiting_captcha",
132
+ "Anti-Spam Guard (Honeypot, Rate Limiting & CAPTCHA)"
133
+ ) }),
134
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
135
+ "settings.ui.three_stage_protection_invisible_bot_trap_field_",
136
+ "Three-stage protection: invisible bot trap field, per-IP sliding-window rate limiter, and fail-closed CAPTCHA verification."
137
+ ) })
138
+ ] }),
139
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
140
+ settings.defaultRateLimitPerHour || 15,
141
+ " ",
142
+ t("settings.ui.req_per_hr_ip", "req/hr per IP")
143
+ ] })
144
+ ]
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsxRuntime.jsxs(
148
+ designSystem.Box,
149
+ {
150
+ paddingTop: 4,
151
+ style: {
152
+ display: "grid",
153
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
154
+ gap: 20
155
+ },
156
+ children: [
157
+ /* @__PURE__ */ jsxRuntime.jsxs(
158
+ designSystem.Field.Root,
159
+ {
160
+ name: "defaultHoneypotField",
161
+ hint: t(
162
+ "settings.ui.hidden_trap_field_name_bots_that_populate_this_f",
163
+ "Hidden trap field name; bots that populate this field are rejected with HTTP 403 Forbidden."
164
+ ),
165
+ children: [
166
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t(
167
+ "field.default_honeypot_field_name",
168
+ "Default Honeypot Field Name"
169
+ ) }),
170
+ /* @__PURE__ */ jsxRuntime.jsx(
171
+ designSystem.TextInput,
172
+ {
173
+ name: "defaultHoneypotField",
174
+ placeholder: t(
175
+ "placeholder.e_g_website_url",
176
+ "e.g., _website_url"
177
+ ),
178
+ value: settings.defaultHoneypotField || "",
179
+ onChange: (e) => setSettings({
180
+ ...settings,
181
+ defaultHoneypotField: e.target.value
182
+ })
183
+ }
184
+ ),
185
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
186
+ ]
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsxRuntime.jsxs(
190
+ designSystem.Field.Root,
191
+ {
192
+ name: "defaultRateLimitPerHour",
193
+ hint: t(
194
+ "settings.ui.maximum_submissions_allowed_per_ip_and_form_slug",
195
+ "Maximum submissions allowed per IP and form slug within a rolling 60-minute window."
196
+ ),
197
+ children: [
198
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t(
199
+ "field.default_hourly_rate_limit_per_ip",
200
+ "Default Hourly Rate Limit per IP"
201
+ ) }),
202
+ /* @__PURE__ */ jsxRuntime.jsx(
203
+ designSystem.NumberInput,
204
+ {
205
+ name: "defaultRateLimitPerHour",
206
+ placeholder: t("placeholder.e_g_15", "e.g., 15"),
207
+ value: settings.defaultRateLimitPerHour ?? 15,
208
+ onValueChange: (val) => setSettings({
209
+ ...settings,
210
+ defaultRateLimitPerHour: typeof val === "number" && val > 0 ? val : 15
211
+ })
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
215
+ ]
216
+ }
217
+ ),
218
+ /* @__PURE__ */ jsxRuntime.jsxs(
219
+ designSystem.Field.Root,
220
+ {
221
+ name: "defaultCaptchaProvider",
222
+ hint: t(
223
+ "settings.ui.server_side_token_verification_enforced_on_publi",
224
+ "Server-side token verification enforced on public submissions unless overridden per form."
225
+ ),
226
+ children: [
227
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("field.default_captcha_provider", "Default CAPTCHA Provider") }),
228
+ /* @__PURE__ */ jsxRuntime.jsx(
229
+ designSystem.SingleSelect,
230
+ {
231
+ placeholder: t(
232
+ "placeholder.select_captcha_provider",
233
+ "Select CAPTCHA provider"
234
+ ),
235
+ value: settings.defaultCaptchaProvider || "none",
236
+ onChange: (val) => setSettings({
237
+ ...settings,
238
+ defaultCaptchaProvider: String(val)
239
+ }),
240
+ children: CAPTCHA_PROVIDER_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: opt.value, children: opt.label }, opt.value))
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
244
+ ]
245
+ }
246
+ )
247
+ ]
248
+ }
249
+ ),
250
+ /* @__PURE__ */ jsxRuntime.jsxs(
251
+ designSystem.Box,
252
+ {
253
+ paddingTop: 5,
254
+ style: {
255
+ display: "grid",
256
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
257
+ gap: 20
258
+ },
259
+ children: [
260
+ /* @__PURE__ */ jsxRuntime.jsx(
261
+ CaptchaProviderCard,
262
+ {
263
+ t,
264
+ title: t(
265
+ "settings.ui.cloudflare_turnstile",
266
+ "Cloudflare Turnstile"
267
+ ),
268
+ isDefaultActive: settings.defaultCaptchaProvider === "turnstile",
269
+ testButtonLabel: t(
270
+ "settings.ui.test_turnstile_secret",
271
+ "Test Turnstile Secret"
272
+ ),
273
+ onTestSecret: () => onTestCaptcha("turnstile", settings.turnstileSecretKey),
274
+ siteKeyName: "turnstileSiteKey",
275
+ siteKeyLabel: t(
276
+ "field.turnstile_site_key_public_widget_key",
277
+ "Turnstile Site Key (Public Widget Key)"
278
+ ),
279
+ siteKeyPlaceholder: t(
280
+ "placeholder.e_g_0x4aaaaaaabkmyinuke",
281
+ "e.g., 0x4AAAAAAABkMYinukE_..."
282
+ ),
283
+ siteKeyValue: settings.turnstileSiteKey || "",
284
+ siteKeyHint: t(
285
+ "settings.ui.public_widget_key_rendered_by_the_frontend_form_",
286
+ "Public widget key rendered by the frontend form component."
287
+ ),
288
+ onSiteKeyChange: (val) => setSettings({ ...settings, turnstileSiteKey: val }),
289
+ secretKeyName: "turnstileSecretKey",
290
+ secretKeyLabel: t(
291
+ "field.turnstile_secret_key_server_verification",
292
+ "Turnstile Secret Key (Server Verification)"
293
+ ),
294
+ secretKeyPlaceholder: t(
295
+ "placeholder.e_g_0x4aaaaaaabkmyin",
296
+ "e.g., 0x4AAAAAAABkMYin..."
297
+ ),
298
+ secretKeyValue: settings.turnstileSecretKey || "",
299
+ secretKeyHint: t(
300
+ "settings.ui.verified_against_challenges_cloudflare_com_turns",
301
+ "Verified against challenges.cloudflare.com/turnstile/v0/siteverify."
302
+ ),
303
+ onSecretKeyChange: (val) => setSettings({ ...settings, turnstileSecretKey: val })
304
+ }
305
+ ),
306
+ /* @__PURE__ */ jsxRuntime.jsx(
307
+ CaptchaProviderCard,
308
+ {
309
+ t,
310
+ title: t("settings.ui.google_recaptcha_v2", "Google reCAPTCHA v2"),
311
+ isDefaultActive: settings.defaultCaptchaProvider === "recaptcha",
312
+ testButtonLabel: t(
313
+ "settings.ui.test_recaptcha_secret",
314
+ "Test reCAPTCHA Secret"
315
+ ),
316
+ onTestSecret: () => onTestCaptcha("recaptcha", settings.recaptchaSecretKey),
317
+ siteKeyName: "recaptchaSiteKey",
318
+ siteKeyLabel: t(
319
+ "field.recaptcha_v2_site_key_public_widget_key",
320
+ "reCAPTCHA v2 Site Key (Public Widget Key)"
321
+ ),
322
+ siteKeyPlaceholder: t(
323
+ "placeholder.e_g_6leixactaaaaajczvrqyhh71umiegnq_mxjizkhi",
324
+ "e.g., 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
325
+ ),
326
+ siteKeyValue: settings.recaptchaSiteKey || "",
327
+ siteKeyHint: t(
328
+ "settings.ui.public_site_key_used_by_client_forms_when_recapt",
329
+ "Public site key used by client forms when reCAPTCHA v2 is enabled."
330
+ ),
331
+ onSiteKeyChange: (val) => setSettings({ ...settings, recaptchaSiteKey: val }),
332
+ secretKeyName: "recaptchaSecretKey",
333
+ secretKeyLabel: t(
334
+ "field.recaptcha_v2_secret_key_server_verification",
335
+ "reCAPTCHA v2 Secret Key (Server Verification)"
336
+ ),
337
+ secretKeyPlaceholder: t(
338
+ "placeholder.e_g_6leixactaaaaagg_vfi1tnrwxmznfuojj4wifjwe",
339
+ "e.g., 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
340
+ ),
341
+ secretKeyValue: settings.recaptchaSecretKey || "",
342
+ secretKeyHint: t(
343
+ "settings.ui.verified_against_www_google_com_recaptcha_api_si",
344
+ "Verified against www.google.com/recaptcha/api/siteverify."
345
+ ),
346
+ onSecretKeyChange: (val) => setSettings({ ...settings, recaptchaSecretKey: val })
347
+ }
348
+ )
349
+ ]
350
+ }
351
+ )
352
+ ]
353
+ }
354
+ ) });
355
+ };
356
+ const subCardStyle = {
357
+ border: "1px solid rgba(128, 128, 128, 0.2)",
358
+ display: "flex",
359
+ flexDirection: "column",
360
+ justifyContent: "space-between"
361
+ };
362
+ const BridgesNotificationsTab = ({ t, settings, setSettings }) => {
363
+ const canonicalNotifyEmails = (settings.defaultNotifyEmails || []).join(", ");
364
+ const [notifyEmailsDraft, setNotifyEmailsDraft] = React__namespace.useState(
365
+ canonicalNotifyEmails
366
+ );
367
+ React__namespace.useEffect(() => {
368
+ setNotifyEmailsDraft(
369
+ (prev) => index.parseCsvList(prev).join(", ") === canonicalNotifyEmails ? prev : canonicalNotifyEmails
370
+ );
371
+ }, [canonicalNotifyEmails]);
372
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "bridges", children: /* @__PURE__ */ jsxRuntime.jsxs(
373
+ designSystem.Box,
374
+ {
375
+ padding: 6,
376
+ background: "neutral0",
377
+ hasRadius: true,
378
+ shadow: "filterShadow",
379
+ style: { borderTopLeftRadius: 0, borderTopRightRadius: 0 },
380
+ children: [
381
+ /* @__PURE__ */ jsxRuntime.jsxs(
382
+ designSystem.Flex,
383
+ {
384
+ justifyContent: "space-between",
385
+ alignItems: "center",
386
+ paddingBottom: 2,
387
+ wrap: "wrap",
388
+ gap: 2,
389
+ children: [
390
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
391
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", tag: "h2", children: t(
392
+ "settings.ui.3_double_opt_in_notifications_ecosystem_bridges",
393
+ "Double Opt-In, Notifications & Ecosystem Bridges"
394
+ ) }),
395
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
396
+ "settings.ui.control_subscriber_confirmation_workflows_staff_",
397
+ "Control subscriber confirmation workflows, staff email/webhook notifications, and 1-click integrations with Form Builder CMS, Bookings, and Certificates."
398
+ ) })
399
+ ] }),
400
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, wrap: "wrap", children: [
401
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
402
+ t("settings.ui.double_opt_in_label", "Double Opt-In"),
403
+ ":",
404
+ " ",
405
+ settings.enableDoubleOptIn ? t("common.on", "On") : t("common.off", "Off")
406
+ ] }),
407
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
408
+ t("settings.ui.bookings_bridge_label", "Bookings Bridge"),
409
+ ":",
410
+ " ",
411
+ settings.enableBookingBridge ? t("common.on", "On") : t("common.off", "Off")
412
+ ] }),
413
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
414
+ t(
415
+ "settings.ui.certificates_bridge_label",
416
+ "Certificates Bridge"
417
+ ),
418
+ ":",
419
+ " ",
420
+ settings.enableCertificateBridge ? t("common.on", "On") : t("common.off", "Off")
421
+ ] })
422
+ ] })
423
+ ]
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsxRuntime.jsxs(
427
+ designSystem.Box,
428
+ {
429
+ paddingTop: 4,
430
+ style: {
431
+ display: "grid",
432
+ gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
433
+ gap: 16
434
+ },
435
+ children: [
436
+ /* @__PURE__ */ jsxRuntime.jsxs(
437
+ designSystem.Box,
438
+ {
439
+ padding: 4,
440
+ background: "neutral100",
441
+ hasRadius: true,
442
+ style: subCardStyle,
443
+ children: [
444
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
445
+ /* @__PURE__ */ jsxRuntime.jsxs(
446
+ designSystem.Flex,
447
+ {
448
+ justifyContent: "space-between",
449
+ alignItems: "center",
450
+ paddingBottom: 2,
451
+ children: [
452
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: t(
453
+ "settings.ui.subscriber_double_opt_in",
454
+ "Subscriber Double Opt-In"
455
+ ) }),
456
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: settings.enableDoubleOptIn ? t("common.enabled", "Enabled") : t("common.disabled", "Disabled") })
457
+ ]
458
+ }
459
+ ),
460
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
461
+ "settings.ui.double_opt_in_desc",
462
+ "New subscribers start in pending status with a cryptographic confirmation token and 1-click unsubscribe token."
463
+ ) })
464
+ ] }),
465
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(
466
+ designSystem.Checkbox,
467
+ {
468
+ checked: Boolean(settings.enableDoubleOptIn),
469
+ onCheckedChange: (checked) => setSettings({
470
+ ...settings,
471
+ enableDoubleOptIn: Boolean(checked)
472
+ }),
473
+ children: t(
474
+ "checkbox.require_email_confirmation_before_activating_sub",
475
+ "Require email confirmation before activating subscribers"
476
+ )
477
+ }
478
+ ) })
479
+ ]
480
+ }
481
+ ),
482
+ /* @__PURE__ */ jsxRuntime.jsxs(
483
+ designSystem.Box,
484
+ {
485
+ padding: 4,
486
+ background: "neutral100",
487
+ hasRadius: true,
488
+ style: subCardStyle,
489
+ children: [
490
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
491
+ /* @__PURE__ */ jsxRuntime.jsxs(
492
+ designSystem.Flex,
493
+ {
494
+ justifyContent: "space-between",
495
+ alignItems: "center",
496
+ paddingBottom: 2,
497
+ children: [
498
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: t(
499
+ "settings.ui.bookings_plugin_bridge",
500
+ "Bookings Plugin Bridge"
501
+ ) }),
502
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: settings.enableBookingBridge ? t("common.enabled", "Enabled") : t("common.disabled", "Disabled") })
503
+ ]
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
507
+ "settings.ui.bookings_bridge_desc",
508
+ "Enables 1-click appointment scheduling from service-desk submissions into @vicacha-devs/strapi-plugin-bookings."
509
+ ) })
510
+ ] }),
511
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(
512
+ designSystem.Checkbox,
513
+ {
514
+ checked: Boolean(settings.enableBookingBridge),
515
+ onCheckedChange: (checked) => setSettings({
516
+ ...settings,
517
+ enableBookingBridge: Boolean(checked)
518
+ }),
519
+ children: t(
520
+ "checkbox.enable_bookings_bridge",
521
+ "Enable @vicacha-devs/strapi-plugin-bookings bridge"
522
+ )
523
+ }
524
+ ) })
525
+ ]
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsxRuntime.jsxs(
529
+ designSystem.Box,
530
+ {
531
+ padding: 4,
532
+ background: "neutral100",
533
+ hasRadius: true,
534
+ style: subCardStyle,
535
+ children: [
536
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
537
+ /* @__PURE__ */ jsxRuntime.jsxs(
538
+ designSystem.Flex,
539
+ {
540
+ justifyContent: "space-between",
541
+ alignItems: "center",
542
+ paddingBottom: 2,
543
+ children: [
544
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: t(
545
+ "settings.ui.certificates_plugin_bridge",
546
+ "Certificates Plugin Bridge"
547
+ ) }),
548
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: settings.enableCertificateBridge ? t("common.enabled", "Enabled") : t("common.disabled", "Disabled") })
549
+ ]
550
+ }
551
+ ),
552
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
553
+ "settings.ui.certificates_bridge_desc",
554
+ "Enables 1-click certificate issuance (Nikah, Shahada, Halal, Consular) via @vicacha-devs/strapi-plugin-certificates after checklist verification."
555
+ ) })
556
+ ] }),
557
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(
558
+ designSystem.Checkbox,
559
+ {
560
+ checked: Boolean(settings.enableCertificateBridge),
561
+ onCheckedChange: (checked) => setSettings({
562
+ ...settings,
563
+ enableCertificateBridge: Boolean(checked)
564
+ }),
565
+ children: t(
566
+ "checkbox.enable_certificates_bridge",
567
+ "Enable @vicacha-devs/strapi-plugin-certificates bridge"
568
+ )
569
+ }
570
+ ) })
571
+ ]
572
+ }
573
+ )
574
+ ]
575
+ }
576
+ ),
577
+ /* @__PURE__ */ jsxRuntime.jsxs(
578
+ designSystem.Box,
579
+ {
580
+ paddingTop: 5,
581
+ style: {
582
+ display: "grid",
583
+ gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
584
+ gap: 20
585
+ },
586
+ children: [
587
+ /* @__PURE__ */ jsxRuntime.jsxs(
588
+ designSystem.Field.Root,
589
+ {
590
+ name: "defaultNotifyEmails",
591
+ hint: t(
592
+ "settings.ui.default_staff_email_addresses_notified_when_a_ne",
593
+ "Default staff email addresses notified when a new form submission or service-desk application is received."
594
+ ),
595
+ children: [
596
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t(
597
+ "field.default_staff_notification_emails_comma_separate",
598
+ "Default Staff Notification Emails (comma-separated)"
599
+ ) }),
600
+ /* @__PURE__ */ jsxRuntime.jsx(
601
+ designSystem.TextInput,
602
+ {
603
+ name: "defaultNotifyEmails",
604
+ placeholder: t(
605
+ "placeholder.e_g_info_mezquitabogota_org_imam_mezquitabogota_",
606
+ "e.g., info@mezquitabogota.org, imam@mezquitabogota.org"
607
+ ),
608
+ value: notifyEmailsDraft,
609
+ onChange: (e) => {
610
+ const nextRaw = e.target.value;
611
+ setNotifyEmailsDraft(nextRaw);
612
+ setSettings({
613
+ ...settings,
614
+ defaultNotifyEmails: index.parseCsvList(nextRaw)
615
+ });
616
+ },
617
+ onBlur: () => setNotifyEmailsDraft(canonicalNotifyEmails)
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
621
+ ]
622
+ }
623
+ ),
624
+ /* @__PURE__ */ jsxRuntime.jsxs(
625
+ designSystem.Field.Root,
626
+ {
627
+ name: "outboundWebhookUrl",
628
+ hint: t(
629
+ "settings.ui.optional_https_webhook_endpoint_notified_on_subm",
630
+ "Optional HTTPS webhook endpoint notified on submission creation, checklist verification, and status transitions."
631
+ ),
632
+ children: [
633
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t(
634
+ "field.outbound_webhook_url_optional",
635
+ "Outbound Webhook URL (Optional)"
636
+ ) }),
637
+ /* @__PURE__ */ jsxRuntime.jsx(
638
+ designSystem.TextInput,
639
+ {
640
+ name: "outboundWebhookUrl",
641
+ placeholder: t(
642
+ "placeholder.e_g_https_hooks_mezquitabogota_org_inbox_events",
643
+ "e.g., https://hooks.mezquitabogota.org/inbox-events"
644
+ ),
645
+ value: settings.outboundWebhookUrl || "",
646
+ onChange: (e) => setSettings({
647
+ ...settings,
648
+ outboundWebhookUrl: e.target.value
649
+ })
650
+ }
651
+ ),
652
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
653
+ ]
654
+ }
655
+ )
656
+ ]
657
+ }
658
+ )
659
+ ]
660
+ }
661
+ ) });
662
+ };
663
+ const SettingsPage = () => {
664
+ const { formatMessage } = reactIntl.useIntl();
665
+ const t = (id, defaultMessage) => formatMessage({ id: `${index.PLUGIN_ID}.${id}`, defaultMessage });
666
+ const { get, put, post } = admin.useFetchClient();
667
+ const [settings, setSettings] = React__namespace.useState(
668
+ index.DEFAULT_INBOX_SETTINGS
669
+ );
670
+ const [savedNotice, setSavedNotice] = React__namespace.useState("");
671
+ const [captchaTestResult, setCaptchaTestResult] = React__namespace.useState(null);
672
+ React__namespace.useEffect(() => {
673
+ const fetchSettings = async () => {
674
+ try {
675
+ const res = await get(`/${index.PLUGIN_ID}/settings`);
676
+ if (res?.data?.data) {
677
+ setSettings({
678
+ ...index.DEFAULT_INBOX_SETTINGS,
679
+ ...res.data.data
680
+ });
681
+ }
682
+ } catch {
683
+ }
684
+ };
685
+ void fetchSettings();
686
+ }, []);
687
+ const handleSave = async () => {
688
+ const res = await put(`/${index.PLUGIN_ID}/settings`, settings);
689
+ if (res?.data?.data) {
690
+ setSettings({
691
+ ...index.DEFAULT_INBOX_SETTINGS,
692
+ ...res.data.data
693
+ });
694
+ setSavedNotice(
695
+ "Inbox, Anti-Spam & Casework settings saved successfully."
696
+ );
697
+ }
698
+ };
699
+ const handleResetDefaults = () => {
700
+ setSettings(index.DEFAULT_INBOX_SETTINGS);
701
+ setSavedNotice(
702
+ 'Settings reset to defaults in editor. Click "Save Settings" to persist.'
703
+ );
704
+ };
705
+ const handleTestCaptcha = async (provider, secret) => {
706
+ const res = await post(`/${index.PLUGIN_ID}/captcha/test`, {
707
+ provider,
708
+ secret: secret || ""
709
+ });
710
+ const out = res?.data?.data;
711
+ const isOk = Boolean(out?.ok);
712
+ setCaptchaTestResult({
713
+ ok: isOk,
714
+ message: isOk ? `${provider === "turnstile" ? "Cloudflare Turnstile" : "Google reCAPTCHA"} secret key verified!` : `Verification failed (${provider}): ${out?.reason || "Invalid or empty secret key"}`
715
+ });
716
+ };
717
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 8, children: [
718
+ /* @__PURE__ */ jsxRuntime.jsxs(
719
+ designSystem.Flex,
720
+ {
721
+ justifyContent: "space-between",
722
+ alignItems: "flex-start",
723
+ paddingBottom: 4,
724
+ wrap: "wrap",
725
+ gap: 4,
726
+ children: [
727
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
728
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: t(
729
+ "settings.ui.inbox_anti_spam_casework_settings",
730
+ "Inbox, Anti-Spam & Casework Settings"
731
+ ) }),
732
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", children: t(
733
+ "settings.ui.configure_multi_locale_forms_secondary_hijri_cal",
734
+ "Configure multi-locale forms, anti-spam protection, double opt-in subscribers, and Bookings / Certificates bridges"
735
+ ) }) }),
736
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, paddingTop: 3, wrap: "wrap", children: [
737
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
738
+ t("settings.ui.locales_badge", "Locales"),
739
+ " (",
740
+ (settings.supportedLocales || []).length,
741
+ "):",
742
+ " ",
743
+ (settings.supportedLocales || []).join(", ")
744
+ ] }),
745
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
746
+ t("settings.ui.captcha_badge", "CAPTCHA"),
747
+ ":",
748
+ " ",
749
+ settings.defaultCaptchaProvider || "none"
750
+ ] }),
751
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
752
+ t(
753
+ "settings.ui.form_builder_bridge_badge",
754
+ "Form Builder Bridge"
755
+ ),
756
+ ":",
757
+ " ",
758
+ settings.enableFormBuilderBridge !== false ? t("common.enabled", "Enabled") : t("common.disabled", "Disabled")
759
+ ] }),
760
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { children: [
761
+ t("settings.ui.double_opt_in_label", "Double Opt-In"),
762
+ ":",
763
+ " ",
764
+ settings.enableDoubleOptIn ? t("common.enabled", "Enabled") : t("common.disabled", "Disabled")
765
+ ] })
766
+ ] })
767
+ ] }),
768
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
769
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", onClick: handleResetDefaults, children: t("settings.ui.reset_to_defaults", "Reset to Defaults") }),
770
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSave, children: t("settings.ui.save_settings", "Save Settings") })
771
+ ] })
772
+ ]
773
+ }
774
+ ),
775
+ savedNotice ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, marginBottom: 4, background: "success100", hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success700", fontWeight: "semiBold", children: savedNotice }) }) : null,
776
+ captchaTestResult ? /* @__PURE__ */ jsxRuntime.jsx(
777
+ designSystem.Box,
778
+ {
779
+ padding: 3,
780
+ marginBottom: 4,
781
+ background: captchaTestResult.ok ? "success100" : "danger100",
782
+ hasRadius: true,
783
+ children: /* @__PURE__ */ jsxRuntime.jsx(
784
+ designSystem.Typography,
785
+ {
786
+ textColor: captchaTestResult.ok ? "success700" : "danger700",
787
+ fontWeight: "semiBold",
788
+ children: captchaTestResult.message
789
+ }
790
+ )
791
+ }
792
+ ) : null,
793
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}),
794
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs.Root, { defaultValue: "routing", children: [
795
+ /* @__PURE__ */ jsxRuntime.jsxs(
796
+ designSystem.Tabs.List,
797
+ {
798
+ "aria-label": t(
799
+ "settings.ui.inbox_anti_spam_casework_settings",
800
+ "Inbox Settings"
801
+ ),
802
+ children: [
803
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "routing", children: t("settings.tab.routing", "Localization & Routing") }),
804
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "antispam", children: t("settings.tab.antispam", "Anti-Spam Guard & CAPTCHA") }),
805
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "bridges", children: t("settings.tab.bridges", "Double Opt-In & Ecosystem Bridges") })
806
+ ]
807
+ }
808
+ ),
809
+ /* @__PURE__ */ jsxRuntime.jsx(
810
+ LocalizationRoutingTab.LocalizationRoutingTab,
811
+ {
812
+ t,
813
+ settings,
814
+ setSettings
815
+ }
816
+ ),
817
+ /* @__PURE__ */ jsxRuntime.jsx(
818
+ AntiSpamCaptchaTab,
819
+ {
820
+ t,
821
+ settings,
822
+ setSettings,
823
+ onTestCaptcha: handleTestCaptcha
824
+ }
825
+ ),
826
+ /* @__PURE__ */ jsxRuntime.jsx(
827
+ BridgesNotificationsTab,
828
+ {
829
+ t,
830
+ settings,
831
+ setSettings
832
+ }
833
+ )
834
+ ] }) })
835
+ ] }) });
836
+ };
837
+ exports.SettingsPage = SettingsPage;