@greatapps/common 1.1.257 → 1.1.258
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/AccountModals.mjs.map +1 -1
- package/dist/components/account/ConfigurationsMyAccountModal.mjs +1 -1
- package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
- package/dist/components/handlers/SearchParamsHandler.mjs.map +1 -1
- package/dist/components/modals/ModalManager.mjs.map +1 -1
- package/dist/components/modals/Modals.mjs.map +1 -1
- package/dist/components/widgets/notifications/NotificationCard.mjs.map +1 -1
- package/dist/hooks/useDebounce.mjs.map +1 -1
- package/dist/hooks/useDebounceState.mjs.map +1 -1
- package/dist/hooks/useDebouncedEffect.mjs.map +1 -1
- package/dist/infra/utils/clsx.mjs.map +1 -1
- package/dist/infra/utils/parser.mjs.map +1 -1
- package/dist/infra/utils/percentage.mjs.map +1 -1
- package/dist/modules/users/services/messages.service.mjs.map +1 -1
- package/dist/store/useAccountModals.mjs.map +1 -1
- package/dist/store/useModalManager.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/account/AccountModals.tsx +17 -17
- package/src/components/account/ConfigurationsMyAccountModal.tsx +1 -1
- package/src/components/handlers/SearchParamsHandler.tsx +61 -61
- package/src/components/modals/ModalManager.tsx +29 -29
- package/src/components/modals/Modals.tsx +26 -26
- package/src/components/widgets/notifications/NotificationCard.tsx +68 -68
- package/src/hooks/useDebounce.ts +26 -26
- package/src/hooks/useDebounceState.ts +11 -11
- package/src/hooks/useDebouncedEffect.ts +69 -69
- package/src/infra/utils/clsx.ts +6 -6
- package/src/infra/utils/parser.ts +52 -52
- package/src/infra/utils/percentage.ts +42 -42
- package/src/modules/users/services/messages.service.ts +48 -48
- package/src/store/useAccountModals.ts +55 -55
- package/src/store/useModalManager.ts +104 -104
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/account/AccountModals.tsx"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../../src/components/account/AccountModals.tsx"],"sourcesContent":["'use client';\n\nimport ConfigurationsMyAccountModal from './ConfigurationsMyAccountModal';\nimport DeleteAccountModal from './DeleteAccountModal';\nimport IsntPossibleDeleteAccountModal from './IsntPossibleDeleteAccountModal';\nimport ConfirmDeleteAccountModal from './ConfirmDeleteAccountModal';\n\nexport default function AccountModals() {\n return (\n <>\n <ConfigurationsMyAccountModal />\n <DeleteAccountModal />\n <IsntPossibleDeleteAccountModal />\n <ConfirmDeleteAccountModal />\n </>\n );\n}\n"],"mappings":";AASI,mBACE,KADF;AAPJ,OAAO,kCAAkC;AACzC,OAAO,wBAAwB;AAC/B,OAAO,oCAAoC;AAC3C,OAAO,+BAA+B;AAEvB,SAAR,gBAAiC;AACtC,SACE,iCACE;AAAA,wBAAC,gCAA6B;AAAA,IAC9B,oBAAC,sBAAmB;AAAA,IACpB,oBAAC,kCAA+B;AAAA,IAChC,oBAAC,6BAA0B;AAAA,KAC7B;AAEJ;","names":[]}
|
|
@@ -105,7 +105,7 @@ function ConfigurationsMyAccountModal() {
|
|
|
105
105
|
]
|
|
106
106
|
}
|
|
107
107
|
),
|
|
108
|
-
/* @__PURE__ */ jsxs("div", { className: "w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative", children: [
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col", children: [
|
|
109
109
|
/* @__PURE__ */ jsx(TabsContent, { value: AccountSectionType.MY_PROFILE, className: "h-full! relative overflow-hidden", children: /* @__PURE__ */ jsx(MyProfileSection, { onClose: close }) }),
|
|
110
110
|
/* @__PURE__ */ jsx(TabsContent, { value: AccountSectionType.SECURITY, className: "h-full! relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
111
111
|
SecuritySection,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/account/ConfigurationsMyAccountModal.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { IconLock, IconSettings2, IconUser, IconX } from '@tabler/icons-react';\r\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';\r\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/data-display/Tabs';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { cn } from '../../infra/utils/clsx';\r\nimport { AccountSectionType } from '../../enums/AccountSectionType';\r\nimport { MyProfileSection } from './sections/MyProfileSection';\r\nimport { PreferencesSection } from './sections/PreferencesSection';\r\nimport { ChangePasswordSection } from './sections/ChangePasswordSection';\r\nimport { SecuritySection } from './sections/SecuritySection';\r\nimport useConfigurationsModal from './hooks/useConfigurationsModal';\r\nimport useIsMobile from '../../hooks/useIsMobile';\r\nimport { useAccountModals } from '../../store/useAccountModals';\r\n\r\nexport default function ConfigurationsMyAccountModal() {\r\n const {\r\n activeModal,\r\n config,\r\n initialSection,\r\n openDeleteAccount,\r\n openIsntPossibleDelete,\r\n close,\r\n } = useAccountModals();\r\n\r\n const open = activeModal === 'configurations';\r\n const { hasActiveSubscription } = config;\r\n\r\n const isMobile = useIsMobile();\r\n const { activeSection, setActiveSection } = useConfigurationsModal({\r\n isOpen: open,\r\n initialSection,\r\n });\r\n\r\n const handleDeleteAccount = () => {\r\n close();\r\n if (hasActiveSubscription) {\r\n openIsntPossibleDelete();\r\n } else {\r\n openDeleteAccount();\r\n }\r\n };\r\n\r\n const tabTriggerClasses = cn(\r\n 'border-0! px-0 py-0',\r\n\r\n 'lg:rounded-md lg:flex lg:items-center lg:gap-2 lg:p-3 lg:justify-start lg:w-full',\r\n 'lg:bg-white lg:hover:bg-gray-100 lg:active:bg-gray-50 lg:border-0',\r\n 'lg:data-[state=active]:bg-gray-50',\r\n\r\n 'flex items-center gap-1.5 px-3 py-3 justify-center whitespace-nowrap',\r\n 'border-b-2 border-transparent',\r\n 'data-[state=active]:bg-gray-50 rounded-lg',\r\n\r\n 'text-gray-500 data-[state=active]:text-gray-950',\r\n 'hover:text-gray-900 transition-colors'\r\n );\r\n\r\n return (\r\n <Dialog open={open} onOpenChange={close}>\r\n <DialogContent\r\n showCloseButton={!isMobile}\r\n overlayClassName=\"bg-black/20 lg:bg-black/50\"\r\n className=\"\r\n flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0\r\n rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0\r\n lg:flex-row lg:w-[892px] lg:max-w-[892px] lg:h-[626px] lg:rounded-lg lg:border\r\n lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]\"\r\n >\r\n <DialogHeader className=\"sr-only\">\r\n <DialogTitle>Configurações</DialogTitle>\r\n </DialogHeader>\r\n <div className=\"md:hidden flex items-center justify-between px-5 py-3 border-b border-gray-200\">\r\n <span className=\"text-gray-950 paragraph-medium-semibold\">Configurações</span>\r\n <button\r\n type=\"button\"\r\n className=\"size-8 flex items-center justify-center text-gray-500 cursor-pointer\"\r\n onClick={close}\r\n >\r\n <IconX size={18} />\r\n </button>\r\n </div>\r\n <Tabs\r\n value={activeSection}\r\n onValueChange={(value) => setActiveSection(value as AccountSectionType)}\r\n orientation=\"vertical\"\r\n className=\"flex lg:flex-row flex-col w-full h-full flex-1 lg:h-full lg:pt-0 lg:gap-0\"\r\n >\r\n <TabsList\r\n className={cn(\r\n 'flex gap-0 bg-transparent border-b-0',\r\n\r\n 'lg:flex-col lg:items-stretch lg:justify-start lg:w-auto lg:min-w-60',\r\n 'lg:border-r lg:border-gray-200 lg:pl-5 lg:pr-5 lg:pt-5 lg:gap-5 lg:overflow-x-visible lg:self-stretch',\r\n\r\n 'flex-row items-center justify-start w-full overflow-x-auto scrollbar-hide shrink-0',\r\n 'px-4 py-3',\r\n '[mask-image:linear-gradient(to_right,transparent,black_16px,black_calc(100%-24px),transparent)] lg:[mask-image:none]'\r\n )}\r\n >\r\n <span className=\"hidden lg:block paragraph-medium-semibold text-gray-950 mb-0\">\r\n Configurações\r\n </span>\r\n\r\n <div className=\"lg:flex lg:flex-col flex flex-row lg:gap-0 gap-0 lg:w-full\">\r\n <TabsTrigger value={AccountSectionType.MY_PROFILE} className={tabTriggerClasses}>\r\n <IconUser size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Meu perfil</span>\r\n </TabsTrigger>\r\n\r\n <TabsTrigger value={AccountSectionType.PREFERENCES} className={tabTriggerClasses}>\r\n <IconSettings2 size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Preferências</span>\r\n </TabsTrigger>\r\n\r\n <TabsTrigger value={AccountSectionType.SECURITY} className={tabTriggerClasses}>\r\n <IconLock size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Segurança</span>\r\n </TabsTrigger>\r\n </div>\r\n </TabsList>\r\n\r\n <div className=\"w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative\">\r\n <TabsContent value={AccountSectionType.MY_PROFILE} className=\"h-full! relative overflow-hidden\">\r\n <MyProfileSection onClose={close} />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.SECURITY} className=\"h-full! relative overflow-hidden\">\r\n <SecuritySection\r\n setActiveSection={setActiveSection}\r\n onClose={close}\r\n hasActiveSubscription={hasActiveSubscription}\r\n onDeleteAccount={handleDeleteAccount}\r\n />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.CHANGE_PASSWORD} className=\"h-full! relative overflow-hidden\">\r\n <ChangePasswordSection onBack={() => setActiveSection(AccountSectionType.SECURITY)} />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.PREFERENCES} className=\"h-full! relative overflow-hidden\">\r\n <PreferencesSection onClose={close} />\r\n </TabsContent>\r\n </div>\r\n </Tabs>\r\n </DialogContent>\r\n </Dialog>\r\n );\r\n}\r\n"],"mappings":";AAuEU,cAEF,YAFE;AArEV,SAAS,UAAU,eAAe,UAAU,aAAa;AACzD,SAAS,QAAQ,eAAe,cAAc,mBAAmB;AACjE,SAAS,MAAM,UAAU,aAAa,mBAAmB;AAEzD,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,uBAAuB;AAChC,OAAO,4BAA4B;AACnC,OAAO,iBAAiB;AACxB,SAAS,wBAAwB;AAElB,SAAR,+BAAgD;AACrD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB;AAErB,QAAM,OAAO,gBAAgB;AAC7B,QAAM,EAAE,sBAAsB,IAAI;AAElC,QAAM,WAAW,YAAY;AAC7B,QAAM,EAAE,eAAe,iBAAiB,IAAI,uBAAuB;AAAA,IACjE,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,sBAAsB,MAAM;AAChC,UAAM;AACN,QAAI,uBAAuB;AACzB,6BAAuB;AAAA,IACzB,OAAO;AACL,wBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,oBAAoB;AAAA,IACxB;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,UAAO,MAAY,cAAc,OAChC;AAAA,IAAC;AAAA;AAAA,MACC,iBAAiB,CAAC;AAAA,MAClB,kBAAiB;AAAA,MACjB,WAAU;AAAA,MAMV;AAAA,4BAAC,gBAAa,WAAU,WACtB,8BAAC,eAAY,iCAAa,GAC5B;AAAA,QACA,qBAAC,SAAI,WAAU,kFACb;AAAA,8BAAC,UAAK,WAAU,2CAA0C,iCAAa;AAAA,UACvE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cAET,8BAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UACnB;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,eAAe,CAAC,UAAU,iBAAiB,KAA2B;AAAA,YACtE,aAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBAEA;AAAA,oBACA;AAAA,oBAEA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,kBAEA;AAAA,wCAAC,UAAK,WAAU,gEAA+D,iCAE/E;AAAA,oBAEA,qBAAC,SAAI,WAAU,8DACb;AAAA,2CAAC,eAAY,OAAO,mBAAmB,YAAY,WAAW,mBAC5D;AAAA,4CAAC,YAAS,MAAM,IAAI,WAAU,YAAW;AAAA,wBACzC,oBAAC,UAAK,WAAU,0BAAyB,wBAAU;AAAA,yBACrD;AAAA,sBAEA,qBAAC,eAAY,OAAO,mBAAmB,aAAa,WAAW,mBAC7D;AAAA,4CAAC,iBAAc,MAAM,IAAI,WAAU,YAAW;AAAA,wBAC9C,oBAAC,UAAK,WAAU,0BAAyB,6BAAY;AAAA,yBACvD;AAAA,sBAEA,qBAAC,eAAY,OAAO,mBAAmB,UAAU,WAAW,mBAC1D;AAAA,4CAAC,YAAS,MAAM,IAAI,WAAU,YAAW;AAAA,wBACzC,oBAAC,UAAK,WAAU,0BAAyB,0BAAS;AAAA,yBACpD;AAAA,uBACF;AAAA;AAAA;AAAA,cACF;AAAA,cAEA,qBAAC,SAAI,WAAU,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/account/ConfigurationsMyAccountModal.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { IconLock, IconSettings2, IconUser, IconX } from '@tabler/icons-react';\r\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';\r\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/data-display/Tabs';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { cn } from '../../infra/utils/clsx';\r\nimport { AccountSectionType } from '../../enums/AccountSectionType';\r\nimport { MyProfileSection } from './sections/MyProfileSection';\r\nimport { PreferencesSection } from './sections/PreferencesSection';\r\nimport { ChangePasswordSection } from './sections/ChangePasswordSection';\r\nimport { SecuritySection } from './sections/SecuritySection';\r\nimport useConfigurationsModal from './hooks/useConfigurationsModal';\r\nimport useIsMobile from '../../hooks/useIsMobile';\r\nimport { useAccountModals } from '../../store/useAccountModals';\r\n\r\nexport default function ConfigurationsMyAccountModal() {\r\n const {\r\n activeModal,\r\n config,\r\n initialSection,\r\n openDeleteAccount,\r\n openIsntPossibleDelete,\r\n close,\r\n } = useAccountModals();\r\n\r\n const open = activeModal === 'configurations';\r\n const { hasActiveSubscription } = config;\r\n\r\n const isMobile = useIsMobile();\r\n const { activeSection, setActiveSection } = useConfigurationsModal({\r\n isOpen: open,\r\n initialSection,\r\n });\r\n\r\n const handleDeleteAccount = () => {\r\n close();\r\n if (hasActiveSubscription) {\r\n openIsntPossibleDelete();\r\n } else {\r\n openDeleteAccount();\r\n }\r\n };\r\n\r\n const tabTriggerClasses = cn(\r\n 'border-0! px-0 py-0',\r\n\r\n 'lg:rounded-md lg:flex lg:items-center lg:gap-2 lg:p-3 lg:justify-start lg:w-full',\r\n 'lg:bg-white lg:hover:bg-gray-100 lg:active:bg-gray-50 lg:border-0',\r\n 'lg:data-[state=active]:bg-gray-50',\r\n\r\n 'flex items-center gap-1.5 px-3 py-3 justify-center whitespace-nowrap',\r\n 'border-b-2 border-transparent',\r\n 'data-[state=active]:bg-gray-50 rounded-lg',\r\n\r\n 'text-gray-500 data-[state=active]:text-gray-950',\r\n 'hover:text-gray-900 transition-colors'\r\n );\r\n\r\n return (\r\n <Dialog open={open} onOpenChange={close}>\r\n <DialogContent\r\n showCloseButton={!isMobile}\r\n overlayClassName=\"bg-black/20 lg:bg-black/50\"\r\n className=\"\r\n flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0\r\n rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0\r\n lg:flex-row lg:w-[892px] lg:max-w-[892px] lg:h-[626px] lg:rounded-lg lg:border\r\n lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]\"\r\n >\r\n <DialogHeader className=\"sr-only\">\r\n <DialogTitle>Configurações</DialogTitle>\r\n </DialogHeader>\r\n <div className=\"md:hidden flex items-center justify-between px-5 py-3 border-b border-gray-200\">\r\n <span className=\"text-gray-950 paragraph-medium-semibold\">Configurações</span>\r\n <button\r\n type=\"button\"\r\n className=\"size-8 flex items-center justify-center text-gray-500 cursor-pointer\"\r\n onClick={close}\r\n >\r\n <IconX size={18} />\r\n </button>\r\n </div>\r\n <Tabs\r\n value={activeSection}\r\n onValueChange={(value) => setActiveSection(value as AccountSectionType)}\r\n orientation=\"vertical\"\r\n className=\"flex lg:flex-row flex-col w-full h-full flex-1 lg:h-full lg:pt-0 lg:gap-0\"\r\n >\r\n <TabsList\r\n className={cn(\r\n 'flex gap-0 bg-transparent border-b-0',\r\n\r\n 'lg:flex-col lg:items-stretch lg:justify-start lg:w-auto lg:min-w-60',\r\n 'lg:border-r lg:border-gray-200 lg:pl-5 lg:pr-5 lg:pt-5 lg:gap-5 lg:overflow-x-visible lg:self-stretch',\r\n\r\n 'flex-row items-center justify-start w-full overflow-x-auto scrollbar-hide shrink-0',\r\n 'px-4 py-3',\r\n '[mask-image:linear-gradient(to_right,transparent,black_16px,black_calc(100%-24px),transparent)] lg:[mask-image:none]'\r\n )}\r\n >\r\n <span className=\"hidden lg:block paragraph-medium-semibold text-gray-950 mb-0\">\r\n Configurações\r\n </span>\r\n\r\n <div className=\"lg:flex lg:flex-col flex flex-row lg:gap-0 gap-0 lg:w-full\">\r\n <TabsTrigger value={AccountSectionType.MY_PROFILE} className={tabTriggerClasses}>\r\n <IconUser size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Meu perfil</span>\r\n </TabsTrigger>\r\n\r\n <TabsTrigger value={AccountSectionType.PREFERENCES} className={tabTriggerClasses}>\r\n <IconSettings2 size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Preferências</span>\r\n </TabsTrigger>\r\n\r\n <TabsTrigger value={AccountSectionType.SECURITY} className={tabTriggerClasses}>\r\n <IconLock size={20} className=\"shrink-0\" />\r\n <span className=\"paragraph-small-medium\">Segurança</span>\r\n </TabsTrigger>\r\n </div>\r\n </TabsList>\r\n\r\n <div className=\"w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col\">\r\n <TabsContent value={AccountSectionType.MY_PROFILE} className=\"h-full! relative overflow-hidden\">\r\n <MyProfileSection onClose={close} />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.SECURITY} className=\"h-full! relative overflow-hidden\">\r\n <SecuritySection\r\n setActiveSection={setActiveSection}\r\n onClose={close}\r\n hasActiveSubscription={hasActiveSubscription}\r\n onDeleteAccount={handleDeleteAccount}\r\n />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.CHANGE_PASSWORD} className=\"h-full! relative overflow-hidden\">\r\n <ChangePasswordSection onBack={() => setActiveSection(AccountSectionType.SECURITY)} />\r\n </TabsContent>\r\n\r\n <TabsContent value={AccountSectionType.PREFERENCES} className=\"h-full! relative overflow-hidden\">\r\n <PreferencesSection onClose={close} />\r\n </TabsContent>\r\n </div>\r\n </Tabs>\r\n </DialogContent>\r\n </Dialog>\r\n );\r\n}\r\n"],"mappings":";AAuEU,cAEF,YAFE;AArEV,SAAS,UAAU,eAAe,UAAU,aAAa;AACzD,SAAS,QAAQ,eAAe,cAAc,mBAAmB;AACjE,SAAS,MAAM,UAAU,aAAa,mBAAmB;AAEzD,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,uBAAuB;AAChC,OAAO,4BAA4B;AACnC,OAAO,iBAAiB;AACxB,SAAS,wBAAwB;AAElB,SAAR,+BAAgD;AACrD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB;AAErB,QAAM,OAAO,gBAAgB;AAC7B,QAAM,EAAE,sBAAsB,IAAI;AAElC,QAAM,WAAW,YAAY;AAC7B,QAAM,EAAE,eAAe,iBAAiB,IAAI,uBAAuB;AAAA,IACjE,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,sBAAsB,MAAM;AAChC,UAAM;AACN,QAAI,uBAAuB;AACzB,6BAAuB;AAAA,IACzB,OAAO;AACL,wBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,oBAAoB;AAAA,IACxB;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,EACF;AAEA,SACE,oBAAC,UAAO,MAAY,cAAc,OAChC;AAAA,IAAC;AAAA;AAAA,MACC,iBAAiB,CAAC;AAAA,MAClB,kBAAiB;AAAA,MACjB,WAAU;AAAA,MAMV;AAAA,4BAAC,gBAAa,WAAU,WACtB,8BAAC,eAAY,iCAAa,GAC5B;AAAA,QACA,qBAAC,SAAI,WAAU,kFACb;AAAA,8BAAC,UAAK,WAAU,2CAA0C,iCAAa;AAAA,UACvE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS;AAAA,cAET,8BAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UACnB;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,eAAe,CAAC,UAAU,iBAAiB,KAA2B;AAAA,YACtE,aAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBAEA;AAAA,oBACA;AAAA,oBAEA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,kBAEA;AAAA,wCAAC,UAAK,WAAU,gEAA+D,iCAE/E;AAAA,oBAEA,qBAAC,SAAI,WAAU,8DACb;AAAA,2CAAC,eAAY,OAAO,mBAAmB,YAAY,WAAW,mBAC5D;AAAA,4CAAC,YAAS,MAAM,IAAI,WAAU,YAAW;AAAA,wBACzC,oBAAC,UAAK,WAAU,0BAAyB,wBAAU;AAAA,yBACrD;AAAA,sBAEA,qBAAC,eAAY,OAAO,mBAAmB,aAAa,WAAW,mBAC7D;AAAA,4CAAC,iBAAc,MAAM,IAAI,WAAU,YAAW;AAAA,wBAC9C,oBAAC,UAAK,WAAU,0BAAyB,6BAAY;AAAA,yBACvD;AAAA,sBAEA,qBAAC,eAAY,OAAO,mBAAmB,UAAU,WAAW,mBAC1D;AAAA,4CAAC,YAAS,MAAM,IAAI,WAAU,YAAW;AAAA,wBACzC,oBAAC,UAAK,WAAU,0BAAyB,0BAAS;AAAA,yBACpD;AAAA,uBACF;AAAA;AAAA;AAAA,cACF;AAAA,cAEA,qBAAC,SAAI,WAAU,8FACb;AAAA,oCAAC,eAAY,OAAO,mBAAmB,YAAY,WAAU,oCAC3D,8BAAC,oBAAiB,SAAS,OAAO,GACpC;AAAA,gBAEA,oBAAC,eAAY,OAAO,mBAAmB,UAAU,WAAU,oCACzD;AAAA,kBAAC;AAAA;AAAA,oBACC;AAAA,oBACA,SAAS;AAAA,oBACT;AAAA,oBACA,iBAAiB;AAAA;AAAA,gBACnB,GACF;AAAA,gBAEA,oBAAC,eAAY,OAAO,mBAAmB,iBAAiB,WAAU,oCAChE,8BAAC,yBAAsB,QAAQ,MAAM,iBAAiB,mBAAmB,QAAQ,GAAG,GACtF;AAAA,gBAEA,oBAAC,eAAY,OAAO,mBAAmB,aAAa,WAAU,oCAC5D,8BAAC,sBAAmB,SAAS,OAAO,GACtC;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/handlers/SearchParamsHandler.tsx"],"sourcesContent":["\"use client\";\
|
|
1
|
+
{"version":3,"sources":["../../../src/components/handlers/SearchParamsHandler.tsx"],"sourcesContent":["\"use client\";\n\nimport { Suspense, useEffect } from \"react\";\nimport { useSearchParams } from \"next/navigation\";\n\ninterface SearchParamsHandlerProps {\n handlers: {\n [key: string]: () => void;\n };\n}\n\n/**\n * SearchParamsHandler\n *\n * Este componente é responsável por ler os parâmetros da URL e executar callbacks\n * correspondentes a cada parâmetro encontrado.\n *\n * Por que precisamos deste componente?\n * - O Next.js 16 exige que useSearchParams() seja envolvido em um <Suspense> boundary\n * - Isso evita erros de prerendering durante o build\n * - Permite que URLs como \"/page?tab=performance\" naveguem diretamente para uma aba específica\n *\n * Exemplo de como funciona\n * 1. Usa useSearchParams() para ler o parâmetro \"tab\" da URL\n * 2. Monitora mudanças nos parâmetros com useEffect\n * 3. Quando encontra um parâmetro \"tab\", chama onTabChange com o valor\n * 4. Retorna null porque não renderiza nada na tela\n *\n * Exemplo de uso:\n * <Suspense fallback={null}>\n * <SearchParamsHandler handlers={{ tab: () => console.log(\"Tab changed\") }} />\n * </Suspense>\n *\n * Exemplos de URL:\n * - /greatpages/123?tab=performance → abre a aba \"performance\"\n * - /greatpages/123?tab=leads → abre a aba \"leads\"\n */\nexport function SearchParamsHandler(options: SearchParamsHandlerProps) {\n return (\n <Suspense fallback={null}>\n <SearchParamsHandlerChildren {...options} />\n </Suspense>\n );\n}\n\nexport function SearchParamsHandlerChildren(options: SearchParamsHandlerProps) {\n const searchParams = useSearchParams();\n\n useEffect(() => {\n Object.keys(options.handlers).forEach((key) => {\n const value = searchParams.get(key);\n\n if (value) {\n options.handlers[key]();\n }\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [searchParams]);\n\n return null;\n}\n"],"mappings":";AAwCM;AAtCN,SAAS,UAAU,iBAAiB;AACpC,SAAS,uBAAuB;AAkCzB,SAAS,oBAAoB,SAAmC;AACrE,SACE,oBAAC,YAAS,UAAU,MAClB,8BAAC,+BAA6B,GAAG,SAAS,GAC5C;AAEJ;AAEO,SAAS,4BAA4B,SAAmC;AAC7E,QAAM,eAAe,gBAAgB;AAErC,YAAU,MAAM;AACd,WAAO,KAAK,QAAQ,QAAQ,EAAE,QAAQ,CAAC,QAAQ;AAC7C,YAAM,QAAQ,aAAa,IAAI,GAAG;AAElC,UAAI,OAAO;AACT,gBAAQ,SAAS,GAAG,EAAE;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EAEH,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO;AACT;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/modals/ModalManager.tsx"],"sourcesContent":["'use client';\
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/modals/Modals.tsx"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../../src/components/modals/Modals.tsx"],"sourcesContent":["'use client';\n\nimport { ComponentType, useEffect } from 'react';\nimport AccountModals from '../account/AccountModals';\nimport { ModalManager } from './ModalManager';\nimport { useAccountModals } from '../../store/useAccountModals';\ninterface ModalsProps {\n registry: Record<string, ComponentType>;\n hasActiveSubscription?: boolean;\n onGoToSubscription?: () => void;\n}\n\nexport function Modals({ registry, hasActiveSubscription, onGoToSubscription }: ModalsProps) {\n const { updateConfig } = useAccountModals();\n\n useEffect(() => {\n updateConfig({ hasActiveSubscription, onGoToSubscription });\n }, [hasActiveSubscription, onGoToSubscription, updateConfig]);\n\n return (\n <>\n <AccountModals />\n <ModalManager registry={registry} />\n </>\n );\n}\n"],"mappings":";AAoBI,mBACE,KADF;AAlBJ,SAAwB,iBAAiB;AACzC,OAAO,mBAAmB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AAO1B,SAAS,OAAO,EAAE,UAAU,uBAAuB,mBAAmB,GAAgB;AAC3F,QAAM,EAAE,aAAa,IAAI,iBAAiB;AAE1C,YAAU,MAAM;AACd,iBAAa,EAAE,uBAAuB,mBAAmB,CAAC;AAAA,EAC5D,GAAG,CAAC,uBAAuB,oBAAoB,YAAY,CAAC;AAE5D,SACE,iCACE;AAAA,wBAAC,iBAAc;AAAA,IACf,oBAAC,gBAAa,UAAoB;AAAA,KACpC;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/widgets/notifications/NotificationCard.tsx"],"sourcesContent":["import { IconClock } from '@tabler/icons-react';\
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/widgets/notifications/NotificationCard.tsx"],"sourcesContent":["import { IconClock } from '@tabler/icons-react';\nimport { ReactNode } from 'react';\nimport { cn } from '../../../infra/utils/clsx';\n\ntype NotificationCardProps = {\n icon: ReactNode;\n iconBgColor?: string;\n title: string;\n description?: string;\n time: string;\n actions?: ReactNode;\n isUnread?: boolean;\n showBorder?: boolean;\n className?: string;\n gapPx: number;\n};\n\nexport default function NotificationCard({\n icon,\n iconBgColor,\n title,\n description,\n time,\n actions,\n isUnread = false,\n showBorder = true,\n className,\n gapPx = 16\n}: NotificationCardProps) {\n return (\n <div\n className={cn(\n 'flex flex-col lg:flex-row items-start p-4 lg:p-5 gap-3 lg:gap-4 relative',\n showBorder && 'border-b border-gray-200',\n className\n )}\n >\n <div\n className={cn(\n 'flex items-center justify-center size-10 rounded-full shrink-0',\n iconBgColor\n )}\n >\n {icon}\n </div>\n\n <div className=\"flex flex-col flex-1\" style={{ gap: `${gapPx}px` }}>\n <div className=\"flex flex-col gap-1\">\n <span className=\"paragraph-small-semibold text-gray-950\">{title}</span>\n {description && (\n <span className=\"paragraph-small-regular text-gray-600\">{description}</span>\n )}\n </div>\n\n <div className=\"flex items-center gap-1.5\">\n <IconClock size={14} className=\"text-gray-400\" />\n <span className=\"paragraph-xsmall-medium text-gray-600\">{time}</span>\n </div>\n\n {actions && <div className=\"flex items-center gap-2\">{actions}</div>}\n </div>\n\n {isUnread && <div className=\"size-2 bg-pages-400 rounded-full shrink-0 mt-1\" />}\n </div>\n );\n}\n\nexport type { NotificationCardProps };\n"],"mappings":"AAqCM,cAUE,YAVF;AArCN,SAAS,iBAAiB;AAE1B,SAAS,UAAU;AAeJ,SAAR,iBAAkC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb;AAAA,EACA,QAAQ;AACV,GAA0B;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,cAAc;AAAA,QACd;AAAA,MACF;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,YACF;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QAEA,qBAAC,SAAI,WAAU,wBAAuB,OAAO,EAAE,KAAK,GAAG,KAAK,KAAK,GAC/D;AAAA,+BAAC,SAAI,WAAU,uBACb;AAAA,gCAAC,UAAK,WAAU,0CAA0C,iBAAM;AAAA,YAC/D,eACC,oBAAC,UAAK,WAAU,yCAAyC,uBAAY;AAAA,aAEzE;AAAA,UAEA,qBAAC,SAAI,WAAU,6BACb;AAAA,gCAAC,aAAU,MAAM,IAAI,WAAU,iBAAgB;AAAA,YAC/C,oBAAC,UAAK,WAAU,yCAAyC,gBAAK;AAAA,aAChE;AAAA,UAEC,WAAW,oBAAC,SAAI,WAAU,2BAA2B,mBAAQ;AAAA,WAChE;AAAA,QAEC,YAAY,oBAAC,SAAI,WAAU,kDAAiD;AAAA;AAAA;AAAA,EAC/E;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useDebounce.ts"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useDebounce.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * Hook para aplicar debounce em valores\n * @param value - Valor a ser debounced\n * @param delay - Delay em milissegundos (padrão: 400ms)\n * @returns Valor debounced\n */\nexport function useDebounce<T>(value: T, delay: number = 400, onDebounce?: () => void): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const handler = setTimeout(() => {\n setDebouncedValue(value);\n onDebounce?.();\n }, delay);\n\n return () => {\n clearTimeout(handler);\n };\n }, [value, delay, onDebounce]);\n\n return debouncedValue;\n}\n"],"mappings":";AAEA,SAAS,WAAW,gBAAgB;AAQ7B,SAAS,YAAe,OAAU,QAAgB,KAAK,YAA4B;AACxF,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAY,KAAK;AAE7D,YAAU,MAAM;AACd,UAAM,UAAU,WAAW,MAAM;AAC/B,wBAAkB,KAAK;AACvB,mBAAa;AAAA,IACf,GAAG,KAAK;AAER,WAAO,MAAM;AACX,mBAAa,OAAO;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,UAAU,CAAC;AAE7B,SAAO;AACT;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useDebounceState.ts"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useDebounceState.ts"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport type React from 'react';\nimport { useDebounce } from './useDebounce';\n\nexport function useDebounceState<T>(initialValue: T, delay: number = 400): [T, React.Dispatch<React.SetStateAction<T>>] {\n const [rawValue, setRawValue] = useState<T>(initialValue);\n const debouncedValue = useDebounce(rawValue, delay);\n return [debouncedValue, setRawValue];\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AAEzB,SAAS,mBAAmB;AAErB,SAAS,iBAAoB,cAAiB,QAAgB,KAAmD;AACtH,QAAM,CAAC,UAAU,WAAW,IAAI,SAAY,YAAY;AACxD,QAAM,iBAAiB,YAAY,UAAU,KAAK;AAClD,SAAO,CAAC,gBAAgB,WAAW;AACrC;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useDebouncedEffect.ts"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useDebouncedEffect.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState, useCallback } from 'react';\n\ninterface UseDebouncedEffectOptions {\n effect: () => void;\n debouncedDeps: React.DependencyList;\n immediateDeps?: React.DependencyList;\n delay?: number;\n}\n\n/**\n * Executes an effect with two trigger modes:\n * - `debouncedDeps`: triggers the effect after a delay (resets on each change)\n * - `immediateDeps`: triggers the effect immediately (also cancels any pending debounce)\n *\n * On mount, the effect fires once immediately via `immediateDeps`.\n * The effect callback always uses the latest closure values via a ref.\n *\n * @returns `{ isDebouncing }` — true while waiting for a debounced trigger to fire\n */\nexport function useDebouncedEffect({\n effect,\n debouncedDeps,\n immediateDeps = [],\n delay = 500,\n}: UseDebouncedEffectOptions) {\n const [isDebouncing, setIsDebouncing] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const effectRef = useRef(effect);\n effectRef.current = effect;\n const hasMounted = useRef(false);\n\n const clearTimer = useCallback(() => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n useEffect(() => {\n clearTimer();\n setIsDebouncing(false);\n effectRef.current();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, immediateDeps);\n\n useEffect(() => {\n if (!hasMounted.current) {\n hasMounted.current = true;\n return;\n }\n\n clearTimer();\n setIsDebouncing(true);\n\n timerRef.current = setTimeout(() => {\n setIsDebouncing(false);\n effectRef.current();\n }, delay);\n\n return clearTimer;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [...debouncedDeps, delay]);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n return { isDebouncing };\n}\n"],"mappings":";AAEA,SAAS,WAAW,QAAQ,UAAU,mBAAmB;AAmBlD,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,QAAQ;AACV,GAA8B;AAC5B,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,WAAW,OAA6C,IAAI;AAClE,QAAM,YAAY,OAAO,MAAM;AAC/B,YAAU,UAAU;AACpB,QAAM,aAAa,OAAO,KAAK;AAE/B,QAAM,aAAa,YAAY,MAAM;AACnC,QAAI,SAAS,SAAS;AACpB,mBAAa,SAAS,OAAO;AAC7B,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,eAAW;AACX,oBAAgB,KAAK;AACrB,cAAU,QAAQ;AAAA,EAEpB,GAAG,aAAa;AAEhB,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,SAAS;AACvB,iBAAW,UAAU;AACrB;AAAA,IACF;AAEA,eAAW;AACX,oBAAgB,IAAI;AAEpB,aAAS,UAAU,WAAW,MAAM;AAClC,sBAAgB,KAAK;AACrB,gBAAU,QAAQ;AAAA,IACpB,GAAG,KAAK;AAER,WAAO;AAAA,EAET,GAAG,CAAC,GAAG,eAAe,KAAK,CAAC;AAE5B,YAAU,MAAM,YAAY,CAAC,UAAU,CAAC;AAExC,SAAO,EAAE,aAAa;AACxB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/utils/clsx.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/utils/clsx.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"],"mappings":"AAAA,SAAS,YAA6B;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/utils/parser.ts"],"sourcesContent":["import z, { ZodTypeAny } from \"zod\";\
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/utils/parser.ts"],"sourcesContent":["import z, { ZodTypeAny } from \"zod\";\nimport { PaginatedSuccessResult, SuccessResult } from \"../api/types\";\n\n/* Overloads */\nexport function parseSchema<T extends ZodTypeAny>(\n schema: T,\n data: unknown[]\n): z.infer<T>[];\n\nexport function parseSchema<T extends ZodTypeAny>(\n schema: T,\n data: unknown\n): z.infer<T>;\n\nexport function parseSchema<T extends ZodTypeAny>(\n schema: T,\n data: unknown | unknown[]\n) {\n if (Array.isArray(data)) {\n return data.map(item => schema.parse(item));\n }\n\n return schema.parse(data);\n}\n\nexport function parseResult<T extends ZodTypeAny>(\n schema: T,\n result: PaginatedSuccessResult<unknown>\n): PaginatedSuccessResult<z.infer<T>>;\n\nexport function parseResult<T extends ZodTypeAny>(\n schema: T,\n result: SuccessResult<unknown>\n): SuccessResult<z.infer<T>>;\n\nexport function parseResult<T extends ZodTypeAny>(\n schema: T,\n result: SuccessResult<unknown> | PaginatedSuccessResult<unknown>\n) {\n if (!result.data) return result;\n\n if (Array.isArray(result.data)) {\n return {\n ...result,\n data: result.data.map(item => schema.parse(item)),\n };\n }\n\n return {\n ...result,\n data: schema.parse(result.data),\n };\n}"],"mappings":"AAcO,SAAS,YACZ,QACA,MACF;AACE,MAAI,MAAM,QAAQ,IAAI,GAAG;AACrB,WAAO,KAAK,IAAI,UAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,EAC9C;AAEA,SAAO,OAAO,MAAM,IAAI;AAC5B;AAYO,SAAS,YACZ,QACA,QACF;AACE,MAAI,CAAC,OAAO,KAAM,QAAO;AAEzB,MAAI,MAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,WAAO;AAAA,MACH,GAAG;AAAA,MACH,MAAM,OAAO,KAAK,IAAI,UAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,IACpD;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,GAAG;AAAA,IACH,MAAM,OAAO,MAAM,OAAO,IAAI;AAAA,EAClC;AACJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/utils/percentage.ts"],"sourcesContent":["/**\
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/utils/percentage.ts"],"sourcesContent":["/**\n * Calcula percentual de um valor em relação ao total\n * @param current - Valor atual\n * @param total - Valor total\n * @returns Percentual (0-100)\n */\nexport const calculatePercentage = (current: number, total: number): number => {\n if (total === 0) return 0;\n return (current / total) * 100;\n};\n\n/**\n * Calcula a circunferência de um círculo\n * @param radius - Raio do círculo\n * @returns Circunferência\n */\nexport const calculateCircumference = (radius: number): number => {\n return 2 * Math.PI * radius;\n};\n\n/**\n * Calcula o offset para circular progress\n * @param percentage - Percentual de progresso (0-100)\n * @param circumference - Circunferência do círculo\n * @returns Valor do offset\n */\nexport const calculateCircularProgressOffset = (\n percentage: number,\n circumference: number\n): number => {\n return circumference - (percentage / 100) * circumference;\n};\n\n/**\n * Calcula raio de círculo baseado no tamanho e stroke\n * @param size - Tamanho total\n * @param strokeWidth - Largura do stroke\n * @returns Raio calculado\n */\nexport const calculateRadius = (size: number, strokeWidth: number): number => {\n return (size - strokeWidth) / 2;\n};\n"],"mappings":"AAMO,MAAM,sBAAsB,CAAC,SAAiB,UAA0B;AAC7E,MAAI,UAAU,EAAG,QAAO;AACxB,SAAQ,UAAU,QAAS;AAC7B;AAOO,MAAM,yBAAyB,CAAC,WAA2B;AAChE,SAAO,IAAI,KAAK,KAAK;AACvB;AAQO,MAAM,kCAAkC,CAC7C,YACA,kBACW;AACX,SAAO,gBAAiB,aAAa,MAAO;AAC9C;AAQO,MAAM,kBAAkB,CAAC,MAAc,gBAAgC;AAC5E,UAAQ,OAAO,eAAe;AAChC;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/users/services/messages.service.ts"],"sourcesContent":["import 'server-only';\
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/users/services/messages.service.ts"],"sourcesContent":["import 'server-only';\n\nimport { api } from '../../../infra/api/client';\nimport { buildQueryParams } from '../../../infra/utils/params';\nimport { getUserContext } from '../../auth/utils/get-user-context';\nimport {\n FindMessagesParams,\n ListMessagesApiResponse,\n MarkAsReadApiResponse,\n MarkAllAsReadApiResponse,\n} from '../schema/messages.schema';\n\nclass MessagesService {\n async listMessages(\n params?: Partial<FindMessagesParams>\n ): Promise<ListMessagesApiResponse> {\n const { id_account, id_user } = await getUserContext();\n\n const query = buildQueryParams({\n id_account,\n id_user,\n type: 'notification',\n limit: 20,\n page: 1,\n order: 'desc',\n ...params,\n });\n\n const url = `/accounts/${id_account}/messages${query ? `?${query}` : ''}`;\n return api.apps.get<ListMessagesApiResponse>(url);\n }\n\n async markAsRead(messageId: string): Promise<MarkAsReadApiResponse> {\n const { id_account } = await getUserContext();\n\n const url = `/accounts/${id_account}/messages/${messageId}/action/markAsRead`;\n return api.apps.put<MarkAsReadApiResponse>(url);\n }\n\n async markAllAsRead(): Promise<MarkAllAsReadApiResponse> {\n const { id_account, id_user } = await getUserContext();\n\n const url = `/accounts/${id_account}/messages/action/markAllAsRead`;\n return api.apps.put<MarkAllAsReadApiResponse>(url, { id_user });\n }\n}\n\nexport const messagesService = new MessagesService();\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,WAAW;AACpB,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAQ/B,MAAM,gBAAgB;AAAA,EACpB,MAAM,aACJ,QACkC;AAClC,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,QAAQ,iBAAiB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,GAAG;AAAA,IACL,CAAC;AAED,UAAM,MAAM,aAAa,UAAU,YAAY,QAAQ,IAAI,KAAK,KAAK,EAAE;AACvE,WAAO,IAAI,KAAK,IAA6B,GAAG;AAAA,EAClD;AAAA,EAEA,MAAM,WAAW,WAAmD;AAClE,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,MAAM,aAAa,UAAU,aAAa,SAAS;AACzD,WAAO,IAAI,KAAK,IAA2B,GAAG;AAAA,EAChD;AAAA,EAEA,MAAM,gBAAmD;AACvD,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AAErD,UAAM,MAAM,aAAa,UAAU;AACnC,WAAO,IAAI,KAAK,IAA8B,KAAK,EAAE,QAAQ,CAAC;AAAA,EAChE;AACF;AAEO,MAAM,kBAAkB,IAAI,gBAAgB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/store/useAccountModals.ts"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../src/store/useAccountModals.ts"],"sourcesContent":["'use client';\n\nimport { create } from 'zustand';\nimport type { AccountSectionType } from '../enums/AccountSectionType';\n\ntype AccountModalType =\n | 'configurations'\n | 'deleteAccount'\n | 'isntPossibleDelete'\n | 'confirmDelete';\n\nexport interface AccountModalsConfig {\n hasActiveSubscription?: boolean;\n onGoToSubscription?: () => void;\n}\n\ninterface AccountModalsState {\n activeModal: AccountModalType | null;\n config: AccountModalsConfig;\n initialSection?: AccountSectionType;\n pagesCount: number;\n\n /** Called by <AccountModals> to keep app-level config in sync */\n updateConfig: (config: AccountModalsConfig) => void;\n\n openConfigurations: (initialSection?: AccountSectionType) => void;\n openDeleteAccount: (pagesCount?: number) => void;\n openIsntPossibleDelete: () => void;\n openConfirmDelete: (pagesCount?: number) => void;\n close: () => void;\n}\n\nexport const useAccountModals = create<AccountModalsState>((set) => ({\n activeModal: null,\n config: {},\n initialSection: undefined,\n pagesCount: 0,\n\n updateConfig: (config) => set({ config }),\n\n openConfigurations: (initialSection) =>\n set({ activeModal: 'configurations', initialSection }),\n\n openDeleteAccount: (pagesCount = 0) =>\n set({ activeModal: 'deleteAccount', pagesCount }),\n\n openIsntPossibleDelete: () =>\n set({ activeModal: 'isntPossibleDelete' }),\n\n openConfirmDelete: (pagesCount = 0) =>\n set({ activeModal: 'confirmDelete', pagesCount }),\n\n close: () =>\n set({ activeModal: null, initialSection: undefined }),\n}));\n"],"mappings":";AAEA,SAAS,cAAc;AA8BhB,MAAM,mBAAmB,OAA2B,CAAC,SAAS;AAAA,EACnE,aAAa;AAAA,EACb,QAAQ,CAAC;AAAA,EACT,gBAAgB;AAAA,EAChB,YAAY;AAAA,EAEZ,cAAc,CAAC,WAAW,IAAI,EAAE,OAAO,CAAC;AAAA,EAExC,oBAAoB,CAAC,mBACnB,IAAI,EAAE,aAAa,kBAAkB,eAAe,CAAC;AAAA,EAEvD,mBAAmB,CAAC,aAAa,MAC/B,IAAI,EAAE,aAAa,iBAAiB,WAAW,CAAC;AAAA,EAElD,wBAAwB,MACtB,IAAI,EAAE,aAAa,qBAAqB,CAAC;AAAA,EAE3C,mBAAmB,CAAC,aAAa,MAC/B,IAAI,EAAE,aAAa,iBAAiB,WAAW,CAAC;AAAA,EAElD,OAAO,MACL,IAAI,EAAE,aAAa,MAAM,gBAAgB,OAAU,CAAC;AACxD,EAAE;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/store/useModalManager.ts"],"sourcesContent":["'use client';\
|
|
1
|
+
{"version":3,"sources":["../../src/store/useModalManager.ts"],"sourcesContent":["'use client';\n\nimport { create } from 'zustand';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ModalData = Record<string, any>;\n\ninterface ModalStackItem {\n key: string;\n data: ModalData;\n}\n\ninterface ModalState {\n modalStack: ModalStackItem[];\n activeModal: string | null;\n modalData: ModalData;\n openModal: (key: string, data?: ModalData) => void;\n /** Closes the top modal in the stack */\n closeModal: () => void;\n /** Closes a specific modal by key */\n closeModalByKey: (key: string) => void;\n updateModalData: (data: ModalData) => void;\n isModalOpen: (key: string) => boolean;\n getModalData: (key: string) => ModalData;\n}\n\nexport const useModalManager = create<ModalState>((set, get) => ({\n modalStack: [],\n activeModal: null,\n modalData: {},\n\n openModal: (key, data = {}) => {\n set((state) => {\n const existingIndex = state.modalStack.findIndex((item) => item.key === key);\n if (existingIndex !== -1) {\n const newStack = [...state.modalStack];\n newStack[existingIndex] = { key, data };\n return {\n modalStack: newStack,\n activeModal: newStack[newStack.length - 1]?.key ?? null,\n modalData: newStack[newStack.length - 1]?.data ?? {},\n };\n }\n\n const newStack = [...state.modalStack, { key, data }];\n return {\n modalStack: newStack,\n activeModal: key,\n modalData: data,\n };\n });\n },\n\n closeModal: () => {\n set((state) => {\n const newStack = state.modalStack.slice(0, -1);\n const topModal = newStack[newStack.length - 1];\n return {\n modalStack: newStack,\n activeModal: topModal?.key ?? null,\n modalData: topModal?.data ?? {},\n };\n });\n },\n\n closeModalByKey: (key: string) => {\n set((state) => {\n const newStack = state.modalStack.filter((item) => item.key !== key);\n const topModal = newStack[newStack.length - 1];\n return {\n modalStack: newStack,\n activeModal: topModal?.key ?? null,\n modalData: topModal?.data ?? {},\n };\n });\n },\n\n updateModalData: (data) => {\n set((state) => {\n if (state.modalStack.length === 0) return state;\n\n const newStack = [...state.modalStack];\n const lastIndex = newStack.length - 1;\n newStack[lastIndex] = {\n ...newStack[lastIndex],\n data: { ...newStack[lastIndex].data, ...data },\n };\n\n return {\n modalStack: newStack,\n modalData: newStack[lastIndex].data,\n };\n });\n },\n\n isModalOpen: (key: string) => {\n return get().modalStack.some((item) => item.key === key);\n },\n\n getModalData: (key: string) => {\n const item = get().modalStack.find((item) => item.key === key);\n return item?.data ?? {};\n },\n}));\n"],"mappings":";AAEA,SAAS,cAAc;AAwBhB,MAAM,kBAAkB,OAAmB,CAAC,KAAK,SAAS;AAAA,EAC/D,YAAY,CAAC;AAAA,EACb,aAAa;AAAA,EACb,WAAW,CAAC;AAAA,EAEZ,WAAW,CAAC,KAAK,OAAO,CAAC,MAAM;AAC7B,QAAI,CAAC,UAAU;AACb,YAAM,gBAAgB,MAAM,WAAW,UAAU,CAAC,SAAS,KAAK,QAAQ,GAAG;AAC3E,UAAI,kBAAkB,IAAI;AACxB,cAAMA,YAAW,CAAC,GAAG,MAAM,UAAU;AACrC,QAAAA,UAAS,aAAa,IAAI,EAAE,KAAK,KAAK;AACtC,eAAO;AAAA,UACL,YAAYA;AAAA,UACZ,aAAaA,UAASA,UAAS,SAAS,CAAC,GAAG,OAAO;AAAA,UACnD,WAAWA,UAASA,UAAS,SAAS,CAAC,GAAG,QAAQ,CAAC;AAAA,QACrD;AAAA,MACF;AAEA,YAAM,WAAW,CAAC,GAAG,MAAM,YAAY,EAAE,KAAK,KAAK,CAAC;AACpD,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,MAAM;AAChB,QAAI,CAAC,UAAU;AACb,YAAM,WAAW,MAAM,WAAW,MAAM,GAAG,EAAE;AAC7C,YAAM,WAAW,SAAS,SAAS,SAAS,CAAC;AAC7C,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,aAAa,UAAU,OAAO;AAAA,QAC9B,WAAW,UAAU,QAAQ,CAAC;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,CAAC,QAAgB;AAChC,QAAI,CAAC,UAAU;AACb,YAAM,WAAW,MAAM,WAAW,OAAO,CAAC,SAAS,KAAK,QAAQ,GAAG;AACnE,YAAM,WAAW,SAAS,SAAS,SAAS,CAAC;AAC7C,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,aAAa,UAAU,OAAO;AAAA,QAC9B,WAAW,UAAU,QAAQ,CAAC;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,CAAC,SAAS;AACzB,QAAI,CAAC,UAAU;AACb,UAAI,MAAM,WAAW,WAAW,EAAG,QAAO;AAE1C,YAAM,WAAW,CAAC,GAAG,MAAM,UAAU;AACrC,YAAM,YAAY,SAAS,SAAS;AACpC,eAAS,SAAS,IAAI;AAAA,QACpB,GAAG,SAAS,SAAS;AAAA,QACrB,MAAM,EAAE,GAAG,SAAS,SAAS,EAAE,MAAM,GAAG,KAAK;AAAA,MAC/C;AAEA,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW,SAAS,SAAS,EAAE;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,CAAC,QAAgB;AAC5B,WAAO,IAAI,EAAE,WAAW,KAAK,CAAC,SAAS,KAAK,QAAQ,GAAG;AAAA,EACzD;AAAA,EAEA,cAAc,CAAC,QAAgB;AAC7B,UAAM,OAAO,IAAI,EAAE,WAAW,KAAK,CAACC,UAASA,MAAK,QAAQ,GAAG;AAC7D,WAAO,MAAM,QAAQ,CAAC;AAAA,EACxB;AACF,EAAE;","names":["newStack","item"]}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import ConfigurationsMyAccountModal from './ConfigurationsMyAccountModal';
|
|
4
|
-
import DeleteAccountModal from './DeleteAccountModal';
|
|
5
|
-
import IsntPossibleDeleteAccountModal from './IsntPossibleDeleteAccountModal';
|
|
6
|
-
import ConfirmDeleteAccountModal from './ConfirmDeleteAccountModal';
|
|
7
|
-
|
|
8
|
-
export default function AccountModals() {
|
|
9
|
-
return (
|
|
10
|
-
<>
|
|
11
|
-
<ConfigurationsMyAccountModal />
|
|
12
|
-
<DeleteAccountModal />
|
|
13
|
-
<IsntPossibleDeleteAccountModal />
|
|
14
|
-
<ConfirmDeleteAccountModal />
|
|
15
|
-
</>
|
|
16
|
-
);
|
|
17
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import ConfigurationsMyAccountModal from './ConfigurationsMyAccountModal';
|
|
4
|
+
import DeleteAccountModal from './DeleteAccountModal';
|
|
5
|
+
import IsntPossibleDeleteAccountModal from './IsntPossibleDeleteAccountModal';
|
|
6
|
+
import ConfirmDeleteAccountModal from './ConfirmDeleteAccountModal';
|
|
7
|
+
|
|
8
|
+
export default function AccountModals() {
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
<ConfigurationsMyAccountModal />
|
|
12
|
+
<DeleteAccountModal />
|
|
13
|
+
<IsntPossibleDeleteAccountModal />
|
|
14
|
+
<ConfirmDeleteAccountModal />
|
|
15
|
+
</>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -121,7 +121,7 @@ export default function ConfigurationsMyAccountModal() {
|
|
|
121
121
|
</div>
|
|
122
122
|
</TabsList>
|
|
123
123
|
|
|
124
|
-
<div className="w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative">
|
|
124
|
+
<div className="w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col">
|
|
125
125
|
<TabsContent value={AccountSectionType.MY_PROFILE} className="h-full! relative overflow-hidden">
|
|
126
126
|
<MyProfileSection onClose={close} />
|
|
127
127
|
</TabsContent>
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Suspense, useEffect } from "react";
|
|
4
|
-
import { useSearchParams } from "next/navigation";
|
|
5
|
-
|
|
6
|
-
interface SearchParamsHandlerProps {
|
|
7
|
-
handlers: {
|
|
8
|
-
[key: string]: () => void;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* SearchParamsHandler
|
|
14
|
-
*
|
|
15
|
-
* Este componente é responsável por ler os parâmetros da URL e executar callbacks
|
|
16
|
-
* correspondentes a cada parâmetro encontrado.
|
|
17
|
-
*
|
|
18
|
-
* Por que precisamos deste componente?
|
|
19
|
-
* - O Next.js 16 exige que useSearchParams() seja envolvido em um <Suspense> boundary
|
|
20
|
-
* - Isso evita erros de prerendering durante o build
|
|
21
|
-
* - Permite que URLs como "/page?tab=performance" naveguem diretamente para uma aba específica
|
|
22
|
-
*
|
|
23
|
-
* Exemplo de como funciona
|
|
24
|
-
* 1. Usa useSearchParams() para ler o parâmetro "tab" da URL
|
|
25
|
-
* 2. Monitora mudanças nos parâmetros com useEffect
|
|
26
|
-
* 3. Quando encontra um parâmetro "tab", chama onTabChange com o valor
|
|
27
|
-
* 4. Retorna null porque não renderiza nada na tela
|
|
28
|
-
*
|
|
29
|
-
* Exemplo de uso:
|
|
30
|
-
* <Suspense fallback={null}>
|
|
31
|
-
* <SearchParamsHandler handlers={{ tab: () => console.log("Tab changed") }} />
|
|
32
|
-
* </Suspense>
|
|
33
|
-
*
|
|
34
|
-
* Exemplos de URL:
|
|
35
|
-
* - /greatpages/123?tab=performance → abre a aba "performance"
|
|
36
|
-
* - /greatpages/123?tab=leads → abre a aba "leads"
|
|
37
|
-
*/
|
|
38
|
-
export function SearchParamsHandler(options: SearchParamsHandlerProps) {
|
|
39
|
-
return (
|
|
40
|
-
<Suspense fallback={null}>
|
|
41
|
-
<SearchParamsHandlerChildren {...options} />
|
|
42
|
-
</Suspense>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function SearchParamsHandlerChildren(options: SearchParamsHandlerProps) {
|
|
47
|
-
const searchParams = useSearchParams();
|
|
48
|
-
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
Object.keys(options.handlers).forEach((key) => {
|
|
51
|
-
const value = searchParams.get(key);
|
|
52
|
-
|
|
53
|
-
if (value) {
|
|
54
|
-
options.handlers[key]();
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
-
}, [searchParams]);
|
|
59
|
-
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Suspense, useEffect } from "react";
|
|
4
|
+
import { useSearchParams } from "next/navigation";
|
|
5
|
+
|
|
6
|
+
interface SearchParamsHandlerProps {
|
|
7
|
+
handlers: {
|
|
8
|
+
[key: string]: () => void;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* SearchParamsHandler
|
|
14
|
+
*
|
|
15
|
+
* Este componente é responsável por ler os parâmetros da URL e executar callbacks
|
|
16
|
+
* correspondentes a cada parâmetro encontrado.
|
|
17
|
+
*
|
|
18
|
+
* Por que precisamos deste componente?
|
|
19
|
+
* - O Next.js 16 exige que useSearchParams() seja envolvido em um <Suspense> boundary
|
|
20
|
+
* - Isso evita erros de prerendering durante o build
|
|
21
|
+
* - Permite que URLs como "/page?tab=performance" naveguem diretamente para uma aba específica
|
|
22
|
+
*
|
|
23
|
+
* Exemplo de como funciona
|
|
24
|
+
* 1. Usa useSearchParams() para ler o parâmetro "tab" da URL
|
|
25
|
+
* 2. Monitora mudanças nos parâmetros com useEffect
|
|
26
|
+
* 3. Quando encontra um parâmetro "tab", chama onTabChange com o valor
|
|
27
|
+
* 4. Retorna null porque não renderiza nada na tela
|
|
28
|
+
*
|
|
29
|
+
* Exemplo de uso:
|
|
30
|
+
* <Suspense fallback={null}>
|
|
31
|
+
* <SearchParamsHandler handlers={{ tab: () => console.log("Tab changed") }} />
|
|
32
|
+
* </Suspense>
|
|
33
|
+
*
|
|
34
|
+
* Exemplos de URL:
|
|
35
|
+
* - /greatpages/123?tab=performance → abre a aba "performance"
|
|
36
|
+
* - /greatpages/123?tab=leads → abre a aba "leads"
|
|
37
|
+
*/
|
|
38
|
+
export function SearchParamsHandler(options: SearchParamsHandlerProps) {
|
|
39
|
+
return (
|
|
40
|
+
<Suspense fallback={null}>
|
|
41
|
+
<SearchParamsHandlerChildren {...options} />
|
|
42
|
+
</Suspense>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function SearchParamsHandlerChildren(options: SearchParamsHandlerProps) {
|
|
47
|
+
const searchParams = useSearchParams();
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
Object.keys(options.handlers).forEach((key) => {
|
|
51
|
+
const value = searchParams.get(key);
|
|
52
|
+
|
|
53
|
+
if (value) {
|
|
54
|
+
options.handlers[key]();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
}, [searchParams]);
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { ComponentType } from 'react';
|
|
4
|
-
import { useModalManager } from '../../store/useModalManager';
|
|
5
|
-
|
|
6
|
-
interface ModalManagerProps {
|
|
7
|
-
registry: Record<string, ComponentType>;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function ModalManager({ registry }: ModalManagerProps) {
|
|
11
|
-
const { modalStack } = useModalManager();
|
|
12
|
-
|
|
13
|
-
if (modalStack.length === 0) return null;
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<>
|
|
17
|
-
{modalStack.map((modal) => {
|
|
18
|
-
const ModalComponent = registry[modal.key];
|
|
19
|
-
|
|
20
|
-
if (!ModalComponent) {
|
|
21
|
-
console.warn(`Modal "${modal.key}" not found in registry`);
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return <ModalComponent key={modal.key} />;
|
|
26
|
-
})}
|
|
27
|
-
</>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
import { useModalManager } from '../../store/useModalManager';
|
|
5
|
+
|
|
6
|
+
interface ModalManagerProps {
|
|
7
|
+
registry: Record<string, ComponentType>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ModalManager({ registry }: ModalManagerProps) {
|
|
11
|
+
const { modalStack } = useModalManager();
|
|
12
|
+
|
|
13
|
+
if (modalStack.length === 0) return null;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{modalStack.map((modal) => {
|
|
18
|
+
const ModalComponent = registry[modal.key];
|
|
19
|
+
|
|
20
|
+
if (!ModalComponent) {
|
|
21
|
+
console.warn(`Modal "${modal.key}" not found in registry`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return <ModalComponent key={modal.key} />;
|
|
26
|
+
})}
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { ComponentType, useEffect } from 'react';
|
|
4
|
-
import AccountModals from '../account/AccountModals';
|
|
5
|
-
import { ModalManager } from './ModalManager';
|
|
6
|
-
import { useAccountModals } from '../../store/useAccountModals';
|
|
7
|
-
interface ModalsProps {
|
|
8
|
-
registry: Record<string, ComponentType>;
|
|
9
|
-
hasActiveSubscription?: boolean;
|
|
10
|
-
onGoToSubscription?: () => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function Modals({ registry, hasActiveSubscription, onGoToSubscription }: ModalsProps) {
|
|
14
|
-
const { updateConfig } = useAccountModals();
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
updateConfig({ hasActiveSubscription, onGoToSubscription });
|
|
18
|
-
}, [hasActiveSubscription, onGoToSubscription, updateConfig]);
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<>
|
|
22
|
-
<AccountModals />
|
|
23
|
-
<ModalManager registry={registry} />
|
|
24
|
-
</>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ComponentType, useEffect } from 'react';
|
|
4
|
+
import AccountModals from '../account/AccountModals';
|
|
5
|
+
import { ModalManager } from './ModalManager';
|
|
6
|
+
import { useAccountModals } from '../../store/useAccountModals';
|
|
7
|
+
interface ModalsProps {
|
|
8
|
+
registry: Record<string, ComponentType>;
|
|
9
|
+
hasActiveSubscription?: boolean;
|
|
10
|
+
onGoToSubscription?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function Modals({ registry, hasActiveSubscription, onGoToSubscription }: ModalsProps) {
|
|
14
|
+
const { updateConfig } = useAccountModals();
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
updateConfig({ hasActiveSubscription, onGoToSubscription });
|
|
18
|
+
}, [hasActiveSubscription, onGoToSubscription, updateConfig]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<AccountModals />
|
|
23
|
+
<ModalManager registry={registry} />
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
}
|