@greatapps/common 1.1.782 → 1.1.785
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 +5 -64
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/AppNavBar.mjs +0 -2
- package/dist/components/layouts/AppNavBar.mjs.map +1 -1
- package/dist/components/layouts/NavBar.mjs +52 -109
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/modals/cards/AddCardModal.mjs +3 -2
- package/dist/components/modals/cards/AddCardModal.mjs.map +1 -1
- package/dist/i18n/messages/en-us.mjs +1 -3
- package/dist/i18n/messages/en-us.mjs.map +1 -1
- package/dist/i18n/messages/es-es.mjs +1 -3
- package/dist/i18n/messages/es-es.mjs.map +1 -1
- package/dist/i18n/messages/pt-br.mjs +1 -3
- package/dist/i18n/messages/pt-br.mjs.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/modules/subscriptions/actions/update-subscription-payment.action.mjs.map +1 -1
- package/dist/modules/subscriptions/hooks/update-subscription-payment.hook.mjs +10 -2
- package/dist/modules/subscriptions/hooks/update-subscription-payment.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/services/subscriptions.service.mjs +12 -1
- package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
- package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/AppMobileNavBar.tsx +6 -90
- package/src/components/layouts/AppNavBar.tsx +1 -5
- package/src/components/layouts/NavBar.tsx +66 -158
- package/src/components/modals/cards/AddCardModal.tsx +15 -2
- package/src/i18n/messages/en-us.ts +0 -2
- package/src/i18n/messages/es-es.ts +0 -2
- package/src/i18n/messages/pt-br.ts +0 -2
- package/src/index.ts +1 -0
- package/src/modules/plans/hooks/use-plan-by-id.hook.ts +1 -1
- package/src/modules/subscriptions/actions/update-subscription-payment.action.ts +6 -1
- package/src/modules/subscriptions/hooks/update-subscription-payment.hook.ts +21 -3
- package/src/modules/subscriptions/services/subscriptions.service.ts +46 -4
- package/src/modules/subscriptions/types/subscription.type.ts +27 -0
- package/dist/components/layouts/GreatDomainIcon.mjs +0 -40
- package/dist/components/layouts/GreatDomainIcon.mjs.map +0 -1
- package/src/components/layouts/GreatDomainIcon.tsx +0 -43
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
import Image from "next/image";
|
|
5
|
-
import { useTranslations } from "next-intl";
|
|
6
5
|
import { IconMenu2, IconX } from "@tabler/icons-react";
|
|
7
6
|
import { ProfilePopover } from "./ProfilePopover";
|
|
8
|
-
import { GreatDomainIcon } from "./GreatDomainIcon";
|
|
9
7
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
10
8
|
import { useMobileNavbarSheet } from "../../store/useMobileNavbarSheet";
|
|
11
9
|
import {
|
|
@@ -17,13 +15,11 @@ import type { ProfileMenuItem } from "./ProfilePopover";
|
|
|
17
15
|
|
|
18
16
|
export interface AppMobileNavBarProps {
|
|
19
17
|
/** Which app is currently active — controls which icon gets the indicator */
|
|
20
|
-
activeApp?: "gapps" | "gpages"
|
|
18
|
+
activeApp?: "gapps" | "gpages";
|
|
21
19
|
/** Called when the GreatApps logo is clicked */
|
|
22
20
|
onLogoClick?: () => void;
|
|
23
21
|
/** Called when the app icon (e.g. GreatPages) is clicked */
|
|
24
22
|
onAppIconClick?: () => void;
|
|
25
|
-
/** Called when the GreatDomain icon is clicked; without it the icon is not rendered (app flag) */
|
|
26
|
-
onDomainIconClick?: () => void;
|
|
27
23
|
/** Extra slot rendered after the app icon (e.g. project selector) */
|
|
28
24
|
extraLeftSlot?: ReactNode;
|
|
29
25
|
menuItems?: ProfileMenuItem[];
|
|
@@ -34,12 +30,10 @@ export function AppMobileNavBar({
|
|
|
34
30
|
activeApp,
|
|
35
31
|
onLogoClick,
|
|
36
32
|
onAppIconClick,
|
|
37
|
-
onDomainIconClick,
|
|
38
33
|
extraLeftSlot,
|
|
39
34
|
menuItems = [],
|
|
40
35
|
showMenuToggle = true,
|
|
41
36
|
}: AppMobileNavBarProps) {
|
|
42
|
-
const translate = useTranslations();
|
|
43
37
|
const { isOpen, toggle } = useMobileNavbarSheet();
|
|
44
38
|
const { whitelabel } = useWhitelabel();
|
|
45
39
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
@@ -48,7 +42,6 @@ export function AppMobileNavBar({
|
|
|
48
42
|
|
|
49
43
|
const isGappsActive = activeApp === "gapps";
|
|
50
44
|
const isGpagesActive = activeApp === "gpages";
|
|
51
|
-
const isGdomainActive = activeApp === "gdomain";
|
|
52
45
|
|
|
53
46
|
const wlIcon = whitelabel?.secondary_logo ? (
|
|
54
47
|
<Image
|
|
@@ -87,9 +80,9 @@ export function AppMobileNavBar({
|
|
|
87
80
|
|
|
88
81
|
return (
|
|
89
82
|
<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">
|
|
90
|
-
<div className="flex items-center gap-1.5
|
|
83
|
+
<div className="flex items-center gap-1.5">
|
|
91
84
|
{/* GreatApps logo */}
|
|
92
|
-
<div className="relative
|
|
85
|
+
<div className="relative">
|
|
93
86
|
<Tooltip>
|
|
94
87
|
<TooltipTrigger asChild>
|
|
95
88
|
<div
|
|
@@ -126,7 +119,7 @@ export function AppMobileNavBar({
|
|
|
126
119
|
</div>
|
|
127
120
|
|
|
128
121
|
{/* GreatPages icon */}
|
|
129
|
-
<div className="relative
|
|
122
|
+
<div className="relative">
|
|
130
123
|
<Tooltip>
|
|
131
124
|
<TooltipTrigger asChild>
|
|
132
125
|
<div
|
|
@@ -194,86 +187,9 @@ export function AppMobileNavBar({
|
|
|
194
187
|
/>
|
|
195
188
|
</div>
|
|
196
189
|
|
|
197
|
-
{
|
|
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}
|
|
190
|
+
{extraLeftSlot}
|
|
275
191
|
</div>
|
|
276
|
-
<div className="flex items-center gap-1.5
|
|
192
|
+
<div className="flex items-center gap-1.5">
|
|
277
193
|
<ProfilePopover
|
|
278
194
|
side="bottom"
|
|
279
195
|
align="end"
|
|
@@ -8,10 +8,8 @@ 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;
|
|
13
11
|
/** Which app is currently active — controls which icon gets the indicator */
|
|
14
|
-
activeApp?: "gapps" | "gpages"
|
|
12
|
+
activeApp?: "gapps" | "gpages";
|
|
15
13
|
showExpandButton?: boolean;
|
|
16
14
|
onExpandClick?: () => void;
|
|
17
15
|
menuItems?: ProfileMenuItem[];
|
|
@@ -21,7 +19,6 @@ export interface AppNavBarProps {
|
|
|
21
19
|
export function AppNavBar({
|
|
22
20
|
logoHref,
|
|
23
21
|
appIconHref,
|
|
24
|
-
domainIconHref,
|
|
25
22
|
activeApp,
|
|
26
23
|
showExpandButton = false,
|
|
27
24
|
onExpandClick,
|
|
@@ -32,7 +29,6 @@ export function AppNavBar({
|
|
|
32
29
|
<NavBar
|
|
33
30
|
logoHref={logoHref}
|
|
34
31
|
appIconHref={appIconHref}
|
|
35
|
-
domainIconHref={domainIconHref}
|
|
36
32
|
activeApp={activeApp}
|
|
37
33
|
showExpandButton={showExpandButton}
|
|
38
34
|
onExpandClick={onExpandClick}
|
|
@@ -6,7 +6,6 @@ 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";
|
|
10
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
11
10
|
import {
|
|
12
11
|
useDesktopSidebarStore,
|
|
@@ -21,9 +20,7 @@ import { cn } from "../../infra/utils/clsx";
|
|
|
21
20
|
type NavBarProps = {
|
|
22
21
|
logoHref: string;
|
|
23
22
|
appIconHref: string;
|
|
24
|
-
|
|
25
|
-
domainIconHref?: string;
|
|
26
|
-
activeApp?: "gapps" | "gpages" | "gdomain";
|
|
23
|
+
activeApp?: "gapps" | "gpages";
|
|
27
24
|
showExpandButton?: boolean;
|
|
28
25
|
onExpandClick?: () => void;
|
|
29
26
|
children?: React.ReactNode;
|
|
@@ -33,7 +30,6 @@ type NavBarProps = {
|
|
|
33
30
|
function NavBar({
|
|
34
31
|
logoHref,
|
|
35
32
|
appIconHref,
|
|
36
|
-
domainIconHref,
|
|
37
33
|
activeApp,
|
|
38
34
|
showExpandButton = false,
|
|
39
35
|
onExpandClick,
|
|
@@ -134,9 +130,7 @@ function NavBar({
|
|
|
134
130
|
<IconChevronRight size={16} className="text-gray-500" />
|
|
135
131
|
</button>
|
|
136
132
|
</TooltipTrigger>
|
|
137
|
-
<TooltipContent side="right">
|
|
138
|
-
{translate("common.layout.navbar.expandMenu")}
|
|
139
|
-
</TooltipContent>
|
|
133
|
+
<TooltipContent side="right">{translate('common.layout.navbar.expandMenu')}</TooltipContent>
|
|
140
134
|
</Tooltip>
|
|
141
135
|
)}
|
|
142
136
|
{/* Desktop expand button */}
|
|
@@ -150,164 +144,78 @@ function NavBar({
|
|
|
150
144
|
<IconChevronRight size={16} className="text-gray-500" />
|
|
151
145
|
</button>
|
|
152
146
|
</TooltipTrigger>
|
|
153
|
-
<TooltipContent side="right">
|
|
154
|
-
{translate("common.layout.navbar.expandMenu")}
|
|
155
|
-
</TooltipContent>
|
|
147
|
+
<TooltipContent side="right">{translate('common.layout.navbar.expandMenu')}</TooltipContent>
|
|
156
148
|
</Tooltip>
|
|
157
149
|
)}
|
|
158
150
|
</div>
|
|
159
151
|
|
|
160
|
-
{/*
|
|
161
|
-
<div className="
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<Link
|
|
167
|
-
href={appIconHref}
|
|
168
|
-
className={cn(
|
|
169
|
-
"size-10 rounded-lg cursor-pointer flex items-center justify-center border-2 ring-2 transition-colors duration-300",
|
|
170
|
-
activeApp === "gpages"
|
|
171
|
-
? isDefaultWl
|
|
172
|
-
? "bg-cyan-100 border-white ring-cyan-300"
|
|
173
|
-
: "border-white ring-transparent"
|
|
174
|
-
: isDefaultWl
|
|
175
|
-
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
176
|
-
: "border-transparent ring-transparent",
|
|
177
|
-
)}
|
|
178
|
-
style={
|
|
179
|
-
!isDefaultWl
|
|
180
|
-
? {
|
|
181
|
-
backgroundColor: primaryColor,
|
|
182
|
-
boxShadow:
|
|
183
|
-
activeApp === "gpages"
|
|
184
|
-
? `0 0 0 2px ${primaryColor}40`
|
|
185
|
-
: undefined,
|
|
186
|
-
opacity: activeApp !== "gpages" ? 0.2 : undefined,
|
|
187
|
-
}
|
|
188
|
-
: undefined
|
|
189
|
-
}
|
|
190
|
-
>
|
|
191
|
-
{isDefaultWl ? (
|
|
192
|
-
<Image
|
|
193
|
-
src="/icons/icon-navbar.svg"
|
|
194
|
-
alt="GreatPages"
|
|
195
|
-
width={24}
|
|
196
|
-
height={24}
|
|
197
|
-
/>
|
|
198
|
-
) : (
|
|
199
|
-
<svg
|
|
200
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
201
|
-
width="24"
|
|
202
|
-
height="24"
|
|
203
|
-
viewBox="0 0 24 24"
|
|
204
|
-
fill="none"
|
|
205
|
-
stroke="white"
|
|
206
|
-
strokeWidth="2"
|
|
207
|
-
strokeLinecap="round"
|
|
208
|
-
strokeLinejoin="round"
|
|
209
|
-
>
|
|
210
|
-
<path d="M4 8h16" />
|
|
211
|
-
<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" />
|
|
212
|
-
<path d="M8 4v4" />
|
|
213
|
-
</svg>
|
|
214
|
-
)}
|
|
215
|
-
</Link>
|
|
216
|
-
</TooltipTrigger>
|
|
217
|
-
<TooltipContent side="right">
|
|
218
|
-
{isDefaultWl
|
|
219
|
-
? translate("common.layout.navbar.greatPages")
|
|
220
|
-
: translate("common.layout.navbar.pages")}
|
|
221
|
-
</TooltipContent>
|
|
222
|
-
</Tooltip>
|
|
223
|
-
<div
|
|
224
|
-
className={cn(
|
|
225
|
-
"absolute -left-4 top-1/2 -translate-y-1/2 z-10 w-[3px] h-5 rounded-r-xl transition-opacity duration-300",
|
|
226
|
-
isDefaultWl ? "bg-cyan-300" : "",
|
|
227
|
-
activeApp === "gpages" ? "opacity-100" : "opacity-0",
|
|
228
|
-
)}
|
|
229
|
-
style={
|
|
230
|
-
!isDefaultWl ? { backgroundColor: primaryColor } : undefined
|
|
231
|
-
}
|
|
232
|
-
/>
|
|
233
|
-
</div>
|
|
234
|
-
|
|
235
|
-
{/* GreatDomain icon */}
|
|
236
|
-
{domainIconHref ? (
|
|
237
|
-
<div className="relative">
|
|
238
|
-
<Tooltip>
|
|
239
|
-
<TooltipTrigger asChild>
|
|
240
|
-
<Link
|
|
241
|
-
href={domainIconHref}
|
|
242
|
-
aria-label={
|
|
243
|
-
isDefaultWl
|
|
244
|
-
? translate("common.layout.navbar.greatDomain")
|
|
245
|
-
: translate("common.layout.navbar.domains")
|
|
246
|
-
}
|
|
247
|
-
className={cn(
|
|
248
|
-
"size-10 rounded-[10px] cursor-pointer flex items-center justify-center border-2 ring-2 transition-colors duration-300",
|
|
249
|
-
activeApp === "gdomain"
|
|
250
|
-
? isDefaultWl
|
|
251
|
-
? "bg-[#EDE9FE] border-white ring-[#C092FF]"
|
|
252
|
-
: "border-white ring-transparent"
|
|
253
|
-
: isDefaultWl
|
|
254
|
-
? "hover:bg-gray-100 border-transparent ring-transparent"
|
|
255
|
-
: "border-transparent ring-transparent",
|
|
256
|
-
)}
|
|
257
|
-
style={
|
|
258
|
-
!isDefaultWl
|
|
259
|
-
? {
|
|
260
|
-
backgroundColor: primaryColor,
|
|
261
|
-
boxShadow:
|
|
262
|
-
activeApp === "gdomain"
|
|
263
|
-
? `0 0 0 2px ${primaryColor}40`
|
|
264
|
-
: undefined,
|
|
265
|
-
opacity: activeApp !== "gdomain" ? 0.2 : undefined,
|
|
266
|
-
}
|
|
267
|
-
: undefined
|
|
268
|
-
}
|
|
269
|
-
>
|
|
270
|
-
{isDefaultWl ? (
|
|
271
|
-
<GreatDomainIcon active={activeApp === "gdomain"} />
|
|
272
|
-
) : (
|
|
273
|
-
<svg
|
|
274
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
275
|
-
width="24"
|
|
276
|
-
height="24"
|
|
277
|
-
viewBox="0 0 24 24"
|
|
278
|
-
fill="none"
|
|
279
|
-
stroke="white"
|
|
280
|
-
strokeWidth="2"
|
|
281
|
-
strokeLinecap="round"
|
|
282
|
-
strokeLinejoin="round"
|
|
283
|
-
>
|
|
284
|
-
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />
|
|
285
|
-
<path d="M3.6 9h16.8" />
|
|
286
|
-
<path d="M3.6 15h16.8" />
|
|
287
|
-
<path d="M11.5 3a17 17 0 0 0 0 18" />
|
|
288
|
-
<path d="M12.5 3a17 17 0 0 1 0 18" />
|
|
289
|
-
</svg>
|
|
290
|
-
)}
|
|
291
|
-
</Link>
|
|
292
|
-
</TooltipTrigger>
|
|
293
|
-
<TooltipContent side="right">
|
|
294
|
-
{isDefaultWl
|
|
295
|
-
? translate("common.layout.navbar.greatDomain")
|
|
296
|
-
: translate("common.layout.navbar.domains")}
|
|
297
|
-
</TooltipContent>
|
|
298
|
-
</Tooltip>
|
|
299
|
-
<div
|
|
152
|
+
{/* GreatPages icon */}
|
|
153
|
+
<div className="relative">
|
|
154
|
+
<Tooltip>
|
|
155
|
+
<TooltipTrigger asChild>
|
|
156
|
+
<Link
|
|
157
|
+
href={appIconHref}
|
|
300
158
|
className={cn(
|
|
301
|
-
"
|
|
302
|
-
|
|
303
|
-
|
|
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",
|
|
304
167
|
)}
|
|
305
168
|
style={
|
|
306
|
-
!isDefaultWl
|
|
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
|
|
307
179
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
+
/>
|
|
311
219
|
</div>
|
|
312
220
|
</div>
|
|
313
221
|
|
|
@@ -87,6 +87,15 @@ export default function AddCardModal() {
|
|
|
87
87
|
const [isAuthenticating, setIsAuthenticating] = useState(false);
|
|
88
88
|
|
|
89
89
|
const onCardAdded = modalData.onCardAdded as ((cardId: string) => void) | undefined;
|
|
90
|
+
/* `set_default` continua true por omissão — todo chamador que só quer cadastrar um cartão segue
|
|
91
|
+
* com o comportamento de sempre. Quem passa `false` é quem vai perguntar ao usuário, logo depois
|
|
92
|
+
* do cadastro, se a assinatura deve migrar para este cartão.
|
|
93
|
+
*
|
|
94
|
+
* Sem esse controle a pergunta seria decorativa: o backend, ao receber `set_default: true`, já
|
|
95
|
+
* grava o padrão do customer E reaponta as assinaturas cobráveis (`#propagateDefaultPm` em
|
|
96
|
+
* cards/services.js), então quando o modal abrisse a troca já teria acontecido e "Recusar" não
|
|
97
|
+
* teria nada para recusar. */
|
|
98
|
+
const setAsDefault = modalData.setAsDefault !== false;
|
|
90
99
|
|
|
91
100
|
const createSetupIntentMutation = useCreateSetupIntent();
|
|
92
101
|
const createCardMutation = useCreateCard();
|
|
@@ -232,7 +241,7 @@ export default function AddCardModal() {
|
|
|
232
241
|
const cardResult = await createCardMutation.mutateAsync({
|
|
233
242
|
setup_intent_id: intent.setup_intent_id,
|
|
234
243
|
name: data.name,
|
|
235
|
-
set_default:
|
|
244
|
+
set_default: setAsDefault,
|
|
236
245
|
...(isInternational
|
|
237
246
|
? {}
|
|
238
247
|
: {
|
|
@@ -250,6 +259,11 @@ export default function AddCardModal() {
|
|
|
250
259
|
country: data.country,
|
|
251
260
|
});
|
|
252
261
|
|
|
262
|
+
/* Fecha ANTES de avisar quem chamou. `closeModal()` remove o topo da pilha do
|
|
263
|
+
* useModalManager, então um modal aberto de dentro do `onCardAdded` seria justamente o topo
|
|
264
|
+
* e sairia junto — abriria e fecharia no mesmo tick, sem o usuário ver nada. */
|
|
265
|
+
handleClose();
|
|
266
|
+
|
|
253
267
|
if (cardResult.success && cardResult.data?.id != null) {
|
|
254
268
|
onCardAdded?.(cardResult.data.id.toString());
|
|
255
269
|
}
|
|
@@ -258,7 +272,6 @@ export default function AddCardModal() {
|
|
|
258
272
|
(t) => <Toast variant="success" message={translate('common.cards.add.successToast')} toastId={t} />,
|
|
259
273
|
{ duration: 5000 }
|
|
260
274
|
);
|
|
261
|
-
handleClose();
|
|
262
275
|
} catch (error) {
|
|
263
276
|
/* O backend fail-closed devolve a razão exata da recusa (ex.: "CPF do pagador inválido —
|
|
264
277
|
* confira os dígitos verificadores"), e o withAction relança como Error com essa mensagem.
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export function usePlanById(idPlan?: number | string | null) {
|
|
|
11
11
|
const queryClient = useQueryClient();
|
|
12
12
|
const plansKey = useAuthQueryKey([...PLANS_QUERY_KEY]);
|
|
13
13
|
|
|
14
|
-
return useQuery
|
|
14
|
+
return useQuery({
|
|
15
15
|
queryKey: [...plansKey, idPlan],
|
|
16
16
|
queryFn: ({ signal }) =>
|
|
17
17
|
apiFetch<SuccessResult<Plan>>(`/api/plans/${idPlan}`, { signal }),
|
|
@@ -5,7 +5,12 @@ import { subscriptionsService } from "../services/subscriptions.service";
|
|
|
5
5
|
|
|
6
6
|
export async function updateSubscriptionPaymentAction(
|
|
7
7
|
subscriptionId: number | string,
|
|
8
|
-
data: {
|
|
8
|
+
data: {
|
|
9
|
+
id_card?: string;
|
|
10
|
+
payment_method_id?: string;
|
|
11
|
+
payment_method: number;
|
|
12
|
+
charge_now?: boolean;
|
|
13
|
+
},
|
|
9
14
|
) {
|
|
10
15
|
return safeMutationAction(async () => {
|
|
11
16
|
return subscriptionsService.updateSubscriptionPayment(subscriptionId, data);
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
4
4
|
import { withAction } from '../../../utils/withAction';
|
|
5
5
|
import { updateSubscriptionPaymentAction } from '../actions/update-subscription-payment.action';
|
|
6
|
-
import { SUBSCRIPTIONS_QUERY_KEY } from '../constants/query-keys.constants';
|
|
6
|
+
import { SUBSCRIPTIONS_QUERY_KEY, CHARGES_QUERY_KEY } from '../constants/query-keys.constants';
|
|
7
7
|
import { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';
|
|
8
|
+
import { CARDS_QUERY_KEY } from '../../cards/hooks/cards.hook';
|
|
8
9
|
|
|
9
10
|
export function useUpdateSubscriptionPayment() {
|
|
10
11
|
const queryClient = useQueryClient();
|
|
11
12
|
const subscriptionsKey = useAuthQueryKey([...SUBSCRIPTIONS_QUERY_KEY]);
|
|
13
|
+
const cardsKey = useAuthQueryKey([...CARDS_QUERY_KEY]);
|
|
14
|
+
const chargesKey = useAuthQueryKey([...CHARGES_QUERY_KEY]);
|
|
12
15
|
|
|
13
16
|
return useMutation({
|
|
14
17
|
mutationFn: ({
|
|
@@ -16,10 +19,25 @@ export function useUpdateSubscriptionPayment() {
|
|
|
16
19
|
data,
|
|
17
20
|
}: {
|
|
18
21
|
subscriptionId: number | string;
|
|
19
|
-
data: {
|
|
22
|
+
data: {
|
|
23
|
+
id_card?: string;
|
|
24
|
+
payment_method_id?: string;
|
|
25
|
+
payment_method: number;
|
|
26
|
+
charge_now?: boolean;
|
|
27
|
+
};
|
|
20
28
|
}) => withAction(updateSubscriptionPaymentAction)(subscriptionId, data),
|
|
21
|
-
onSuccess
|
|
29
|
+
/* `onSettled`, e não `onSuccess`, pelo mesmo motivo do irmão `updateSubscriptionPlan`: a troca
|
|
30
|
+
* é aplicada no backend ANTES do 3DS, então a falha de autenticação também precisa refletir na
|
|
31
|
+
* tela. */
|
|
32
|
+
onSettled: () => {
|
|
22
33
|
queryClient.invalidateQueries({ queryKey: subscriptionsKey });
|
|
34
|
+
/* A troca reaponta o cartão padrão da conta na mesma operação, então sem esta invalidação o
|
|
35
|
+
* selo "padrão" continuaria no cartão antigo depois de uma troca que já aconteceu. */
|
|
36
|
+
queryClient.invalidateQueries({ queryKey: cardsKey });
|
|
37
|
+
/* A operação passou a mutar um TERCEIRO estado: com `charge_now`, ela paga a fatura. A mesma
|
|
38
|
+
* tela lê isso por `useCharges`, e com `refetchOnWindowFocus: false` nada refaz a busca —
|
|
39
|
+
* a fatura recém-paga seguiria com selo "pendente" e botão "Pagar". */
|
|
40
|
+
queryClient.invalidateQueries({ queryKey: chargesKey });
|
|
23
41
|
},
|
|
24
42
|
});
|
|
25
43
|
}
|