@greatapps/common 1.1.24 → 1.1.26

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 (128) hide show
  1. package/dist/components/account/ConfigurationsMyAccountModal.mjs +121 -0
  2. package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -0
  3. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs +45 -0
  4. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -0
  5. package/dist/components/account/DisableTwoFactorAuthModal.mjs +67 -0
  6. package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -0
  7. package/dist/components/account/TwoFactorAuthModal.mjs +190 -0
  8. package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -0
  9. package/dist/components/account/constants.mjs +32 -0
  10. package/dist/components/account/constants.mjs.map +1 -0
  11. package/dist/components/account/hooks/useChangeEmailForm.mjs +53 -0
  12. package/dist/components/account/hooks/useChangeEmailForm.mjs.map +1 -0
  13. package/dist/components/account/hooks/useChangePasswordForm.mjs +47 -0
  14. package/dist/components/account/hooks/useChangePasswordForm.mjs.map +1 -0
  15. package/dist/components/account/hooks/useChangePhoneForm.mjs +64 -0
  16. package/dist/components/account/hooks/useChangePhoneForm.mjs.map +1 -0
  17. package/dist/components/account/hooks/useConfigurationsModal.mjs +33 -0
  18. package/dist/components/account/hooks/useConfigurationsModal.mjs.map +1 -0
  19. package/dist/components/account/hooks/useDisableTwoFactorAuthForm.mjs +54 -0
  20. package/dist/components/account/hooks/useDisableTwoFactorAuthForm.mjs.map +1 -0
  21. package/dist/components/account/hooks/useOtpVerification.mjs +94 -0
  22. package/dist/components/account/hooks/useOtpVerification.mjs.map +1 -0
  23. package/dist/components/account/hooks/useTwoFactorAuthForm.mjs +88 -0
  24. package/dist/components/account/hooks/useTwoFactorAuthForm.mjs.map +1 -0
  25. package/dist/components/account/sections/ChangeEmailModal.mjs +180 -0
  26. package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -0
  27. package/dist/components/account/sections/ChangePasswordSection.mjs +64 -0
  28. package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -0
  29. package/dist/components/account/sections/ChangePhoneModal.mjs +182 -0
  30. package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -0
  31. package/dist/components/account/sections/MyProfileSection.mjs +312 -0
  32. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -0
  33. package/dist/components/account/sections/PreferencesSection.mjs +246 -0
  34. package/dist/components/account/sections/PreferencesSection.mjs.map +1 -0
  35. package/dist/components/account/sections/SecuritySection.mjs +147 -0
  36. package/dist/components/account/sections/SecuritySection.mjs.map +1 -0
  37. package/dist/components/ui/form/ComboboxField.mjs +130 -0
  38. package/dist/components/ui/form/ComboboxField.mjs.map +1 -0
  39. package/dist/components/ui/form/FormField.mjs +103 -0
  40. package/dist/components/ui/form/FormField.mjs.map +1 -0
  41. package/dist/components/ui/form/PhoneInput.mjs +78 -0
  42. package/dist/components/ui/form/PhoneInput.mjs.map +1 -0
  43. package/dist/components/ui/form/SelectField.mjs +80 -0
  44. package/dist/components/ui/form/SelectField.mjs.map +1 -0
  45. package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs +40 -0
  46. package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs.map +1 -0
  47. package/dist/components/ui/form/TextAreaField.mjs +56 -0
  48. package/dist/components/ui/form/TextAreaField.mjs.map +1 -0
  49. package/dist/enums/AccountSectionType.mjs +11 -0
  50. package/dist/enums/AccountSectionType.mjs.map +1 -0
  51. package/dist/hooks/useCountdownTimer.mjs +29 -0
  52. package/dist/hooks/useCountdownTimer.mjs.map +1 -0
  53. package/dist/hooks/useIsMobile.mjs +18 -0
  54. package/dist/hooks/useIsMobile.mjs.map +1 -0
  55. package/dist/hooks/usePasswordVisibility.mjs +13 -0
  56. package/dist/hooks/usePasswordVisibility.mjs.map +1 -0
  57. package/dist/index.mjs +80 -0
  58. package/dist/index.mjs.map +1 -1
  59. package/dist/modules/accounts/actions/account-management.action.mjs +163 -0
  60. package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -0
  61. package/dist/modules/accounts/hooks/useAccountManagement.mjs +64 -0
  62. package/dist/modules/accounts/hooks/useAccountManagement.mjs.map +1 -0
  63. package/dist/modules/accounts/services/account.service.mjs +162 -25
  64. package/dist/modules/accounts/services/account.service.mjs.map +1 -1
  65. package/dist/modules/accounts/services/two-factor.service.mjs +77 -0
  66. package/dist/modules/accounts/services/two-factor.service.mjs.map +1 -0
  67. package/dist/modules/auth/services/auth.service.mjs +7 -4
  68. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  69. package/dist/server.mjs +36 -0
  70. package/dist/server.mjs.map +1 -1
  71. package/dist/utils/browser/clipboard.mjs +36 -0
  72. package/dist/utils/browser/clipboard.mjs.map +1 -0
  73. package/dist/utils/file/index.mjs +9 -0
  74. package/dist/utils/file/index.mjs.map +1 -0
  75. package/dist/utils/format/masks.mjs +56 -0
  76. package/dist/utils/format/masks.mjs.map +1 -0
  77. package/dist/utils/intl/locales.mjs +12 -0
  78. package/dist/utils/intl/locales.mjs.map +1 -0
  79. package/dist/utils/intl/timezones.mjs +41 -0
  80. package/dist/utils/intl/timezones.mjs.map +1 -0
  81. package/dist/utils/validators/account.mjs +26 -0
  82. package/dist/utils/validators/account.mjs.map +1 -0
  83. package/dist/utils/validators/common.mjs +47 -0
  84. package/dist/utils/validators/common.mjs.map +1 -0
  85. package/package.json +5 -1
  86. package/src/components/account/ConfigurationsMyAccountModal.tsx +147 -0
  87. package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -0
  88. package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -0
  89. package/src/components/account/TwoFactorAuthModal.tsx +221 -0
  90. package/src/components/account/constants.ts +29 -0
  91. package/src/components/account/hooks/useChangeEmailForm.tsx +56 -0
  92. package/src/components/account/hooks/useChangePasswordForm.tsx +59 -0
  93. package/src/components/account/hooks/useChangePhoneForm.tsx +69 -0
  94. package/src/components/account/hooks/useConfigurationsModal.ts +40 -0
  95. package/src/components/account/hooks/useDisableTwoFactorAuthForm.tsx +69 -0
  96. package/src/components/account/hooks/useOtpVerification.tsx +116 -0
  97. package/src/components/account/hooks/useTwoFactorAuthForm.tsx +114 -0
  98. package/src/components/account/sections/ChangeEmailModal.tsx +224 -0
  99. package/src/components/account/sections/ChangePasswordSection.tsx +64 -0
  100. package/src/components/account/sections/ChangePhoneModal.tsx +229 -0
  101. package/src/components/account/sections/MyProfileSection.tsx +337 -0
  102. package/src/components/account/sections/PreferencesSection.tsx +277 -0
  103. package/src/components/account/sections/SecuritySection.tsx +160 -0
  104. package/src/components/ui/form/ComboboxField.tsx +154 -0
  105. package/src/components/ui/form/FormField.tsx +130 -0
  106. package/src/components/ui/form/PhoneInput.tsx +98 -0
  107. package/src/components/ui/form/SelectField.tsx +118 -0
  108. package/src/components/ui/form/SwitchOptionFieldWithIcon.tsx +47 -0
  109. package/src/components/ui/form/TextAreaField.tsx +70 -0
  110. package/src/enums/AccountSectionType.ts +6 -0
  111. package/src/hooks/useCountdownTimer.ts +41 -0
  112. package/src/hooks/useIsMobile.ts +19 -0
  113. package/src/hooks/usePasswordVisibility.ts +13 -0
  114. package/src/index.ts +70 -0
  115. package/src/modules/accounts/actions/account-management.action.ts +197 -0
  116. package/src/modules/accounts/hooks/useAccountManagement.ts +79 -0
  117. package/src/modules/accounts/services/account.service.ts +229 -50
  118. package/src/modules/accounts/services/two-factor.service.ts +98 -0
  119. package/src/modules/accounts/types.ts +157 -0
  120. package/src/modules/auth/services/auth.service.ts +9 -5
  121. package/src/server.ts +21 -0
  122. package/src/utils/browser/clipboard.ts +34 -0
  123. package/src/utils/file/index.ts +5 -0
  124. package/src/utils/format/masks.ts +52 -0
  125. package/src/utils/intl/locales.ts +15 -0
  126. package/src/utils/intl/timezones.ts +53 -0
  127. package/src/utils/validators/account.ts +36 -0
  128. package/src/utils/validators/common.ts +43 -0
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useForm } from "react-hook-form";
4
+ import { zodResolver } from "@hookform/resolvers/zod";
5
+ import { useMutation } from "@tanstack/react-query";
6
+ import { toast } from "sonner";
7
+ import { Toast } from "../../ui/feedback/Toast";
8
+ import { changePasswordSchema } from "../../../utils/validators/account";
9
+ import { changePasswordAction } from "../../../modules/accounts/actions/account-management.action";
10
+ function useChangePasswordForm({ onSuccess } = {}) {
11
+ const form = useForm({
12
+ resolver: zodResolver(changePasswordSchema),
13
+ mode: "onChange",
14
+ defaultValues: {
15
+ currentPassword: "",
16
+ newPassword: ""
17
+ }
18
+ });
19
+ const mutation = useMutation({
20
+ mutationFn: changePasswordAction,
21
+ onSuccess: (result) => {
22
+ if (!result.success) {
23
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: result.error ?? "Erro ao alterar senha", toastId: t }));
24
+ return;
25
+ }
26
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "success", message: "Senha alterada com sucesso", toastId: t }));
27
+ form.reset();
28
+ onSuccess?.();
29
+ },
30
+ onError: () => {
31
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: "Erro ao alterar senha. Tente novamente.", toastId: t }));
32
+ }
33
+ });
34
+ const onSubmit = (data) => {
35
+ mutation.mutate(data);
36
+ };
37
+ return {
38
+ register: form.register,
39
+ handleSubmit: form.handleSubmit(onSubmit),
40
+ errors: form.formState.errors,
41
+ isLoading: mutation.isPending
42
+ };
43
+ }
44
+ export {
45
+ useChangePasswordForm as default
46
+ };
47
+ //# sourceMappingURL=useChangePasswordForm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useChangePasswordForm.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useForm } from 'react-hook-form';\r\nimport { zodResolver } from '@hookform/resolvers/zod';\r\nimport { useMutation } from '@tanstack/react-query';\r\nimport { toast } from 'sonner';\r\nimport { Toast } from '../../ui/feedback/Toast';\r\nimport { changePasswordSchema, type ChangePasswordFormData } from '../../../utils/validators/account';\r\nimport { changePasswordAction } from '../../../modules/accounts/actions/account-management.action';\r\n\r\ninterface UseChangePasswordFormProps {\r\n onSuccess?: () => void;\r\n}\r\n\r\nexport default function useChangePasswordForm({ onSuccess }: UseChangePasswordFormProps = {}) {\r\n const form = useForm<ChangePasswordFormData>({\r\n resolver: zodResolver(changePasswordSchema),\r\n mode: 'onChange',\r\n defaultValues: {\r\n currentPassword: '',\r\n newPassword: '',\r\n },\r\n });\r\n\r\n const mutation = useMutation({\r\n mutationFn: changePasswordAction,\r\n onSuccess: (result) => {\r\n if (!result.success) {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message={result.error ?? 'Erro ao alterar senha'} toastId={t} />\r\n ));\r\n return;\r\n }\r\n\r\n toast.custom((t) => (\r\n <Toast variant=\"success\" message=\"Senha alterada com sucesso\" toastId={t} />\r\n ));\r\n\r\n form.reset();\r\n onSuccess?.();\r\n },\r\n onError: () => {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message=\"Erro ao alterar senha. Tente novamente.\" toastId={t} />\r\n ));\r\n },\r\n });\r\n\r\n const onSubmit = (data: ChangePasswordFormData) => {\r\n mutation.mutate(data);\r\n };\r\n\r\n return {\r\n register: form.register,\r\n handleSubmit: form.handleSubmit(onSubmit),\r\n errors: form.formState.errors,\r\n isLoading: mutation.isPending,\r\n };\r\n}\r\n"],"mappings":";AA6BU;AA3BV,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,4BAAyD;AAClE,SAAS,4BAA4B;AAMtB,SAAR,sBAAuC,EAAE,UAAU,IAAgC,CAAC,GAAG;AAC5F,QAAM,OAAO,QAAgC;AAAA,IAC3C,UAAU,YAAY,oBAAoB;AAAA,IAC1C,MAAM;AAAA,IACN,eAAe;AAAA,MACb,iBAAiB;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAED,QAAM,WAAW,YAAY;AAAA,IAC3B,YAAY;AAAA,IACZ,WAAW,CAAC,WAAW;AACrB,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAS,OAAO,SAAS,yBAAyB,SAAS,GAAG,CACtF;AACD;AAAA,MACF;AAEA,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,WAAU,SAAQ,8BAA6B,SAAS,GAAG,CAC3E;AAED,WAAK,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,IACA,SAAS,MAAM;AACb,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAQ,2CAA0C,SAAS,GAAG,CACtF;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,WAAW,CAAC,SAAiC;AACjD,aAAS,OAAO,IAAI;AAAA,EACtB;AAEA,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,cAAc,KAAK,aAAa,QAAQ;AAAA,IACxC,QAAQ,KAAK,UAAU;AAAA,IACvB,WAAW,SAAS;AAAA,EACtB;AACF;","names":[]}
@@ -0,0 +1,64 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { useForm } from "react-hook-form";
5
+ import { zodResolver } from "@hookform/resolvers/zod";
6
+ import { toast } from "sonner";
7
+ import { Toast } from "../../ui/feedback/Toast";
8
+ import { changePhoneSchema } from "../../../utils/validators/account";
9
+ import { formatPhone } from "../../../utils/format/masks";
10
+ import { requestPhoneChangeAction } from "../../../modules/accounts/actions/account-management.action";
11
+ function useChangePhoneForm() {
12
+ const [showVerification, setShowVerification] = useState(false);
13
+ const form = useForm({
14
+ resolver: zodResolver(changePhoneSchema),
15
+ mode: "onChange",
16
+ defaultValues: { phone: "" }
17
+ });
18
+ const phoneValue = form.watch("phone");
19
+ const errors = form.formState.errors;
20
+ const isSubmitting = form.formState.isSubmitting;
21
+ const handlePhoneChange = useCallback(
22
+ (e) => {
23
+ const formatted = formatPhone(e.target.value);
24
+ form.setValue("phone", formatted, { shouldValidate: true });
25
+ },
26
+ [form]
27
+ );
28
+ const handleContinue = form.handleSubmit(async (data) => {
29
+ const result = await requestPhoneChangeAction(data.phone);
30
+ if (!result.success) {
31
+ toast.custom((t) => /* @__PURE__ */ jsx(
32
+ Toast,
33
+ {
34
+ variant: "error",
35
+ message: result.error ?? "N\xFAmero j\xE1 existente ou ocorreu um erro. Tente novamente mais tarde.",
36
+ toastId: t
37
+ }
38
+ ));
39
+ return;
40
+ }
41
+ setShowVerification(true);
42
+ });
43
+ const handleBack = useCallback(() => {
44
+ setShowVerification(false);
45
+ }, []);
46
+ const resetForm = useCallback(() => {
47
+ form.reset();
48
+ setShowVerification(false);
49
+ }, [form]);
50
+ return {
51
+ showVerification,
52
+ phoneValue,
53
+ isSubmitting,
54
+ errors,
55
+ handlePhoneChange,
56
+ handleContinue,
57
+ handleBack,
58
+ resetForm
59
+ };
60
+ }
61
+ export {
62
+ useChangePhoneForm as default
63
+ };
64
+ //# sourceMappingURL=useChangePhoneForm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useChangePhoneForm.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport { useForm } from 'react-hook-form';\r\nimport { zodResolver } from '@hookform/resolvers/zod';\r\nimport { toast } from 'sonner';\r\nimport { Toast } from '../../ui/feedback/Toast';\r\nimport { changePhoneSchema, type ChangePhoneFormData } from '../../../utils/validators/account';\r\nimport { formatPhone } from '../../../utils/format/masks';\r\nimport { requestPhoneChangeAction } from '../../../modules/accounts/actions/account-management.action';\r\n\r\nexport default function useChangePhoneForm() {\r\n const [showVerification, setShowVerification] = useState(false);\r\n\r\n const form = useForm<ChangePhoneFormData>({\r\n resolver: zodResolver(changePhoneSchema),\r\n mode: 'onChange',\r\n defaultValues: { phone: '' },\r\n });\r\n\r\n const phoneValue = form.watch('phone');\r\n const errors = form.formState.errors;\r\n const isSubmitting = form.formState.isSubmitting;\r\n\r\n const handlePhoneChange = useCallback(\r\n (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const formatted = formatPhone(e.target.value);\r\n form.setValue('phone', formatted, { shouldValidate: true });\r\n },\r\n [form]\r\n );\r\n\r\n const handleContinue = form.handleSubmit(async (data) => {\r\n const result = await requestPhoneChangeAction(data.phone);\r\n\r\n if (!result.success) {\r\n toast.custom((t) => (\r\n <Toast\r\n variant=\"error\"\r\n message={result.error ?? 'Número já existente ou ocorreu um erro. Tente novamente mais tarde.'}\r\n toastId={t}\r\n />\r\n ));\r\n return;\r\n }\r\n\r\n setShowVerification(true);\r\n });\r\n\r\n const handleBack = useCallback(() => {\r\n setShowVerification(false);\r\n }, []);\r\n\r\n const resetForm = useCallback(() => {\r\n form.reset();\r\n setShowVerification(false);\r\n }, [form]);\r\n\r\n return {\r\n showVerification,\r\n phoneValue,\r\n isSubmitting,\r\n errors,\r\n handlePhoneChange,\r\n handleContinue,\r\n handleBack,\r\n resetForm,\r\n };\r\n}\r\n"],"mappings":";AAqCQ;AAnCR,SAAS,UAAU,mBAAmB;AACtC,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,yBAAmD;AAC5D,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AAE1B,SAAR,qBAAsC;AAC3C,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAE9D,QAAM,OAAO,QAA6B;AAAA,IACxC,UAAU,YAAY,iBAAiB;AAAA,IACvC,MAAM;AAAA,IACN,eAAe,EAAE,OAAO,GAAG;AAAA,EAC7B,CAAC;AAED,QAAM,aAAa,KAAK,MAAM,OAAO;AACrC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,eAAe,KAAK,UAAU;AAEpC,QAAM,oBAAoB;AAAA,IACxB,CAAC,MAA2C;AAC1C,YAAM,YAAY,YAAY,EAAE,OAAO,KAAK;AAC5C,WAAK,SAAS,SAAS,WAAW,EAAE,gBAAgB,KAAK,CAAC;AAAA,IAC5D;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAEA,QAAM,iBAAiB,KAAK,aAAa,OAAO,SAAS;AACvD,UAAM,SAAS,MAAM,yBAAyB,KAAK,KAAK;AAExD,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,OAAO,CAAC,MACZ;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAS,OAAO,SAAS;AAAA,UACzB,SAAS;AAAA;AAAA,MACX,CACD;AACD;AAAA,IACF;AAEA,wBAAoB,IAAI;AAAA,EAC1B,CAAC;AAED,QAAM,aAAa,YAAY,MAAM;AACnC,wBAAoB,KAAK;AAAA,EAC3B,GAAG,CAAC,CAAC;AAEL,QAAM,YAAY,YAAY,MAAM;AAClC,SAAK,MAAM;AACX,wBAAoB,KAAK;AAAA,EAC3B,GAAG,CAAC,IAAI,CAAC;AAET,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { useState, useCallback, useEffect } from "react";
3
+ import { AccountSectionType } from "../../../enums/AccountSectionType";
4
+ function useConfigurationsModal({
5
+ isOpen,
6
+ initialSection
7
+ }) {
8
+ const [activeSection, setActiveSection] = useState(
9
+ AccountSectionType.MY_PROFILE
10
+ );
11
+ useEffect(() => {
12
+ if (isOpen && initialSection) {
13
+ setActiveSection(initialSection);
14
+ } else if (isOpen && !initialSection) {
15
+ setActiveSection(AccountSectionType.MY_PROFILE);
16
+ }
17
+ }, [isOpen, initialSection]);
18
+ const handleSectionChange = useCallback((section) => {
19
+ setActiveSection(section);
20
+ }, []);
21
+ const resetSection = useCallback(() => {
22
+ setActiveSection(AccountSectionType.MY_PROFILE);
23
+ }, []);
24
+ return {
25
+ activeSection,
26
+ setActiveSection: handleSectionChange,
27
+ resetSection
28
+ };
29
+ }
30
+ export {
31
+ useConfigurationsModal as default
32
+ };
33
+ //# sourceMappingURL=useConfigurationsModal.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useConfigurationsModal.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback, useEffect } from 'react';\r\nimport { AccountSectionType } from '../../../enums/AccountSectionType';\r\n\r\ninterface UseConfigurationsModalProps {\r\n isOpen: boolean;\r\n initialSection?: AccountSectionType;\r\n}\r\n\r\nexport default function useConfigurationsModal({\r\n isOpen,\r\n initialSection,\r\n}: UseConfigurationsModalProps) {\r\n const [activeSection, setActiveSection] = useState<AccountSectionType>(\r\n AccountSectionType.MY_PROFILE\r\n );\r\n\r\n useEffect(() => {\r\n if (isOpen && initialSection) {\r\n setActiveSection(initialSection);\r\n } else if (isOpen && !initialSection) {\r\n setActiveSection(AccountSectionType.MY_PROFILE);\r\n }\r\n }, [isOpen, initialSection]);\r\n\r\n const handleSectionChange = useCallback((section: AccountSectionType) => {\r\n setActiveSection(section);\r\n }, []);\r\n\r\n const resetSection = useCallback(() => {\r\n setActiveSection(AccountSectionType.MY_PROFILE);\r\n }, []);\r\n\r\n return {\r\n activeSection,\r\n setActiveSection: handleSectionChange,\r\n resetSection,\r\n };\r\n}\r\n"],"mappings":";AAEA,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,0BAA0B;AAOpB,SAAR,uBAAwC;AAAA,EAC7C;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,CAAC,eAAe,gBAAgB,IAAI;AAAA,IACxC,mBAAmB;AAAA,EACrB;AAEA,YAAU,MAAM;AACd,QAAI,UAAU,gBAAgB;AAC5B,uBAAiB,cAAc;AAAA,IACjC,WAAW,UAAU,CAAC,gBAAgB;AACpC,uBAAiB,mBAAmB,UAAU;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,CAAC;AAE3B,QAAM,sBAAsB,YAAY,CAAC,YAAgC;AACvE,qBAAiB,OAAO;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,MAAM;AACrC,qBAAiB,mBAAmB,UAAU;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
5
+ import { toast } from "sonner";
6
+ import { Toast } from "../../ui/feedback/Toast";
7
+ import { USER_QUERY_KEY } from "../../../modules/auth/hooks/useUserQuery";
8
+ import { disableTwoFactorAction } from "../../../modules/accounts/actions/account-management.action";
9
+ function useDisableTwoFactorAuthForm({
10
+ onClose,
11
+ onSuccess
12
+ }) {
13
+ const [code, setCode] = useState("");
14
+ const queryClient = useQueryClient();
15
+ const isValid = code.length === 6;
16
+ const mutation = useMutation({
17
+ mutationFn: (otpCode) => disableTwoFactorAction(otpCode),
18
+ onSuccess: (result) => {
19
+ if (!result.success) {
20
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: result.error ?? "C\xF3digo inv\xE1lido", toastId: t }));
21
+ return;
22
+ }
23
+ queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
24
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "success", message: "Autentica\xE7\xE3o de dois fatores desabilitada", toastId: t }));
25
+ setCode("");
26
+ onSuccess?.();
27
+ },
28
+ onError: () => {
29
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: "Erro ao desabilitar 2FA. Tente novamente.", toastId: t }));
30
+ }
31
+ });
32
+ const { mutate, reset } = mutation;
33
+ const handleClose = useCallback(() => {
34
+ setCode("");
35
+ reset();
36
+ onClose();
37
+ }, [onClose, reset]);
38
+ const handleSubmit = useCallback(() => {
39
+ if (!isValid) return;
40
+ mutate(code);
41
+ }, [code, isValid, mutate]);
42
+ return {
43
+ code,
44
+ setCode,
45
+ isValid,
46
+ isLoading: mutation.isPending,
47
+ handleClose,
48
+ handleSubmit
49
+ };
50
+ }
51
+ export {
52
+ useDisableTwoFactorAuthForm as default
53
+ };
54
+ //# sourceMappingURL=useDisableTwoFactorAuthForm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useDisableTwoFactorAuthForm.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\r\nimport { toast } from 'sonner';\r\nimport { Toast } from '../../ui/feedback/Toast';\r\nimport { USER_QUERY_KEY } from '../../../modules/auth/hooks/useUserQuery';\r\nimport { disableTwoFactorAction } from '../../../modules/accounts/actions/account-management.action';\r\n\r\ninterface UseDisableTwoFactorAuthFormProps {\r\n onClose: () => void;\r\n onSuccess?: () => void;\r\n}\r\n\r\nexport default function useDisableTwoFactorAuthForm({\r\n onClose,\r\n onSuccess,\r\n}: UseDisableTwoFactorAuthFormProps) {\r\n const [code, setCode] = useState('');\r\n const queryClient = useQueryClient();\r\n\r\n const isValid = code.length === 6;\r\n\r\n const mutation = useMutation({\r\n mutationFn: (otpCode: string) => disableTwoFactorAction(otpCode),\r\n onSuccess: (result) => {\r\n if (!result.success) {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message={result.error ?? 'Código inválido'} toastId={t} />\r\n ));\r\n return;\r\n }\r\n\r\n queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n toast.custom((t) => (\r\n <Toast variant=\"success\" message=\"Autenticação de dois fatores desabilitada\" toastId={t} />\r\n ));\r\n setCode('');\r\n onSuccess?.();\r\n },\r\n onError: () => {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message=\"Erro ao desabilitar 2FA. Tente novamente.\" toastId={t} />\r\n ));\r\n },\r\n });\r\n\r\n const { mutate, reset } = mutation;\r\n\r\n const handleClose = useCallback(() => {\r\n setCode('');\r\n reset();\r\n onClose();\r\n }, [onClose, reset]);\r\n\r\n const handleSubmit = useCallback(() => {\r\n if (!isValid) return;\r\n mutate(code);\r\n }, [code, isValid, mutate]);\r\n\r\n return {\r\n code,\r\n setCode,\r\n isValid,\r\n isLoading: mutation.isPending,\r\n handleClose,\r\n handleSubmit,\r\n };\r\n}\r\n"],"mappings":";AA4BU;AA1BV,SAAS,UAAU,mBAAmB;AACtC,SAAS,aAAa,sBAAsB;AAC5C,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,sBAAsB;AAC/B,SAAS,8BAA8B;AAOxB,SAAR,4BAA6C;AAAA,EAClD;AAAA,EACA;AACF,GAAqC;AACnC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,cAAc,eAAe;AAEnC,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,WAAW,YAAY;AAAA,IAC3B,YAAY,CAAC,YAAoB,uBAAuB,OAAO;AAAA,IAC/D,WAAW,CAAC,WAAW;AACrB,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAS,OAAO,SAAS,yBAAmB,SAAS,GAAG,CAChF;AACD;AAAA,MACF;AAEA,kBAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AAC1D,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,WAAU,SAAQ,mDAA4C,SAAS,GAAG,CAC1F;AACD,cAAQ,EAAE;AACV,kBAAY;AAAA,IACd;AAAA,IACA,SAAS,MAAM;AACb,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAQ,6CAA4C,SAAS,GAAG,CACxF;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,EAAE,QAAQ,MAAM,IAAI;AAE1B,QAAM,cAAc,YAAY,MAAM;AACpC,YAAQ,EAAE;AACV,UAAM;AACN,YAAQ;AAAA,EACV,GAAG,CAAC,SAAS,KAAK,CAAC;AAEnB,QAAM,eAAe,YAAY,MAAM;AACrC,QAAI,CAAC,QAAS;AACd,WAAO,IAAI;AAAA,EACb,GAAG,CAAC,MAAM,SAAS,MAAM,CAAC;AAE1B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,SAAS;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { toast } from "sonner";
5
+ import { Toast } from "../../ui/feedback/Toast";
6
+ import useCountdownTimer from "../../../hooks/useCountdownTimer";
7
+ import { OTP_CODE_LENGTH, VALID_OTP_CODE } from "../../../utils/validators/account";
8
+ import { hasExactLength } from "../../../utils/validators/common";
9
+ function useOtpVerification({
10
+ onSuccess,
11
+ successMessage,
12
+ validateFn,
13
+ resendFn
14
+ }) {
15
+ const [code, setCode] = useState("");
16
+ const [isLoading, setIsLoading] = useState(false);
17
+ const [hasError, setHasError] = useState(false);
18
+ const {
19
+ seconds: timer,
20
+ isExpired: canResend,
21
+ reset: resetTimer
22
+ } = useCountdownTimer({ initialSeconds: 59 });
23
+ const handleCodeChange = useCallback(
24
+ (value) => {
25
+ setCode(value.toUpperCase());
26
+ if (hasError) {
27
+ setHasError(false);
28
+ }
29
+ },
30
+ [hasError]
31
+ );
32
+ const handleValidate = useCallback(async () => {
33
+ if (!hasExactLength(code, OTP_CODE_LENGTH)) return;
34
+ setIsLoading(true);
35
+ setHasError(false);
36
+ try {
37
+ let isValid;
38
+ if (validateFn) {
39
+ isValid = await validateFn(code);
40
+ } else {
41
+ await new Promise((resolve) => setTimeout(resolve, 500));
42
+ isValid = code === VALID_OTP_CODE;
43
+ }
44
+ if (!isValid) {
45
+ setHasError(true);
46
+ return;
47
+ }
48
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "success", message: successMessage, toastId: t }));
49
+ setCode("");
50
+ onSuccess();
51
+ } catch (error) {
52
+ console.error("Erro ao validar c\xF3digo:", error);
53
+ setHasError(true);
54
+ } finally {
55
+ setIsLoading(false);
56
+ }
57
+ }, [code, onSuccess, successMessage, validateFn]);
58
+ const handleResend = useCallback(async () => {
59
+ if (!canResend) return;
60
+ try {
61
+ resetTimer();
62
+ setHasError(false);
63
+ setCode("");
64
+ if (resendFn) {
65
+ await resendFn();
66
+ }
67
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "success", message: "C\xF3digo reenviado", toastId: t }));
68
+ } catch (error) {
69
+ console.error("Erro ao reenviar c\xF3digo:", error);
70
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: "Erro ao reenviar c\xF3digo. Tente novamente.", toastId: t }));
71
+ }
72
+ }, [canResend, resetTimer, resendFn]);
73
+ const reset = useCallback(() => {
74
+ setCode("");
75
+ setHasError(false);
76
+ }, []);
77
+ const isValidLength = hasExactLength(code, OTP_CODE_LENGTH);
78
+ return {
79
+ code,
80
+ isLoading,
81
+ hasError,
82
+ timer,
83
+ canResend,
84
+ isValidLength,
85
+ handleCodeChange,
86
+ handleValidate,
87
+ handleResend,
88
+ reset
89
+ };
90
+ }
91
+ export {
92
+ useOtpVerification as default
93
+ };
94
+ //# sourceMappingURL=useOtpVerification.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useOtpVerification.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport { toast } from 'sonner';\r\nimport { Toast } from '../../ui/feedback/Toast';\r\nimport useCountdownTimer from '../../../hooks/useCountdownTimer';\r\nimport { OTP_CODE_LENGTH, VALID_OTP_CODE } from '../../../utils/validators/account';\r\nimport { hasExactLength } from '../../../utils/validators/common';\r\n\r\ninterface UseOtpVerificationOptions {\r\n onSuccess: () => void;\r\n successMessage: string;\r\n validateFn?: (code: string) => Promise<boolean>;\r\n resendFn?: () => Promise<void>;\r\n}\r\n\r\nexport default function useOtpVerification({\r\n onSuccess,\r\n successMessage,\r\n validateFn,\r\n resendFn,\r\n}: UseOtpVerificationOptions) {\r\n const [code, setCode] = useState('');\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [hasError, setHasError] = useState(false);\r\n\r\n const {\r\n seconds: timer,\r\n isExpired: canResend,\r\n reset: resetTimer,\r\n } = useCountdownTimer({ initialSeconds: 59 });\r\n\r\n const handleCodeChange = useCallback(\r\n (value: string) => {\r\n setCode(value.toUpperCase());\r\n if (hasError) {\r\n setHasError(false);\r\n }\r\n },\r\n [hasError]\r\n );\r\n\r\n const handleValidate = useCallback(async () => {\r\n if (!hasExactLength(code, OTP_CODE_LENGTH)) return;\r\n\r\n setIsLoading(true);\r\n setHasError(false);\r\n\r\n try {\r\n let isValid: boolean;\r\n\r\n if (validateFn) {\r\n isValid = await validateFn(code);\r\n } else {\r\n await new Promise((resolve) => setTimeout(resolve, 500));\r\n isValid = code === VALID_OTP_CODE;\r\n }\r\n\r\n if (!isValid) {\r\n setHasError(true);\r\n return;\r\n }\r\n\r\n toast.custom((t) => <Toast variant=\"success\" message={successMessage} toastId={t} />);\r\n\r\n setCode('');\r\n onSuccess();\r\n } catch (error) {\r\n console.error('Erro ao validar código:', error);\r\n setHasError(true);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [code, onSuccess, successMessage, validateFn]);\r\n\r\n const handleResend = useCallback(async () => {\r\n if (!canResend) return;\r\n\r\n try {\r\n resetTimer();\r\n setHasError(false);\r\n setCode('');\r\n\r\n if (resendFn) {\r\n await resendFn();\r\n }\r\n\r\n toast.custom((t) => <Toast variant=\"success\" message=\"Código reenviado\" toastId={t} />);\r\n } catch (error) {\r\n console.error('Erro ao reenviar código:', error);\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message=\"Erro ao reenviar código. Tente novamente.\" toastId={t} />\r\n ));\r\n }\r\n }, [canResend, resetTimer, resendFn]);\r\n\r\n const reset = useCallback(() => {\r\n setCode('');\r\n setHasError(false);\r\n }, []);\r\n\r\n const isValidLength = hasExactLength(code, OTP_CODE_LENGTH);\r\n\r\n return {\r\n code,\r\n isLoading,\r\n hasError,\r\n timer,\r\n canResend,\r\n isValidLength,\r\n handleCodeChange,\r\n handleValidate,\r\n handleResend,\r\n reset,\r\n };\r\n}\r\n"],"mappings":";AA+D0B;AA7D1B,SAAS,UAAU,mBAAmB;AACtC,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,OAAO,uBAAuB;AAC9B,SAAS,iBAAiB,sBAAsB;AAChD,SAAS,sBAAsB;AAShB,SAAR,mBAAoC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAO;AAAA,EACT,IAAI,kBAAkB,EAAE,gBAAgB,GAAG,CAAC;AAE5C,QAAM,mBAAmB;AAAA,IACvB,CAAC,UAAkB;AACjB,cAAQ,MAAM,YAAY,CAAC;AAC3B,UAAI,UAAU;AACZ,oBAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,iBAAiB,YAAY,YAAY;AAC7C,QAAI,CAAC,eAAe,MAAM,eAAe,EAAG;AAE5C,iBAAa,IAAI;AACjB,gBAAY,KAAK;AAEjB,QAAI;AACF,UAAI;AAEJ,UAAI,YAAY;AACd,kBAAU,MAAM,WAAW,IAAI;AAAA,MACjC,OAAO;AACL,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AACvD,kBAAU,SAAS;AAAA,MACrB;AAEA,UAAI,CAAC,SAAS;AACZ,oBAAY,IAAI;AAChB;AAAA,MACF;AAEA,YAAM,OAAO,CAAC,MAAM,oBAAC,SAAM,SAAQ,WAAU,SAAS,gBAAgB,SAAS,GAAG,CAAE;AAEpF,cAAQ,EAAE;AACV,gBAAU;AAAA,IACZ,SAAS,OAAO;AACd,cAAQ,MAAM,8BAA2B,KAAK;AAC9C,kBAAY,IAAI;AAAA,IAClB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,MAAM,WAAW,gBAAgB,UAAU,CAAC;AAEhD,QAAM,eAAe,YAAY,YAAY;AAC3C,QAAI,CAAC,UAAW;AAEhB,QAAI;AACF,iBAAW;AACX,kBAAY,KAAK;AACjB,cAAQ,EAAE;AAEV,UAAI,UAAU;AACZ,cAAM,SAAS;AAAA,MACjB;AAEA,YAAM,OAAO,CAAC,MAAM,oBAAC,SAAM,SAAQ,WAAU,SAAQ,uBAAmB,SAAS,GAAG,CAAE;AAAA,IACxF,SAAS,OAAO;AACd,cAAQ,MAAM,+BAA4B,KAAK;AAC/C,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAQ,gDAA4C,SAAS,GAAG,CACxF;AAAA,IACH;AAAA,EACF,GAAG,CAAC,WAAW,YAAY,QAAQ,CAAC;AAEpC,QAAM,QAAQ,YAAY,MAAM;AAC9B,YAAQ,EAAE;AACV,gBAAY,KAAK;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,eAAe,MAAM,eAAe;AAE1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,88 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useState, useCallback, useEffect } from "react";
4
+ import { useMutation } from "@tanstack/react-query";
5
+ import { toast } from "sonner";
6
+ import { Toast } from "../../ui/feedback/Toast";
7
+ import { copyToClipboard } from "../../../utils/browser/clipboard";
8
+ import {
9
+ generateTwoFactorAction,
10
+ confirmTwoFactorAction
11
+ } from "../../../modules/accounts/actions/account-management.action";
12
+ function useTwoFactorAuthForm({ onSuccess, open } = {}) {
13
+ const [code, setCode] = useState("");
14
+ const [step, setStep] = useState("code");
15
+ const generateMutation = useMutation({
16
+ mutationFn: generateTwoFactorAction,
17
+ onSuccess: (result) => {
18
+ if (!result.success) {
19
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: result.error ?? "Erro ao gerar QR Code. Tente novamente.", toastId: t }));
20
+ }
21
+ },
22
+ onError: () => {
23
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: "Erro ao gerar QR Code. Tente novamente.", toastId: t }));
24
+ }
25
+ });
26
+ const confirmMutation = useMutation({
27
+ mutationFn: (otpCode) => confirmTwoFactorAction(otpCode),
28
+ onSuccess: (result) => {
29
+ if (!result.success) {
30
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: result.error ?? "C\xF3digo inv\xE1lido", toastId: t }));
31
+ return;
32
+ }
33
+ setStep("recovery");
34
+ },
35
+ onError: () => {
36
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message: "Erro ao confirmar c\xF3digo. Tente novamente.", toastId: t }));
37
+ }
38
+ });
39
+ const { mutate: triggerGenerate } = generateMutation;
40
+ useEffect(() => {
41
+ if (open) {
42
+ triggerGenerate();
43
+ }
44
+ }, [open, triggerGenerate]);
45
+ const generateFailed = generateMutation.isSuccess && !generateMutation.data?.success || generateMutation.isError;
46
+ const isCodeComplete = code.length === 6;
47
+ const handleSubmit = () => {
48
+ if (!isCodeComplete) return;
49
+ confirmMutation.mutate(code);
50
+ };
51
+ const handleFinalize = () => {
52
+ onSuccess?.();
53
+ setTimeout(resetForm, 300);
54
+ };
55
+ const handleCopyCodes = useCallback(async () => {
56
+ const codes = generateMutation.data?.backupCodes ?? [];
57
+ const success = await copyToClipboard(codes.join("\n"));
58
+ if (success) {
59
+ toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "success", message: "C\xF3digos copiados com sucesso", toastId: t }));
60
+ }
61
+ }, [generateMutation.data]);
62
+ const resetForm = () => {
63
+ setCode("");
64
+ setStep("code");
65
+ generateMutation.reset();
66
+ confirmMutation.reset();
67
+ };
68
+ return {
69
+ code,
70
+ setCode,
71
+ isCodeComplete,
72
+ isGenerating: generateMutation.isPending,
73
+ isConfirming: confirmMutation.isPending,
74
+ generateFailed,
75
+ retryGenerate: triggerGenerate,
76
+ qrcode: generateMutation.data?.qrcode,
77
+ backupCodes: generateMutation.data?.backupCodes ?? [],
78
+ step,
79
+ handleSubmit,
80
+ handleFinalize,
81
+ handleCopyCodes,
82
+ resetForm
83
+ };
84
+ }
85
+ export {
86
+ useTwoFactorAuthForm as default
87
+ };
88
+ //# sourceMappingURL=useTwoFactorAuthForm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/account/hooks/useTwoFactorAuthForm.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback, useEffect } from 'react';\r\nimport { useMutation } from '@tanstack/react-query';\r\nimport { toast } from 'sonner';\r\nimport { Toast } from '../../ui/feedback/Toast';\r\nimport { copyToClipboard } from '../../../utils/browser/clipboard';\r\nimport {\r\n generateTwoFactorAction,\r\n confirmTwoFactorAction,\r\n} from '../../../modules/accounts/actions/account-management.action';\r\n\r\ntype Step = 'code' | 'recovery';\r\n\r\ninterface UseTwoFactorAuthFormProps {\r\n onSuccess?: () => void;\r\n open?: boolean;\r\n}\r\n\r\nexport default function useTwoFactorAuthForm({ onSuccess, open }: UseTwoFactorAuthFormProps = {}) {\r\n const [code, setCode] = useState('');\r\n const [step, setStep] = useState<Step>('code');\r\n\r\n const generateMutation = useMutation({\r\n mutationFn: generateTwoFactorAction,\r\n onSuccess: (result) => {\r\n if (!result.success) {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message={result.error ?? 'Erro ao gerar QR Code. Tente novamente.'} toastId={t} />\r\n ));\r\n }\r\n },\r\n onError: () => {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message=\"Erro ao gerar QR Code. Tente novamente.\" toastId={t} />\r\n ));\r\n },\r\n });\r\n\r\n const confirmMutation = useMutation({\r\n mutationFn: (otpCode: string) => confirmTwoFactorAction(otpCode),\r\n onSuccess: (result) => {\r\n if (!result.success) {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message={result.error ?? 'Código inválido'} toastId={t} />\r\n ));\r\n return;\r\n }\r\n setStep('recovery');\r\n },\r\n onError: () => {\r\n toast.custom((t) => (\r\n <Toast variant=\"error\" message=\"Erro ao confirmar código. Tente novamente.\" toastId={t} />\r\n ));\r\n },\r\n });\r\n\r\n const { mutate: triggerGenerate } = generateMutation;\r\n\r\n useEffect(() => {\r\n if (open) {\r\n triggerGenerate();\r\n }\r\n }, [open, triggerGenerate]);\r\n\r\n const generateFailed =\r\n (generateMutation.isSuccess && !generateMutation.data?.success) || generateMutation.isError;\r\n\r\n const isCodeComplete = code.length === 6;\r\n\r\n const handleSubmit = () => {\r\n if (!isCodeComplete) return;\r\n confirmMutation.mutate(code);\r\n };\r\n\r\n const handleFinalize = () => {\r\n onSuccess?.();\r\n setTimeout(resetForm, 300);\r\n };\r\n\r\n const handleCopyCodes = useCallback(async () => {\r\n const codes = generateMutation.data?.backupCodes ?? [];\r\n const success = await copyToClipboard(codes.join('\\n'));\r\n if (success) {\r\n toast.custom((t) => (\r\n <Toast variant=\"success\" message=\"Códigos copiados com sucesso\" toastId={t} />\r\n ));\r\n }\r\n }, [generateMutation.data]);\r\n\r\n const resetForm = () => {\r\n setCode('');\r\n setStep('code');\r\n generateMutation.reset();\r\n confirmMutation.reset();\r\n };\r\n\r\n return {\r\n code,\r\n setCode,\r\n isCodeComplete,\r\n isGenerating: generateMutation.isPending,\r\n isConfirming: confirmMutation.isPending,\r\n generateFailed,\r\n retryGenerate: triggerGenerate,\r\n qrcode: generateMutation.data?.qrcode,\r\n backupCodes: generateMutation.data?.backupCodes ?? [],\r\n step,\r\n handleSubmit,\r\n handleFinalize,\r\n handleCopyCodes,\r\n resetForm,\r\n };\r\n}\r\n"],"mappings":";AA4BU;AA1BV,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AASQ,SAAR,qBAAsC,EAAE,WAAW,KAAK,IAA+B,CAAC,GAAG;AAChG,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAe,MAAM;AAE7C,QAAM,mBAAmB,YAAY;AAAA,IACnC,YAAY;AAAA,IACZ,WAAW,CAAC,WAAW;AACrB,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAS,OAAO,SAAS,2CAA2C,SAAS,GAAG,CACxG;AAAA,MACH;AAAA,IACF;AAAA,IACA,SAAS,MAAM;AACb,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAQ,2CAA0C,SAAS,GAAG,CACtF;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,kBAAkB,YAAY;AAAA,IAClC,YAAY,CAAC,YAAoB,uBAAuB,OAAO;AAAA,IAC/D,WAAW,CAAC,WAAW;AACrB,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAS,OAAO,SAAS,yBAAmB,SAAS,GAAG,CAChF;AACD;AAAA,MACF;AACA,cAAQ,UAAU;AAAA,IACpB;AAAA,IACA,SAAS,MAAM;AACb,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,SAAQ,SAAQ,iDAA6C,SAAS,GAAG,CACzF;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,EAAE,QAAQ,gBAAgB,IAAI;AAEpC,YAAU,MAAM;AACd,QAAI,MAAM;AACR,sBAAgB;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,MAAM,eAAe,CAAC;AAE1B,QAAM,iBACH,iBAAiB,aAAa,CAAC,iBAAiB,MAAM,WAAY,iBAAiB;AAEtF,QAAM,iBAAiB,KAAK,WAAW;AAEvC,QAAM,eAAe,MAAM;AACzB,QAAI,CAAC,eAAgB;AACrB,oBAAgB,OAAO,IAAI;AAAA,EAC7B;AAEA,QAAM,iBAAiB,MAAM;AAC3B,gBAAY;AACZ,eAAW,WAAW,GAAG;AAAA,EAC3B;AAEA,QAAM,kBAAkB,YAAY,YAAY;AAC9C,UAAM,QAAQ,iBAAiB,MAAM,eAAe,CAAC;AACrD,UAAM,UAAU,MAAM,gBAAgB,MAAM,KAAK,IAAI,CAAC;AACtD,QAAI,SAAS;AACX,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,WAAU,SAAQ,mCAA+B,SAAS,GAAG,CAC7E;AAAA,IACH;AAAA,EACF,GAAG,CAAC,iBAAiB,IAAI,CAAC;AAE1B,QAAM,YAAY,MAAM;AACtB,YAAQ,EAAE;AACV,YAAQ,MAAM;AACd,qBAAiB,MAAM;AACvB,oBAAgB,MAAM;AAAA,EACxB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,cAAc,gBAAgB;AAAA,IAC9B;AAAA,IACA,eAAe;AAAA,IACf,QAAQ,iBAAiB,MAAM;AAAA,IAC/B,aAAa,iBAAiB,MAAM,eAAe,CAAC;AAAA,IACpD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,180 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { ChevronLeft, X, Mail } from "lucide-react";
4
+ import { Button } from "../../ui/buttons/Button";
5
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../../ui/overlay/Dialog";
6
+ import { Separator } from "../../ui/data-display/Separator";
7
+ import { InputOTP, InputOTPGroup, InputOTPSlot } from "../../ui/form/InputOtp";
8
+ import { FormField } from "../../ui/form/FormField";
9
+ import { formatTimer } from "../../../utils/format/masks";
10
+ import { OTP_CODE_LENGTH } from "../../../utils/validators/account";
11
+ import { useAuth } from "../../../providers/auth.provider";
12
+ import { useInvalidateUser } from "../../../modules/auth/hooks/useUserQuery";
13
+ import { confirmEmailChangeAction } from "../../../modules/accounts/actions/account-management.action";
14
+ import useChangeEmailForm from "../hooks/useChangeEmailForm";
15
+ import useOtpVerification from "../hooks/useOtpVerification";
16
+ function ChangeEmailModal({ open, onClose }) {
17
+ const { user } = useAuth();
18
+ const invalidateUser = useInvalidateUser();
19
+ const {
20
+ showVerification,
21
+ emailToVerify,
22
+ isSubmitting,
23
+ errors,
24
+ register,
25
+ handleContinue,
26
+ handleBack,
27
+ resetForm
28
+ } = useChangeEmailForm();
29
+ const handleSuccess = () => {
30
+ invalidateUser();
31
+ resetForm();
32
+ onClose();
33
+ };
34
+ const {
35
+ code,
36
+ isLoading,
37
+ hasError,
38
+ timer,
39
+ canResend,
40
+ isValidLength,
41
+ handleCodeChange,
42
+ handleValidate,
43
+ handleResend,
44
+ reset: resetOtp
45
+ } = useOtpVerification({
46
+ onSuccess: handleSuccess,
47
+ successMessage: "E-mail alterado com sucesso",
48
+ validateFn: async (token) => {
49
+ const result = await confirmEmailChangeAction(token, emailToVerify);
50
+ return result.success;
51
+ },
52
+ resendFn: async () => {
53
+ const { requestEmailChangeAction } = await import("../../../modules/accounts/actions/account-management.action");
54
+ const result = await requestEmailChangeAction(emailToVerify);
55
+ if (!result.success) {
56
+ throw new Error(result.error);
57
+ }
58
+ }
59
+ });
60
+ const handleClose = () => {
61
+ resetForm();
62
+ resetOtp();
63
+ onClose();
64
+ };
65
+ const handleBackFromVerification = () => {
66
+ resetOtp();
67
+ handleBack();
68
+ };
69
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(
70
+ DialogContent,
71
+ {
72
+ showCloseButton: false,
73
+ className: "flex flex-col p-0 gap-0 max-w-full! border-0 rounded-t-2xl rounded-b-none h-dvh top-0! bottom-0! left-0! right-0! translate-x-0! translate-y-0! lg:max-w-125! lg:h-auto! lg:rounded-lg lg:border lg:top-[50%]! lg:left-[50%]! lg:right-auto! lg:bottom-auto! lg:translate-x-[-50%]! lg:translate-y-[-50%]!",
74
+ children: [
75
+ showVerification ? /* @__PURE__ */ jsxs(DialogHeader, { className: "flex flex-row items-center justify-between px-4 py-3 border-b border-gray-200 lg:border-b-0", children: [
76
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", className: "size-8! p-0", onClick: handleBackFromVerification, children: /* @__PURE__ */ jsx(ChevronLeft, { size: 20, className: "text-gray-950" }) }),
77
+ /* @__PURE__ */ jsx(DialogTitle, { className: "paragraph-medium-semibold text-gray-950 text-center flex-1", children: "Alterar e-mail" }),
78
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", className: "size-8! p-0", onClick: handleClose, children: /* @__PURE__ */ jsx(X, { size: 18, className: "text-gray-500" }) })
79
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
80
+ /* @__PURE__ */ jsx(DialogHeader, { className: "sr-only", children: /* @__PURE__ */ jsx(DialogTitle, { children: "Alterar e-mail" }) }),
81
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0", children: [
82
+ /* @__PURE__ */ jsx("span", { className: "paragraph-medium-semibold text-gray-950 text-center", children: "Alterar e-mail" }),
83
+ /* @__PURE__ */ jsx(
84
+ Button,
85
+ {
86
+ variant: "ghost",
87
+ className: "absolute right-2 size-8! p-0",
88
+ onClick: handleClose,
89
+ children: /* @__PURE__ */ jsx(X, { size: 18, className: "text-gray-500" })
90
+ }
91
+ )
92
+ ] })
93
+ ] }),
94
+ /* @__PURE__ */ jsx("div", { className: `${showVerification ? "w-full" : "w-1/2"} h-0.75 bg-pages-300` }),
95
+ showVerification ? /* @__PURE__ */ jsxs(
96
+ "form",
97
+ {
98
+ onSubmit: (e) => {
99
+ e.preventDefault();
100
+ handleValidate();
101
+ },
102
+ className: "flex flex-col flex-1 lg:flex-none",
103
+ children: [
104
+ /* @__PURE__ */ jsxs("div", { className: "px-4 lg:px-5 py-5 lg:py-6 flex flex-col gap-4 flex-1 lg:flex-none", children: [
105
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center size-12 bg-white rounded-lg shadow-xs border border-gray-200", children: /* @__PURE__ */ jsx(Mail, { size: 20, className: "text-gray-950" }) }),
106
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
107
+ /* @__PURE__ */ jsx("h3", { className: "paragraph-medium-semibold text-gray-950", children: "C\xF3digo de valida\xE7\xE3o" }),
108
+ /* @__PURE__ */ jsxs("p", { className: "paragraph-small-regular text-gray-600", children: [
109
+ "Enviamos um c\xF3digo de valida\xE7\xE3o para o E-mail",
110
+ " ",
111
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-950 break-all", children: [
112
+ user?.email,
113
+ "."
114
+ ] })
115
+ ] })
116
+ ] }),
117
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
118
+ /* @__PURE__ */ jsx(InputOTP, { maxLength: OTP_CODE_LENGTH, value: code, onChange: handleCodeChange, children: /* @__PURE__ */ jsx(InputOTPGroup, { className: "flex flex-row gap-2", children: [...Array(OTP_CODE_LENGTH)].map((_, i) => /* @__PURE__ */ jsx(
119
+ InputOTPSlot,
120
+ {
121
+ index: i,
122
+ className: `uppercase text-2xl font-medium w-11 lg:w-12 h-13 lg:h-14 rounded-lg border bg-white shadow-none [&_div.animate-caret-blink]:bg-gray-950 ${hasError ? "border-red-500" : "border-gray-200"}`
123
+ },
124
+ i
125
+ )) }) }),
126
+ hasError && /* @__PURE__ */ jsx("p", { className: "paragraph-small-regular text-red-500", children: "C\xF3digo incorreto" })
127
+ ] }),
128
+ canResend ? /* @__PURE__ */ jsx(
129
+ "button",
130
+ {
131
+ type: "button",
132
+ onClick: handleResend,
133
+ className: "paragraph-small-medium text-gray-950 underline cursor-pointer hover:text-gray-700 w-fit",
134
+ children: "Reenviar c\xF3digo"
135
+ }
136
+ ) : /* @__PURE__ */ jsxs("p", { className: "paragraph-small-regular text-gray-500", children: [
137
+ "Reenviar em",
138
+ " ",
139
+ /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-gray-950", children: formatTimer(timer) })
140
+ ] })
141
+ ] }),
142
+ /* @__PURE__ */ jsx(Separator, {}),
143
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 lg:px-5 py-4 lg:py-5 mt-auto lg:mt-0", children: [
144
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "h-10!", type: "button", onClick: handleClose, children: "Cancelar" }),
145
+ /* @__PURE__ */ jsx(Button, { className: "h-10!", type: "submit", disabled: !isValidLength || isLoading, children: isLoading ? "Validando..." : "Alterar e-mail" })
146
+ ] })
147
+ ]
148
+ }
149
+ ) : /* @__PURE__ */ jsxs("form", { onSubmit: handleContinue, className: "flex flex-col flex-1 lg:flex-none", children: [
150
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5 lg:gap-6 px-4 lg:px-5 py-5 lg:py-6 flex-1 lg:flex-none", children: [
151
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
152
+ /* @__PURE__ */ jsx("span", { className: "paragraph-medium-semibold text-gray-950", children: "Atualizar E-mail de contato" }),
153
+ /* @__PURE__ */ jsx("span", { className: "paragraph-small-regular text-gray-600", children: "Informe o seu novo E-mail para manter seu contato atualizado." })
154
+ ] }),
155
+ /* @__PURE__ */ jsx(
156
+ FormField,
157
+ {
158
+ label: "Novo e-mail",
159
+ placeholder: "Digite seu novo e-mail",
160
+ type: "email",
161
+ ...register("email"),
162
+ error: !!errors.email,
163
+ errorMessage: errors.email?.message,
164
+ leftIcon: Mail
165
+ }
166
+ )
167
+ ] }),
168
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 lg:p-5 border-t border-gray-200 mt-auto lg:mt-0", children: [
169
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "h-10!", type: "button", onClick: handleClose, children: "Cancelar" }),
170
+ /* @__PURE__ */ jsx(Button, { className: "h-10!", type: "submit", disabled: isSubmitting, children: isSubmitting ? "Enviando..." : "Continuar" })
171
+ ] })
172
+ ] })
173
+ ]
174
+ }
175
+ ) });
176
+ }
177
+ export {
178
+ ChangeEmailModal
179
+ };
180
+ //# sourceMappingURL=ChangeEmailModal.mjs.map