strapi-identity 0.1.2 → 0.3.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 (88) hide show
  1. package/README.md +2 -1
  2. package/dist/admin/{AdminReset-H453s-DE.mjs → AdminReset-CCGgw-0k.mjs} +2 -2
  3. package/dist/admin/{AdminReset-C0QibZXW.js → AdminReset-QClQP2Il.js} +2 -2
  4. package/dist/admin/{ProfileToggle-BFmIWCrN.js → ProfileToggle-H31GHNDA.js} +299 -39
  5. package/dist/admin/{ProfileToggle-DQeXCx34.mjs → ProfileToggle-gPuH6dGP.mjs} +299 -39
  6. package/dist/admin/{SettingsPage-OwMik_IK.mjs → SettingsPage-DgPikS3m.mjs} +344 -102
  7. package/dist/admin/{SettingsPage-DyF7YbsX.js → SettingsPage-DulEjadb.js} +343 -101
  8. package/dist/admin/{ar-i2eiMZkz.js → ar-BYnI7Tsa.js} +36 -23
  9. package/dist/admin/{ar-BXaam37U.mjs → ar-DwZqj0qM.mjs} +36 -23
  10. package/dist/admin/{ca-DZ9DbEcQ.mjs → ca-aKVVc8iQ.mjs} +36 -23
  11. package/dist/admin/{ca-BVpGzY8r.js → ca-sBRHuaFU.js} +36 -23
  12. package/dist/admin/{cs-Gok16KLy.mjs → cs--prflMHS.mjs} +36 -23
  13. package/dist/admin/{cs-_PZVkwt0.js → cs-gU7KP3Lx.js} +36 -23
  14. package/dist/admin/de-BT25lv_6.mjs +49 -0
  15. package/dist/admin/de-CrlCAUuf.js +49 -0
  16. package/dist/admin/{dk-B7EOsAdU.js → dk-BNC3WUzY.js} +36 -23
  17. package/dist/admin/{dk-CI64Xmli.mjs → dk-Ck3AQYU7.mjs} +36 -23
  18. package/dist/admin/{en-B_vJwdfS.mjs → en-9qzlpde0.mjs} +36 -23
  19. package/dist/admin/{en-D4KP9t1Y.js → en-DBj0AD5g.js} +36 -23
  20. package/dist/admin/{es-CHwF7YK-.js → es-D5Sn41_H.js} +36 -23
  21. package/dist/admin/{es-CqJcXo4j.mjs → es-lh6XoPb7.mjs} +36 -23
  22. package/dist/admin/{eu-D-snytN8.mjs → eu-Cuz6ijBX.mjs} +36 -23
  23. package/dist/admin/{eu-DvdbwE5E.js → eu-Qr3RvDPW.js} +36 -23
  24. package/dist/admin/fr-C4pmkPYn.js +49 -0
  25. package/dist/admin/fr-ChlDcZsG.mjs +49 -0
  26. package/dist/admin/{gu-3wJbbAmw.mjs → gu-B6zyD1bW.mjs} +36 -23
  27. package/dist/admin/{gu-D2LgVfMp.js → gu-BMZL76zM.js} +36 -23
  28. package/dist/admin/{he-Bjv7eygt.mjs → he-C5V-qZCX.mjs} +36 -23
  29. package/dist/admin/{he-DnhYpbvN.js → he-H6iBa45A.js} +36 -23
  30. package/dist/admin/{hi-DDD2E3A3.js → hi-Be8rPk7I.js} +36 -23
  31. package/dist/admin/{hi-CNiDezU7.mjs → hi-czhOWo6-.mjs} +36 -23
  32. package/dist/admin/{hu-C1_YkZHU.js → hu-DKp6kOmc.js} +36 -23
  33. package/dist/admin/{hu-aLaIWmGw.mjs → hu-NbZ3aiYV.mjs} +36 -23
  34. package/dist/admin/{id-u3wVE6Rv.js → id-DO0bwFgY.js} +36 -23
  35. package/dist/admin/{id-C8WRgGm1.mjs → id-NH9PvcR5.mjs} +36 -23
  36. package/dist/admin/{index-BXZI8nMZ.js → index-C9K2h5UC.js} +65 -12
  37. package/dist/admin/{index-D45I6rWF.mjs → index-C_4USMnn.mjs} +65 -12
  38. package/dist/admin/index.js +1 -1
  39. package/dist/admin/index.mjs +1 -1
  40. package/dist/admin/{it-CjoRoJj1.mjs → it-Cmrey6tg.mjs} +36 -23
  41. package/dist/admin/{it-CDw6dG9Z.js → it-Df6-7-M7.js} +36 -23
  42. package/dist/admin/{ja-CewucIUY.mjs → ja-DH3KMqOL.mjs} +36 -23
  43. package/dist/admin/{ja-CbMXy2ym.js → ja-HuAq9ZwT.js} +36 -23
  44. package/dist/admin/{ko-D-kAxDtd.mjs → ko-DPN28RE8.mjs} +36 -23
  45. package/dist/admin/{ko-BEtJPpfJ.js → ko-S9k8KA8K.js} +36 -23
  46. package/dist/admin/{ml-0fR2_MmA.js → ml-Bh9GGqcW.js} +36 -23
  47. package/dist/admin/{ml-DR3AaofF.mjs → ml-MsHNacm6.mjs} +36 -23
  48. package/dist/admin/{ms-COHLS5e5.mjs → ms-TjHAaxTd.mjs} +36 -23
  49. package/dist/admin/{ms-DLvuGSlk.js → ms-hO5YeEg4.js} +36 -23
  50. package/dist/admin/{nl-wj6kn642.js → nl-BF98NBwL.js} +36 -23
  51. package/dist/admin/{nl-DVtHsM2H.mjs → nl-BLILZU8-.mjs} +36 -23
  52. package/dist/admin/{no-D_0yjyCy.mjs → no-BtVZ-siy.mjs} +36 -23
  53. package/dist/admin/{no-DVBgWt8q.js → no-bl1OXlfa.js} +36 -23
  54. package/dist/admin/{pl-C3GNxjVX.mjs → pl-DCSB6LwZ.mjs} +36 -23
  55. package/dist/admin/{pl-B2ghisbC.js → pl-DCnOWIDw.js} +36 -23
  56. package/dist/admin/{pt-BR-BbKV8YoX.mjs → pt-BR-CeLqmj88.mjs} +36 -23
  57. package/dist/admin/{pt-BR-CfgNaB1-.js → pt-BR-D2_UrxTp.js} +36 -23
  58. package/dist/admin/{pt-DKe8rRWa.js → pt-DIu8RT_X.js} +36 -23
  59. package/dist/admin/{pt-z4K3cCjf.mjs → pt-fgjdOyW5.mjs} +36 -23
  60. package/dist/admin/{ru-C85izLFa.mjs → ru-B_hlpAyP.mjs} +36 -23
  61. package/dist/admin/{ru-BFSm68HC.js → ru-BccMCf0l.js} +36 -23
  62. package/dist/admin/{sa-B1XoTTrE.mjs → sa-BtuJ_I1t.mjs} +36 -23
  63. package/dist/admin/{sa-BOPaqylt.js → sa-D3A-fo85.js} +36 -23
  64. package/dist/admin/{sk-C48lUPuC.mjs → sk-mmuTFlCK.mjs} +36 -23
  65. package/dist/admin/{sk-Dd-S1612.js → sk-uSLC6KhO.js} +36 -23
  66. package/dist/admin/{sv-BLma_kJl.mjs → sv-BlaHc5ax.mjs} +36 -23
  67. package/dist/admin/{sv-lg64Cw78.js → sv-CuKk5tE-.js} +36 -23
  68. package/dist/admin/{th-DPbm5NrX.js → th-Bv3NKkYO.js} +36 -23
  69. package/dist/admin/{th-BJEu5n7q.mjs → th-BwyhFaeE.mjs} +36 -23
  70. package/dist/admin/{tokenHelpers-jtoRu0q5.js → tokenHelpers-B54WRTn1.js} +4 -10
  71. package/dist/admin/{tokenHelpers-DagDzpso.mjs → tokenHelpers-CKVyT1sz.mjs} +4 -10
  72. package/dist/admin/{tr-DkIUODKq.mjs → tr-BLocNlbZ.mjs} +36 -23
  73. package/dist/admin/{tr-Bm1QZr4v.js → tr-Bmvs-Hx-.js} +36 -23
  74. package/dist/admin/{uk-FARzIGx4.js → uk-BDxn-EZU.js} +36 -23
  75. package/dist/admin/{uk-D7ArtSe3.mjs → uk-CyZ10xtq.mjs} +36 -23
  76. package/dist/admin/{vi-DS0yslPP.mjs → vi-Bx_UJ8up.mjs} +36 -23
  77. package/dist/admin/{vi-Bi9B6eTY.js → vi-F_mqQCme.js} +36 -23
  78. package/dist/admin/{zh-DkEx28ZA.js → zh-CFZJPG5N.js} +36 -23
  79. package/dist/admin/{zh-DwCvIPSz.mjs → zh-CjJdRa3l.mjs} +36 -23
  80. package/dist/admin/{zh-Hans-BwwKCR6_.js → zh-Hans-4BhSwSQw.js} +36 -23
  81. package/dist/admin/{zh-Hans-DP2xZyda.mjs → zh-Hans-s7G2GUHU.mjs} +36 -23
  82. package/dist/server/index.js +487 -50
  83. package/dist/server/index.mjs +487 -50
  84. package/package.json +5 -4
  85. package/dist/admin/de-BuYn1AYX.mjs +0 -26
  86. package/dist/admin/de-GItli7en.js +0 -26
  87. package/dist/admin/fr-Bt6sS5GX.mjs +0 -26
  88. package/dist/admin/fr-CbCW6hVD.js +0 -26
@@ -2,10 +2,10 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
3
  import { Modal, Flex, Typography, Grid, Button, TextInput, Box, Field, Toggle } from "@strapi/design-system";
4
4
  import styled from "styled-components";
5
- import { g as getTranslation, I as InputOTP, a as InputOTPGroup, b as InputOTPSlot, c as InputOTPSeparator } from "./index-D45I6rWF.mjs";
5
+ import { g as getTranslation, I as InputOTP, a as InputOTPGroup, b as InputOTPSlot, c as InputOTPSeparator } from "./index-C_4USMnn.mjs";
6
6
  import { QRCodeCanvas } from "qrcode.react";
7
7
  import { useIntl } from "react-intl";
8
- import { g as getToken } from "./tokenHelpers-DagDzpso.mjs";
8
+ import { g as getToken } from "./tokenHelpers-CKVyT1sz.mjs";
9
9
  function ConfirmModal({
10
10
  open,
11
11
  onOpenChange,
@@ -120,11 +120,155 @@ function RemoveModal({ open, onOpenChange, onSubmit }) {
120
120
  ] })
121
121
  ] }) }) });
122
122
  }
123
+ function EmailOTPModal({
124
+ mode,
125
+ open,
126
+ email,
127
+ onOpenChange,
128
+ onSuccess
129
+ }) {
130
+ const { formatMessage } = useIntl();
131
+ const [step, setStep] = useState("send");
132
+ const [loading, setLoading] = useState(false);
133
+ const [error, setError] = useState(null);
134
+ const handleOpenChange = (nextOpen) => {
135
+ if (!nextOpen) {
136
+ setStep("send");
137
+ setError(null);
138
+ }
139
+ onOpenChange(nextOpen);
140
+ };
141
+ const handleSend = async () => {
142
+ const token = getToken();
143
+ setLoading(true);
144
+ setError(null);
145
+ try {
146
+ const endpoint = mode === "setup" ? "/strapi-identity/enable-email" : "/strapi-identity/disable-email/request";
147
+ const response = await fetch(endpoint, {
148
+ method: "POST",
149
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` }
150
+ });
151
+ const body = await response.json();
152
+ if (!response.ok) {
153
+ throw new Error(body.error || "Failed to send verification email");
154
+ }
155
+ setStep("confirm");
156
+ } catch (err) {
157
+ setError(err.message);
158
+ } finally {
159
+ setLoading(false);
160
+ }
161
+ };
162
+ const handleConfirm = async (e) => {
163
+ e.preventDefault();
164
+ const token = getToken();
165
+ const formData = new FormData(e.target);
166
+ const code = formData.get("otp");
167
+ setLoading(true);
168
+ setError(null);
169
+ try {
170
+ const endpoint = mode === "setup" ? "/strapi-identity/setup-email" : "/strapi-identity/disable";
171
+ const response = await fetch(endpoint, {
172
+ method: "POST",
173
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
174
+ body: JSON.stringify({ code })
175
+ });
176
+ const body = await response.json();
177
+ if (!response.ok) {
178
+ throw new Error(body.error || "Invalid or expired code");
179
+ }
180
+ handleOpenChange(false);
181
+ onSuccess();
182
+ } catch (err) {
183
+ setError(err.message);
184
+ } finally {
185
+ setLoading(false);
186
+ }
187
+ };
188
+ const title = mode === "setup" ? formatMessage({
189
+ id: getTranslation("email_otp.setup_title"),
190
+ defaultMessage: "Enable Email OTP"
191
+ }) : formatMessage({
192
+ id: getTranslation("email_otp.disable_title"),
193
+ defaultMessage: "Disable Email OTP"
194
+ });
195
+ return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
196
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
197
+ step === "send" ? /* @__PURE__ */ jsxs(Fragment, { children: [
198
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
199
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: mode === "setup" ? formatMessage(
200
+ {
201
+ id: getTranslation("email_otp.setup_description"),
202
+ defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to enable Email OTP."
203
+ },
204
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
205
+ ) : formatMessage(
206
+ {
207
+ id: getTranslation("email_otp.disable_description"),
208
+ defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to disable Email OTP."
209
+ },
210
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
211
+ ) }),
212
+ error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null
213
+ ] }) }),
214
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
215
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
216
+ /* @__PURE__ */ jsx(Button, { onClick: handleSend, loading, children: formatMessage({
217
+ id: getTranslation("email_otp.send_code"),
218
+ defaultMessage: "Send verification email"
219
+ }) })
220
+ ] })
221
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleConfirm, children: [
222
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
223
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage(
224
+ {
225
+ id: getTranslation("email_otp.confirm_description"),
226
+ defaultMessage: "Enter the 6-digit code sent to {email}."
227
+ },
228
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
229
+ ) }),
230
+ /* @__PURE__ */ jsxs(InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
231
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
232
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 0 }),
233
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 1 }),
234
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 2 })
235
+ ] }),
236
+ /* @__PURE__ */ jsx(InputOTPSeparator, {}),
237
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
238
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 3 }),
239
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 4 }),
240
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 5 })
241
+ ] })
242
+ ] }),
243
+ error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null,
244
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: () => handleSend(), children: formatMessage({
245
+ id: getTranslation("email_otp.resend_code"),
246
+ defaultMessage: "Resend code"
247
+ }) })
248
+ ] }) }),
249
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
250
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
251
+ id: "app.components.Button.cancel",
252
+ defaultMessage: "Cancel"
253
+ }) }) }),
254
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading, children: formatMessage({
255
+ id: "app.components.Button.confirm",
256
+ defaultMessage: "Confirm"
257
+ }) })
258
+ ] })
259
+ ] })
260
+ ] }) });
261
+ }
123
262
  const ProfileToggle = () => {
124
263
  const { formatMessage } = useIntl();
125
264
  const [enabled, setEnabled] = useState(null);
265
+ const [mfaType, setMfaType] = useState(null);
126
266
  const [mfaEnabled, setMfaEnabled] = useState(false);
267
+ const [emailConfigured, setEmailConfigured] = useState(false);
268
+ const [userEmail, setUserEmail] = useState("");
127
269
  const [disableDialogOpen, setDisableDialogOpen] = useState(false);
270
+ const [emailSetupOpen, setEmailSetupOpen] = useState(false);
271
+ const [emailDisableOpen, setEmailDisableOpen] = useState(false);
128
272
  const [modalOpen, setModalOpen] = useState(false);
129
273
  const [uri, setUri] = useState(null);
130
274
  const [secret, setSecret] = useState(null);
@@ -136,6 +280,9 @@ const ProfileToggle = () => {
136
280
  setDisableDialogOpen(true);
137
281
  return;
138
282
  }
283
+ if (enable && enabled === "full" && mfaType === "email") {
284
+ return;
285
+ }
139
286
  try {
140
287
  const response = await fetch("/strapi-identity/enable", {
141
288
  method: "POST",
@@ -154,11 +301,25 @@ const ProfileToggle = () => {
154
301
  setUri(data?.uri || null);
155
302
  setSecret(data?.secret || null);
156
303
  setEnabled(enable ? "temp" : null);
304
+ if (enable) setMfaType("totp");
157
305
  } catch (error) {
158
306
  console.error(error);
159
307
  setEnabled(null);
160
308
  }
161
309
  };
310
+ const handleEmailToggle = ({ target }) => {
311
+ const enable = target?.checked || false;
312
+ if (!enable && enabled === "full" && mfaType === "email") {
313
+ setEmailDisableOpen(true);
314
+ return;
315
+ }
316
+ if (enable && enabled === "full") {
317
+ return;
318
+ }
319
+ if (enable) {
320
+ setEmailSetupOpen(true);
321
+ }
322
+ };
162
323
  const handleConfirm = async (e) => {
163
324
  e.preventDefault();
164
325
  const form = e.target;
@@ -183,6 +344,7 @@ const ProfileToggle = () => {
183
344
  setUri(null);
184
345
  setSecret(null);
185
346
  setEnabled("full");
347
+ setMfaType("totp");
186
348
  } catch (error) {
187
349
  console.error(error);
188
350
  }
@@ -214,6 +376,7 @@ const ProfileToggle = () => {
214
376
  setUri(null);
215
377
  setSecret(null);
216
378
  setEnabled(null);
379
+ setMfaType(null);
217
380
  } catch (error) {
218
381
  console.error(error);
219
382
  }
@@ -223,7 +386,7 @@ const ProfileToggle = () => {
223
386
  (async () => {
224
387
  const token = getToken();
225
388
  try {
226
- const [status, enabled2] = await Promise.all([
389
+ const [statusRes, enabledRes, meRes] = await Promise.all([
227
390
  fetch("/strapi-identity/status", {
228
391
  method: "GET",
229
392
  headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
@@ -233,18 +396,37 @@ const ProfileToggle = () => {
233
396
  method: "GET",
234
397
  headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
235
398
  signal: ac.signal
399
+ }),
400
+ fetch("/admin/users/me", {
401
+ method: "GET",
402
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
403
+ signal: ac.signal
236
404
  })
237
405
  ]);
238
- const statusBody = await status.json();
239
- const enabledBody = await enabled2.json();
240
- if (!status.ok) {
241
- throw new Error(`${status.status} - ${statusBody.error || "Failed to set up MFA"}`);
406
+ const statusBody = await statusRes.json();
407
+ const enabledBody = await enabledRes.json();
408
+ if (!statusRes.ok) {
409
+ throw new Error(`${statusRes.status} - ${statusBody.error || "Failed to get MFA status"}`);
242
410
  }
243
- if (!enabled2.ok) {
244
- throw new Error(`${enabled2.status} - ${enabledBody.error || "Failed to get MFA config"}`);
411
+ if (!enabledRes.ok) {
412
+ throw new Error(`${enabledRes.status} - ${enabledBody.error || "Failed to get MFA config"}`);
245
413
  }
246
414
  setMfaEnabled(enabledBody.data);
247
415
  setEnabled(statusBody.data?.status || null);
416
+ setMfaType(statusBody.data?.type || null);
417
+ if (meRes.ok) {
418
+ const meBody = await meRes.json();
419
+ setUserEmail(meBody.data?.email || "");
420
+ const configRes = await fetch("/strapi-identity/config", {
421
+ method: "GET",
422
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
423
+ signal: ac.signal
424
+ });
425
+ if (configRes.ok) {
426
+ const configBody = await configRes.json();
427
+ setEmailConfigured(!!configBody.data?.email_enabled);
428
+ }
429
+ }
248
430
  } catch (error) {
249
431
  if (error.name === "AbortError") return;
250
432
  console.error("Failed to fetch MFA status:", error);
@@ -253,6 +435,10 @@ const ProfileToggle = () => {
253
435
  return () => ac.abort();
254
436
  }, []);
255
437
  if (!mfaEnabled) return null;
438
+ const totpChecked = enabled !== null && mfaType === "totp";
439
+ const emailChecked = enabled !== null && mfaType === "email";
440
+ const totpDisabled = enabled !== null && mfaType === "email";
441
+ const emailDisabled = enabled !== null && mfaType === "totp";
256
442
  return /* @__PURE__ */ jsxs(Fragment, { children: [
257
443
  /* @__PURE__ */ jsx(
258
444
  Box,
@@ -275,36 +461,78 @@ const ProfileToggle = () => {
275
461
  defaultMessage: "Add an additional layer of security to your account."
276
462
  }) })
277
463
  ] }),
278
- /* @__PURE__ */ jsx(Grid.Root, { tag: "div", gap: 5, children: /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, alignItems: "stretch", children: /* @__PURE__ */ jsxs(
279
- Field.Root,
280
- {
281
- width: "100%",
282
- name: "two-factor-authentication",
283
- id: "two-factor-authentication",
284
- children: [
285
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
286
- id: getTranslation("profile.toggle_label"),
287
- defaultMessage: "Enable Two-Factor Authentication"
288
- }) }),
289
- /* @__PURE__ */ jsx(
290
- Toggle,
291
- {
292
- offLabel: formatMessage({
293
- id: "app.components.ToggleCheckbox.off-label",
294
- defaultMessage: "False"
295
- }),
296
- onLabel: formatMessage({
297
- id: "app.components.ToggleCheckbox.on-label",
298
- defaultMessage: "True"
299
- }),
300
- checked: enabled !== null,
301
- onChange: handleToggle
302
- }
303
- ),
304
- /* @__PURE__ */ jsx(Field.Hint, {})
305
- ]
306
- }
307
- ) }) })
464
+ /* @__PURE__ */ jsxs(Grid.Root, { tag: "div", gap: 5, children: [
465
+ /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, alignItems: "stretch", children: /* @__PURE__ */ jsxs(
466
+ Field.Root,
467
+ {
468
+ width: "100%",
469
+ name: "two-factor-authentication",
470
+ id: "two-factor-authentication",
471
+ hint: totpDisabled ? formatMessage({
472
+ id: getTranslation("profile.totp_disabled_hint"),
473
+ defaultMessage: "Disable Email OTP first to enable the authenticator app."
474
+ }) : void 0,
475
+ children: [
476
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
477
+ id: getTranslation("profile.toggle_label"),
478
+ defaultMessage: "Enable Two-Factor Authentication"
479
+ }) }),
480
+ /* @__PURE__ */ jsx(
481
+ Toggle,
482
+ {
483
+ offLabel: formatMessage({
484
+ id: "app.components.ToggleCheckbox.off-label",
485
+ defaultMessage: "False"
486
+ }),
487
+ onLabel: formatMessage({
488
+ id: "app.components.ToggleCheckbox.on-label",
489
+ defaultMessage: "True"
490
+ }),
491
+ checked: totpChecked,
492
+ onChange: handleToggle,
493
+ disabled: totpDisabled
494
+ }
495
+ ),
496
+ /* @__PURE__ */ jsx(Field.Hint, {})
497
+ ]
498
+ }
499
+ ) }),
500
+ emailConfigured && /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, alignItems: "stretch", children: /* @__PURE__ */ jsxs(
501
+ Field.Root,
502
+ {
503
+ width: "100%",
504
+ name: "email-otp",
505
+ id: "email-otp",
506
+ hint: emailDisabled ? formatMessage({
507
+ id: getTranslation("profile.email_otp_disabled_hint"),
508
+ defaultMessage: "Disable the authenticator app first to enable Email OTP."
509
+ }) : void 0,
510
+ children: [
511
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
512
+ id: getTranslation("profile.email_otp_label"),
513
+ defaultMessage: "Enable Email OTP"
514
+ }) }),
515
+ /* @__PURE__ */ jsx(
516
+ Toggle,
517
+ {
518
+ offLabel: formatMessage({
519
+ id: "app.components.ToggleCheckbox.off-label",
520
+ defaultMessage: "False"
521
+ }),
522
+ onLabel: formatMessage({
523
+ id: "app.components.ToggleCheckbox.on-label",
524
+ defaultMessage: "True"
525
+ }),
526
+ checked: emailChecked,
527
+ onChange: handleEmailToggle,
528
+ disabled: emailDisabled
529
+ }
530
+ ),
531
+ /* @__PURE__ */ jsx(Field.Hint, {})
532
+ ]
533
+ }
534
+ ) })
535
+ ] })
308
536
  ] })
309
537
  }
310
538
  ),
@@ -326,6 +554,38 @@ const ProfileToggle = () => {
326
554
  onOpenChange: setDisableDialogOpen,
327
555
  onSubmit: handleDisable
328
556
  }
557
+ ),
558
+ /* @__PURE__ */ jsx(
559
+ EmailOTPModal,
560
+ {
561
+ mode: "setup",
562
+ open: emailSetupOpen,
563
+ email: userEmail,
564
+ onOpenChange: (open) => {
565
+ if (!open) setEmailSetupOpen(false);
566
+ },
567
+ onSuccess: () => {
568
+ setEnabled("full");
569
+ setMfaType("email");
570
+ setEmailSetupOpen(false);
571
+ }
572
+ }
573
+ ),
574
+ /* @__PURE__ */ jsx(
575
+ EmailOTPModal,
576
+ {
577
+ mode: "disable",
578
+ open: emailDisableOpen,
579
+ email: userEmail,
580
+ onOpenChange: (open) => {
581
+ if (!open) setEmailDisableOpen(false);
582
+ },
583
+ onSuccess: () => {
584
+ setEnabled(null);
585
+ setMfaType(null);
586
+ setEmailDisableOpen(false);
587
+ }
588
+ }
329
589
  )
330
590
  ] });
331
591
  };