@greatapps/common 1.1.776 → 1.1.778
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account/DisableTwoFactorAuthModal.mjs +44 -40
- package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/TwoFactorAuthModal.mjs +130 -125
- package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/embeds/ClarityEmbed.mjs +1 -2
- package/dist/components/embeds/ClarityEmbed.mjs.map +1 -1
- package/dist/components/embeds/FrillEmbed.mjs +1 -2
- package/dist/components/embeds/FrillEmbed.mjs.map +1 -1
- package/dist/components/modals/ModalManager.mjs +5 -2
- package/dist/components/modals/ModalManager.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +12 -15
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/account/DisableTwoFactorAuthModal.tsx +59 -55
- package/src/components/account/TwoFactorAuthModal.tsx +154 -149
- package/src/components/embeds/ClarityEmbed.tsx +1 -2
- package/src/components/embeds/FrillEmbed.tsx +1 -2
- package/src/components/modals/ModalManager.tsx +13 -3
- package/src/components/widgets/ImageUpload/ImageTooSmallModal.tsx +24 -23
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useContext } from "react";
|
|
3
4
|
import { useModalManager } from "../../store/useModalManager";
|
|
5
|
+
import { DialogDepthContext } from "../ui/overlay/layers";
|
|
4
6
|
function ModalManager({ registry }) {
|
|
5
7
|
const { modalStack } = useModalManager();
|
|
8
|
+
const depth = useContext(DialogDepthContext);
|
|
6
9
|
if (modalStack.length === 0) return null;
|
|
7
|
-
return /* @__PURE__ */ jsx(Fragment, { children: modalStack.map((modal) => {
|
|
10
|
+
return /* @__PURE__ */ jsx(Fragment, { children: modalStack.map((modal, index) => {
|
|
8
11
|
const ModalComponent = registry[modal.key];
|
|
9
12
|
if (!ModalComponent) {
|
|
10
13
|
console.warn(`Modal "${modal.key}" not found in registry`);
|
|
11
14
|
return null;
|
|
12
15
|
}
|
|
13
|
-
return /* @__PURE__ */ jsx(ModalComponent, {}, modal.key);
|
|
16
|
+
return /* @__PURE__ */ jsx(DialogDepthContext.Provider, { value: depth + index, children: /* @__PURE__ */ jsx(ModalComponent, {}) }, modal.key);
|
|
14
17
|
}) });
|
|
15
18
|
}
|
|
16
19
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/modals/ModalManager.tsx"],"sourcesContent":["'use client';\n\nimport { ComponentType } from 'react';\nimport { useModalManager } from '../../store/useModalManager';\n\ninterface ModalManagerProps {\n registry: Record<string, ComponentType>;\n}\n\nexport function ModalManager({ registry }: ModalManagerProps) {\n const { modalStack } = useModalManager();\n\n if (modalStack.length === 0) return null;\n\n return (\n <>\n {modalStack.map((modal) => {\n const ModalComponent = registry[modal.key];\n\n if (!ModalComponent) {\n console.warn(`Modal \"${modal.key}\" not found in registry`);\n return null;\n }\n\n return <
|
|
1
|
+
{"version":3,"sources":["../../../src/components/modals/ModalManager.tsx"],"sourcesContent":["'use client';\n\nimport { ComponentType, useContext } from 'react';\nimport { useModalManager } from '../../store/useModalManager';\nimport { DialogDepthContext } from '../ui/overlay/layers';\n\ninterface ModalManagerProps {\n registry: Record<string, ComponentType>;\n}\n\nexport function ModalManager({ registry }: ModalManagerProps) {\n const { modalStack } = useModalManager();\n const depth = useContext(DialogDepthContext);\n\n if (modalStack.length === 0) return null;\n\n // Modais da pilha nascem irmaos na arvore React: sem isso, todos cairiam na\n // mesma profundidade e na mesma faixa de z-index (ver layers.tsx). A\n // posicao na pilha vira a profundidade, relativa a onde o ModalManager\n // esta montado.\n return (\n <>\n {modalStack.map((modal, index) => {\n const ModalComponent = registry[modal.key];\n\n if (!ModalComponent) {\n console.warn(`Modal \"${modal.key}\" not found in registry`);\n return null;\n }\n\n return (\n <DialogDepthContext.Provider value={depth + index} key={modal.key}>\n <ModalComponent />\n </DialogDepthContext.Provider>\n );\n })}\n </>\n );\n}\n"],"mappings":";AAqBI,mBAWQ,WAXR;AAnBJ,SAAwB,kBAAkB;AAC1C,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AAM5B,SAAS,aAAa,EAAE,SAAS,GAAsB;AAC5D,QAAM,EAAE,WAAW,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,kBAAkB;AAE3C,MAAI,WAAW,WAAW,EAAG,QAAO;AAMpC,SACE,gCACG,qBAAW,IAAI,CAAC,OAAO,UAAU;AAChC,UAAM,iBAAiB,SAAS,MAAM,GAAG;AAEzC,QAAI,CAAC,gBAAgB;AACnB,cAAQ,KAAK,UAAU,MAAM,GAAG,yBAAyB;AACzD,aAAO;AAAA,IACT;AAEA,WACE,oBAAC,mBAAmB,UAAnB,EAA4B,OAAO,QAAQ,OAC1C,8BAAC,kBAAe,KADsC,MAAM,GAE9D;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DialogHeader,
|
|
9
9
|
DialogTitle
|
|
10
10
|
} from "../../ui/overlay/Dialog";
|
|
11
|
+
import { DialogLayer } from "../../ui/overlay/layers";
|
|
11
12
|
import { Button } from "../../ui/buttons/Button";
|
|
12
13
|
function ImageTooSmallModal({
|
|
13
14
|
open,
|
|
@@ -20,21 +21,17 @@ function ImageTooSmallModal({
|
|
|
20
21
|
}) {
|
|
21
22
|
const translate = useTranslations();
|
|
22
23
|
const dimensionText = `${minWidth}x${minHeight}px`;
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
className: "
|
|
27
|
-
|
|
28
|
-
children: [
|
|
29
|
-
/* @__PURE__ */ jsx(
|
|
30
|
-
/* @__PURE__ */ jsx(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
] })
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
) });
|
|
24
|
+
return (
|
|
25
|
+
// Abre por cima do modal/uploader que a disparou.
|
|
26
|
+
/* @__PURE__ */ jsx(DialogLayer, { children: /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0", children: [
|
|
27
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "p-5", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-center text-[16px]!", children: translate("common.imageUpload.tooSmallTitleWithDimension", { dimensionText }) }) }),
|
|
28
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 pb-5", children: /* @__PURE__ */ jsx("p", { className: "paragraph-small-regular text-zinc-600 text-center", children: translate("common.imageUpload.tooSmallBodyFileWithDimension", { fileName, dimensionText }) }) }),
|
|
29
|
+
/* @__PURE__ */ jsxs(DialogFooter, { className: "flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200", children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Button, { onClick: onSelectAnother, children: translate("common.imageUpload.sendAnother") }),
|
|
31
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onCancel, children: translate("common.actions.cancel") })
|
|
32
|
+
] })
|
|
33
|
+
] }) }) })
|
|
34
|
+
);
|
|
38
35
|
}
|
|
39
36
|
export {
|
|
40
37
|
ImageTooSmallModal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageTooSmallModal.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslations } from 'next-intl'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { Button } from '../../ui/buttons/Button'\n\ninterface ImageTooSmallModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n fileName: string\n minWidth: number\n minHeight: number\n onSelectAnother: () => void\n onCancel: () => void\n}\n\nexport function ImageTooSmallModal({\n open,\n onOpenChange,\n fileName,\n minWidth,\n minHeight,\n onSelectAnother,\n onCancel,\n}: ImageTooSmallModalProps) {\n const translate = useTranslations()\n const dimensionText = `${minWidth}x${minHeight}px`\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageTooSmallModal.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslations } from 'next-intl'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { DialogLayer } from '../../ui/overlay/layers'\nimport { Button } from '../../ui/buttons/Button'\n\ninterface ImageTooSmallModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n fileName: string\n minWidth: number\n minHeight: number\n onSelectAnother: () => void\n onCancel: () => void\n}\n\nexport function ImageTooSmallModal({\n open,\n onOpenChange,\n fileName,\n minWidth,\n minHeight,\n onSelectAnother,\n onCancel,\n}: ImageTooSmallModalProps) {\n const translate = useTranslations()\n const dimensionText = `${minWidth}x${minHeight}px`\n\n return (\n // Abre por cima do modal/uploader que a disparou.\n <DialogLayer>\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0\">\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n {translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"px-5 pb-5\">\n <p className=\"paragraph-small-regular text-zinc-600 text-center\">\n {translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })}\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n <Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>\n <Button variant=\"secondary\" onClick={onCancel}>\n {translate('common.actions.cancel')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </DialogLayer>\n )\n}\n"],"mappings":";AAyCY,cAWF,YAXE;AAvCZ,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AAYhB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,YAAY,gBAAgB;AAClC,QAAM,gBAAgB,GAAG,QAAQ,IAAI,SAAS;AAE9C;AAAA;AAAA,IAEE,oBAAC,eACC,8BAAC,UAAO,MAAY,cAClB,+BAAC,iBAAc,WAAU,+FACvB;AAAA,0BAAC,gBAAa,WAAU,OACtB,8BAAC,eAAY,WAAU,4BACpB,oBAAU,iDAAiD,EAAE,cAAc,CAAC,GAC/E,GACF;AAAA,MAEA,oBAAC,SAAI,WAAU,aACb,8BAAC,OAAE,WAAU,qDACV,oBAAU,oDAAoD,EAAE,UAAU,cAAc,CAAC,GAC5F,GACF;AAAA,MAEA,qBAAC,gBAAa,WAAU,4EACtB;AAAA,4BAAC,UAAO,SAAS,iBAAkB,oBAAU,gCAAgC,GAAE;AAAA,QAC/E,oBAAC,UAAO,SAAQ,aAAY,SAAS,UAClC,oBAAU,uBAAuB,GACpC;AAAA,SACF;AAAA,OACF,GACF,GACF;AAAA;AAEJ;","names":[]}
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DialogHeader,
|
|
11
11
|
DialogTitle,
|
|
12
12
|
} from '../ui/overlay/Dialog';
|
|
13
|
+
import { DialogLayer } from '../ui/overlay/layers';
|
|
13
14
|
import { InputOTP, InputOTPGroup, InputOTPSlot } from '../ui/form/InputOtp';
|
|
14
15
|
import { REGEXP_ONLY_DIGITS } from 'input-otp';
|
|
15
16
|
import useDisableTwoFactorAuthForm from './hooks/useDisableTwoFactorAuthForm';
|
|
@@ -30,63 +31,66 @@ export default function DisableTwoFactorAuthModal({
|
|
|
30
31
|
useDisableTwoFactorAuthForm({ onClose, onSuccess });
|
|
31
32
|
|
|
32
33
|
return (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
// Abre por cima do modal de configurações da conta, que é irmão na árvore.
|
|
35
|
+
<DialogLayer>
|
|
36
|
+
<Dialog open={open} onOpenChange={handleClose}>
|
|
37
|
+
<DialogContent className="flex flex-col p-0 gap-0 max-w-full sm: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-117.5 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%]">
|
|
38
|
+
<form
|
|
39
|
+
onSubmit={(e) => {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
handleSubmit();
|
|
42
|
+
}}
|
|
43
|
+
className="flex flex-col flex-1 lg:flex-none"
|
|
44
|
+
>
|
|
45
|
+
<div className="flex flex-col gap-4 lg:gap-5 p-4 lg:p-5 flex-1 lg:flex-none">
|
|
46
|
+
<div className="flex items-center justify-center w-fit bg-gray-50 rounded-lg p-2">
|
|
47
|
+
<IconShieldCheck size={20} className="text-gray-600" />
|
|
48
|
+
</div>
|
|
49
|
+
<DialogHeader className="p-0 gap-2">
|
|
50
|
+
<DialogTitle className="paragraph-medium-semibold text-gray-950">
|
|
51
|
+
{translate('common.account.twoFactor.disableTitle')}
|
|
52
|
+
</DialogTitle>
|
|
53
|
+
<DialogDescription className="paragraph-small-regular text-gray-600">
|
|
54
|
+
{translate('common.account.twoFactor.disableDescription')}
|
|
55
|
+
</DialogDescription>
|
|
56
|
+
</DialogHeader>
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
<div className="flex flex-col gap-2">
|
|
59
|
+
<span className="paragraph-small-medium text-gray-700">
|
|
60
|
+
{translate('common.account.twoFactor.authenticatorCode')}
|
|
61
|
+
</span>
|
|
62
|
+
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
|
|
63
|
+
<InputOTPGroup className="gap-2">
|
|
64
|
+
{Array.from({ length: 6 }).map((_, i) => (
|
|
65
|
+
<InputOTPSlot
|
|
66
|
+
key={i}
|
|
67
|
+
index={i}
|
|
68
|
+
className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
|
|
69
|
+
/>
|
|
70
|
+
))}
|
|
71
|
+
</InputOTPGroup>
|
|
72
|
+
</InputOTP>
|
|
73
|
+
</div>
|
|
70
74
|
</div>
|
|
71
|
-
</div>
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
<div className="flex flex-row items-center gap-2 p-4 lg:p-5 border-t border-gray-200 mt-auto lg:mt-0">
|
|
77
|
+
<Button className="h-10! flex-1" disabled={!isValid || isLoading} type="submit">
|
|
78
|
+
{isLoading
|
|
79
|
+
? translate('common.account.twoFactor.disabling')
|
|
80
|
+
: translate('common.account.twoFactor.disable')}
|
|
81
|
+
</Button>
|
|
82
|
+
<Button
|
|
83
|
+
variant="secondary"
|
|
84
|
+
className="h-10! flex-1"
|
|
85
|
+
type="button"
|
|
86
|
+
onClick={handleClose}
|
|
87
|
+
>
|
|
88
|
+
{translate('common.actions.cancel')}
|
|
89
|
+
</Button>
|
|
90
|
+
</div>
|
|
91
|
+
</form>
|
|
92
|
+
</DialogContent>
|
|
93
|
+
</Dialog>
|
|
94
|
+
</DialogLayer>
|
|
91
95
|
);
|
|
92
96
|
}
|
|
@@ -4,6 +4,7 @@ import { useTranslations } from 'next-intl';
|
|
|
4
4
|
import { IconX, IconCopy, IconRefresh } from '@tabler/icons-react';
|
|
5
5
|
import { Button } from '../ui/buttons/Button';
|
|
6
6
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';
|
|
7
|
+
import { DialogLayer } from '../ui/overlay/layers';
|
|
7
8
|
import { Separator } from '../ui/data-display/Separator';
|
|
8
9
|
import { InputOTP, InputOTPGroup, InputOTPSlot } from '../ui/form/InputOtp';
|
|
9
10
|
import { REGEXP_ONLY_DIGITS } from 'input-otp';
|
|
@@ -41,18 +42,88 @@ export default function TwoFactorAuthModal({ open, onClose, onSuccess }: TwoFact
|
|
|
41
42
|
|
|
42
43
|
if (step === 'recovery') {
|
|
43
44
|
return (
|
|
45
|
+
// Abre por cima do modal de configurações da conta, que é irmão na árvore.
|
|
46
|
+
<DialogLayer>
|
|
47
|
+
<Dialog open={open} onOpenChange={handleClose}>
|
|
48
|
+
<DialogContent
|
|
49
|
+
showCloseButton={false}
|
|
50
|
+
className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] 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%]"
|
|
51
|
+
>
|
|
52
|
+
<DialogHeader className="sr-only">
|
|
53
|
+
<DialogTitle>{translate('common.account.twoFactor.recoveryTitle')}</DialogTitle>
|
|
54
|
+
</DialogHeader>
|
|
55
|
+
<div className="flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
|
|
56
|
+
<span className="paragraph-medium-semibold text-gray-950 text-center">
|
|
57
|
+
{translate('common.account.twoFactor.recoveryTitle')}
|
|
58
|
+
</span>
|
|
59
|
+
<Button
|
|
60
|
+
type="button"
|
|
61
|
+
variant="ghost"
|
|
62
|
+
className="size-8! p-0 absolute right-4"
|
|
63
|
+
onClick={handleClose}
|
|
64
|
+
>
|
|
65
|
+
<IconX size={18} />
|
|
66
|
+
</Button>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<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">
|
|
70
|
+
<div className="flex flex-col gap-2">
|
|
71
|
+
<h3 className="paragraph-medium-semibold text-gray-950 max-w-[269px]">
|
|
72
|
+
{translate('common.account.twoFactor.recoveryHeading')}
|
|
73
|
+
</h3>
|
|
74
|
+
<div className="paragraph-small-regular text-gray-600">
|
|
75
|
+
<p>{translate('common.account.twoFactor.recoveryText1')}</p>
|
|
76
|
+
<br />
|
|
77
|
+
<p>{translate('common.account.twoFactor.recoveryText2')}</p>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div className="bg-gray-50 rounded-lg p-4 flex flex-col gap-4">
|
|
82
|
+
<div className="paragraph-small-medium text-gray-950 whitespace-nowrap">
|
|
83
|
+
{backupCodes.map((backupCode, i) => (
|
|
84
|
+
<p key={i}>{backupCode}</p>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
<Button
|
|
88
|
+
type="button"
|
|
89
|
+
variant="secondary"
|
|
90
|
+
className="h-8! w-fit"
|
|
91
|
+
onClick={handleCopyCodes}
|
|
92
|
+
>
|
|
93
|
+
<IconCopy size={16} />
|
|
94
|
+
{translate('common.account.twoFactor.copyCodes')}
|
|
95
|
+
</Button>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div className="flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between mt-auto lg:mt-0">
|
|
100
|
+
<Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
|
|
101
|
+
{translate('common.actions.cancel')}
|
|
102
|
+
</Button>
|
|
103
|
+
<Button className="h-10!" type="button" onClick={handleFinalize}>
|
|
104
|
+
{translate('common.account.twoFactor.finish')}
|
|
105
|
+
</Button>
|
|
106
|
+
</div>
|
|
107
|
+
</DialogContent>
|
|
108
|
+
</Dialog>
|
|
109
|
+
</DialogLayer>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
// Abre por cima do modal de configurações da conta, que é irmão na árvore.
|
|
115
|
+
<DialogLayer>
|
|
44
116
|
<Dialog open={open} onOpenChange={handleClose}>
|
|
45
117
|
<DialogContent
|
|
46
118
|
showCloseButton={false}
|
|
47
|
-
|
|
48
|
-
className="z-[1011] flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] 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%]"
|
|
119
|
+
className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:max-h-[90vh] 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%]"
|
|
49
120
|
>
|
|
50
121
|
<DialogHeader className="sr-only">
|
|
51
|
-
<DialogTitle>{translate('common.account.twoFactor.
|
|
122
|
+
<DialogTitle>{translate('common.account.twoFactor.title')}</DialogTitle>
|
|
52
123
|
</DialogHeader>
|
|
53
|
-
<div className="flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
|
|
124
|
+
<div className="shrink-0 flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
|
|
54
125
|
<span className="paragraph-medium-semibold text-gray-950 text-center">
|
|
55
|
-
{translate('common.account.twoFactor.
|
|
126
|
+
{translate('common.account.twoFactor.title')}
|
|
56
127
|
</span>
|
|
57
128
|
<Button
|
|
58
129
|
type="button"
|
|
@@ -64,157 +135,91 @@ export default function TwoFactorAuthModal({ open, onClose, onSuccess }: TwoFact
|
|
|
64
135
|
</Button>
|
|
65
136
|
</div>
|
|
66
137
|
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<p>{translate('common.account.twoFactor.recoveryText1')}</p>
|
|
74
|
-
<br />
|
|
75
|
-
<p>{translate('common.account.twoFactor.recoveryText2')}</p>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<div className="bg-gray-50 rounded-lg p-4 flex flex-col gap-4">
|
|
80
|
-
<div className="paragraph-small-medium text-gray-950 whitespace-nowrap">
|
|
81
|
-
{backupCodes.map((backupCode, i) => (
|
|
82
|
-
<p key={i}>{backupCode}</p>
|
|
83
|
-
))}
|
|
84
|
-
</div>
|
|
85
|
-
<Button
|
|
86
|
-
type="button"
|
|
87
|
-
variant="secondary"
|
|
88
|
-
className="h-8! w-fit"
|
|
89
|
-
onClick={handleCopyCodes}
|
|
90
|
-
>
|
|
91
|
-
<IconCopy size={16} />
|
|
92
|
-
{translate('common.account.twoFactor.copyCodes')}
|
|
93
|
-
</Button>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
<div className="flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between mt-auto lg:mt-0">
|
|
98
|
-
<Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
|
|
99
|
-
{translate('common.actions.cancel')}
|
|
100
|
-
</Button>
|
|
101
|
-
<Button className="h-10!" type="button" onClick={handleFinalize}>
|
|
102
|
-
{translate('common.account.twoFactor.finish')}
|
|
103
|
-
</Button>
|
|
104
|
-
</div>
|
|
105
|
-
</DialogContent>
|
|
106
|
-
</Dialog>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<Dialog open={open} onOpenChange={handleClose}>
|
|
112
|
-
<DialogContent
|
|
113
|
-
showCloseButton={false}
|
|
114
|
-
overlayClassName="z-[1010]"
|
|
115
|
-
className="z-[1011] flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:max-h-[90vh] 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%]"
|
|
116
|
-
>
|
|
117
|
-
<DialogHeader className="sr-only">
|
|
118
|
-
<DialogTitle>{translate('common.account.twoFactor.title')}</DialogTitle>
|
|
119
|
-
</DialogHeader>
|
|
120
|
-
<div className="shrink-0 flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
|
|
121
|
-
<span className="paragraph-medium-semibold text-gray-950 text-center">
|
|
122
|
-
{translate('common.account.twoFactor.title')}
|
|
123
|
-
</span>
|
|
124
|
-
<Button
|
|
125
|
-
type="button"
|
|
126
|
-
variant="ghost"
|
|
127
|
-
className="size-8! p-0 absolute right-4"
|
|
128
|
-
onClick={handleClose}
|
|
138
|
+
<form
|
|
139
|
+
className="flex-1 min-h-0 flex flex-col"
|
|
140
|
+
onSubmit={(e) => {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
if (isCodeComplete) handleSubmit();
|
|
143
|
+
}}
|
|
129
144
|
>
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
<div className="flex-1 min-h-0 overflow-y-auto overscroll-contain lg:overflow-visible">
|
|
146
|
+
<div className="flex flex-col items-center gap-4 lg:gap-8 px-4 lg:px-5 py-4 lg:py-6 pb-60 lg:pb-6">
|
|
147
|
+
<p className="paragraph-small-regular text-gray-950 text-center max-w-full lg:max-w-[412px]">
|
|
148
|
+
{translate.rich('common.account.twoFactor.instructions', {
|
|
149
|
+
link: (chunks) => (
|
|
150
|
+
<a
|
|
151
|
+
href="https://support.google.com/accounts/answer/1066447"
|
|
152
|
+
target="_blank"
|
|
153
|
+
rel="noopener noreferrer"
|
|
154
|
+
className="paragraph-small-medium underline"
|
|
155
|
+
>
|
|
156
|
+
{chunks}
|
|
157
|
+
</a>
|
|
158
|
+
),
|
|
159
|
+
})}
|
|
160
|
+
</p>
|
|
133
161
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
>
|
|
141
|
-
<div className="flex-1 min-h-0 overflow-y-auto overscroll-contain lg:overflow-visible">
|
|
142
|
-
<div className="flex flex-col items-center gap-4 lg:gap-8 px-4 lg:px-5 py-4 lg:py-6 pb-60 lg:pb-6">
|
|
143
|
-
<p className="paragraph-small-regular text-gray-950 text-center max-w-full lg:max-w-[412px]">
|
|
144
|
-
{translate.rich('common.account.twoFactor.instructions', {
|
|
145
|
-
link: (chunks) => (
|
|
146
|
-
<a
|
|
147
|
-
href="https://support.google.com/accounts/answer/1066447"
|
|
148
|
-
target="_blank"
|
|
149
|
-
rel="noopener noreferrer"
|
|
150
|
-
className="paragraph-small-medium underline"
|
|
162
|
+
<div className="border border-gray-200 rounded-lg overflow-hidden p-2 lg:p-3 flex items-center justify-center w-[136px] h-[136px] lg:w-[203px] lg:h-[203px]">
|
|
163
|
+
{generateFailed ? (
|
|
164
|
+
<button
|
|
165
|
+
type="button"
|
|
166
|
+
onClick={() => retryGenerate()}
|
|
167
|
+
className="flex flex-col items-center gap-1.5 text-center"
|
|
151
168
|
>
|
|
152
|
-
{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
</span>
|
|
169
|
-
</button>
|
|
170
|
-
) : isGenerating || !qrcode ? (
|
|
171
|
-
<div className="skeleton w-full h-full rounded" />
|
|
172
|
-
) : (
|
|
173
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
174
|
-
<img
|
|
175
|
-
src={qrcode}
|
|
176
|
-
alt={translate('common.account.twoFactor.qrAlt')}
|
|
177
|
-
className="w-full h-full"
|
|
178
|
-
/>
|
|
179
|
-
)}
|
|
180
|
-
</div>
|
|
169
|
+
<IconRefresh size={20} className="text-gray-400" />
|
|
170
|
+
<span className="paragraph-xsmall-medium text-gray-500">
|
|
171
|
+
{translate('common.account.twoFactor.retry')}
|
|
172
|
+
</span>
|
|
173
|
+
</button>
|
|
174
|
+
) : isGenerating || !qrcode ? (
|
|
175
|
+
<div className="skeleton w-full h-full rounded" />
|
|
176
|
+
) : (
|
|
177
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
178
|
+
<img
|
|
179
|
+
src={qrcode}
|
|
180
|
+
alt={translate('common.account.twoFactor.qrAlt')}
|
|
181
|
+
className="w-full h-full"
|
|
182
|
+
/>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
181
185
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
<div className="flex items-center gap-3 w-full">
|
|
187
|
+
<Separator className="flex-1" />
|
|
188
|
+
<span className="paragraph-xsmall-medium text-gray-500 opacity-80 whitespace-nowrap">
|
|
189
|
+
{translate('common.account.twoFactor.pasteDigits')}
|
|
190
|
+
</span>
|
|
191
|
+
<Separator className="flex-1" />
|
|
192
|
+
</div>
|
|
189
193
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
194
|
+
<div className="scroll-mt-20">
|
|
195
|
+
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
|
|
196
|
+
<InputOTPGroup className="gap-2">
|
|
197
|
+
{Array.from({ length: 6 }).map((_, i) => (
|
|
198
|
+
<InputOTPSlot
|
|
199
|
+
key={i}
|
|
200
|
+
index={i}
|
|
201
|
+
className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
|
|
202
|
+
/>
|
|
203
|
+
))}
|
|
204
|
+
</InputOTPGroup>
|
|
205
|
+
</InputOTP>
|
|
206
|
+
</div>
|
|
202
207
|
</div>
|
|
203
208
|
</div>
|
|
204
|
-
</div>
|
|
205
209
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
210
|
+
<div className="shrink-0 flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between gap-2 bg-white">
|
|
211
|
+
<Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
|
|
212
|
+
{translate('common.actions.cancel')}
|
|
213
|
+
</Button>
|
|
214
|
+
<Button type="submit" className="h-10!" disabled={!isCodeComplete || isConfirming}>
|
|
215
|
+
{isConfirming
|
|
216
|
+
? translate('common.account.twoFactor.activating')
|
|
217
|
+
: translate('common.account.twoFactor.activate')}
|
|
218
|
+
</Button>
|
|
219
|
+
</div>
|
|
220
|
+
</form>
|
|
221
|
+
</DialogContent>
|
|
222
|
+
</Dialog>
|
|
223
|
+
</DialogLayer>
|
|
219
224
|
);
|
|
220
225
|
}
|
|
@@ -28,8 +28,7 @@ function loadClarityScript() {
|
|
|
28
28
|
const t = document.createElement('script');
|
|
29
29
|
t.async = true;
|
|
30
30
|
t.src = src;
|
|
31
|
-
|
|
32
|
-
y?.parentNode?.insertBefore(t, y);
|
|
31
|
+
document.head.appendChild(t);
|
|
33
32
|
} catch {}
|
|
34
33
|
}
|
|
35
34
|
|
|
@@ -58,12 +58,11 @@ function initFrillLoader() {
|
|
|
58
58
|
function loadFrillScript() {
|
|
59
59
|
try {
|
|
60
60
|
if (document.querySelector(`script[src="${FRILL_SCRIPT_URL}"]`)) return;
|
|
61
|
-
const anchor = document.getElementsByTagName('script')[0];
|
|
62
61
|
const script = document.createElement('script');
|
|
63
62
|
script.type = 'text/javascript';
|
|
64
63
|
script.async = true;
|
|
65
64
|
script.src = FRILL_SCRIPT_URL;
|
|
66
|
-
|
|
65
|
+
document.head.appendChild(script);
|
|
67
66
|
} catch {}
|
|
68
67
|
}
|
|
69
68
|
|