@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.
@@ -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 <ModalComponent key={modal.key} />;\n })}\n </>\n );\n}\n"],"mappings":";AAeI,mBASW,WATX;AAZJ,SAAS,uBAAuB;AAMzB,SAAS,aAAa,EAAE,SAAS,GAAsB;AAC5D,QAAM,EAAE,WAAW,IAAI,gBAAgB;AAEvC,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,SACE,gCACG,qBAAW,IAAI,CAAC,UAAU;AACzB,UAAM,iBAAiB,SAAS,MAAM,GAAG;AAEzC,QAAI,CAAC,gBAAgB;AACnB,cAAQ,KAAK,UAAU,MAAM,GAAG,yBAAyB;AACzD,aAAO;AAAA,IACT;AAEA,WAAO,oBAAC,oBAAoB,MAAM,GAAK;AAAA,EACzC,CAAC,GACH;AAEJ;","names":[]}
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 /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
24
- DialogContent,
25
- {
26
- className: "w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0 z-[1003]",
27
- overlayClassName: "z-[1002]",
28
- children: [
29
- /* @__PURE__ */ jsx(DialogHeader, { className: "p-5", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-center text-[16px]!", children: translate("common.imageUpload.tooSmallTitleWithDimension", { dimensionText }) }) }),
30
- /* @__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 }) }) }),
31
- /* @__PURE__ */ jsxs(DialogFooter, { className: "flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200", children: [
32
- /* @__PURE__ */ jsx(Button, { onClick: onSelectAnother, children: translate("common.imageUpload.sendAnother") }),
33
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onCancel, children: translate("common.actions.cancel") })
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 <DialogContent\n className=\"w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0 z-[1003]\"\n overlayClassName=\"z-[1002]\"\n >\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 )\n}\n"],"mappings":";AAyCU,cAWF,YAXE;AAvCV,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,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,SACE,oBAAC,UAAO,MAAY,cAClB;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,kBAAiB;AAAA,MAEjB;AAAA,4BAAC,gBAAa,WAAU,OACtB,8BAAC,eAAY,WAAU,4BACpB,oBAAU,iDAAiD,EAAE,cAAc,CAAC,GAC/E,GACF;AAAA,QAEA,oBAAC,SAAI,WAAU,aACb,8BAAC,OAAE,WAAU,qDACV,oBAAU,oDAAoD,EAAE,UAAU,cAAc,CAAC,GAC5F,GACF;AAAA,QAEA,qBAAC,gBAAa,WAAU,4EACtB;AAAA,8BAAC,UAAO,SAAS,iBAAkB,oBAAU,gCAAgC,GAAE;AAAA,UAC/E,oBAAC,UAAO,SAAQ,aAAY,SAAS,UAClC,oBAAU,uBAAuB,GACpC;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.776",
3
+ "version": "1.1.778",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -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
- <Dialog open={open} onOpenChange={handleClose}>
34
- <DialogContent overlayClassName="z-[1010]" 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-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%]">
35
- <form
36
- onSubmit={(e) => {
37
- e.preventDefault();
38
- handleSubmit();
39
- }}
40
- className="flex flex-col flex-1 lg:flex-none"
41
- >
42
- <div className="flex flex-col gap-4 lg:gap-5 p-4 lg:p-5 flex-1 lg:flex-none">
43
- <div className="flex items-center justify-center w-fit bg-gray-50 rounded-lg p-2">
44
- <IconShieldCheck size={20} className="text-gray-600" />
45
- </div>
46
- <DialogHeader className="p-0 gap-2">
47
- <DialogTitle className="paragraph-medium-semibold text-gray-950">
48
- {translate('common.account.twoFactor.disableTitle')}
49
- </DialogTitle>
50
- <DialogDescription className="paragraph-small-regular text-gray-600">
51
- {translate('common.account.twoFactor.disableDescription')}
52
- </DialogDescription>
53
- </DialogHeader>
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
- <div className="flex flex-col gap-2">
56
- <span className="paragraph-small-medium text-gray-700">
57
- {translate('common.account.twoFactor.authenticatorCode')}
58
- </span>
59
- <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
60
- <InputOTPGroup className="gap-2">
61
- {Array.from({ length: 6 }).map((_, i) => (
62
- <InputOTPSlot
63
- key={i}
64
- index={i}
65
- className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
66
- />
67
- ))}
68
- </InputOTPGroup>
69
- </InputOTP>
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
- <div className="flex flex-row items-center gap-2 p-4 lg:p-5 border-t border-gray-200 mt-auto lg:mt-0">
74
- <Button className="h-10! flex-1" disabled={!isValid || isLoading} type="submit">
75
- {isLoading
76
- ? translate('common.account.twoFactor.disabling')
77
- : translate('common.account.twoFactor.disable')}
78
- </Button>
79
- <Button
80
- variant="secondary"
81
- className="h-10! flex-1"
82
- type="button"
83
- onClick={handleClose}
84
- >
85
- {translate('common.actions.cancel')}
86
- </Button>
87
- </div>
88
- </form>
89
- </DialogContent>
90
- </Dialog>
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
- overlayClassName="z-[1010]"
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.recoveryTitle')}</DialogTitle>
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.recoveryTitle')}
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
- <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">
68
- <div className="flex flex-col gap-2">
69
- <h3 className="paragraph-medium-semibold text-gray-950 max-w-[269px]">
70
- {translate('common.account.twoFactor.recoveryHeading')}
71
- </h3>
72
- <div className="paragraph-small-regular text-gray-600">
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
- <IconX size={18} />
131
- </Button>
132
- </div>
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
- <form
135
- className="flex-1 min-h-0 flex flex-col"
136
- onSubmit={(e) => {
137
- e.preventDefault();
138
- if (isCodeComplete) handleSubmit();
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
- {chunks}
153
- </a>
154
- ),
155
- })}
156
- </p>
157
-
158
- <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]">
159
- {generateFailed ? (
160
- <button
161
- type="button"
162
- onClick={() => retryGenerate()}
163
- className="flex flex-col items-center gap-1.5 text-center"
164
- >
165
- <IconRefresh size={20} className="text-gray-400" />
166
- <span className="paragraph-xsmall-medium text-gray-500">
167
- {translate('common.account.twoFactor.retry')}
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
- <div className="flex items-center gap-3 w-full">
183
- <Separator className="flex-1" />
184
- <span className="paragraph-xsmall-medium text-gray-500 opacity-80 whitespace-nowrap">
185
- {translate('common.account.twoFactor.pasteDigits')}
186
- </span>
187
- <Separator className="flex-1" />
188
- </div>
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
- <div className="scroll-mt-20">
191
- <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
192
- <InputOTPGroup className="gap-2">
193
- {Array.from({ length: 6 }).map((_, i) => (
194
- <InputOTPSlot
195
- key={i}
196
- index={i}
197
- className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
198
- />
199
- ))}
200
- </InputOTPGroup>
201
- </InputOTP>
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
- <div className="shrink-0 flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between gap-2 bg-white">
207
- <Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
208
- {translate('common.actions.cancel')}
209
- </Button>
210
- <Button type="submit" className="h-10!" disabled={!isCodeComplete || isConfirming}>
211
- {isConfirming
212
- ? translate('common.account.twoFactor.activating')
213
- : translate('common.account.twoFactor.activate')}
214
- </Button>
215
- </div>
216
- </form>
217
- </DialogContent>
218
- </Dialog>
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
- const y = document.getElementsByTagName('script')[0];
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
- anchor?.parentNode?.insertBefore(script, anchor);
65
+ document.head.appendChild(script);
67
66
  } catch {}
68
67
  }
69
68