@greatapps/common 1.1.785 → 1.1.787
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 +64 -5
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/AppNavBar.mjs +2 -0
- package/dist/components/layouts/AppNavBar.mjs.map +1 -1
- package/dist/components/layouts/GreatDomainIcon.mjs +40 -0
- package/dist/components/layouts/GreatDomainIcon.mjs.map +1 -0
- package/dist/components/layouts/NavBar.mjs +111 -52
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/ui/form/PhoneInput.mjs +1 -1
- package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
- package/dist/handlers.mjs +2 -0
- package/dist/handlers.mjs.map +1 -1
- package/dist/i18n/messages/en-us.mjs +3 -1
- package/dist/i18n/messages/en-us.mjs.map +1 -1
- package/dist/i18n/messages/es-es.mjs +3 -1
- package/dist/i18n/messages/es-es.mjs.map +1 -1
- package/dist/i18n/messages/pt-br.mjs +3 -1
- package/dist/i18n/messages/pt-br.mjs.map +1 -1
- package/dist/index.mjs +11 -2
- package/dist/index.mjs.map +1 -1
- package/dist/infra/api/client.mjs +5 -1
- package/dist/infra/api/client.mjs.map +1 -1
- package/dist/infra/api/types.mjs +1 -1
- package/dist/infra/api/types.mjs.map +1 -1
- package/dist/infra/route/safe-route-handler.mjs +4 -1
- package/dist/infra/route/safe-route-handler.mjs.map +1 -1
- package/dist/middlewares/create-auth-middleware.mjs +11 -1
- package/dist/middlewares/create-auth-middleware.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-account-not-frozen.mjs +6 -5
- package/dist/modules/auth/utils/assert-account-not-frozen.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-management-subscription.mjs +7 -14
- package/dist/modules/auth/utils/assert-management-subscription.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-paid-subscription.mjs +7 -12
- package/dist/modules/auth/utils/assert-paid-subscription.mjs.map +1 -1
- package/dist/modules/auth/utils/assert-subscription-addon.mjs +2 -10
- package/dist/modules/auth/utils/assert-subscription-addon.mjs.map +1 -1
- package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs +10 -0
- package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs.map +1 -0
- package/dist/modules/subscriptions/constants/subscription.constants.mjs +2 -0
- package/dist/modules/subscriptions/constants/subscription.constants.mjs.map +1 -1
- package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs +17 -0
- package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs.map +1 -0
- package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs +2 -13
- package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs +28 -0
- package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs.map +1 -0
- package/dist/modules/subscriptions/services/subscriptions.service.mjs +26 -0
- package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
- package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs +16 -0
- package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs.map +1 -0
- package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs +1 -1
- package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/has-paid-subscription.mjs +1 -1
- package/dist/modules/subscriptions/utils/has-paid-subscription.mjs.map +1 -1
- package/dist/modules/subscriptions/utils/read-current-subscription.mjs +21 -0
- package/dist/modules/subscriptions/utils/read-current-subscription.mjs.map +1 -0
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs +9 -6
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
- package/dist/modules/whitelabel/services/whitelabel.service.mjs +28 -2
- package/dist/modules/whitelabel/services/whitelabel.service.mjs.map +1 -1
- package/dist/providers/auth.provider.mjs +12 -9
- package/dist/providers/auth.provider.mjs.map +1 -1
- package/dist/server.mjs +4 -0
- package/dist/server.mjs.map +1 -1
- package/dist/store/useMdSidebarStore.mjs +17 -4
- package/dist/store/useMdSidebarStore.mjs.map +1 -1
- package/dist/utils/redirect.mjs +10 -0
- package/dist/utils/redirect.mjs.map +1 -1
- package/dist/utils/safeServerAction.mjs +4 -1
- package/dist/utils/safeServerAction.mjs.map +1 -1
- package/dist/utils/withAction.mjs +2 -1
- package/dist/utils/withAction.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/AppMobileNavBar.tsx +90 -6
- package/src/components/layouts/AppNavBar.tsx +5 -1
- package/src/components/layouts/GreatDomainIcon.tsx +43 -0
- package/src/components/layouts/NavBar.tsx +160 -66
- package/src/components/ui/form/PhoneInput.tsx +1 -1
- package/src/handlers.ts +1 -0
- package/src/i18n/messages/en-us.ts +2 -0
- package/src/i18n/messages/es-es.ts +2 -0
- package/src/i18n/messages/pt-br.ts +2 -0
- package/src/index.ts +8 -2
- package/src/infra/api/client.ts +11 -3
- package/src/infra/api/types.ts +7 -5
- package/src/infra/route/safe-route-handler.ts +4 -1
- package/src/middlewares/create-auth-middleware.ts +12 -1
- package/src/modules/auth/utils/assert-account-not-frozen.ts +7 -6
- package/src/modules/auth/utils/assert-management-subscription.ts +15 -23
- package/src/modules/auth/utils/assert-paid-subscription.ts +7 -15
- package/src/modules/auth/utils/assert-subscription-addon.ts +2 -12
- package/src/modules/plans/hooks/use-plan-by-id.hook.ts +1 -1
- package/src/modules/subscriptions/actions/get-current-subscription.action.ts +8 -0
- package/src/modules/subscriptions/constants/subscription.constants.ts +3 -0
- package/src/modules/subscriptions/handlers/current-subscription.handler.ts +16 -0
- package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +7 -17
- package/src/modules/subscriptions/hooks/use-current-subscription.hook.ts +38 -0
- package/src/modules/subscriptions/services/subscriptions.service.ts +34 -0
- package/src/modules/subscriptions/types/subscription.type.ts +2 -0
- package/src/modules/subscriptions/utils/group-subscriptions-by-product.ts +23 -0
- package/src/modules/subscriptions/utils/has-active-paid-subscription.ts +1 -2
- package/src/modules/subscriptions/utils/has-paid-subscription.ts +1 -2
- package/src/modules/subscriptions/utils/read-current-subscription.ts +34 -0
- package/src/modules/whitelabel/actions/find-whitelabel.action.ts +13 -9
- package/src/modules/whitelabel/services/whitelabel.service.ts +34 -2
- package/src/providers/auth.provider.tsx +13 -10
- package/src/server.ts +2 -0
- package/src/store/useMdSidebarStore.ts +20 -5
- package/src/utils/redirect.ts +10 -0
- package/src/utils/safeServerAction.ts +4 -6
- package/src/utils/withAction.ts +2 -1
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
import Image from "next/image";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
5
6
|
import { IconMenu2, IconX } from "@tabler/icons-react";
|
|
6
7
|
import { ProfilePopover } from "./ProfilePopover";
|
|
8
|
+
import { GreatDomainIcon } from "./GreatDomainIcon";
|
|
7
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
8
10
|
import { useMobileNavbarSheet } from "../../store/useMobileNavbarSheet";
|
|
9
11
|
import {
|
|
@@ -15,11 +17,13 @@ import type { ProfileMenuItem } from "./ProfilePopover";
|
|
|
15
17
|
|
|
16
18
|
export interface AppMobileNavBarProps {
|
|
17
19
|
/** Which app is currently active — controls which icon gets the indicator */
|
|
18
|
-
activeApp?: "gapps" | "gpages";
|
|
20
|
+
activeApp?: "gapps" | "gpages" | "gdomain";
|
|
19
21
|
/** Called when the GreatApps logo is clicked */
|
|
20
22
|
onLogoClick?: () => void;
|
|
21
23
|
/** Called when the app icon (e.g. GreatPages) is clicked */
|
|
22
24
|
onAppIconClick?: () => void;
|
|
25
|
+
/** Called when the GreatDomain icon is clicked; without it the icon is not rendered (app flag) */
|
|
26
|
+
onDomainIconClick?: () => void;
|
|
23
27
|
/** Extra slot rendered after the app icon (e.g. project selector) */
|
|
24
28
|
extraLeftSlot?: ReactNode;
|
|
25
29
|
menuItems?: ProfileMenuItem[];
|
|
@@ -30,10 +34,12 @@ export function AppMobileNavBar({
|
|
|
30
34
|
activeApp,
|
|
31
35
|
onLogoClick,
|
|
32
36
|
onAppIconClick,
|
|
37
|
+
onDomainIconClick,
|
|
33
38
|
extraLeftSlot,
|
|
34
39
|
menuItems = [],
|
|
35
40
|
showMenuToggle = true,
|
|
36
41
|
}: AppMobileNavBarProps) {
|
|
42
|
+
const translate = useTranslations();
|
|
37
43
|
const { isOpen, toggle } = useMobileNavbarSheet();
|
|
38
44
|
const { whitelabel } = useWhitelabel();
|
|
39
45
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
@@ -42,6 +48,7 @@ export function AppMobileNavBar({
|
|
|
42
48
|
|
|
43
49
|
const isGappsActive = activeApp === "gapps";
|
|
44
50
|
const isGpagesActive = activeApp === "gpages";
|
|
51
|
+
const isGdomainActive = activeApp === "gdomain";
|
|
45
52
|
|
|
46
53
|
const wlIcon = whitelabel?.secondary_logo ? (
|
|
47
54
|
<Image
|
|
@@ -80,9 +87,9 @@ export function AppMobileNavBar({
|
|
|
80
87
|
|
|
81
88
|
return (
|
|
82
89
|
<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">
|
|
83
|
-
<div className="flex items-center gap-1.5">
|
|
90
|
+
<div className="flex items-center gap-1.5 min-w-0">
|
|
84
91
|
{/* GreatApps logo */}
|
|
85
|
-
<div className="relative">
|
|
92
|
+
<div className="relative shrink-0">
|
|
86
93
|
<Tooltip>
|
|
87
94
|
<TooltipTrigger asChild>
|
|
88
95
|
<div
|
|
@@ -119,7 +126,7 @@ export function AppMobileNavBar({
|
|
|
119
126
|
</div>
|
|
120
127
|
|
|
121
128
|
{/* GreatPages icon */}
|
|
122
|
-
<div className="relative">
|
|
129
|
+
<div className="relative shrink-0">
|
|
123
130
|
<Tooltip>
|
|
124
131
|
<TooltipTrigger asChild>
|
|
125
132
|
<div
|
|
@@ -187,9 +194,86 @@ export function AppMobileNavBar({
|
|
|
187
194
|
/>
|
|
188
195
|
</div>
|
|
189
196
|
|
|
190
|
-
{
|
|
197
|
+
{/* GreatDomain icon */}
|
|
198
|
+
{onDomainIconClick ? (
|
|
199
|
+
<div className="relative shrink-0">
|
|
200
|
+
<Tooltip>
|
|
201
|
+
<TooltipTrigger asChild>
|
|
202
|
+
<div
|
|
203
|
+
aria-label={
|
|
204
|
+
isDefaultWl
|
|
205
|
+
? translate("common.layout.navbar.greatDomain")
|
|
206
|
+
: translate("common.layout.navbar.domains")
|
|
207
|
+
}
|
|
208
|
+
className={cn(
|
|
209
|
+
"size-10 rounded-[10px] flex items-center justify-center border-2 ring-2 transition-colors duration-300",
|
|
210
|
+
isGdomainActive
|
|
211
|
+
? isDefaultWl
|
|
212
|
+
? "bg-[#EDE9FE] border-white ring-[#C092FF]"
|
|
213
|
+
: "border-white ring-transparent"
|
|
214
|
+
: isDefaultWl
|
|
215
|
+
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
216
|
+
: "border-transparent ring-transparent",
|
|
217
|
+
"cursor-pointer",
|
|
218
|
+
)}
|
|
219
|
+
style={
|
|
220
|
+
!isDefaultWl
|
|
221
|
+
? {
|
|
222
|
+
backgroundColor: primaryColor,
|
|
223
|
+
boxShadow: isGdomainActive
|
|
224
|
+
? `0 0 0 2px ${primaryColor}40`
|
|
225
|
+
: undefined,
|
|
226
|
+
opacity: !isGdomainActive ? 0.2 : undefined,
|
|
227
|
+
}
|
|
228
|
+
: undefined
|
|
229
|
+
}
|
|
230
|
+
onClick={onDomainIconClick}
|
|
231
|
+
>
|
|
232
|
+
{isDefaultWl ? (
|
|
233
|
+
<GreatDomainIcon active={isGdomainActive} />
|
|
234
|
+
) : (
|
|
235
|
+
<svg
|
|
236
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
237
|
+
width="24"
|
|
238
|
+
height="24"
|
|
239
|
+
viewBox="0 0 24 24"
|
|
240
|
+
fill="none"
|
|
241
|
+
stroke="white"
|
|
242
|
+
strokeWidth="2"
|
|
243
|
+
strokeLinecap="round"
|
|
244
|
+
strokeLinejoin="round"
|
|
245
|
+
>
|
|
246
|
+
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
|
|
247
|
+
<path d="M3.6 9h16.8" />
|
|
248
|
+
<path d="M3.6 15h16.8" />
|
|
249
|
+
<path d="M11.5 3a17 17 0 0 0 0 18" />
|
|
250
|
+
<path d="M12.5 3a17 17 0 0 1 0 18" />
|
|
251
|
+
</svg>
|
|
252
|
+
)}
|
|
253
|
+
</div>
|
|
254
|
+
</TooltipTrigger>
|
|
255
|
+
<TooltipContent side="bottom">
|
|
256
|
+
{isDefaultWl
|
|
257
|
+
? translate("common.layout.navbar.greatDomain")
|
|
258
|
+
: translate("common.layout.navbar.domains")}
|
|
259
|
+
</TooltipContent>
|
|
260
|
+
</Tooltip>
|
|
261
|
+
<div
|
|
262
|
+
className={cn(
|
|
263
|
+
"absolute -bottom-[17px] left-1/2 -translate-x-1/2 w-5 h-[3px] rounded-t-xl transition-opacity duration-300",
|
|
264
|
+
isDefaultWl ? "bg-[#984DFF]" : "",
|
|
265
|
+
isGdomainActive ? "opacity-100" : "opacity-0",
|
|
266
|
+
)}
|
|
267
|
+
style={!isDefaultWl ? { backgroundColor: primaryColor } : undefined}
|
|
268
|
+
/>
|
|
269
|
+
</div>
|
|
270
|
+
) : null}
|
|
271
|
+
|
|
272
|
+
{extraLeftSlot ? (
|
|
273
|
+
<div className="min-w-0 shrink [&>*]:max-w-full">{extraLeftSlot}</div>
|
|
274
|
+
) : null}
|
|
191
275
|
</div>
|
|
192
|
-
<div className="flex items-center gap-1.5">
|
|
276
|
+
<div className="flex items-center gap-1.5 shrink-0">
|
|
193
277
|
<ProfilePopover
|
|
194
278
|
side="bottom"
|
|
195
279
|
align="end"
|
|
@@ -8,8 +8,10 @@ import type { ProfileMenuItem } from "./ProfilePopover";
|
|
|
8
8
|
export interface AppNavBarProps {
|
|
9
9
|
logoHref: string;
|
|
10
10
|
appIconHref: string;
|
|
11
|
+
/** Sem href o ícone do GreatDomain não é renderizado: é a flag do app. */
|
|
12
|
+
domainIconHref?: string;
|
|
11
13
|
/** Which app is currently active — controls which icon gets the indicator */
|
|
12
|
-
activeApp?: "gapps" | "gpages";
|
|
14
|
+
activeApp?: "gapps" | "gpages" | "gdomain";
|
|
13
15
|
showExpandButton?: boolean;
|
|
14
16
|
onExpandClick?: () => void;
|
|
15
17
|
menuItems?: ProfileMenuItem[];
|
|
@@ -19,6 +21,7 @@ export interface AppNavBarProps {
|
|
|
19
21
|
export function AppNavBar({
|
|
20
22
|
logoHref,
|
|
21
23
|
appIconHref,
|
|
24
|
+
domainIconHref,
|
|
22
25
|
activeApp,
|
|
23
26
|
showExpandButton = false,
|
|
24
27
|
onExpandClick,
|
|
@@ -29,6 +32,7 @@ export function AppNavBar({
|
|
|
29
32
|
<NavBar
|
|
30
33
|
logoHref={logoHref}
|
|
31
34
|
appIconHref={appIconHref}
|
|
35
|
+
domainIconHref={domainIconHref}
|
|
32
36
|
activeApp={activeApp}
|
|
33
37
|
showExpandButton={showExpandButton}
|
|
34
38
|
onExpandClick={onExpandClick}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../infra/utils/clsx";
|
|
4
|
+
|
|
5
|
+
type GreatDomainIconProps = {
|
|
6
|
+
/** Em repouso o círculo é #650CE4; só no estado ativo vira #984DFF. */
|
|
7
|
+
active?: boolean;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Glifo do GreatDomain — geometria exportada do Figma (node 5929:2700), 23×23.
|
|
13
|
+
* O círculo só troca de cor quando ativo. No hover o container ganha fundo cinza
|
|
14
|
+
* (igual ao GreatPages) e o glifo fica como está.
|
|
15
|
+
*/
|
|
16
|
+
function GreatDomainIcon({ active, className }: GreatDomainIconProps) {
|
|
17
|
+
return (
|
|
18
|
+
<svg
|
|
19
|
+
width="23"
|
|
20
|
+
height="23"
|
|
21
|
+
viewBox="0 0 23 23"
|
|
22
|
+
fill="none"
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
className={className}
|
|
25
|
+
aria-hidden="true"
|
|
26
|
+
>
|
|
27
|
+
<path
|
|
28
|
+
d="M11.8444 17.0777C11.8444 20.3487 9.19292 23.0003 5.92218 23.0003C2.65145 23.0003 0 20.3487 0 17.0777C0 13.8068 2.65145 11.1551 5.92218 11.1551C9.19292 11.1551 11.8444 13.8068 11.8444 17.0777Z"
|
|
29
|
+
className={cn(
|
|
30
|
+
"transition-colors duration-300",
|
|
31
|
+
active ? "fill-[#984DFF]" : "fill-[#650CE4]",
|
|
32
|
+
)}
|
|
33
|
+
/>
|
|
34
|
+
<path
|
|
35
|
+
d="M11.8436 3.06666C11.8436 1.37299 13.2166 0 14.9103 0H19.9331C21.6267 0 22.9997 1.37299 22.9997 3.06666V19.9333C22.9997 21.6269 21.6267 22.9999 19.9331 22.9999H14.9103C13.2166 22.9999 11.8436 21.6269 11.8436 19.9333V3.06666Z"
|
|
36
|
+
fill="#C9B2FF"
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { GreatDomainIcon };
|
|
43
|
+
export type { GreatDomainIconProps };
|
|
@@ -6,11 +6,13 @@ import Link from "next/link";
|
|
|
6
6
|
import { useTranslations } from "next-intl";
|
|
7
7
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
8
8
|
import { Separator } from "../ui/data-display/Separator";
|
|
9
|
+
import { GreatDomainIcon } from "./GreatDomainIcon";
|
|
9
10
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
10
11
|
import {
|
|
11
12
|
useDesktopSidebarStore,
|
|
12
13
|
useDesktopSidebarHydration,
|
|
13
14
|
} from "../../store/useDesktopSidebarStore";
|
|
15
|
+
import { useMdSidebarHydration } from "../../store/useMdSidebarStore";
|
|
14
16
|
import {
|
|
15
17
|
useWhitelabel,
|
|
16
18
|
useIsDefaultWhitelabel,
|
|
@@ -20,7 +22,9 @@ import { cn } from "../../infra/utils/clsx";
|
|
|
20
22
|
type NavBarProps = {
|
|
21
23
|
logoHref: string;
|
|
22
24
|
appIconHref: string;
|
|
23
|
-
|
|
25
|
+
/** Sem href o ícone do GreatDomain não é renderizado: é a flag do app. */
|
|
26
|
+
domainIconHref?: string;
|
|
27
|
+
activeApp?: "gapps" | "gpages" | "gdomain";
|
|
24
28
|
showExpandButton?: boolean;
|
|
25
29
|
onExpandClick?: () => void;
|
|
26
30
|
children?: React.ReactNode;
|
|
@@ -30,6 +34,7 @@ type NavBarProps = {
|
|
|
30
34
|
function NavBar({
|
|
31
35
|
logoHref,
|
|
32
36
|
appIconHref,
|
|
37
|
+
domainIconHref,
|
|
33
38
|
activeApp,
|
|
34
39
|
showExpandButton = false,
|
|
35
40
|
onExpandClick,
|
|
@@ -40,6 +45,7 @@ function NavBar({
|
|
|
40
45
|
const { isExpanded: isDesktopExpanded, toggle: toggleDesktop } =
|
|
41
46
|
useDesktopSidebarStore();
|
|
42
47
|
useDesktopSidebarHydration();
|
|
48
|
+
useMdSidebarHydration();
|
|
43
49
|
const { whitelabel } = useWhitelabel();
|
|
44
50
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
45
51
|
const primaryColor = whitelabel?.general?.primary_color;
|
|
@@ -130,7 +136,9 @@ function NavBar({
|
|
|
130
136
|
<IconChevronRight size={16} className="text-gray-500" />
|
|
131
137
|
</button>
|
|
132
138
|
</TooltipTrigger>
|
|
133
|
-
<TooltipContent side="right">
|
|
139
|
+
<TooltipContent side="right">
|
|
140
|
+
{translate("common.layout.navbar.expandMenu")}
|
|
141
|
+
</TooltipContent>
|
|
134
142
|
</Tooltip>
|
|
135
143
|
)}
|
|
136
144
|
{/* Desktop expand button */}
|
|
@@ -144,78 +152,164 @@ function NavBar({
|
|
|
144
152
|
<IconChevronRight size={16} className="text-gray-500" />
|
|
145
153
|
</button>
|
|
146
154
|
</TooltipTrigger>
|
|
147
|
-
<TooltipContent side="right">
|
|
155
|
+
<TooltipContent side="right">
|
|
156
|
+
{translate("common.layout.navbar.expandMenu")}
|
|
157
|
+
</TooltipContent>
|
|
148
158
|
</Tooltip>
|
|
149
159
|
)}
|
|
150
160
|
</div>
|
|
151
161
|
|
|
152
|
-
{/*
|
|
153
|
-
<div className="
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
{/* Ícones de app — 8px entre eles (Figma 5929:2676) */}
|
|
163
|
+
<div className="flex flex-col gap-2 items-center">
|
|
164
|
+
{/* GreatPages icon */}
|
|
165
|
+
<div className="relative">
|
|
166
|
+
<Tooltip>
|
|
167
|
+
<TooltipTrigger asChild>
|
|
168
|
+
<Link
|
|
169
|
+
href={appIconHref}
|
|
170
|
+
className={cn(
|
|
171
|
+
"size-10 rounded-lg cursor-pointer flex items-center justify-center border-2 ring-2 transition-colors duration-300",
|
|
172
|
+
activeApp === "gpages"
|
|
173
|
+
? isDefaultWl
|
|
174
|
+
? "bg-cyan-100 border-white ring-cyan-300"
|
|
175
|
+
: "border-white ring-transparent"
|
|
176
|
+
: isDefaultWl
|
|
177
|
+
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
178
|
+
: "border-transparent ring-transparent",
|
|
179
|
+
)}
|
|
180
|
+
style={
|
|
181
|
+
!isDefaultWl
|
|
182
|
+
? {
|
|
183
|
+
backgroundColor: primaryColor,
|
|
184
|
+
boxShadow:
|
|
185
|
+
activeApp === "gpages"
|
|
186
|
+
? `0 0 0 2px ${primaryColor}40`
|
|
187
|
+
: undefined,
|
|
188
|
+
opacity: activeApp !== "gpages" ? 0.2 : undefined,
|
|
189
|
+
}
|
|
190
|
+
: undefined
|
|
191
|
+
}
|
|
192
|
+
>
|
|
193
|
+
{isDefaultWl ? (
|
|
194
|
+
<Image
|
|
195
|
+
src="/icons/icon-navbar.svg"
|
|
196
|
+
alt="GreatPages"
|
|
197
|
+
width={24}
|
|
198
|
+
height={24}
|
|
199
|
+
/>
|
|
200
|
+
) : (
|
|
201
|
+
<svg
|
|
202
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
203
|
+
width="24"
|
|
204
|
+
height="24"
|
|
205
|
+
viewBox="0 0 24 24"
|
|
206
|
+
fill="none"
|
|
207
|
+
stroke="white"
|
|
208
|
+
strokeWidth="2"
|
|
209
|
+
strokeLinecap="round"
|
|
210
|
+
strokeLinejoin="round"
|
|
211
|
+
>
|
|
212
|
+
<path d="M4 8h16" />
|
|
213
|
+
<path d="M4 6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2l0 -12" />
|
|
214
|
+
<path d="M8 4v4" />
|
|
215
|
+
</svg>
|
|
216
|
+
)}
|
|
217
|
+
</Link>
|
|
218
|
+
</TooltipTrigger>
|
|
219
|
+
<TooltipContent side="right">
|
|
220
|
+
{isDefaultWl
|
|
221
|
+
? translate("common.layout.navbar.greatPages")
|
|
222
|
+
: translate("common.layout.navbar.pages")}
|
|
223
|
+
</TooltipContent>
|
|
224
|
+
</Tooltip>
|
|
225
|
+
<div
|
|
226
|
+
className={cn(
|
|
227
|
+
"absolute -left-4 top-1/2 -translate-y-1/2 z-10 w-[3px] h-5 rounded-r-xl transition-opacity duration-300",
|
|
228
|
+
isDefaultWl ? "bg-cyan-300" : "",
|
|
229
|
+
activeApp === "gpages" ? "opacity-100" : "opacity-0",
|
|
230
|
+
)}
|
|
231
|
+
style={
|
|
232
|
+
!isDefaultWl ? { backgroundColor: primaryColor } : undefined
|
|
233
|
+
}
|
|
234
|
+
/>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
{/* GreatDomain icon */}
|
|
238
|
+
{domainIconHref ? (
|
|
239
|
+
<div className="relative">
|
|
240
|
+
<Tooltip>
|
|
241
|
+
<TooltipTrigger asChild>
|
|
242
|
+
<Link
|
|
243
|
+
href={domainIconHref}
|
|
244
|
+
aria-label={
|
|
245
|
+
isDefaultWl
|
|
246
|
+
? translate("common.layout.navbar.greatDomain")
|
|
247
|
+
: translate("common.layout.navbar.domains")
|
|
248
|
+
}
|
|
249
|
+
className={cn(
|
|
250
|
+
"size-10 rounded-[10px] cursor-pointer flex items-center justify-center border-2 ring-2 transition-colors duration-300",
|
|
251
|
+
activeApp === "gdomain"
|
|
252
|
+
? isDefaultWl
|
|
253
|
+
? "bg-[#EDE9FE] border-white ring-[#C092FF]"
|
|
254
|
+
: "border-white ring-transparent"
|
|
255
|
+
: isDefaultWl
|
|
256
|
+
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
257
|
+
: "border-transparent ring-transparent",
|
|
258
|
+
)}
|
|
259
|
+
style={
|
|
260
|
+
!isDefaultWl
|
|
261
|
+
? {
|
|
262
|
+
backgroundColor: primaryColor,
|
|
263
|
+
boxShadow:
|
|
264
|
+
activeApp === "gdomain"
|
|
265
|
+
? `0 0 0 2px ${primaryColor}40`
|
|
266
|
+
: undefined,
|
|
267
|
+
opacity: activeApp !== "gdomain" ? 0.2 : undefined,
|
|
268
|
+
}
|
|
269
|
+
: undefined
|
|
270
|
+
}
|
|
271
|
+
>
|
|
272
|
+
{isDefaultWl ? (
|
|
273
|
+
<GreatDomainIcon active={activeApp === "gdomain"} />
|
|
274
|
+
) : (
|
|
275
|
+
<svg
|
|
276
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
277
|
+
width="24"
|
|
278
|
+
height="24"
|
|
279
|
+
viewBox="0 0 24 24"
|
|
280
|
+
fill="none"
|
|
281
|
+
stroke="white"
|
|
282
|
+
strokeWidth="2"
|
|
283
|
+
strokeLinecap="round"
|
|
284
|
+
strokeLinejoin="round"
|
|
285
|
+
>
|
|
286
|
+
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
|
|
287
|
+
<path d="M3.6 9h16.8" />
|
|
288
|
+
<path d="M3.6 15h16.8" />
|
|
289
|
+
<path d="M11.5 3a17 17 0 0 0 0 18" />
|
|
290
|
+
<path d="M12.5 3a17 17 0 0 1 0 18" />
|
|
291
|
+
</svg>
|
|
292
|
+
)}
|
|
293
|
+
</Link>
|
|
294
|
+
</TooltipTrigger>
|
|
295
|
+
<TooltipContent side="right">
|
|
296
|
+
{isDefaultWl
|
|
297
|
+
? translate("common.layout.navbar.greatDomain")
|
|
298
|
+
: translate("common.layout.navbar.domains")}
|
|
299
|
+
</TooltipContent>
|
|
300
|
+
</Tooltip>
|
|
301
|
+
<div
|
|
158
302
|
className={cn(
|
|
159
|
-
"
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
? "bg-cyan-100 border-white ring-cyan-300"
|
|
163
|
-
: "border-white ring-transparent"
|
|
164
|
-
: isDefaultWl
|
|
165
|
-
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
166
|
-
: "border-transparent ring-transparent",
|
|
303
|
+
"absolute -left-4 top-1/2 -translate-y-1/2 z-10 w-[3px] h-5 rounded-r-xl transition-opacity duration-300",
|
|
304
|
+
isDefaultWl ? "bg-[#984DFF]" : "",
|
|
305
|
+
activeApp === "gdomain" ? "opacity-100" : "opacity-0",
|
|
167
306
|
)}
|
|
168
307
|
style={
|
|
169
|
-
!isDefaultWl
|
|
170
|
-
? {
|
|
171
|
-
backgroundColor: primaryColor,
|
|
172
|
-
boxShadow:
|
|
173
|
-
activeApp === "gpages"
|
|
174
|
-
? `0 0 0 2px ${primaryColor}40`
|
|
175
|
-
: undefined,
|
|
176
|
-
opacity: activeApp !== "gpages" ? 0.2 : undefined,
|
|
177
|
-
}
|
|
178
|
-
: undefined
|
|
308
|
+
!isDefaultWl ? { backgroundColor: primaryColor } : undefined
|
|
179
309
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
src="/icons/icon-navbar.svg"
|
|
184
|
-
alt="GreatPages"
|
|
185
|
-
width={24}
|
|
186
|
-
height={24}
|
|
187
|
-
/>
|
|
188
|
-
) : (
|
|
189
|
-
<svg
|
|
190
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
191
|
-
width="24"
|
|
192
|
-
height="24"
|
|
193
|
-
viewBox="0 0 24 24"
|
|
194
|
-
fill="none"
|
|
195
|
-
stroke="white"
|
|
196
|
-
strokeWidth="2"
|
|
197
|
-
strokeLinecap="round"
|
|
198
|
-
strokeLinejoin="round"
|
|
199
|
-
>
|
|
200
|
-
<path d="M4 8h16" />
|
|
201
|
-
<path d="M4 6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2l0 -12" />
|
|
202
|
-
<path d="M8 4v4" />
|
|
203
|
-
</svg>
|
|
204
|
-
)}
|
|
205
|
-
</Link>
|
|
206
|
-
</TooltipTrigger>
|
|
207
|
-
<TooltipContent side="right">
|
|
208
|
-
{isDefaultWl ? translate('common.layout.navbar.greatPages') : translate('common.layout.navbar.pages')}
|
|
209
|
-
</TooltipContent>
|
|
210
|
-
</Tooltip>
|
|
211
|
-
<div
|
|
212
|
-
className={cn(
|
|
213
|
-
"absolute -left-4 top-1/2 -translate-y-1/2 z-10 w-[3px] h-5 rounded-r-xl transition-opacity duration-300",
|
|
214
|
-
isDefaultWl ? "bg-cyan-300" : "",
|
|
215
|
-
activeApp === "gpages" ? "opacity-100" : "opacity-0",
|
|
216
|
-
)}
|
|
217
|
-
style={!isDefaultWl ? { backgroundColor: primaryColor } : undefined}
|
|
218
|
-
/>
|
|
310
|
+
/>
|
|
311
|
+
</div>
|
|
312
|
+
) : null}
|
|
219
313
|
</div>
|
|
220
314
|
</div>
|
|
221
315
|
|
|
@@ -45,7 +45,7 @@ export default function PhoneInput({
|
|
|
45
45
|
const translate = useTranslations();
|
|
46
46
|
const parsed = parsePhoneValue(value ?? '');
|
|
47
47
|
const [selectedCountry, setSelectedCountry] = useState<Country>(parsed.country);
|
|
48
|
-
const [phoneNumber, setPhoneNumber] = useState(parsed.number);
|
|
48
|
+
const [phoneNumber, setPhoneNumber] = useState(formatNational(parsed.number, parsed.country.iso));
|
|
49
49
|
const [search, setSearch] = useState('');
|
|
50
50
|
const [open, setOpen] = useState(false);
|
|
51
51
|
const prevValueRef = useRef(value);
|
package/src/handlers.ts
CHANGED
|
@@ -20,6 +20,7 @@ export { createListAvailableUsersHandler } from './modules/projects/handlers/lis
|
|
|
20
20
|
export { createListAllAccountUsersHandler } from './modules/projects/handlers/list-all-account-users.handler';
|
|
21
21
|
|
|
22
22
|
export { createListSubscriptionsHandler } from './modules/subscriptions/handlers/list-subscriptions.handler';
|
|
23
|
+
export { createCurrentSubscriptionHandler } from './modules/subscriptions/handlers/current-subscription.handler';
|
|
23
24
|
export { createFreezeNoticeHandler } from './modules/subscriptions/handlers/freeze-notice.handler';
|
|
24
25
|
|
|
25
26
|
export { createListMessagesHandler } from './modules/users/handlers/list-messages.handler';
|
package/src/index.ts
CHANGED
|
@@ -86,6 +86,8 @@ export {
|
|
|
86
86
|
CHARGES_QUERY_KEY,
|
|
87
87
|
FREEZE_NOTICE_QUERY_KEY,
|
|
88
88
|
} from "./modules/subscriptions/constants/query-keys.constants";
|
|
89
|
+
export { useCurrentSubscription } from "./modules/subscriptions/hooks/use-current-subscription.hook";
|
|
90
|
+
/** @deprecated Use `useCurrentSubscription`. Sai na 1.1.784. */
|
|
89
91
|
export { useActiveSubscription } from "./modules/subscriptions/hooks/find-active-subscription.hook";
|
|
90
92
|
export { useCancelledSubscriptionGuard } from "./modules/subscriptions/hooks/use-cancelled-subscription-guard";
|
|
91
93
|
export { useAccountFreeze } from "./modules/subscriptions/hooks/use-account-freeze.hook";
|
|
@@ -222,7 +224,11 @@ export {
|
|
|
222
224
|
confirmPaymentIfRequired,
|
|
223
225
|
PaymentAuthenticationError,
|
|
224
226
|
} from "./modules/subscriptions/utils/confirm-payment-if-required";
|
|
225
|
-
export {
|
|
227
|
+
export {
|
|
228
|
+
SUBSCRIPTION_GRACE_PERIOD_DAYS,
|
|
229
|
+
FREE_PLAN_ID,
|
|
230
|
+
} from "./modules/subscriptions/constants/subscription.constants";
|
|
231
|
+
export { groupSubscriptionsByProduct } from "./modules/subscriptions/utils/group-subscriptions-by-product";
|
|
226
232
|
export { getSubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
|
|
227
233
|
export type { SubscriptionCancellationState } from "./modules/subscriptions/utils/get-subscription-cancellation-state";
|
|
228
234
|
export {
|
|
@@ -291,7 +297,7 @@ export { formatShortDate, formatDateTime, calendarDateSchema, toCalendarDate, da
|
|
|
291
297
|
export { buildQueryParams } from "./infra/utils/params";
|
|
292
298
|
export { parseSchema, parseResult } from "./infra/utils/parser";
|
|
293
299
|
export { withAction } from "./utils/withAction";
|
|
294
|
-
export { resolveSafeRedirect, sameHostOr } from "./utils/redirect";
|
|
300
|
+
export { resolveSafeRedirect, sameHostOr, isSameSiteUrl } from "./utils/redirect";
|
|
295
301
|
export { COUNTRIES, flagUrl } from "./utils/countries";
|
|
296
302
|
export type { Country } from "./utils/countries";
|
|
297
303
|
|
package/src/infra/api/client.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface ApiClientOptions {
|
|
|
31
31
|
emitLogs?: boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
interface ApiErrorResponseBody {
|
|
35
|
+
message?: string | { message?: string };
|
|
36
|
+
code?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
export interface RequestConfig extends RequestInit {
|
|
35
40
|
timeout?: number;
|
|
36
41
|
/** Padrão `json`. Use `text` quando a API devolve corpo não-JSON. */
|
|
@@ -169,9 +174,12 @@ class ApiClient {
|
|
|
169
174
|
let message = `HTTP error ${response.status} ${response.statusText} ${errBody}`;
|
|
170
175
|
let code = "HTTP_ERROR";
|
|
171
176
|
try {
|
|
172
|
-
const errorData = JSON.parse(errBody)
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
const errorData: ApiErrorResponseBody = JSON.parse(errBody);
|
|
178
|
+
if (typeof errorData.message === "string") {
|
|
179
|
+
message = errorData.message;
|
|
180
|
+
} else if (errorData.message?.message) {
|
|
181
|
+
message = errorData.message.message;
|
|
182
|
+
}
|
|
175
183
|
if (typeof errorData.code === "string") code = errorData.code;
|
|
176
184
|
} catch {
|
|
177
185
|
if (errBody.trim()) message = errBody.trim();
|
package/src/infra/api/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
|
|
3
|
-
export const PaginationParamsSchema = z.object({
|
|
4
|
-
page: z.number().min(1).optional().default(1),
|
|
5
|
-
limit: z.number().optional().default(20),
|
|
6
|
-
});
|
|
3
|
+
export const PaginationParamsSchema = z.object({
|
|
4
|
+
page: z.number().min(1).optional().default(1),
|
|
5
|
+
limit: z.number().optional().default(20),
|
|
6
|
+
});
|
|
7
7
|
|
|
8
8
|
export interface PaginationParams extends z.infer<typeof PaginationParamsSchema> {}
|
|
9
9
|
|
|
@@ -51,6 +51,8 @@ export interface PaginatedSuccessResult<T> extends Omit<SuccessResult<T>, 'data'
|
|
|
51
51
|
export interface ErrorResult {
|
|
52
52
|
success: false;
|
|
53
53
|
error?: string;
|
|
54
|
+
code?: string;
|
|
55
|
+
statusCode?: number;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export type ActionResult<T> = SuccessResult<T> | ErrorResult;
|
|
@@ -60,7 +62,7 @@ export class ApiError extends Error {
|
|
|
60
62
|
public readonly code: string;
|
|
61
63
|
public readonly statusCode: number;
|
|
62
64
|
|
|
63
|
-
constructor(message: string, code: string = 'UNKNOWN_ERROR', statusCode: number = 500) {
|
|
65
|
+
constructor(message: string = 'Erro desconhecido', code: string = 'UNKNOWN_ERROR', statusCode: number = 500) {
|
|
64
66
|
super(message);
|
|
65
67
|
this.name = 'ApiError';
|
|
66
68
|
this.code = code;
|
|
@@ -8,7 +8,10 @@ export async function safeRouteHandler<T>(fn: () => Promise<T>): Promise<Respons
|
|
|
8
8
|
return Response.json({ success: true, data });
|
|
9
9
|
} catch (error) {
|
|
10
10
|
if (error instanceof ApiError) {
|
|
11
|
-
return Response.json(
|
|
11
|
+
return Response.json(
|
|
12
|
+
{ success: false, error: error.message, code: error.code },
|
|
13
|
+
{ status: error.statusCode },
|
|
14
|
+
);
|
|
12
15
|
}
|
|
13
16
|
console.error('[safeRouteHandler] erro inesperado', error);
|
|
14
17
|
return Response.json({ success: false, error: 'Erro interno do servidor' }, { status: 500 });
|