@greatapps/common 1.1.110 → 1.1.112
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/layouts/AppMobileNavBar.mjs +28 -7
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/AppNavBar.mjs +23 -15
- package/dist/components/layouts/AppNavBar.mjs.map +1 -1
- package/dist/modules/auth/services/auth.service.mjs +18 -9
- package/dist/modules/auth/services/auth.service.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/AppMobileNavBar.tsx +35 -18
- package/src/components/layouts/AppNavBar.tsx +31 -21
|
@@ -5,9 +5,7 @@ import { ProfilePopover } from "./ProfilePopover";
|
|
|
5
5
|
import { useAccountModals } from "../../store/useAccountModals";
|
|
6
6
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
7
7
|
function AppMobileNavBar({
|
|
8
|
-
|
|
9
|
-
appIconIndicator = false,
|
|
10
|
-
logoIndicator = false,
|
|
8
|
+
activeApp,
|
|
11
9
|
onLogoClick,
|
|
12
10
|
onAppIconClick,
|
|
13
11
|
extraLeftSlot,
|
|
@@ -16,6 +14,8 @@ function AppMobileNavBar({
|
|
|
16
14
|
onCreditsClick
|
|
17
15
|
}) {
|
|
18
16
|
const { openConfigurations } = useAccountModals();
|
|
17
|
+
const isGpagesActive = activeApp === "gpages";
|
|
18
|
+
const isGappsActive = activeApp === "gapps";
|
|
19
19
|
return /* @__PURE__ */ jsxs("div", { className: "fixed top-0 left-0 right-0 flex md:hidden items-center justify-between p-4 bg-white z-50 border-b border-gray-200", children: [
|
|
20
20
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
21
21
|
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
@@ -26,7 +26,7 @@ function AppMobileNavBar({
|
|
|
26
26
|
onClick: onLogoClick,
|
|
27
27
|
children: [
|
|
28
28
|
/* @__PURE__ */ jsx(Image, { src: "/icons/great-icon.svg", alt: "GreatApps", width: 28, height: 28 }),
|
|
29
|
-
|
|
29
|
+
isGappsActive && /* @__PURE__ */ jsx("div", { className: "absolute bottom-[-17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-gray-950 rounded-t-xl" })
|
|
30
30
|
]
|
|
31
31
|
}
|
|
32
32
|
) }),
|
|
@@ -34,17 +34,38 @@ function AppMobileNavBar({
|
|
|
34
34
|
] }),
|
|
35
35
|
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
36
36
|
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
37
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
37
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: isGpagesActive ? /* @__PURE__ */ jsx(
|
|
38
38
|
"div",
|
|
39
39
|
{
|
|
40
|
-
className:
|
|
40
|
+
className: "size-10 rounded-xl cursor-pointer p-[2px]",
|
|
41
|
+
style: {
|
|
42
|
+
border: "1.5px solid rgba(153,234,255,0.75)",
|
|
43
|
+
background: "white",
|
|
44
|
+
boxShadow: "0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)"
|
|
45
|
+
},
|
|
46
|
+
onClick: onAppIconClick,
|
|
47
|
+
children: /* @__PURE__ */ jsx(
|
|
48
|
+
"div",
|
|
49
|
+
{
|
|
50
|
+
className: "w-full h-full rounded-lg flex items-center justify-center",
|
|
51
|
+
style: {
|
|
52
|
+
background: "radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)"
|
|
53
|
+
},
|
|
54
|
+
children: /* @__PURE__ */ jsx(Image, { src: "/icons/icon-navbar.svg", alt: "GreatPages", width: 24, height: 24 })
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
) : /* @__PURE__ */ jsx(
|
|
59
|
+
"div",
|
|
60
|
+
{
|
|
61
|
+
className: `size-10 flex items-center justify-center rounded-lg transition-colors duration-300 bg-pages-50 ${onAppIconClick ? "cursor-pointer hover:opacity-80" : ""}`,
|
|
41
62
|
onClick: onAppIconClick,
|
|
42
63
|
children: /* @__PURE__ */ jsx(Image, { src: "/icons/icon-navbar.svg", alt: "GreatPages", width: 24, height: 24 })
|
|
43
64
|
}
|
|
44
65
|
) }),
|
|
45
66
|
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "GreatPages" })
|
|
46
67
|
] }),
|
|
47
|
-
|
|
68
|
+
isGpagesActive && /* @__PURE__ */ jsx("div", { className: "absolute -bottom-[17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-pages-500 rounded-t-xl" })
|
|
48
69
|
] }),
|
|
49
70
|
extraLeftSlot
|
|
50
71
|
] }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/layouts/AppMobileNavBar.tsx"],"sourcesContent":["'use client';\n\nimport { ReactNode } from 'react';\nimport Image from 'next/image';\nimport { ProfilePopover } from './ProfilePopover';\nimport { useAccountModals } from '../../store/useAccountModals';\nimport type { ProfileMenuItem } from './ProfilePopover';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\n\nexport interface AppMobileNavBarProps {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/AppMobileNavBar.tsx"],"sourcesContent":["'use client';\n\nimport { ReactNode } from 'react';\nimport Image from 'next/image';\nimport { ProfilePopover } from './ProfilePopover';\nimport { useAccountModals } from '../../store/useAccountModals';\nimport type { ProfileMenuItem } from './ProfilePopover';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\n\nexport interface AppMobileNavBarProps {\n /** Which app is currently active — controls which icon gets the indicator */\n activeApp?: 'gapps' | 'gpages';\n /** Called when the GreatApps logo is clicked */\n onLogoClick?: () => void;\n /** Called when the app icon (e.g. GreatPages) is clicked */\n onAppIconClick?: () => void;\n /** Extra slot rendered after the app icon (e.g. project selector) */\n extraLeftSlot?: ReactNode;\n /** Required: the right-side action element (toggle button, sheet button, etc.) */\n rightActionSlot: ReactNode;\n menuItems?: ProfileMenuItem[];\n onCreditsClick?: () => void;\n}\n\nexport function AppMobileNavBar({\n activeApp,\n onLogoClick,\n onAppIconClick,\n extraLeftSlot,\n rightActionSlot,\n menuItems = [],\n onCreditsClick,\n}: AppMobileNavBarProps) {\n const { openConfigurations } = useAccountModals();\n\n const isGpagesActive = activeApp === 'gpages';\n const isGappsActive = activeApp === 'gapps';\n\n return (\n <div className=\"fixed top-0 left-0 right-0 flex md:hidden items-center justify-between p-4 bg-white z-50 border-b border-gray-200\">\n <div className=\"flex items-center gap-1.5\">\n <Tooltip>\n <TooltipTrigger asChild>\n <div\n className={`relative size-10 flex items-center justify-center rounded-lg transition-colors ${onLogoClick ? 'cursor-pointer hover:bg-gray-100' : ''}`}\n onClick={onLogoClick}\n >\n <Image src=\"/icons/great-icon.svg\" alt=\"GreatApps\" width={28} height={28} />\n {isGappsActive && (\n <div className=\"absolute bottom-[-17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-gray-950 rounded-t-xl\" />\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">GreatApps</TooltipContent>\n </Tooltip>\n <div className=\"relative\">\n <Tooltip>\n <TooltipTrigger asChild>\n {isGpagesActive ? (\n <div\n className=\"size-10 rounded-xl cursor-pointer p-[2px]\"\n style={{\n border: '1.5px solid rgba(153,234,255,0.75)',\n background: 'white',\n boxShadow: '0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)',\n }}\n onClick={onAppIconClick}\n >\n <div\n className=\"w-full h-full rounded-lg flex items-center justify-center\"\n style={{\n background: 'radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)',\n }}\n >\n <Image src=\"/icons/icon-navbar.svg\" alt=\"GreatPages\" width={24} height={24} />\n </div>\n </div>\n ) : (\n <div\n className={`size-10 flex items-center justify-center rounded-lg transition-colors duration-300 bg-pages-50 ${onAppIconClick ? 'cursor-pointer hover:opacity-80' : ''}`}\n onClick={onAppIconClick}\n >\n <Image src=\"/icons/icon-navbar.svg\" alt=\"GreatPages\" width={24} height={24} />\n </div>\n )}\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">GreatPages</TooltipContent>\n </Tooltip>\n {isGpagesActive && (\n <div className=\"absolute -bottom-[17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-pages-500 rounded-t-xl\" />\n )}\n </div>\n {extraLeftSlot}\n </div>\n <div className=\"flex items-center gap-1.5\">\n <ProfilePopover\n side=\"bottom\"\n align=\"end\"\n contentClassName=\"\"\n onEditProfile={() => openConfigurations()}\n onCreditsClick={onCreditsClick}\n menuItems={menuItems}\n />\n {rightActionSlot}\n </div>\n </div>\n );\n}\n"],"mappings":";AA2CY,SAIE,KAJF;AAxCZ,OAAO,WAAW;AAClB,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAEjC,SAAS,SAAS,gBAAgB,sBAAsB;AAiBjD,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,CAAC;AAAA,EACb;AACF,GAAyB;AACvB,QAAM,EAAE,mBAAmB,IAAI,iBAAiB;AAEhD,QAAM,iBAAiB,cAAc;AACrC,QAAM,gBAAgB,cAAc;AAEpC,SACE,qBAAC,SAAI,WAAU,qHACb;AAAA,yBAAC,SAAI,WAAU,6BACb;AAAA,2BAAC,WACC;AAAA,4BAAC,kBAAe,SAAO,MACrB;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,kFAAkF,cAAc,qCAAqC,EAAE;AAAA,YAClJ,SAAS;AAAA,YAET;AAAA,kCAAC,SAAM,KAAI,yBAAwB,KAAI,aAAY,OAAO,IAAI,QAAQ,IAAI;AAAA,cACzE,iBACC,oBAAC,SAAI,WAAU,0FAAyF;AAAA;AAAA;AAAA,QAE5G,GACF;AAAA,QACA,oBAAC,kBAAe,MAAK,UAAS,uBAAS;AAAA,SACzC;AAAA,MACA,qBAAC,SAAI,WAAU,YACb;AAAA,6BAAC,WACC;AAAA,8BAAC,kBAAe,SAAO,MACpB,2BACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,QAAQ;AAAA,gBACR,YAAY;AAAA,gBACZ,WAAW;AAAA,cACb;AAAA,cACA,SAAS;AAAA,cAET;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,OAAO;AAAA,oBACL,YAAY;AAAA,kBACd;AAAA,kBAEA,8BAAC,SAAM,KAAI,0BAAyB,KAAI,cAAa,OAAO,IAAI,QAAQ,IAAI;AAAA;AAAA,cAC9E;AAAA;AAAA,UACF,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,kGAAkG,iBAAiB,oCAAoC,EAAE;AAAA,cACpK,SAAS;AAAA,cAET,8BAAC,SAAM,KAAI,0BAAyB,KAAI,cAAa,OAAO,IAAI,QAAQ,IAAI;AAAA;AAAA,UAC9E,GAEJ;AAAA,UACA,oBAAC,kBAAe,MAAK,UAAS,wBAAU;AAAA,WAC1C;AAAA,QACC,kBACC,oBAAC,SAAI,WAAU,2FAA0F;AAAA,SAE7G;AAAA,MACC;AAAA,OACH;AAAA,IACA,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAM;AAAA,UACN,kBAAiB;AAAA,UACjB,eAAe,MAAM,mBAAmB;AAAA,UACxC;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MACC;AAAA,OACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -9,10 +9,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
|
9
9
|
import { useAccountModals } from "../../store/useAccountModals";
|
|
10
10
|
function AppNavBar({
|
|
11
11
|
onLogoClick,
|
|
12
|
-
|
|
12
|
+
activeApp,
|
|
13
13
|
appIconHref = "/",
|
|
14
|
-
appIconActive = false,
|
|
15
|
-
appIconIndicator = false,
|
|
16
14
|
showExpandButton = false,
|
|
17
15
|
onExpandClick,
|
|
18
16
|
menuItems = [],
|
|
@@ -23,38 +21,48 @@ function AppNavBar({
|
|
|
23
21
|
const { openConfigurations } = useAccountModals();
|
|
24
22
|
const handleLogoClick = onLogoClick ?? (() => router.push("/"));
|
|
25
23
|
const handleAppIconClick = () => router.push(appIconHref);
|
|
24
|
+
const isGpagesActive = activeApp === "gpages";
|
|
26
25
|
return /* @__PURE__ */ jsxs(
|
|
27
26
|
NavBar,
|
|
28
27
|
{
|
|
29
28
|
onLogoClick: handleLogoClick,
|
|
30
|
-
logoIndicatorClassName,
|
|
29
|
+
logoIndicatorClassName: isGpagesActive ? "opacity-0" : void 0,
|
|
31
30
|
showExpandButton,
|
|
32
31
|
onExpandClick,
|
|
33
32
|
appIconSlot: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
34
33
|
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
35
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, onClick: handleAppIconClick, children: /* @__PURE__ */ jsx(
|
|
34
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, onClick: handleAppIconClick, children: isGpagesActive ? /* @__PURE__ */ jsx(
|
|
36
35
|
"div",
|
|
37
36
|
{
|
|
38
|
-
className:
|
|
39
|
-
|
|
37
|
+
className: "size-10 rounded-xl cursor-pointer p-[2px]",
|
|
38
|
+
style: {
|
|
39
|
+
border: "1.5px solid rgba(153,234,255,0.75)",
|
|
40
|
+
background: "white",
|
|
41
|
+
boxShadow: "0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)"
|
|
42
|
+
},
|
|
43
|
+
children: /* @__PURE__ */ jsx(
|
|
44
|
+
"div",
|
|
45
|
+
{
|
|
46
|
+
className: "w-full h-full rounded-lg flex items-center justify-center",
|
|
47
|
+
style: {
|
|
48
|
+
background: "radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)"
|
|
49
|
+
},
|
|
50
|
+
children: /* @__PURE__ */ jsx(Image, { src: "/icons/icon-navbar.svg", alt: "GreatPages", width: 24, height: 24 })
|
|
51
|
+
}
|
|
52
|
+
)
|
|
40
53
|
}
|
|
41
|
-
) }),
|
|
54
|
+
) : /* @__PURE__ */ jsx("div", { className: "size-10 flex items-center justify-center rounded-lg cursor-pointer hover:bg-pages-50 transition-colors duration-300", children: /* @__PURE__ */ jsx(Image, { src: "/icons/icon-navbar.svg", alt: "GreatPages", width: 24, height: 24 }) }) }),
|
|
42
55
|
/* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "GreatPages" })
|
|
43
56
|
] }),
|
|
44
57
|
/* @__PURE__ */ jsx(
|
|
45
58
|
"div",
|
|
46
59
|
{
|
|
47
|
-
className: `absolute -left-4 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-pages-
|
|
60
|
+
className: `absolute -left-4 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-pages-500 rounded-r-xl transition-opacity duration-300 ${isGpagesActive ? "opacity-100" : "opacity-0"}`
|
|
48
61
|
}
|
|
49
62
|
)
|
|
50
63
|
] }),
|
|
51
64
|
children: [
|
|
52
|
-
/* @__PURE__ */ jsx(
|
|
53
|
-
NotificationsPopover,
|
|
54
|
-
{
|
|
55
|
-
onViewAll: onNotificationsViewAll
|
|
56
|
-
}
|
|
57
|
-
),
|
|
65
|
+
/* @__PURE__ */ jsx(NotificationsPopover, { onViewAll: onNotificationsViewAll }),
|
|
58
66
|
/* @__PURE__ */ jsx(
|
|
59
67
|
ProfilePopover,
|
|
60
68
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/layouts/AppNavBar.tsx"],"sourcesContent":["'use client';\n\nimport Image from 'next/image';\nimport { useRouter } from 'next/navigation';\nimport { NavBar } from './NavBar';\nimport { ProfilePopover } from './ProfilePopover';\nimport { NotificationsPopover } from './NotificationsPopover';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\nimport { useAccountModals } from '../../store/useAccountModals';\nimport type { ProfileMenuItem } from './ProfilePopover';\n\nexport interface AppNavBarProps {\n onLogoClick?: () => void;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/AppNavBar.tsx"],"sourcesContent":["'use client';\n\nimport Image from 'next/image';\nimport { useRouter } from 'next/navigation';\nimport { NavBar } from './NavBar';\nimport { ProfilePopover } from './ProfilePopover';\nimport { NotificationsPopover } from './NotificationsPopover';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\nimport { useAccountModals } from '../../store/useAccountModals';\nimport type { ProfileMenuItem } from './ProfilePopover';\n\nexport interface AppNavBarProps {\n onLogoClick?: () => void;\n /** Which app is currently active — controls which icon gets the indicator */\n activeApp?: 'gapps' | 'gpages';\n appIconHref?: string;\n showExpandButton?: boolean;\n onExpandClick?: () => void;\n menuItems?: ProfileMenuItem[];\n onCreditsClick?: () => void;\n onNotificationsViewAll?: () => void;\n}\n\nexport function AppNavBar({\n onLogoClick,\n activeApp,\n appIconHref = '/',\n showExpandButton = false,\n onExpandClick,\n menuItems = [],\n onCreditsClick,\n onNotificationsViewAll,\n}: AppNavBarProps) {\n const router = useRouter();\n const { openConfigurations } = useAccountModals();\n\n const handleLogoClick = onLogoClick ?? (() => router.push('/'));\n const handleAppIconClick = () => router.push(appIconHref);\n\n const isGpagesActive = activeApp === 'gpages';\n\n return (\n <NavBar\n onLogoClick={handleLogoClick}\n logoIndicatorClassName={isGpagesActive ? 'opacity-0' : undefined}\n showExpandButton={showExpandButton}\n onExpandClick={onExpandClick}\n appIconSlot={\n <div className=\"relative\">\n <Tooltip>\n <TooltipTrigger asChild onClick={handleAppIconClick}>\n {isGpagesActive ? (\n <div\n className=\"size-10 rounded-xl cursor-pointer p-[2px]\"\n style={{\n border: '1.5px solid rgba(153,234,255,0.75)',\n background: 'white',\n boxShadow: '0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)',\n }}\n >\n <div\n className=\"w-full h-full rounded-lg flex items-center justify-center\"\n style={{\n background: 'radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)',\n }}\n >\n <Image src=\"/icons/icon-navbar.svg\" alt=\"GreatPages\" width={24} height={24} />\n </div>\n </div>\n ) : (\n <div className=\"size-10 flex items-center justify-center rounded-lg cursor-pointer hover:bg-pages-50 transition-colors duration-300\">\n <Image src=\"/icons/icon-navbar.svg\" alt=\"GreatPages\" width={24} height={24} />\n </div>\n )}\n </TooltipTrigger>\n <TooltipContent side=\"right\">GreatPages</TooltipContent>\n </Tooltip>\n <div\n className={`absolute -left-4 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-pages-500 rounded-r-xl transition-opacity duration-300 ${\n isGpagesActive ? 'opacity-100' : 'opacity-0'\n }`}\n />\n </div>\n }\n >\n <NotificationsPopover onViewAll={onNotificationsViewAll} />\n <ProfilePopover\n onEditProfile={() => openConfigurations()}\n onCreditsClick={onCreditsClick}\n menuItems={menuItems}\n />\n </NavBar>\n );\n}\n"],"mappings":";AAiDU,SAiBU,KAjBV;AA/CV,OAAO,WAAW;AAClB,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,4BAA4B;AACrC,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,wBAAwB;AAe1B,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB;AAAA,EACA,YAAY,CAAC;AAAA,EACb;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,mBAAmB,IAAI,iBAAiB;AAEhD,QAAM,kBAAkB,gBAAgB,MAAM,OAAO,KAAK,GAAG;AAC7D,QAAM,qBAAqB,MAAM,OAAO,KAAK,WAAW;AAExD,QAAM,iBAAiB,cAAc;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAa;AAAA,MACb,wBAAwB,iBAAiB,cAAc;AAAA,MACvD;AAAA,MACA;AAAA,MACA,aACE,qBAAC,SAAI,WAAU,YACb;AAAA,6BAAC,WACC;AAAA,8BAAC,kBAAe,SAAO,MAAC,SAAS,oBAC9B,2BACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,QAAQ;AAAA,gBACR,YAAY;AAAA,gBACZ,WAAW;AAAA,cACb;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,OAAO;AAAA,oBACL,YAAY;AAAA,kBACd;AAAA,kBAEA,8BAAC,SAAM,KAAI,0BAAyB,KAAI,cAAa,OAAO,IAAI,QAAQ,IAAI;AAAA;AAAA,cAC9E;AAAA;AAAA,UACF,IAEA,oBAAC,SAAI,WAAU,uHACb,8BAAC,SAAM,KAAI,0BAAyB,KAAI,cAAa,OAAO,IAAI,QAAQ,IAAI,GAC9E,GAEJ;AAAA,UACA,oBAAC,kBAAe,MAAK,SAAQ,wBAAU;AAAA,WACzC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,mHACT,iBAAiB,gBAAgB,WACnC;AAAA;AAAA,QACF;AAAA,SACF;AAAA,MAGF;AAAA,4BAAC,wBAAqB,WAAW,wBAAwB;AAAA,QACzD;AAAA,UAAC;AAAA;AAAA,YACC,eAAe,MAAM,mBAAmB;AAAA,YACxC;AAAA,YACA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -82,7 +82,7 @@ class AuthService {
|
|
|
82
82
|
await this.setAuthCookie(response.data.cookie);
|
|
83
83
|
return { status: 1 };
|
|
84
84
|
}
|
|
85
|
-
async register(data,
|
|
85
|
+
async register(data, _clientInfo) {
|
|
86
86
|
const today = /* @__PURE__ */ new Date();
|
|
87
87
|
const trialEndDate = new Date(today);
|
|
88
88
|
trialEndDate.setDate(today.getDate() + 7);
|
|
@@ -131,18 +131,27 @@ class AuthService {
|
|
|
131
131
|
500
|
|
132
132
|
);
|
|
133
133
|
}
|
|
134
|
+
if (!response.cookie) {
|
|
135
|
+
throw new ApiError(
|
|
136
|
+
"Resposta de autentica\xE7\xE3o inv\xE1lida",
|
|
137
|
+
"INVALID_RESPONSE",
|
|
138
|
+
500
|
|
139
|
+
);
|
|
140
|
+
}
|
|
134
141
|
const accountData = response.data[0];
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const account =
|
|
141
|
-
|
|
142
|
+
await this.setAuthCookie(response.cookie);
|
|
143
|
+
const [{ userService }, { accountService }] = await Promise.all([
|
|
144
|
+
import("../../users/services/user.service"),
|
|
145
|
+
import("../../accounts/services/account.service")
|
|
146
|
+
]);
|
|
147
|
+
const [user, account] = await Promise.all([
|
|
148
|
+
userService.findById(),
|
|
149
|
+
accountService.findCurrentAccount()
|
|
150
|
+
]);
|
|
142
151
|
return {
|
|
143
152
|
user,
|
|
144
153
|
account,
|
|
145
|
-
accessToken,
|
|
154
|
+
accessToken: response.cookie,
|
|
146
155
|
refreshToken: "",
|
|
147
156
|
expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1e3).toISOString(),
|
|
148
157
|
requiresEmailVerification: !accountData.verified
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["import { cookies } from \"next/headers\";\r\n\r\nimport { api } from \"../../../infra/api/client\";\r\nimport { ApiError } from \"../../../infra/api/types\";\r\nimport { User } from \"../../users/schema\";\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from \"../schema\";\r\n\r\nconst AUTH_COOKIE_NAME = \"greatapps\";\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === \"production\",\r\n sameSite: \"lax\" as const,\r\n path: \"/\",\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nclass AuthService {\r\n async login(\r\n credentials: LoginRequest,\r\n clientInfo: ClientInfo\r\n ): Promise<LoginResponse> {\r\n const response = await api.apps.post<LoginApiResponse>(\"/auth/login\", {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n console.log(\"[AuthService.login] response\", JSON.stringify(response));\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"E-mail ou senha incorretos\",\r\n response.code || \"LOGIN_FAILED\",\r\n 401\r\n );\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n if (response.two_factor_required) {\r\n return { result: 'two_factor_required', cookie: response.cookie };\r\n }\r\n\r\n await this.setAuthCookie(response.cookie);\r\n\r\n const [{ userService }, { accountService }] = await Promise.all([\r\n import('../../users/services/user.service'),\r\n import('../../accounts/services/account.service'),\r\n ]);\r\n const [user, account] = await Promise.all([\r\n userService.findById(),\r\n accountService.findCurrentAccount(),\r\n ]);\r\n\r\n return {\r\n result: 'success',\r\n user,\r\n account,\r\n accessToken: response.cookie,\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(\r\n cookie: string,\r\n code: string,\r\n clientInfo: ClientInfo\r\n ): Promise<TwoFactorResponse> {\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n code,\r\n };\r\n\r\n const response = await api.apps.post<TwoFactorApiResponse>(\r\n \"/auth/code\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\"Código 2FA inválido\", \"TWO_FACTOR_FAILED\", 401);\r\n }\r\n\r\n if (!response?.data?.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida após 2FA\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n await this.setAuthCookie(response.data.cookie);\r\n\r\n return { status: 1 };\r\n }\r\n async register(data: RegisterRequest, clientInfo: ClientInfo): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: \"pt-br\",\r\n timezone: \"America/Sao_Paulo\",\r\n currency: \"BRL\",\r\n user: {\r\n id_api: \"\",\r\n name: data.name,\r\n last_name: data.lastName || \"\",\r\n rg: data.rg || \"\",\r\n cpf: data.cpf || \"\",\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: \"owner\",\r\n language: \"pt-br\",\r\n },\r\n subscription: {\r\n type: \"trial\",\r\n id_cupom: \"\",\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split(\"T\")[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await api.apps.post<RegisterApiResponse>(\r\n \"/accounts\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao criar conta\",\r\n \"REGISTER_FAILED\",\r\n 400\r\n );\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError(\r\n \"Resposta de registro inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n const loginResult = await this.login(\r\n { email: data.email, password: data.password },\r\n clientInfo\r\n );\r\n\r\n const user = loginResult.result === 'success' ? loginResult.user : {} as User;\r\n const account = loginResult.result === 'success' ? loginResult.account : {} as import('../../accounts/types').Account;\r\n const accessToken = loginResult.result === 'success' ? loginResult.accessToken : \"\";\r\n\r\n return {\r\n user,\r\n account,\r\n accessToken,\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n throw new ApiError(\r\n \"Usuário não autenticado\",\r\n \"NOT_AUTHENTICATED_LOGOUT\",\r\n 401\r\n );\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await api.apps.post<LogoutApiResponse>(\r\n \"/auth/logout\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao realizar logout\",\r\n response.code || \"LOGOUT_FAILED\",\r\n 400\r\n );\r\n }\r\n } finally {\r\n await this.removeAuthCookie();\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(\r\n _data: ForgotPasswordRequest\r\n ): Promise<ForgotPasswordResponse> {\r\n throw new ApiError(\r\n \"Recuperação de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resetPassword(\r\n _data: ResetPasswordRequest\r\n ): Promise<ResetPasswordResponse> {\r\n throw new ApiError(\r\n \"Redefinição de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError(\r\n \"Verificação de email não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resendVerification(\r\n _data: ResendVerificationRequest\r\n ): Promise<ResendVerificationResponse> {\r\n throw new ApiError(\r\n \"Reenvio de verificação não implementado\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await api.apps.post<SessionKeepResponse>(\r\n \"/auth/keep\",\r\n payload\r\n );\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error(\"[AuthService] validateSession error\", error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await this.getToken();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n }\r\n\r\n private async setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, {\r\n ...COOKIE_OPTIONS,\r\n maxAge: COOKIE_MAX_AGE,\r\n });\r\n }\r\n\r\n async removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({\r\n name: AUTH_COOKIE_NAME,\r\n ...COOKIE_OPTIONS,\r\n });\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"AAAA,SAAS,eAAe;AAExB,SAAS,WAAW;AACpB,SAAS,gBAAgB;AA8BzB,MAAM,mBAAmB;AACzB,MAAM,iBAAiB,KAAK,KAAK,KAAK;AAEtC,MAAM,iBAAiB;AAAA,EACrB,UAAU;AAAA,EACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,EACjC,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ,QAAQ,IAAI;AACtB;AAEA,MAAM,YAAY;AAAA,EAChB,MAAM,MACJ,aACA,YACwB;AACxB,UAAM,WAAW,MAAM,IAAI,KAAK,KAAuB,eAAe;AAAA,MACpE,OAAO,YAAY;AAAA,MACnB,UAAU,YAAY;AAAA,MACtB,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,IACpB,CAAC;AAED,YAAQ,IAAI,gCAAgC,KAAK,UAAU,QAAQ,CAAC;AAEpE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,QAAQ;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,qBAAqB;AAChC,aAAO,EAAE,QAAQ,uBAAuB,QAAQ,SAAS,OAAO;AAAA,IAClE;AAEA,UAAM,KAAK,cAAc,SAAS,MAAM;AAExC,UAAM,CAAC,EAAE,YAAY,GAAG,EAAE,eAAe,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC9D,OAAO,mCAAmC;AAAA,MAC1C,OAAO,yCAAyC;AAAA,IAClD,CAAC;AACD,UAAM,CAAC,MAAM,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MACxC,YAAY,SAAS;AAAA,MACrB,eAAe,mBAAmB;AAAA,IACpC,CAAC;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,aAAa,SAAS;AAAA,MACtB,cAAc;AAAA,MACd,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,GAAI,EAAE,YAAY;AAAA,IACtE;AAAA,EACF;AAAA,EAEA,MAAM,gBACJ,QACA,MACA,YAC4B;AAC5B,UAAM,UAA4B;AAAA,MAChC,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B;AAAA,MACA;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,SAAS,6BAAuB,qBAAqB,GAAG;AAAA,IACpE;AAEA,QAAI,CAAC,UAAU,MAAM,QAAQ;AAC3B,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK,cAAc,SAAS,KAAK,MAAM;AAE7C,WAAO,EAAE,QAAQ,EAAE;AAAA,EACrB;AAAA,EACA,MAAM,SAAS,MAAuB,YAAmD;AACvF,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,eAAe,IAAI,KAAK,KAAK;AACnC,iBAAa,QAAQ,MAAM,QAAQ,IAAI,CAAC;AAExC,UAAM,UAA8B;AAAA,MAClC,MAAM,KAAK;AAAA,MACX,gBAAgB,KAAK;AAAA,MACrB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,QACJ,QAAQ;AAAA,QACR,MAAM,KAAK;AAAA,QACX,WAAW,KAAK,YAAY;AAAA,QAC5B,IAAI,KAAK,MAAM;AAAA,QACf,KAAK,KAAK,OAAO;AAAA,QACjB,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK;AAAA,QACZ,UAAU,KAAK;AAAA,QACf,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,MACA,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,aAAa,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QACjD,YAAY;AAAA,MACd;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B;AAAA,MACA;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,WAAW,GAAG;AAChD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,cAAc,SAAS,KAAK,CAAC;AAEnC,UAAM,cAAc,MAAM,KAAK;AAAA,MAC7B,EAAE,OAAO,KAAK,OAAO,UAAU,KAAK,SAAS;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,OAAO,YAAY,WAAW,YAAY,YAAY,OAAO,CAAC;AACpE,UAAM,UAAU,YAAY,WAAW,YAAY,YAAY,UAAU,CAAC;AAC1E,UAAM,cAAc,YAAY,WAAW,YAAY,YAAY,cAAc;AAEjF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,GAAI,EAAE,YAAY;AAAA,MACpE,2BAA2B,CAAC,YAAY;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,YAAiD;AAC5D,UAAM,SAAS,MAAM,KAAK,SAAS;AAEnC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAyB;AAAA,MAC7B,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,MAClB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,IAAI,KAAK;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AAEA,UAAI,SAAS,WAAW,GAAG;AACzB,cAAM,IAAI;AAAA,UACR,SAAS,WAAW;AAAA,UACpB,SAAS,QAAQ;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,YAAM,KAAK,iBAAiB;AAAA,IAC9B;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OACiC;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,OACgC;AAChC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAyD;AACzE,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,OACqC;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,YAA0C;AAC9D,UAAM,SAAS,MAAM,KAAK,SAAS;AAEnC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,UAA8B;AAAA,QAClC,UAAU,WAAW;AAAA,QACrB,IAAI,WAAW;AAAA,QACf,UAAU,WAAW;AAAA,QACrB,OAAO,WAAW;AAAA,QAClB;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,IAAI,KAAK;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AAEA,aAAO,SAAS,WAAW;AAAA,IAC7B,SAAS,OAAO;AACd,cAAQ,MAAM,uCAAuC,KAAK;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,kBAAoC;AACxC,UAAM,QAAQ,MAAM,KAAK,SAAS;AAClC,WAAO,CAAC,CAAC;AAAA,EACX;AAAA,EAEA,MAAM,WAAwC;AAC5C,QAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,UAAM,cAAc,MAAM,QAAQ;AAClC,WAAO,YAAY,IAAI,gBAAgB,GAAG;AAAA,EAC5C;AAAA,EAEA,MAAc,cAAc,OAA8B;AACxD,UAAM,cAAc,MAAM,QAAQ;AAClC,gBAAY,IAAI,kBAAkB,OAAO;AAAA,MACvC,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,mBAAkC;AACtC,UAAM,cAAc,MAAM,QAAQ;AAClC,gBAAY,OAAO;AAAA,MACjB,MAAM;AAAA,MACN,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["import { cookies } from \"next/headers\";\r\n\r\nimport { api } from \"../../../infra/api/client\";\r\nimport { ApiError } from \"../../../infra/api/types\";\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from \"../schema\";\r\n\r\nconst AUTH_COOKIE_NAME = \"greatapps\";\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === \"production\",\r\n sameSite: \"lax\" as const,\r\n path: \"/\",\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nclass AuthService {\r\n async login(\r\n credentials: LoginRequest,\r\n clientInfo: ClientInfo\r\n ): Promise<LoginResponse> {\r\n const response = await api.apps.post<LoginApiResponse>(\"/auth/login\", {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n console.log(\"[AuthService.login] response\", JSON.stringify(response));\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"E-mail ou senha incorretos\",\r\n response.code || \"LOGIN_FAILED\",\r\n 401\r\n );\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n if (response.two_factor_required) {\r\n return { result: 'two_factor_required', cookie: response.cookie };\r\n }\r\n\r\n await this.setAuthCookie(response.cookie);\r\n\r\n const [{ userService }, { accountService }] = await Promise.all([\r\n import('../../users/services/user.service'),\r\n import('../../accounts/services/account.service'),\r\n ]);\r\n const [user, account] = await Promise.all([\r\n userService.findById(),\r\n accountService.findCurrentAccount(),\r\n ]);\r\n\r\n return {\r\n result: 'success',\r\n user,\r\n account,\r\n accessToken: response.cookie,\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(\r\n cookie: string,\r\n code: string,\r\n clientInfo: ClientInfo\r\n ): Promise<TwoFactorResponse> {\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n code,\r\n };\r\n\r\n const response = await api.apps.post<TwoFactorApiResponse>(\r\n \"/auth/code\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\"Código 2FA inválido\", \"TWO_FACTOR_FAILED\", 401);\r\n }\r\n\r\n if (!response?.data?.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida após 2FA\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n await this.setAuthCookie(response.data.cookie);\r\n\r\n return { status: 1 };\r\n }\r\n async register(data: RegisterRequest, _clientInfo: ClientInfo): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: \"pt-br\",\r\n timezone: \"America/Sao_Paulo\",\r\n currency: \"BRL\",\r\n user: {\r\n id_api: \"\",\r\n name: data.name,\r\n last_name: data.lastName || \"\",\r\n rg: data.rg || \"\",\r\n cpf: data.cpf || \"\",\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: \"owner\",\r\n language: \"pt-br\",\r\n },\r\n subscription: {\r\n type: \"trial\",\r\n id_cupom: \"\",\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split(\"T\")[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await api.apps.post<RegisterApiResponse>(\r\n \"/accounts\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao criar conta\",\r\n \"REGISTER_FAILED\",\r\n 400\r\n );\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError(\r\n \"Resposta de registro inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n await this.setAuthCookie(response.cookie);\r\n\r\n const [{ userService }, { accountService }] = await Promise.all([\r\n import('../../users/services/user.service'),\r\n import('../../accounts/services/account.service'),\r\n ]);\r\n const [user, account] = await Promise.all([\r\n userService.findById(),\r\n accountService.findCurrentAccount(),\r\n ]);\r\n\r\n return {\r\n user,\r\n account,\r\n accessToken: response.cookie,\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n throw new ApiError(\r\n \"Usuário não autenticado\",\r\n \"NOT_AUTHENTICATED_LOGOUT\",\r\n 401\r\n );\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await api.apps.post<LogoutApiResponse>(\r\n \"/auth/logout\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao realizar logout\",\r\n response.code || \"LOGOUT_FAILED\",\r\n 400\r\n );\r\n }\r\n } finally {\r\n await this.removeAuthCookie();\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(\r\n _data: ForgotPasswordRequest\r\n ): Promise<ForgotPasswordResponse> {\r\n throw new ApiError(\r\n \"Recuperação de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resetPassword(\r\n _data: ResetPasswordRequest\r\n ): Promise<ResetPasswordResponse> {\r\n throw new ApiError(\r\n \"Redefinição de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError(\r\n \"Verificação de email não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resendVerification(\r\n _data: ResendVerificationRequest\r\n ): Promise<ResendVerificationResponse> {\r\n throw new ApiError(\r\n \"Reenvio de verificação não implementado\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await api.apps.post<SessionKeepResponse>(\r\n \"/auth/keep\",\r\n payload\r\n );\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error(\"[AuthService] validateSession error\", error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await this.getToken();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n }\r\n\r\n private async setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, {\r\n ...COOKIE_OPTIONS,\r\n maxAge: COOKIE_MAX_AGE,\r\n });\r\n }\r\n\r\n async removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({\r\n name: AUTH_COOKIE_NAME,\r\n ...COOKIE_OPTIONS,\r\n });\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -8,11 +8,8 @@ import type { ProfileMenuItem } from './ProfilePopover';
|
|
|
8
8
|
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';
|
|
9
9
|
|
|
10
10
|
export interface AppMobileNavBarProps {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
appIconIndicator?: boolean;
|
|
14
|
-
/** Shows the gray indicator bar below the GreatApps logo */
|
|
15
|
-
logoIndicator?: boolean;
|
|
11
|
+
/** Which app is currently active — controls which icon gets the indicator */
|
|
12
|
+
activeApp?: 'gapps' | 'gpages';
|
|
16
13
|
/** Called when the GreatApps logo is clicked */
|
|
17
14
|
onLogoClick?: () => void;
|
|
18
15
|
/** Called when the app icon (e.g. GreatPages) is clicked */
|
|
@@ -26,9 +23,7 @@ export interface AppMobileNavBarProps {
|
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
export function AppMobileNavBar({
|
|
29
|
-
|
|
30
|
-
appIconIndicator = false,
|
|
31
|
-
logoIndicator = false,
|
|
26
|
+
activeApp,
|
|
32
27
|
onLogoClick,
|
|
33
28
|
onAppIconClick,
|
|
34
29
|
extraLeftSlot,
|
|
@@ -38,6 +33,9 @@ export function AppMobileNavBar({
|
|
|
38
33
|
}: AppMobileNavBarProps) {
|
|
39
34
|
const { openConfigurations } = useAccountModals();
|
|
40
35
|
|
|
36
|
+
const isGpagesActive = activeApp === 'gpages';
|
|
37
|
+
const isGappsActive = activeApp === 'gapps';
|
|
38
|
+
|
|
41
39
|
return (
|
|
42
40
|
<div className="fixed top-0 left-0 right-0 flex md:hidden items-center justify-between p-4 bg-white z-50 border-b border-gray-200">
|
|
43
41
|
<div className="flex items-center gap-1.5">
|
|
@@ -48,7 +46,7 @@ export function AppMobileNavBar({
|
|
|
48
46
|
onClick={onLogoClick}
|
|
49
47
|
>
|
|
50
48
|
<Image src="/icons/great-icon.svg" alt="GreatApps" width={28} height={28} />
|
|
51
|
-
{
|
|
49
|
+
{isGappsActive && (
|
|
52
50
|
<div className="absolute bottom-[-17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-gray-950 rounded-t-xl" />
|
|
53
51
|
)}
|
|
54
52
|
</div>
|
|
@@ -58,18 +56,37 @@ export function AppMobileNavBar({
|
|
|
58
56
|
<div className="relative">
|
|
59
57
|
<Tooltip>
|
|
60
58
|
<TooltipTrigger asChild>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
{isGpagesActive ? (
|
|
60
|
+
<div
|
|
61
|
+
className="size-10 rounded-xl cursor-pointer p-[2px]"
|
|
62
|
+
style={{
|
|
63
|
+
border: '1.5px solid rgba(153,234,255,0.75)',
|
|
64
|
+
background: 'white',
|
|
65
|
+
boxShadow: '0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)',
|
|
66
|
+
}}
|
|
67
|
+
onClick={onAppIconClick}
|
|
68
|
+
>
|
|
69
|
+
<div
|
|
70
|
+
className="w-full h-full rounded-lg flex items-center justify-center"
|
|
71
|
+
style={{
|
|
72
|
+
background: 'radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)',
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
) : (
|
|
79
|
+
<div
|
|
80
|
+
className={`size-10 flex items-center justify-center rounded-lg transition-colors duration-300 bg-pages-50 ${onAppIconClick ? 'cursor-pointer hover:opacity-80' : ''}`}
|
|
81
|
+
onClick={onAppIconClick}
|
|
82
|
+
>
|
|
83
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
69
86
|
</TooltipTrigger>
|
|
70
87
|
<TooltipContent side="bottom">GreatPages</TooltipContent>
|
|
71
88
|
</Tooltip>
|
|
72
|
-
{
|
|
89
|
+
{isGpagesActive && (
|
|
73
90
|
<div className="absolute -bottom-[17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-pages-500 rounded-t-xl" />
|
|
74
91
|
)}
|
|
75
92
|
</div>
|
|
@@ -11,11 +11,9 @@ import type { ProfileMenuItem } from './ProfilePopover';
|
|
|
11
11
|
|
|
12
12
|
export interface AppNavBarProps {
|
|
13
13
|
onLogoClick?: () => void;
|
|
14
|
-
|
|
14
|
+
/** Which app is currently active — controls which icon gets the indicator */
|
|
15
|
+
activeApp?: 'gapps' | 'gpages';
|
|
15
16
|
appIconHref?: string;
|
|
16
|
-
appIconActive?: boolean;
|
|
17
|
-
/** Controls the left-side indicator bar on the app icon (opacity transition) */
|
|
18
|
-
appIconIndicator?: boolean;
|
|
19
17
|
showExpandButton?: boolean;
|
|
20
18
|
onExpandClick?: () => void;
|
|
21
19
|
menuItems?: ProfileMenuItem[];
|
|
@@ -25,10 +23,8 @@ export interface AppNavBarProps {
|
|
|
25
23
|
|
|
26
24
|
export function AppNavBar({
|
|
27
25
|
onLogoClick,
|
|
28
|
-
|
|
26
|
+
activeApp,
|
|
29
27
|
appIconHref = '/',
|
|
30
|
-
appIconActive = false,
|
|
31
|
-
appIconIndicator = false,
|
|
32
28
|
showExpandButton = false,
|
|
33
29
|
onExpandClick,
|
|
34
30
|
menuItems = [],
|
|
@@ -41,39 +37,53 @@ export function AppNavBar({
|
|
|
41
37
|
const handleLogoClick = onLogoClick ?? (() => router.push('/'));
|
|
42
38
|
const handleAppIconClick = () => router.push(appIconHref);
|
|
43
39
|
|
|
40
|
+
const isGpagesActive = activeApp === 'gpages';
|
|
41
|
+
|
|
44
42
|
return (
|
|
45
43
|
<NavBar
|
|
46
44
|
onLogoClick={handleLogoClick}
|
|
47
|
-
logoIndicatorClassName={
|
|
45
|
+
logoIndicatorClassName={isGpagesActive ? 'opacity-0' : undefined}
|
|
48
46
|
showExpandButton={showExpandButton}
|
|
49
47
|
onExpandClick={onExpandClick}
|
|
50
48
|
appIconSlot={
|
|
51
49
|
<div className="relative">
|
|
52
50
|
<Tooltip>
|
|
53
51
|
<TooltipTrigger asChild onClick={handleAppIconClick}>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
: '
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
{isGpagesActive ? (
|
|
53
|
+
<div
|
|
54
|
+
className="size-10 rounded-xl cursor-pointer p-[2px]"
|
|
55
|
+
style={{
|
|
56
|
+
border: '1.5px solid rgba(153,234,255,0.75)',
|
|
57
|
+
background: 'white',
|
|
58
|
+
boxShadow: '0 0 8px rgba(153,234,255,0.5), 0 0 18px rgba(153,234,255,0.2)',
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
<div
|
|
62
|
+
className="w-full h-full rounded-lg flex items-center justify-center"
|
|
63
|
+
style={{
|
|
64
|
+
background: 'radial-gradient(circle at center, rgba(255,255,255,0.95) 0%, rgba(153,234,255,0.45) 100%)',
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
) : (
|
|
71
|
+
<div className="size-10 flex items-center justify-center rounded-lg cursor-pointer hover:bg-pages-50 transition-colors duration-300">
|
|
72
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
63
75
|
</TooltipTrigger>
|
|
64
76
|
<TooltipContent side="right">GreatPages</TooltipContent>
|
|
65
77
|
</Tooltip>
|
|
66
78
|
<div
|
|
67
79
|
className={`absolute -left-4 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-pages-500 rounded-r-xl transition-opacity duration-300 ${
|
|
68
|
-
|
|
80
|
+
isGpagesActive ? 'opacity-100' : 'opacity-0'
|
|
69
81
|
}`}
|
|
70
82
|
/>
|
|
71
83
|
</div>
|
|
72
84
|
}
|
|
73
85
|
>
|
|
74
|
-
<NotificationsPopover
|
|
75
|
-
onViewAll={onNotificationsViewAll}
|
|
76
|
-
/>
|
|
86
|
+
<NotificationsPopover onViewAll={onNotificationsViewAll} />
|
|
77
87
|
<ProfilePopover
|
|
78
88
|
onEditProfile={() => openConfigurations()}
|
|
79
89
|
onCreditsClick={onCreditsClick}
|