@greatapps/common 1.1.342 → 1.1.344
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/ConfigurationsMyAccountModal.mjs +88 -11
- package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
- package/dist/components/account/hooks/useConfigurationsModal.mjs +3 -3
- package/dist/components/account/hooks/useConfigurationsModal.mjs.map +1 -1
- package/dist/components/account/sections/PreferencesSection.mjs +16 -0
- package/dist/components/account/sections/PreferencesSection.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/account/ConfigurationsMyAccountModal.tsx +102 -11
- package/src/components/account/hooks/useConfigurationsModal.ts +3 -3
- package/src/components/account/sections/PreferencesSection.tsx +18 -0
- package/src/modules/accounts/types.ts +1 -0
|
@@ -1,30 +1,59 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { IconX } from "@tabler/icons-react";
|
|
3
|
+
import { IconLock, IconSettings2, IconX } from "@tabler/icons-react";
|
|
4
4
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/overlay/Dialog";
|
|
5
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/data-display/Tabs";
|
|
5
6
|
import { cn } from "../../infra/utils/clsx";
|
|
7
|
+
import { AccountSectionType } from "../../enums/AccountSectionType";
|
|
6
8
|
import { PreferencesSection } from "./sections/PreferencesSection";
|
|
9
|
+
import { ChangePasswordSection } from "./sections/ChangePasswordSection";
|
|
10
|
+
import { SecuritySection } from "./sections/SecuritySection";
|
|
11
|
+
import useConfigurationsModal from "./hooks/useConfigurationsModal";
|
|
7
12
|
import useIsMobile from "../../hooks/useIsMobile";
|
|
8
13
|
import { useAccountModals } from "../../store/useAccountModals";
|
|
9
14
|
function ConfigurationsMyAccountModal() {
|
|
10
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
activeModal,
|
|
17
|
+
config,
|
|
18
|
+
openDeleteAccount,
|
|
19
|
+
openIsntPossibleDelete,
|
|
20
|
+
close
|
|
21
|
+
} = useAccountModals();
|
|
11
22
|
const open = activeModal === "configurations";
|
|
23
|
+
const { hasActiveSubscription } = config;
|
|
12
24
|
const isMobile = useIsMobile();
|
|
25
|
+
const { activeSection, setActiveSection } = useConfigurationsModal({
|
|
26
|
+
isOpen: open
|
|
27
|
+
});
|
|
28
|
+
const handleDeleteAccount = () => {
|
|
29
|
+
close();
|
|
30
|
+
if (hasActiveSubscription) {
|
|
31
|
+
openIsntPossibleDelete();
|
|
32
|
+
} else {
|
|
33
|
+
openDeleteAccount();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const tabTriggerClasses = cn(
|
|
37
|
+
"border-0! px-0 py-0",
|
|
38
|
+
"lg:rounded-md lg:flex lg:items-center lg:gap-2 lg:p-3 lg:justify-start lg:w-full",
|
|
39
|
+
"lg:bg-white lg:hover:bg-gray-100 lg:active:bg-gray-50 lg:border-0",
|
|
40
|
+
"lg:data-[state=active]:bg-gray-50",
|
|
41
|
+
"flex items-center gap-1.5 px-3 py-3 justify-center whitespace-nowrap",
|
|
42
|
+
"border-b-2 border-transparent",
|
|
43
|
+
"data-[state=active]:bg-gray-50 rounded-lg",
|
|
44
|
+
"text-gray-500 data-[state=active]:text-gray-950",
|
|
45
|
+
"hover:text-gray-900 transition-colors"
|
|
46
|
+
);
|
|
13
47
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: close, children: /* @__PURE__ */ jsxs(
|
|
14
48
|
DialogContent,
|
|
15
49
|
{
|
|
16
50
|
showCloseButton: !isMobile,
|
|
17
51
|
overlayClassName: "bg-black/20 lg:bg-black/50",
|
|
18
|
-
className:
|
|
19
|
-
"flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0",
|
|
20
|
-
"rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0",
|
|
21
|
-
"lg:w-[650px] lg:max-w-[650px] lg:h-auto lg:rounded-lg lg:border",
|
|
22
|
-
"lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
|
|
23
|
-
),
|
|
52
|
+
className: "\n flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0\n rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0\n lg:flex-row lg:w-[892px] lg:max-w-[892px] lg:h-[626px] lg:rounded-lg lg:border\n lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]",
|
|
24
53
|
children: [
|
|
25
|
-
/* @__PURE__ */ jsx(DialogHeader, { className: "sr-only", children: /* @__PURE__ */ jsx(DialogTitle, { children: "
|
|
54
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "sr-only", children: /* @__PURE__ */ jsx(DialogTitle, { children: "Configura\xE7\xF5es" }) }),
|
|
26
55
|
/* @__PURE__ */ jsxs("div", { className: "md:hidden flex items-center justify-between px-5 py-3 border-b border-gray-200", children: [
|
|
27
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-950 paragraph-medium-semibold", children: "
|
|
56
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-950 paragraph-medium-semibold", children: "Configura\xE7\xF5es" }),
|
|
28
57
|
/* @__PURE__ */ jsx(
|
|
29
58
|
"button",
|
|
30
59
|
{
|
|
@@ -35,7 +64,55 @@ function ConfigurationsMyAccountModal() {
|
|
|
35
64
|
}
|
|
36
65
|
)
|
|
37
66
|
] }),
|
|
38
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ jsxs(
|
|
68
|
+
Tabs,
|
|
69
|
+
{
|
|
70
|
+
value: activeSection,
|
|
71
|
+
onValueChange: (value) => setActiveSection(value),
|
|
72
|
+
orientation: "vertical",
|
|
73
|
+
className: "flex lg:flex-row flex-col w-full h-full flex-1 lg:h-full lg:pt-0 lg:gap-0",
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsxs(
|
|
76
|
+
TabsList,
|
|
77
|
+
{
|
|
78
|
+
className: cn(
|
|
79
|
+
"flex gap-0 bg-transparent border-b-0",
|
|
80
|
+
"lg:flex-col lg:items-stretch lg:justify-start lg:w-auto lg:min-w-60",
|
|
81
|
+
"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",
|
|
82
|
+
"flex-row items-center justify-start w-full overflow-x-auto scrollbar-hide shrink-0",
|
|
83
|
+
"px-4 py-3",
|
|
84
|
+
"[mask-image:linear-gradient(to_right,transparent,black_16px,black_calc(100%-24px),transparent)] lg:[mask-image:none]"
|
|
85
|
+
),
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx("span", { className: "hidden lg:block paragraph-medium-semibold text-gray-950 mb-0", children: "Configura\xE7\xF5es" }),
|
|
88
|
+
/* @__PURE__ */ jsxs("div", { className: "lg:flex lg:flex-col flex flex-row lg:gap-0 gap-0 lg:w-full", children: [
|
|
89
|
+
/* @__PURE__ */ jsxs(TabsTrigger, { value: AccountSectionType.PREFERENCES, className: tabTriggerClasses, children: [
|
|
90
|
+
/* @__PURE__ */ jsx(IconSettings2, { size: 20, className: "shrink-0" }),
|
|
91
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium", children: "Prefer\xEAncias" })
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsxs(TabsTrigger, { value: AccountSectionType.SECURITY, className: tabTriggerClasses, children: [
|
|
94
|
+
/* @__PURE__ */ jsx(IconLock, { size: 20, className: "shrink-0" }),
|
|
95
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium", children: "Seguran\xE7a" })
|
|
96
|
+
] })
|
|
97
|
+
] })
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col", children: [
|
|
102
|
+
/* @__PURE__ */ jsx(TabsContent, { value: AccountSectionType.PREFERENCES, className: "h-full! relative overflow-hidden", children: /* @__PURE__ */ jsx(PreferencesSection, { onClose: close }) }),
|
|
103
|
+
/* @__PURE__ */ jsx(TabsContent, { value: AccountSectionType.SECURITY, className: "h-full! relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
104
|
+
SecuritySection,
|
|
105
|
+
{
|
|
106
|
+
setActiveSection,
|
|
107
|
+
onClose: close,
|
|
108
|
+
onDeleteAccount: handleDeleteAccount
|
|
109
|
+
}
|
|
110
|
+
) }),
|
|
111
|
+
/* @__PURE__ */ jsx(TabsContent, { value: AccountSectionType.CHANGE_PASSWORD, className: "h-full! relative overflow-hidden", children: /* @__PURE__ */ jsx(ChangePasswordSection, { onBack: () => setActiveSection(AccountSectionType.SECURITY) }) })
|
|
112
|
+
] })
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
39
116
|
]
|
|
40
117
|
}
|
|
41
118
|
) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/account/ConfigurationsMyAccountModal.tsx"],"sourcesContent":["'use client';\n\nimport { IconX } from '@tabler/icons-react';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';\nimport { cn } from '../../infra/utils/clsx';\nimport { PreferencesSection } from './sections/PreferencesSection';\nimport useIsMobile from '../../hooks/useIsMobile';\nimport { useAccountModals } from '../../store/useAccountModals';\n\nexport default function ConfigurationsMyAccountModal() {\n const {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/account/ConfigurationsMyAccountModal.tsx"],"sourcesContent":["'use client';\n\nimport { IconLock, IconSettings2, IconX } from '@tabler/icons-react';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/data-display/Tabs';\nimport { cn } from '../../infra/utils/clsx';\nimport { AccountSectionType } from '../../enums/AccountSectionType';\nimport { PreferencesSection } from './sections/PreferencesSection';\nimport { ChangePasswordSection } from './sections/ChangePasswordSection';\nimport { SecuritySection } from './sections/SecuritySection';\nimport useConfigurationsModal from './hooks/useConfigurationsModal';\nimport useIsMobile from '../../hooks/useIsMobile';\nimport { useAccountModals } from '../../store/useAccountModals';\n\nexport default function ConfigurationsMyAccountModal() {\n const {\n activeModal,\n config,\n openDeleteAccount,\n openIsntPossibleDelete,\n close,\n } = useAccountModals();\n\n const open = activeModal === 'configurations';\n const { hasActiveSubscription } = config;\n\n const isMobile = useIsMobile();\n const { activeSection, setActiveSection } = useConfigurationsModal({\n isOpen: open,\n });\n\n const handleDeleteAccount = () => {\n close();\n if (hasActiveSubscription) {\n openIsntPossibleDelete();\n } else {\n openDeleteAccount();\n }\n };\n\n const tabTriggerClasses = cn(\n 'border-0! px-0 py-0',\n\n 'lg:rounded-md lg:flex lg:items-center lg:gap-2 lg:p-3 lg:justify-start lg:w-full',\n 'lg:bg-white lg:hover:bg-gray-100 lg:active:bg-gray-50 lg:border-0',\n 'lg:data-[state=active]:bg-gray-50',\n\n 'flex items-center gap-1.5 px-3 py-3 justify-center whitespace-nowrap',\n 'border-b-2 border-transparent',\n 'data-[state=active]:bg-gray-50 rounded-lg',\n\n 'text-gray-500 data-[state=active]:text-gray-950',\n 'hover:text-gray-900 transition-colors'\n );\n\n return (\n <Dialog open={open} onOpenChange={close}>\n <DialogContent\n showCloseButton={!isMobile}\n overlayClassName=\"bg-black/20 lg:bg-black/50\"\n className=\"\n flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0\n rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0\n lg:flex-row lg:w-[892px] lg:max-w-[892px] lg:h-[626px] lg:rounded-lg lg:border\n lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]\"\n >\n <DialogHeader className=\"sr-only\">\n <DialogTitle>Configurações</DialogTitle>\n </DialogHeader>\n <div className=\"md:hidden flex items-center justify-between px-5 py-3 border-b border-gray-200\">\n <span className=\"text-gray-950 paragraph-medium-semibold\">Configurações</span>\n <button\n type=\"button\"\n className=\"size-8 flex items-center justify-center text-gray-500 cursor-pointer\"\n onClick={close}\n >\n <IconX size={18} />\n </button>\n </div>\n <Tabs\n value={activeSection}\n onValueChange={(value) => setActiveSection(value as AccountSectionType)}\n orientation=\"vertical\"\n className=\"flex lg:flex-row flex-col w-full h-full flex-1 lg:h-full lg:pt-0 lg:gap-0\"\n >\n <TabsList\n className={cn(\n 'flex gap-0 bg-transparent border-b-0',\n\n 'lg:flex-col lg:items-stretch lg:justify-start lg:w-auto lg:min-w-60',\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',\n\n 'flex-row items-center justify-start w-full overflow-x-auto scrollbar-hide shrink-0',\n 'px-4 py-3',\n '[mask-image:linear-gradient(to_right,transparent,black_16px,black_calc(100%-24px),transparent)] lg:[mask-image:none]'\n )}\n >\n <span className=\"hidden lg:block paragraph-medium-semibold text-gray-950 mb-0\">\n Configurações\n </span>\n\n <div className=\"lg:flex lg:flex-col flex flex-row lg:gap-0 gap-0 lg:w-full\">\n <TabsTrigger value={AccountSectionType.PREFERENCES} className={tabTriggerClasses}>\n <IconSettings2 size={20} className=\"shrink-0\" />\n <span className=\"paragraph-small-medium\">Preferências</span>\n </TabsTrigger>\n\n <TabsTrigger value={AccountSectionType.SECURITY} className={tabTriggerClasses}>\n <IconLock size={20} className=\"shrink-0\" />\n <span className=\"paragraph-small-medium\">Segurança</span>\n </TabsTrigger>\n </div>\n </TabsList>\n\n <div className=\"w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col\">\n <TabsContent value={AccountSectionType.PREFERENCES} className=\"h-full! relative overflow-hidden\">\n <PreferencesSection onClose={close} />\n </TabsContent>\n\n <TabsContent value={AccountSectionType.SECURITY} className=\"h-full! relative overflow-hidden\">\n <SecuritySection\n setActiveSection={setActiveSection}\n onClose={close}\n onDeleteAccount={handleDeleteAccount}\n />\n </TabsContent>\n\n <TabsContent value={AccountSectionType.CHANGE_PASSWORD} className=\"h-full! relative overflow-hidden\">\n <ChangePasswordSection onBack={() => setActiveSection(AccountSectionType.SECURITY)} />\n </TabsContent>\n </div>\n </Tabs>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,21 +6,21 @@ function useConfigurationsModal({
|
|
|
6
6
|
initialSection
|
|
7
7
|
}) {
|
|
8
8
|
const [activeSection, setActiveSection] = useState(
|
|
9
|
-
AccountSectionType.
|
|
9
|
+
AccountSectionType.PREFERENCES
|
|
10
10
|
);
|
|
11
11
|
const isValidSection = (section) => Object.values(AccountSectionType).includes(section);
|
|
12
12
|
useEffect(() => {
|
|
13
13
|
if (isOpen && isValidSection(initialSection)) {
|
|
14
14
|
setActiveSection(initialSection);
|
|
15
15
|
} else if (isOpen) {
|
|
16
|
-
setActiveSection(AccountSectionType.
|
|
16
|
+
setActiveSection(AccountSectionType.PREFERENCES);
|
|
17
17
|
}
|
|
18
18
|
}, [isOpen, initialSection]);
|
|
19
19
|
const handleSectionChange = useCallback((section) => {
|
|
20
20
|
setActiveSection(section);
|
|
21
21
|
}, []);
|
|
22
22
|
const resetSection = useCallback(() => {
|
|
23
|
-
setActiveSection(AccountSectionType.
|
|
23
|
+
setActiveSection(AccountSectionType.PREFERENCES);
|
|
24
24
|
}, []);
|
|
25
25
|
return {
|
|
26
26
|
activeSection,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/account/hooks/useConfigurationsModal.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { useState, useCallback, useEffect } from \"react\";\r\nimport { AccountSectionType } from \"../../../enums/AccountSectionType\";\r\n\r\ninterface UseConfigurationsModalProps {\r\n isOpen: boolean;\r\n initialSection?: AccountSectionType;\r\n}\r\n\r\nexport default function useConfigurationsModal({\r\n isOpen,\r\n initialSection,\r\n}: UseConfigurationsModalProps) {\r\n const [activeSection, setActiveSection] = useState<AccountSectionType>(\r\n AccountSectionType.
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/account/hooks/useConfigurationsModal.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { useState, useCallback, useEffect } from \"react\";\r\nimport { AccountSectionType } from \"../../../enums/AccountSectionType\";\r\n\r\ninterface UseConfigurationsModalProps {\r\n isOpen: boolean;\r\n initialSection?: AccountSectionType;\r\n}\r\n\r\nexport default function useConfigurationsModal({\r\n isOpen,\r\n initialSection,\r\n}: UseConfigurationsModalProps) {\r\n const [activeSection, setActiveSection] = useState<AccountSectionType>(\r\n AccountSectionType.PREFERENCES,\r\n );\r\n\r\n const isValidSection = (\r\n section?: AccountSectionType,\r\n ): section is AccountSectionType =>\r\n Object.values(AccountSectionType).includes(section as AccountSectionType);\r\n\r\n useEffect(() => {\r\n if (isOpen && isValidSection(initialSection)) {\r\n setActiveSection(initialSection);\r\n } else if (isOpen) {\r\n setActiveSection(AccountSectionType.PREFERENCES);\r\n }\r\n }, [isOpen, initialSection]);\r\n\r\n const handleSectionChange = useCallback((section: AccountSectionType) => {\r\n setActiveSection(section);\r\n }, []);\r\n\r\n const resetSection = useCallback(() => {\r\n setActiveSection(AccountSectionType.PREFERENCES);\r\n }, []);\r\n\r\n return {\r\n activeSection,\r\n setActiveSection: handleSectionChange,\r\n resetSection,\r\n };\r\n}\r\n"],"mappings":";AAEA,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,0BAA0B;AAOpB,SAAR,uBAAwC;AAAA,EAC7C;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,CAAC,eAAe,gBAAgB,IAAI;AAAA,IACxC,mBAAmB;AAAA,EACrB;AAEA,QAAM,iBAAiB,CACrB,YAEA,OAAO,OAAO,kBAAkB,EAAE,SAAS,OAA6B;AAE1E,YAAU,MAAM;AACd,QAAI,UAAU,eAAe,cAAc,GAAG;AAC5C,uBAAiB,cAAc;AAAA,IACjC,WAAW,QAAQ;AACjB,uBAAiB,mBAAmB,WAAW;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,CAAC;AAE3B,QAAM,sBAAsB,YAAY,CAAC,YAAgC;AACvE,qBAAiB,OAAO;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,MAAM;AACrC,qBAAiB,mBAAmB,WAAW;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -7,6 +7,7 @@ import { IconLock } from "@tabler/icons-react";
|
|
|
7
7
|
import { Button } from "../../ui/buttons/Button";
|
|
8
8
|
import { Separator } from "../../ui/data-display/Separator";
|
|
9
9
|
import { Toast } from "../../ui/feedback/Toast";
|
|
10
|
+
import { FormField } from "../../ui/form/FormField";
|
|
10
11
|
import { ComboboxField } from "../../ui/form/ComboboxField";
|
|
11
12
|
import { SelectField } from "../../ui/form/SelectField";
|
|
12
13
|
import ConfirmGlobalPreferencesModal from "../ConfirmGlobalPreferencesModal";
|
|
@@ -34,6 +35,7 @@ function PreferencesSection({ onClose }) {
|
|
|
34
35
|
const [isSaving, setIsSaving] = useState(false);
|
|
35
36
|
const { watch, setValue, handleSubmit, reset, formState: { dirtyFields } } = useForm({
|
|
36
37
|
defaultValues: {
|
|
38
|
+
companyName: "",
|
|
37
39
|
language: "",
|
|
38
40
|
currency: "",
|
|
39
41
|
timezone: "",
|
|
@@ -45,6 +47,7 @@ function PreferencesSection({ onClose }) {
|
|
|
45
47
|
useEffect(() => {
|
|
46
48
|
if (!user || !account) return;
|
|
47
49
|
reset({
|
|
50
|
+
companyName: account.name ?? "",
|
|
48
51
|
language: LANGUAGE_OPTIONS.find(
|
|
49
52
|
(o) => o.apiValue === user.language?.toLowerCase()
|
|
50
53
|
)?.value ?? "pt-BR",
|
|
@@ -85,6 +88,7 @@ function PreferencesSection({ onClose }) {
|
|
|
85
88
|
};
|
|
86
89
|
const onSubmit = (data) => {
|
|
87
90
|
const accountFields = {
|
|
91
|
+
...canEditPreferences && dirtyFields.companyName && { name: data.companyName },
|
|
88
92
|
...canEditPreferences && dirtyFields.currency && { currency: data.currency },
|
|
89
93
|
...canEditPreferences && dirtyFields.timezone && { timezone: data.timezone }
|
|
90
94
|
};
|
|
@@ -112,6 +116,18 @@ function PreferencesSection({ onClose }) {
|
|
|
112
116
|
/* @__PURE__ */ jsxs("div", { className: "overflow-y-auto overscroll-contain px-4 pb-4 lg:p-5 flex flex-col gap-5 lg:gap-6", children: [
|
|
113
117
|
/* @__PURE__ */ jsx("span", { className: "paragraph-medium-semibold text-gray-950", children: "Prefer\xEAncias" }),
|
|
114
118
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-8", children: [
|
|
119
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col lg:flex-row items-center gap-3", children: /* @__PURE__ */ jsx(
|
|
120
|
+
FormField,
|
|
121
|
+
{
|
|
122
|
+
label: "Nome da empresa",
|
|
123
|
+
placeholder: "Digite o nome da empresa",
|
|
124
|
+
classnameContainer: "w-full",
|
|
125
|
+
value: watch("companyName"),
|
|
126
|
+
onChange: (e) => setValue("companyName", e.target.value, { shouldDirty: true }),
|
|
127
|
+
disabled: !canEditPreferences
|
|
128
|
+
}
|
|
129
|
+
) }),
|
|
130
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
115
131
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row items-center gap-3", children: [
|
|
116
132
|
/* @__PURE__ */ jsx(
|
|
117
133
|
ComboboxField,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/account/sections/PreferencesSection.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { IconLock } from '@tabler/icons-react';\nimport { Button } from '../../ui/buttons/Button';\nimport { Separator } from '../../ui/data-display/Separator';\nimport { Toast } from '../../ui/feedback/Toast';\nimport { ComboboxField } from '../../ui/form/ComboboxField';\nimport { SelectField } from '../../ui/form/SelectField';\nimport ConfirmGlobalPreferencesModal from '../ConfirmGlobalPreferencesModal';\nimport { useAuth } from '../../../providers/auth.provider';\nimport { UserProfile } from '../../../modules/users/schema';\nimport type { UpdateAccountRequest } from '../../../modules/accounts/types';\nimport {\n useUpdateAccountUser,\n useUpdateAccount,\n} from '../../../modules/accounts/hooks/useAccountManagement';\nimport {\n LANGUAGE_OPTIONS,\n TIME_FORMAT_OPTIONS,\n} from '../constants';\nimport { useTimezones } from '../../../modules/accounts/hooks/useTimezones';\nimport { useCurrencies } from '../../../modules/accounts/hooks/useCurrencies';\n\ninterface PreferencesFormValues {\n language: string;\n currency: string;\n timezone: string;\n timeFormat: string;\n receive_sms: boolean;\n receive_email: boolean;\n}\n\ninterface PreferencesSectionProps {\n onClose: () => void;\n}\n\nexport function PreferencesSection({ onClose }: PreferencesSectionProps) {\n const { data: timezones = [] } = useTimezones();\n const { data: currencies = [] } = useCurrencies();\n const { user, account } = useAuth();\n const canEditPreferences =\n user?.profile === UserProfile.owner || user?.profile === UserProfile.admin;\n const updateAccountUser = useUpdateAccountUser();\n const updateAccount = useUpdateAccount();\n const [confirmGlobalOpen, setConfirmGlobalOpen] = useState(false);\n const [pendingSubmit, setPendingSubmit] = useState<{\n data: PreferencesFormValues;\n accountFields: UpdateAccountRequest;\n } | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n\n const { watch, setValue, handleSubmit, reset, formState: { dirtyFields } } =\n useForm<PreferencesFormValues>({\n defaultValues: {\n language: '',\n currency: '',\n timezone: '',\n timeFormat: '24h',\n receive_sms: false,\n receive_email: false,\n },\n });\n\n useEffect(() => {\n if (!user || !account) return;\n reset({\n language: LANGUAGE_OPTIONS.find(\n (o) => o.apiValue === user.language?.toLowerCase()\n )?.value ?? 'pt-BR',\n currency: account.currency,\n timezone: account.timezone,\n timeFormat: '24h',\n receive_sms: user.receive_sms ?? false,\n receive_email: user.receive_email ?? false,\n });\n }, [user, account, reset]);\n\n const doSave = async (data: PreferencesFormValues, accountFields: UpdateAccountRequest) => {\n setIsSaving(true);\n try {\n const apiLanguage = LANGUAGE_OPTIONS.find((o) => o.value === data.language)?.apiValue ?? data.language.toLowerCase();\n await updateAccountUser.mutateAsync({\n language: apiLanguage,\n receive_sms: data.receive_sms,\n receive_email: data.receive_email,\n });\n\n if (canEditPreferences && Object.keys(accountFields).length > 0) {\n await updateAccount.mutateAsync(accountFields);\n }\n\n reset(data);\n toast.custom((t) => (\n <Toast variant=\"success\" message=\"Preferências salvas com sucesso\" toastId={t} />\n ));\n onClose();\n } catch (error) {\n toast.custom((t) => (\n <Toast\n variant=\"error\"\n message={error instanceof Error ? error.message : 'Erro ao salvar preferências'}\n toastId={t}\n />\n ));\n } finally {\n setIsSaving(false);\n }\n };\n\n const onSubmit = (data: PreferencesFormValues) => {\n const accountFields: UpdateAccountRequest = {\n ...(canEditPreferences && dirtyFields.currency && { currency: data.currency }),\n ...(canEditPreferences && dirtyFields.timezone && { timezone: data.timezone }),\n };\n const globalFieldChanged = Object.keys(accountFields).length > 0;\n\n if (globalFieldChanged) {\n setPendingSubmit({ data, accountFields });\n setConfirmGlobalOpen(true);\n } else {\n doSave(data, accountFields);\n }\n };\n\n const handleConfirmGlobal = () => {\n setConfirmGlobalOpen(false);\n if (pendingSubmit) {\n doSave(pendingSubmit.data, pendingSubmit.accountFields);\n setPendingSubmit(null);\n }\n };\n\n const handleCancelGlobal = () => {\n setConfirmGlobalOpen(false);\n setPendingSubmit(null);\n };\n\n return (\n <>\n <form onSubmit={handleSubmit(onSubmit)} className=\"flex flex-col\">\n <div className=\"overflow-y-auto overscroll-contain px-4 pb-4 lg:p-5 flex flex-col gap-5 lg:gap-6\">\n <span className=\"paragraph-medium-semibold text-gray-950\">Preferências</span>\n <div className=\"flex flex-col gap-8\">\n <div className=\"flex flex-col lg:flex-row items-center gap-3\">\n <ComboboxField\n label=\"Idioma\"\n placeholder=\"Selecione o idioma\"\n searchPlaceholder=\"Buscar idioma...\"\n containerClassName=\"w-full\"\n options={LANGUAGE_OPTIONS}\n value={watch('language')}\n onChange={(value) => setValue('language', value, { shouldDirty: true })}\n />\n <ComboboxField\n label=\"Moeda\"\n placeholder=\"Selecione a moeda\"\n searchPlaceholder=\"Buscar moeda...\"\n containerClassName=\"w-full\"\n options={currencies}\n value={watch('currency')}\n onChange={(value) => setValue('currency', value, { shouldDirty: true })}\n icon={!canEditPreferences ? <IconLock className=\"size-4 text-gray-400\" /> : undefined}\n disabled={!canEditPreferences}\n />\n </div>\n\n <Separator />\n\n <div className=\"flex flex-col gap-4\">\n <span className=\"paragraph-medium-semibold text-gray-950\">Exibição hora</span>\n <div className=\"flex flex-col lg:flex-row items-center gap-3\">\n <ComboboxField\n label=\"Fuso horário\"\n placeholder=\"Selecione o fuso horário\"\n searchPlaceholder=\"Buscar fuso horário...\"\n containerClassName=\"w-full\"\n options={timezones}\n value={watch('timezone')}\n onChange={(value) => setValue('timezone', value, { shouldDirty: true })}\n icon={!canEditPreferences ? <IconLock className=\"size-4 text-gray-400\" /> : undefined}\n disabled={!canEditPreferences}\n />\n <SelectField\n label=\"Formato hora\"\n placeholder=\"Selecione o formato\"\n className=\"h-10!\"\n containerClassName=\"w-full\"\n options={TIME_FORMAT_OPTIONS}\n value={watch('timeFormat')}\n onChange={(value) =>\n setValue('timeFormat', value as string, { shouldDirty: true })\n }\n icon={<IconLock className=\"size-4 text-gray-400\" />}\n disabled\n />\n </div>\n </div>\n\n </div>\n </div>\n\n <div className=\"flex items-center h-20 px-4 lg:px-5 border-t border-gray-200 justify-between bg-white\">\n <Button\n variant=\"secondary\"\n className=\"h-10!\"\n type=\"button\"\n disabled={isSaving}\n onClick={() => {\n reset();\n onClose();\n }}\n >\n Cancelar\n </Button>\n <Button className=\"h-10!\" type=\"submit\" disabled={isSaving}>\n {isSaving ? 'Salvando...' : 'Salvar alterações'}\n </Button>\n </div>\n </form>\n\n <ConfirmGlobalPreferencesModal\n open={confirmGlobalOpen}\n onConfirm={handleConfirmGlobal}\n onCancel={handleCancelGlobal}\n />\n </>\n );\n}\n"],"mappings":";AAgGQ,SA6CJ,UA7CI,KAkDI,YAlDJ;AA9FR,SAAS,UAAU,iBAAiB;AACpC,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B,SAAS,aAAa;AACtB,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,OAAO,mCAAmC;AAC1C,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAE5B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAevB,SAAS,mBAAmB,EAAE,QAAQ,GAA4B;AACvE,QAAM,EAAE,MAAM,YAAY,CAAC,EAAE,IAAI,aAAa;AAC9C,QAAM,EAAE,MAAM,aAAa,CAAC,EAAE,IAAI,cAAc;AAChD,QAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ;AAClC,QAAM,qBACJ,MAAM,YAAY,YAAY,SAAS,MAAM,YAAY,YAAY;AACvE,QAAM,oBAAoB,qBAAqB;AAC/C,QAAM,gBAAgB,iBAAiB;AACvC,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAChE,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAGhC,IAAI;AACd,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,QAAM,EAAE,OAAO,UAAU,cAAc,OAAO,WAAW,EAAE,YAAY,EAAE,IACvE,QAA+B;AAAA,IAC7B,eAAe;AAAA,MACb,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,eAAe;AAAA,IACjB;AAAA,EACF,CAAC;AAEH,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,CAAC,QAAS;AACvB,UAAM;AAAA,MACJ,UAAU,iBAAiB;AAAA,QACzB,CAAC,MAAM,EAAE,aAAa,KAAK,UAAU,YAAY;AAAA,MACnD,GAAG,SAAS;AAAA,MACZ,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,YAAY;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe,KAAK,iBAAiB;AAAA,IACvC,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC;AAEzB,QAAM,SAAS,OAAO,MAA6B,kBAAwC;AACzF,gBAAY,IAAI;AAChB,QAAI;AACF,YAAM,cAAc,iBAAiB,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK,QAAQ,GAAG,YAAY,KAAK,SAAS,YAAY;AACnH,YAAM,kBAAkB,YAAY;AAAA,QAClC,UAAU;AAAA,QACV,aAAa,KAAK;AAAA,QAClB,eAAe,KAAK;AAAA,MACtB,CAAC;AAED,UAAI,sBAAsB,OAAO,KAAK,aAAa,EAAE,SAAS,GAAG;AAC/D,cAAM,cAAc,YAAY,aAAa;AAAA,MAC/C;AAEA,YAAM,IAAI;AACV,YAAM,OAAO,CAAC,MACZ,oBAAC,SAAM,SAAQ,WAAU,SAAQ,sCAAkC,SAAS,GAAG,CAChF;AACD,cAAQ;AAAA,IACV,SAAS,OAAO;AACd,YAAM,OAAO,CAAC,MACZ;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAClD,SAAS;AAAA;AAAA,MACX,CACD;AAAA,IACH,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,SAAgC;AAChD,UAAM,gBAAsC;AAAA,MAC1C,GAAI,sBAAsB,YAAY,YAAY,EAAE,UAAU,KAAK,SAAS;AAAA,MAC5E,GAAI,sBAAsB,YAAY,YAAY,EAAE,UAAU,KAAK,SAAS;AAAA,IAC9E;AACA,UAAM,qBAAqB,OAAO,KAAK,aAAa,EAAE,SAAS;AAE/D,QAAI,oBAAoB;AACtB,uBAAiB,EAAE,MAAM,cAAc,CAAC;AACxC,2BAAqB,IAAI;AAAA,IAC3B,OAAO;AACL,aAAO,MAAM,aAAa;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,sBAAsB,MAAM;AAChC,yBAAqB,KAAK;AAC1B,QAAI,eAAe;AACjB,aAAO,cAAc,MAAM,cAAc,aAAa;AACtD,uBAAiB,IAAI;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,qBAAqB,MAAM;AAC/B,yBAAqB,KAAK;AAC1B,qBAAiB,IAAI;AAAA,EACvB;AAEA,SACE,iCACE;AAAA,yBAAC,UAAK,UAAU,aAAa,QAAQ,GAAG,WAAU,iBAChD;AAAA,2BAAC,SAAI,WAAU,oFACb;AAAA,4BAAC,UAAK,WAAU,2CAA0C,6BAAY;AAAA,QACtE,qBAAC,SAAI,WAAU,uBACb;AAAA,+BAAC,SAAI,WAAU,gDACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,aAAY;AAAA,gBACZ,mBAAkB;AAAA,gBAClB,oBAAmB;AAAA,gBACnB,SAAS;AAAA,gBACT,OAAO,MAAM,UAAU;AAAA,gBACvB,UAAU,CAAC,UAAU,SAAS,YAAY,OAAO,EAAE,aAAa,KAAK,CAAC;AAAA;AAAA,YACxE;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,aAAY;AAAA,gBACZ,mBAAkB;AAAA,gBAClB,oBAAmB;AAAA,gBACnB,SAAS;AAAA,gBACT,OAAO,MAAM,UAAU;AAAA,gBACvB,UAAU,CAAC,UAAU,SAAS,YAAY,OAAO,EAAE,aAAa,KAAK,CAAC;AAAA,gBACtE,MAAM,CAAC,qBAAqB,oBAAC,YAAS,WAAU,wBAAuB,IAAK;AAAA,gBAC5E,UAAU,CAAC;AAAA;AAAA,YACb;AAAA,aACF;AAAA,UAEA,oBAAC,aAAU;AAAA,UAEX,qBAAC,SAAI,WAAU,uBACb;AAAA,gCAAC,UAAK,WAAU,2CAA0C,iCAAa;AAAA,YACvE,qBAAC,SAAI,WAAU,gDACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,aAAY;AAAA,kBACZ,mBAAkB;AAAA,kBAClB,oBAAmB;AAAA,kBACnB,SAAS;AAAA,kBACT,OAAO,MAAM,UAAU;AAAA,kBACvB,UAAU,CAAC,UAAU,SAAS,YAAY,OAAO,EAAE,aAAa,KAAK,CAAC;AAAA,kBACtE,MAAM,CAAC,qBAAqB,oBAAC,YAAS,WAAU,wBAAuB,IAAK;AAAA,kBAC5E,UAAU,CAAC;AAAA;AAAA,cACb;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,aAAY;AAAA,kBACZ,WAAU;AAAA,kBACV,oBAAmB;AAAA,kBACnB,SAAS;AAAA,kBACT,OAAO,MAAM,YAAY;AAAA,kBACzB,UAAU,CAAC,UACT,SAAS,cAAc,OAAiB,EAAE,aAAa,KAAK,CAAC;AAAA,kBAE/D,MAAM,oBAAC,YAAS,WAAU,wBAAuB;AAAA,kBACjD,UAAQ;AAAA;AAAA,cACV;AAAA,eACF;AAAA,aACF;AAAA,WAEF;AAAA,SACF;AAAA,MAEA,qBAAC,SAAI,WAAU,yFACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,MAAK;AAAA,YACL,UAAU;AAAA,YACV,SAAS,MAAM;AACb,oBAAM;AACN,sBAAQ;AAAA,YACV;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA,oBAAC,UAAO,WAAU,SAAQ,MAAK,UAAS,UAAU,UAC/C,qBAAW,gBAAgB,2BAC9B;AAAA,SACF;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,WAAW;AAAA,QACX,UAAU;AAAA;AAAA,IACZ;AAAA,KACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/account/sections/PreferencesSection.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { IconLock } from '@tabler/icons-react';\nimport { Button } from '../../ui/buttons/Button';\nimport { Separator } from '../../ui/data-display/Separator';\nimport { Toast } from '../../ui/feedback/Toast';\nimport { FormField } from '../../ui/form/FormField';\nimport { ComboboxField } from '../../ui/form/ComboboxField';\nimport { SelectField } from '../../ui/form/SelectField';\nimport ConfirmGlobalPreferencesModal from '../ConfirmGlobalPreferencesModal';\nimport { useAuth } from '../../../providers/auth.provider';\nimport { UserProfile } from '../../../modules/users/schema';\nimport type { UpdateAccountRequest } from '../../../modules/accounts/types';\nimport {\n useUpdateAccountUser,\n useUpdateAccount,\n} from '../../../modules/accounts/hooks/useAccountManagement';\nimport {\n LANGUAGE_OPTIONS,\n TIME_FORMAT_OPTIONS,\n} from '../constants';\nimport { useTimezones } from '../../../modules/accounts/hooks/useTimezones';\nimport { useCurrencies } from '../../../modules/accounts/hooks/useCurrencies';\n\ninterface PreferencesFormValues {\n companyName: string;\n language: string;\n currency: string;\n timezone: string;\n timeFormat: string;\n receive_sms: boolean;\n receive_email: boolean;\n}\n\ninterface PreferencesSectionProps {\n onClose: () => void;\n}\n\nexport function PreferencesSection({ onClose }: PreferencesSectionProps) {\n const { data: timezones = [] } = useTimezones();\n const { data: currencies = [] } = useCurrencies();\n const { user, account } = useAuth();\n const canEditPreferences =\n user?.profile === UserProfile.owner || user?.profile === UserProfile.admin;\n const updateAccountUser = useUpdateAccountUser();\n const updateAccount = useUpdateAccount();\n const [confirmGlobalOpen, setConfirmGlobalOpen] = useState(false);\n const [pendingSubmit, setPendingSubmit] = useState<{\n data: PreferencesFormValues;\n accountFields: UpdateAccountRequest;\n } | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n\n const { watch, setValue, handleSubmit, reset, formState: { dirtyFields } } =\n useForm<PreferencesFormValues>({\n defaultValues: {\n companyName: '',\n language: '',\n currency: '',\n timezone: '',\n timeFormat: '24h',\n receive_sms: false,\n receive_email: false,\n },\n });\n\n useEffect(() => {\n if (!user || !account) return;\n reset({\n companyName: account.name ?? '',\n language: LANGUAGE_OPTIONS.find(\n (o) => o.apiValue === user.language?.toLowerCase()\n )?.value ?? 'pt-BR',\n currency: account.currency,\n timezone: account.timezone,\n timeFormat: '24h',\n receive_sms: user.receive_sms ?? false,\n receive_email: user.receive_email ?? false,\n });\n }, [user, account, reset]);\n\n const doSave = async (data: PreferencesFormValues, accountFields: UpdateAccountRequest) => {\n setIsSaving(true);\n try {\n const apiLanguage = LANGUAGE_OPTIONS.find((o) => o.value === data.language)?.apiValue ?? data.language.toLowerCase();\n await updateAccountUser.mutateAsync({\n language: apiLanguage,\n receive_sms: data.receive_sms,\n receive_email: data.receive_email,\n });\n\n if (canEditPreferences && Object.keys(accountFields).length > 0) {\n await updateAccount.mutateAsync(accountFields);\n }\n\n reset(data);\n toast.custom((t) => (\n <Toast variant=\"success\" message=\"Preferências salvas com sucesso\" toastId={t} />\n ));\n onClose();\n } catch (error) {\n toast.custom((t) => (\n <Toast\n variant=\"error\"\n message={error instanceof Error ? error.message : 'Erro ao salvar preferências'}\n toastId={t}\n />\n ));\n } finally {\n setIsSaving(false);\n }\n };\n\n const onSubmit = (data: PreferencesFormValues) => {\n const accountFields: UpdateAccountRequest = {\n ...(canEditPreferences && dirtyFields.companyName && { name: data.companyName }),\n ...(canEditPreferences && dirtyFields.currency && { currency: data.currency }),\n ...(canEditPreferences && dirtyFields.timezone && { timezone: data.timezone }),\n };\n const globalFieldChanged = Object.keys(accountFields).length > 0;\n\n if (globalFieldChanged) {\n setPendingSubmit({ data, accountFields });\n setConfirmGlobalOpen(true);\n } else {\n doSave(data, accountFields);\n }\n };\n\n const handleConfirmGlobal = () => {\n setConfirmGlobalOpen(false);\n if (pendingSubmit) {\n doSave(pendingSubmit.data, pendingSubmit.accountFields);\n setPendingSubmit(null);\n }\n };\n\n const handleCancelGlobal = () => {\n setConfirmGlobalOpen(false);\n setPendingSubmit(null);\n };\n\n return (\n <>\n <form onSubmit={handleSubmit(onSubmit)} className=\"flex flex-col\">\n <div className=\"overflow-y-auto overscroll-contain px-4 pb-4 lg:p-5 flex flex-col gap-5 lg:gap-6\">\n <span className=\"paragraph-medium-semibold text-gray-950\">Preferências</span>\n <div className=\"flex flex-col gap-8\">\n <div className=\"flex flex-col lg:flex-row items-center gap-3\">\n <FormField\n label=\"Nome da empresa\"\n placeholder=\"Digite o nome da empresa\"\n classnameContainer=\"w-full\"\n value={watch('companyName')}\n onChange={(e) => setValue('companyName', e.target.value, { shouldDirty: true })}\n disabled={!canEditPreferences}\n />\n </div>\n\n <Separator />\n\n <div className=\"flex flex-col lg:flex-row items-center gap-3\">\n <ComboboxField\n label=\"Idioma\"\n placeholder=\"Selecione o idioma\"\n searchPlaceholder=\"Buscar idioma...\"\n containerClassName=\"w-full\"\n options={LANGUAGE_OPTIONS}\n value={watch('language')}\n onChange={(value) => setValue('language', value, { shouldDirty: true })}\n />\n <ComboboxField\n label=\"Moeda\"\n placeholder=\"Selecione a moeda\"\n searchPlaceholder=\"Buscar moeda...\"\n containerClassName=\"w-full\"\n options={currencies}\n value={watch('currency')}\n onChange={(value) => setValue('currency', value, { shouldDirty: true })}\n icon={!canEditPreferences ? <IconLock className=\"size-4 text-gray-400\" /> : undefined}\n disabled={!canEditPreferences}\n />\n </div>\n\n <Separator />\n\n <div className=\"flex flex-col gap-4\">\n <span className=\"paragraph-medium-semibold text-gray-950\">Exibição hora</span>\n <div className=\"flex flex-col lg:flex-row items-center gap-3\">\n <ComboboxField\n label=\"Fuso horário\"\n placeholder=\"Selecione o fuso horário\"\n searchPlaceholder=\"Buscar fuso horário...\"\n containerClassName=\"w-full\"\n options={timezones}\n value={watch('timezone')}\n onChange={(value) => setValue('timezone', value, { shouldDirty: true })}\n icon={!canEditPreferences ? <IconLock className=\"size-4 text-gray-400\" /> : undefined}\n disabled={!canEditPreferences}\n />\n <SelectField\n label=\"Formato hora\"\n placeholder=\"Selecione o formato\"\n className=\"h-10!\"\n containerClassName=\"w-full\"\n options={TIME_FORMAT_OPTIONS}\n value={watch('timeFormat')}\n onChange={(value) =>\n setValue('timeFormat', value as string, { shouldDirty: true })\n }\n icon={<IconLock className=\"size-4 text-gray-400\" />}\n disabled\n />\n </div>\n </div>\n\n </div>\n </div>\n\n <div className=\"flex items-center h-20 px-4 lg:px-5 border-t border-gray-200 justify-between bg-white\">\n <Button\n variant=\"secondary\"\n className=\"h-10!\"\n type=\"button\"\n disabled={isSaving}\n onClick={() => {\n reset();\n onClose();\n }}\n >\n Cancelar\n </Button>\n <Button className=\"h-10!\" type=\"submit\" disabled={isSaving}>\n {isSaving ? 'Salvando...' : 'Salvar alterações'}\n </Button>\n </div>\n </form>\n\n <ConfirmGlobalPreferencesModal\n open={confirmGlobalOpen}\n onConfirm={handleConfirmGlobal}\n onCancel={handleCancelGlobal}\n />\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,35 +1,74 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { IconX } from '@tabler/icons-react';
|
|
3
|
+
import { IconLock, IconSettings2, IconX } from '@tabler/icons-react';
|
|
4
4
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';
|
|
5
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/data-display/Tabs';
|
|
5
6
|
import { cn } from '../../infra/utils/clsx';
|
|
7
|
+
import { AccountSectionType } from '../../enums/AccountSectionType';
|
|
6
8
|
import { PreferencesSection } from './sections/PreferencesSection';
|
|
9
|
+
import { ChangePasswordSection } from './sections/ChangePasswordSection';
|
|
10
|
+
import { SecuritySection } from './sections/SecuritySection';
|
|
11
|
+
import useConfigurationsModal from './hooks/useConfigurationsModal';
|
|
7
12
|
import useIsMobile from '../../hooks/useIsMobile';
|
|
8
13
|
import { useAccountModals } from '../../store/useAccountModals';
|
|
9
14
|
|
|
10
15
|
export default function ConfigurationsMyAccountModal() {
|
|
11
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
activeModal,
|
|
18
|
+
config,
|
|
19
|
+
openDeleteAccount,
|
|
20
|
+
openIsntPossibleDelete,
|
|
21
|
+
close,
|
|
22
|
+
} = useAccountModals();
|
|
12
23
|
|
|
13
24
|
const open = activeModal === 'configurations';
|
|
25
|
+
const { hasActiveSubscription } = config;
|
|
26
|
+
|
|
14
27
|
const isMobile = useIsMobile();
|
|
28
|
+
const { activeSection, setActiveSection } = useConfigurationsModal({
|
|
29
|
+
isOpen: open,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const handleDeleteAccount = () => {
|
|
33
|
+
close();
|
|
34
|
+
if (hasActiveSubscription) {
|
|
35
|
+
openIsntPossibleDelete();
|
|
36
|
+
} else {
|
|
37
|
+
openDeleteAccount();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const tabTriggerClasses = cn(
|
|
42
|
+
'border-0! px-0 py-0',
|
|
43
|
+
|
|
44
|
+
'lg:rounded-md lg:flex lg:items-center lg:gap-2 lg:p-3 lg:justify-start lg:w-full',
|
|
45
|
+
'lg:bg-white lg:hover:bg-gray-100 lg:active:bg-gray-50 lg:border-0',
|
|
46
|
+
'lg:data-[state=active]:bg-gray-50',
|
|
47
|
+
|
|
48
|
+
'flex items-center gap-1.5 px-3 py-3 justify-center whitespace-nowrap',
|
|
49
|
+
'border-b-2 border-transparent',
|
|
50
|
+
'data-[state=active]:bg-gray-50 rounded-lg',
|
|
51
|
+
|
|
52
|
+
'text-gray-500 data-[state=active]:text-gray-950',
|
|
53
|
+
'hover:text-gray-900 transition-colors'
|
|
54
|
+
);
|
|
15
55
|
|
|
16
56
|
return (
|
|
17
57
|
<Dialog open={open} onOpenChange={close}>
|
|
18
58
|
<DialogContent
|
|
19
59
|
showCloseButton={!isMobile}
|
|
20
60
|
overlayClassName="bg-black/20 lg:bg-black/50"
|
|
21
|
-
className=
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)}
|
|
61
|
+
className="
|
|
62
|
+
flex flex-col p-0 gap-0 max-w-full sm:max-w-full overflow-x-hidden border-0
|
|
63
|
+
rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0
|
|
64
|
+
lg:flex-row lg:w-[892px] lg:max-w-[892px] lg:h-[626px] lg:rounded-lg lg:border
|
|
65
|
+
lg:top-[50%] lg:bottom-auto lg:left-[50%] lg:right-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
|
|
27
66
|
>
|
|
28
67
|
<DialogHeader className="sr-only">
|
|
29
|
-
<DialogTitle>
|
|
68
|
+
<DialogTitle>Configurações</DialogTitle>
|
|
30
69
|
</DialogHeader>
|
|
31
70
|
<div className="md:hidden flex items-center justify-between px-5 py-3 border-b border-gray-200">
|
|
32
|
-
<span className="text-gray-950 paragraph-medium-semibold">
|
|
71
|
+
<span className="text-gray-950 paragraph-medium-semibold">Configurações</span>
|
|
33
72
|
<button
|
|
34
73
|
type="button"
|
|
35
74
|
className="size-8 flex items-center justify-center text-gray-500 cursor-pointer"
|
|
@@ -38,7 +77,59 @@ export default function ConfigurationsMyAccountModal() {
|
|
|
38
77
|
<IconX size={18} />
|
|
39
78
|
</button>
|
|
40
79
|
</div>
|
|
41
|
-
<
|
|
80
|
+
<Tabs
|
|
81
|
+
value={activeSection}
|
|
82
|
+
onValueChange={(value) => setActiveSection(value as AccountSectionType)}
|
|
83
|
+
orientation="vertical"
|
|
84
|
+
className="flex lg:flex-row flex-col w-full h-full flex-1 lg:h-full lg:pt-0 lg:gap-0"
|
|
85
|
+
>
|
|
86
|
+
<TabsList
|
|
87
|
+
className={cn(
|
|
88
|
+
'flex gap-0 bg-transparent border-b-0',
|
|
89
|
+
|
|
90
|
+
'lg:flex-col lg:items-stretch lg:justify-start lg:w-auto lg:min-w-60',
|
|
91
|
+
'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',
|
|
92
|
+
|
|
93
|
+
'flex-row items-center justify-start w-full overflow-x-auto scrollbar-hide shrink-0',
|
|
94
|
+
'px-4 py-3',
|
|
95
|
+
'[mask-image:linear-gradient(to_right,transparent,black_16px,black_calc(100%-24px),transparent)] lg:[mask-image:none]'
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
<span className="hidden lg:block paragraph-medium-semibold text-gray-950 mb-0">
|
|
99
|
+
Configurações
|
|
100
|
+
</span>
|
|
101
|
+
|
|
102
|
+
<div className="lg:flex lg:flex-col flex flex-row lg:gap-0 gap-0 lg:w-full">
|
|
103
|
+
<TabsTrigger value={AccountSectionType.PREFERENCES} className={tabTriggerClasses}>
|
|
104
|
+
<IconSettings2 size={20} className="shrink-0" />
|
|
105
|
+
<span className="paragraph-small-medium">Preferências</span>
|
|
106
|
+
</TabsTrigger>
|
|
107
|
+
|
|
108
|
+
<TabsTrigger value={AccountSectionType.SECURITY} className={tabTriggerClasses}>
|
|
109
|
+
<IconLock size={20} className="shrink-0" />
|
|
110
|
+
<span className="paragraph-small-medium">Segurança</span>
|
|
111
|
+
</TabsTrigger>
|
|
112
|
+
</div>
|
|
113
|
+
</TabsList>
|
|
114
|
+
|
|
115
|
+
<div className="w-full flex-1 min-h-0 lg:h-full overflow-hidden lg:overflow-visible relative flex flex-col">
|
|
116
|
+
<TabsContent value={AccountSectionType.PREFERENCES} className="h-full! relative overflow-hidden">
|
|
117
|
+
<PreferencesSection onClose={close} />
|
|
118
|
+
</TabsContent>
|
|
119
|
+
|
|
120
|
+
<TabsContent value={AccountSectionType.SECURITY} className="h-full! relative overflow-hidden">
|
|
121
|
+
<SecuritySection
|
|
122
|
+
setActiveSection={setActiveSection}
|
|
123
|
+
onClose={close}
|
|
124
|
+
onDeleteAccount={handleDeleteAccount}
|
|
125
|
+
/>
|
|
126
|
+
</TabsContent>
|
|
127
|
+
|
|
128
|
+
<TabsContent value={AccountSectionType.CHANGE_PASSWORD} className="h-full! relative overflow-hidden">
|
|
129
|
+
<ChangePasswordSection onBack={() => setActiveSection(AccountSectionType.SECURITY)} />
|
|
130
|
+
</TabsContent>
|
|
131
|
+
</div>
|
|
132
|
+
</Tabs>
|
|
42
133
|
</DialogContent>
|
|
43
134
|
</Dialog>
|
|
44
135
|
);
|
|
@@ -13,7 +13,7 @@ export default function useConfigurationsModal({
|
|
|
13
13
|
initialSection,
|
|
14
14
|
}: UseConfigurationsModalProps) {
|
|
15
15
|
const [activeSection, setActiveSection] = useState<AccountSectionType>(
|
|
16
|
-
AccountSectionType.
|
|
16
|
+
AccountSectionType.PREFERENCES,
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
const isValidSection = (
|
|
@@ -25,7 +25,7 @@ export default function useConfigurationsModal({
|
|
|
25
25
|
if (isOpen && isValidSection(initialSection)) {
|
|
26
26
|
setActiveSection(initialSection);
|
|
27
27
|
} else if (isOpen) {
|
|
28
|
-
setActiveSection(AccountSectionType.
|
|
28
|
+
setActiveSection(AccountSectionType.PREFERENCES);
|
|
29
29
|
}
|
|
30
30
|
}, [isOpen, initialSection]);
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ export default function useConfigurationsModal({
|
|
|
34
34
|
}, []);
|
|
35
35
|
|
|
36
36
|
const resetSection = useCallback(() => {
|
|
37
|
-
setActiveSection(AccountSectionType.
|
|
37
|
+
setActiveSection(AccountSectionType.PREFERENCES);
|
|
38
38
|
}, []);
|
|
39
39
|
|
|
40
40
|
return {
|
|
@@ -7,6 +7,7 @@ import { IconLock } from '@tabler/icons-react';
|
|
|
7
7
|
import { Button } from '../../ui/buttons/Button';
|
|
8
8
|
import { Separator } from '../../ui/data-display/Separator';
|
|
9
9
|
import { Toast } from '../../ui/feedback/Toast';
|
|
10
|
+
import { FormField } from '../../ui/form/FormField';
|
|
10
11
|
import { ComboboxField } from '../../ui/form/ComboboxField';
|
|
11
12
|
import { SelectField } from '../../ui/form/SelectField';
|
|
12
13
|
import ConfirmGlobalPreferencesModal from '../ConfirmGlobalPreferencesModal';
|
|
@@ -25,6 +26,7 @@ import { useTimezones } from '../../../modules/accounts/hooks/useTimezones';
|
|
|
25
26
|
import { useCurrencies } from '../../../modules/accounts/hooks/useCurrencies';
|
|
26
27
|
|
|
27
28
|
interface PreferencesFormValues {
|
|
29
|
+
companyName: string;
|
|
28
30
|
language: string;
|
|
29
31
|
currency: string;
|
|
30
32
|
timezone: string;
|
|
@@ -55,6 +57,7 @@ export function PreferencesSection({ onClose }: PreferencesSectionProps) {
|
|
|
55
57
|
const { watch, setValue, handleSubmit, reset, formState: { dirtyFields } } =
|
|
56
58
|
useForm<PreferencesFormValues>({
|
|
57
59
|
defaultValues: {
|
|
60
|
+
companyName: '',
|
|
58
61
|
language: '',
|
|
59
62
|
currency: '',
|
|
60
63
|
timezone: '',
|
|
@@ -67,6 +70,7 @@ export function PreferencesSection({ onClose }: PreferencesSectionProps) {
|
|
|
67
70
|
useEffect(() => {
|
|
68
71
|
if (!user || !account) return;
|
|
69
72
|
reset({
|
|
73
|
+
companyName: account.name ?? '',
|
|
70
74
|
language: LANGUAGE_OPTIONS.find(
|
|
71
75
|
(o) => o.apiValue === user.language?.toLowerCase()
|
|
72
76
|
)?.value ?? 'pt-BR',
|
|
@@ -112,6 +116,7 @@ export function PreferencesSection({ onClose }: PreferencesSectionProps) {
|
|
|
112
116
|
|
|
113
117
|
const onSubmit = (data: PreferencesFormValues) => {
|
|
114
118
|
const accountFields: UpdateAccountRequest = {
|
|
119
|
+
...(canEditPreferences && dirtyFields.companyName && { name: data.companyName }),
|
|
115
120
|
...(canEditPreferences && dirtyFields.currency && { currency: data.currency }),
|
|
116
121
|
...(canEditPreferences && dirtyFields.timezone && { timezone: data.timezone }),
|
|
117
122
|
};
|
|
@@ -144,6 +149,19 @@ export function PreferencesSection({ onClose }: PreferencesSectionProps) {
|
|
|
144
149
|
<div className="overflow-y-auto overscroll-contain px-4 pb-4 lg:p-5 flex flex-col gap-5 lg:gap-6">
|
|
145
150
|
<span className="paragraph-medium-semibold text-gray-950">Preferências</span>
|
|
146
151
|
<div className="flex flex-col gap-8">
|
|
152
|
+
<div className="flex flex-col lg:flex-row items-center gap-3">
|
|
153
|
+
<FormField
|
|
154
|
+
label="Nome da empresa"
|
|
155
|
+
placeholder="Digite o nome da empresa"
|
|
156
|
+
classnameContainer="w-full"
|
|
157
|
+
value={watch('companyName')}
|
|
158
|
+
onChange={(e) => setValue('companyName', e.target.value, { shouldDirty: true })}
|
|
159
|
+
disabled={!canEditPreferences}
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<Separator />
|
|
164
|
+
|
|
147
165
|
<div className="flex flex-col lg:flex-row items-center gap-3">
|
|
148
166
|
<ComboboxField
|
|
149
167
|
label="Idioma"
|