@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.
Files changed (113) hide show
  1. package/dist/components/layouts/AppMobileNavBar.mjs +64 -5
  2. package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
  3. package/dist/components/layouts/AppNavBar.mjs +2 -0
  4. package/dist/components/layouts/AppNavBar.mjs.map +1 -1
  5. package/dist/components/layouts/GreatDomainIcon.mjs +40 -0
  6. package/dist/components/layouts/GreatDomainIcon.mjs.map +1 -0
  7. package/dist/components/layouts/NavBar.mjs +111 -52
  8. package/dist/components/layouts/NavBar.mjs.map +1 -1
  9. package/dist/components/ui/form/PhoneInput.mjs +1 -1
  10. package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
  11. package/dist/handlers.mjs +2 -0
  12. package/dist/handlers.mjs.map +1 -1
  13. package/dist/i18n/messages/en-us.mjs +3 -1
  14. package/dist/i18n/messages/en-us.mjs.map +1 -1
  15. package/dist/i18n/messages/es-es.mjs +3 -1
  16. package/dist/i18n/messages/es-es.mjs.map +1 -1
  17. package/dist/i18n/messages/pt-br.mjs +3 -1
  18. package/dist/i18n/messages/pt-br.mjs.map +1 -1
  19. package/dist/index.mjs +11 -2
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/infra/api/client.mjs +5 -1
  22. package/dist/infra/api/client.mjs.map +1 -1
  23. package/dist/infra/api/types.mjs +1 -1
  24. package/dist/infra/api/types.mjs.map +1 -1
  25. package/dist/infra/route/safe-route-handler.mjs +4 -1
  26. package/dist/infra/route/safe-route-handler.mjs.map +1 -1
  27. package/dist/middlewares/create-auth-middleware.mjs +11 -1
  28. package/dist/middlewares/create-auth-middleware.mjs.map +1 -1
  29. package/dist/modules/auth/utils/assert-account-not-frozen.mjs +6 -5
  30. package/dist/modules/auth/utils/assert-account-not-frozen.mjs.map +1 -1
  31. package/dist/modules/auth/utils/assert-management-subscription.mjs +7 -14
  32. package/dist/modules/auth/utils/assert-management-subscription.mjs.map +1 -1
  33. package/dist/modules/auth/utils/assert-paid-subscription.mjs +7 -12
  34. package/dist/modules/auth/utils/assert-paid-subscription.mjs.map +1 -1
  35. package/dist/modules/auth/utils/assert-subscription-addon.mjs +2 -10
  36. package/dist/modules/auth/utils/assert-subscription-addon.mjs.map +1 -1
  37. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
  38. package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs +10 -0
  39. package/dist/modules/subscriptions/actions/get-current-subscription.action.mjs.map +1 -0
  40. package/dist/modules/subscriptions/constants/subscription.constants.mjs +2 -0
  41. package/dist/modules/subscriptions/constants/subscription.constants.mjs.map +1 -1
  42. package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs +17 -0
  43. package/dist/modules/subscriptions/handlers/current-subscription.handler.mjs.map +1 -0
  44. package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs +2 -13
  45. package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
  46. package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs +28 -0
  47. package/dist/modules/subscriptions/hooks/use-current-subscription.hook.mjs.map +1 -0
  48. package/dist/modules/subscriptions/services/subscriptions.service.mjs +26 -0
  49. package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
  50. package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
  51. package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs +16 -0
  52. package/dist/modules/subscriptions/utils/group-subscriptions-by-product.mjs.map +1 -0
  53. package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs +1 -1
  54. package/dist/modules/subscriptions/utils/has-active-paid-subscription.mjs.map +1 -1
  55. package/dist/modules/subscriptions/utils/has-paid-subscription.mjs +1 -1
  56. package/dist/modules/subscriptions/utils/has-paid-subscription.mjs.map +1 -1
  57. package/dist/modules/subscriptions/utils/read-current-subscription.mjs +21 -0
  58. package/dist/modules/subscriptions/utils/read-current-subscription.mjs.map +1 -0
  59. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs +9 -6
  60. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
  61. package/dist/modules/whitelabel/services/whitelabel.service.mjs +28 -2
  62. package/dist/modules/whitelabel/services/whitelabel.service.mjs.map +1 -1
  63. package/dist/providers/auth.provider.mjs +12 -9
  64. package/dist/providers/auth.provider.mjs.map +1 -1
  65. package/dist/server.mjs +4 -0
  66. package/dist/server.mjs.map +1 -1
  67. package/dist/store/useMdSidebarStore.mjs +17 -4
  68. package/dist/store/useMdSidebarStore.mjs.map +1 -1
  69. package/dist/utils/redirect.mjs +10 -0
  70. package/dist/utils/redirect.mjs.map +1 -1
  71. package/dist/utils/safeServerAction.mjs +4 -1
  72. package/dist/utils/safeServerAction.mjs.map +1 -1
  73. package/dist/utils/withAction.mjs +2 -1
  74. package/dist/utils/withAction.mjs.map +1 -1
  75. package/package.json +1 -1
  76. package/src/components/layouts/AppMobileNavBar.tsx +90 -6
  77. package/src/components/layouts/AppNavBar.tsx +5 -1
  78. package/src/components/layouts/GreatDomainIcon.tsx +43 -0
  79. package/src/components/layouts/NavBar.tsx +160 -66
  80. package/src/components/ui/form/PhoneInput.tsx +1 -1
  81. package/src/handlers.ts +1 -0
  82. package/src/i18n/messages/en-us.ts +2 -0
  83. package/src/i18n/messages/es-es.ts +2 -0
  84. package/src/i18n/messages/pt-br.ts +2 -0
  85. package/src/index.ts +8 -2
  86. package/src/infra/api/client.ts +11 -3
  87. package/src/infra/api/types.ts +7 -5
  88. package/src/infra/route/safe-route-handler.ts +4 -1
  89. package/src/middlewares/create-auth-middleware.ts +12 -1
  90. package/src/modules/auth/utils/assert-account-not-frozen.ts +7 -6
  91. package/src/modules/auth/utils/assert-management-subscription.ts +15 -23
  92. package/src/modules/auth/utils/assert-paid-subscription.ts +7 -15
  93. package/src/modules/auth/utils/assert-subscription-addon.ts +2 -12
  94. package/src/modules/plans/hooks/use-plan-by-id.hook.ts +1 -1
  95. package/src/modules/subscriptions/actions/get-current-subscription.action.ts +8 -0
  96. package/src/modules/subscriptions/constants/subscription.constants.ts +3 -0
  97. package/src/modules/subscriptions/handlers/current-subscription.handler.ts +16 -0
  98. package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +7 -17
  99. package/src/modules/subscriptions/hooks/use-current-subscription.hook.ts +38 -0
  100. package/src/modules/subscriptions/services/subscriptions.service.ts +34 -0
  101. package/src/modules/subscriptions/types/subscription.type.ts +2 -0
  102. package/src/modules/subscriptions/utils/group-subscriptions-by-product.ts +23 -0
  103. package/src/modules/subscriptions/utils/has-active-paid-subscription.ts +1 -2
  104. package/src/modules/subscriptions/utils/has-paid-subscription.ts +1 -2
  105. package/src/modules/subscriptions/utils/read-current-subscription.ts +34 -0
  106. package/src/modules/whitelabel/actions/find-whitelabel.action.ts +13 -9
  107. package/src/modules/whitelabel/services/whitelabel.service.ts +34 -2
  108. package/src/providers/auth.provider.tsx +13 -10
  109. package/src/server.ts +2 -0
  110. package/src/store/useMdSidebarStore.ts +20 -5
  111. package/src/utils/redirect.ts +10 -0
  112. package/src/utils/safeServerAction.ts +4 -6
  113. 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
- {extraLeftSlot}
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
- activeApp?: "gapps" | "gpages";
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">{translate('common.layout.navbar.expandMenu')}</TooltipContent>
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">{translate('common.layout.navbar.expandMenu')}</TooltipContent>
155
+ <TooltipContent side="right">
156
+ {translate("common.layout.navbar.expandMenu")}
157
+ </TooltipContent>
148
158
  </Tooltip>
149
159
  )}
150
160
  </div>
151
161
 
152
- {/* GreatPages icon */}
153
- <div className="relative">
154
- <Tooltip>
155
- <TooltipTrigger asChild>
156
- <Link
157
- href={appIconHref}
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
- "size-10 rounded-lg cursor-pointer flex items-center justify-center border-2 ring-2 transition-colors duration-300",
160
- activeApp === "gpages"
161
- ? isDefaultWl
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
- {isDefaultWl ? (
182
- <Image
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';
@@ -540,6 +540,8 @@ const messages = {
540
540
  expandMenu: 'Expand menu',
541
541
  greatPages: 'GreatPages',
542
542
  pages: 'Pages',
543
+ greatDomain: 'GreatDomain',
544
+ domains: 'Domains',
543
545
  },
544
546
  profile: {
545
547
  usedCredits: 'Credits used',
@@ -541,6 +541,8 @@ const messages = {
541
541
  expandMenu: 'Expandir menú',
542
542
  greatPages: 'GreatPages',
543
543
  pages: 'Páginas',
544
+ greatDomain: 'GreatDomain',
545
+ domains: 'Dominios',
544
546
  },
545
547
  profile: {
546
548
  usedCredits: 'Créditos utilizados',
@@ -620,6 +620,8 @@ const messages = {
620
620
  expandMenu: 'Expandir menu',
621
621
  greatPages: 'GreatPages',
622
622
  pages: 'Páginas',
623
+ greatDomain: 'GreatDomain',
624
+ domains: 'Domínios',
623
625
  },
624
626
  profile: {
625
627
  usedCredits: 'Créditos usados',
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 { SUBSCRIPTION_GRACE_PERIOD_DAYS } from "./modules/subscriptions/constants/subscription.constants";
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
 
@@ -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) as Record<string, unknown>;
173
- // @ts-ignore -- msg pode ser string ou objeto com .message
174
- message = errorData.message?.message ?? errorData.message ?? message;
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();
@@ -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({ success: false, error: error.message }, { status: error.statusCode });
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 });