@greatapps/common 1.1.746 → 1.1.747
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/modals/AccountFrozenModal.mjs +80 -37
- package/dist/components/modals/AccountFrozenModal.mjs.map +1 -1
- package/dist/components/navigation/SubscriptionBanner.mjs +2 -2
- package/dist/components/navigation/SubscriptionBanner.mjs.map +1 -1
- package/dist/i18n/messages/en-us.mjs +16 -11
- package/dist/i18n/messages/en-us.mjs.map +1 -1
- package/dist/i18n/messages/es-es.mjs +16 -11
- package/dist/i18n/messages/es-es.mjs.map +1 -1
- package/dist/i18n/messages/pt-br.mjs +16 -11
- package/dist/i18n/messages/pt-br.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/modals/AccountFrozenModal.tsx +115 -47
- package/src/components/navigation/SubscriptionBanner.tsx +2 -2
- package/src/i18n/messages/en-us.ts +16 -11
- package/src/i18n/messages/es-es.ts +16 -11
- package/src/i18n/messages/pt-br.ts +16 -11
|
@@ -1,38 +1,43 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
IconLock,
|
|
5
|
+
IconFile,
|
|
6
|
+
IconFolder,
|
|
7
|
+
IconWorld,
|
|
8
|
+
IconInfoCircle,
|
|
9
|
+
type IconProps,
|
|
10
|
+
} from '@tabler/icons-react';
|
|
11
|
+
import type { ComponentType } from 'react';
|
|
4
12
|
import { useTranslations } from 'next-intl';
|
|
5
13
|
import { Button } from '../ui/buttons/Button';
|
|
6
|
-
import { Separator } from '../ui/data-display/Separator';
|
|
7
14
|
import {
|
|
8
15
|
Dialog,
|
|
9
16
|
DialogContent,
|
|
10
17
|
DialogDescription,
|
|
11
|
-
DialogHeader,
|
|
12
18
|
DialogTitle,
|
|
13
19
|
} from '../ui/overlay/Dialog';
|
|
20
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';
|
|
14
21
|
import { useWhitelabelUrls, useExternalContracting } from '../../providers/whitelabel.provider';
|
|
15
22
|
import { useModalManager } from '../../store/useModalManager';
|
|
16
23
|
import { formatShortDate } from '../../infra/utils/date';
|
|
17
24
|
|
|
18
|
-
/*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
'users',
|
|
26
|
-
'abTests',
|
|
27
|
-
'uploads',
|
|
28
|
-
'integrations',
|
|
29
|
-
] as const;
|
|
25
|
+
/* Os 9 recursos do card agrupados nos 3 grupos que o usuário reconhece na plataforma.
|
|
26
|
+
* Um ícone por grupo; o texto mora no catálogo. */
|
|
27
|
+
const RESOURCE_GROUPS: { key: string; icon: ComponentType<IconProps> }[] = [
|
|
28
|
+
{ key: 'pages', icon: IconFile },
|
|
29
|
+
{ key: 'projects', icon: IconFolder },
|
|
30
|
+
{ key: 'domains', icon: IconWorld },
|
|
31
|
+
];
|
|
30
32
|
|
|
31
|
-
/* `freezeDate` no data = ainda VAI congelar (véspera); sem ele = já congelado.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
33
|
+
/* `freezeDate` no data = ainda VAI congelar (véspera); sem ele = já congelado.
|
|
34
|
+
*
|
|
35
|
+
* A LISTA só aparece quando o usuário PEDIU por ela, clicando em "Detalhes" no banner
|
|
36
|
+
* (`showResources`). Na modal que abre sozinha ao entrar numa conta bloqueada fica só o
|
|
37
|
+
* recado curto e o botão. */
|
|
34
38
|
interface FrozenModalData {
|
|
35
39
|
freezeDate?: Date | string | null;
|
|
40
|
+
showResources?: boolean;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export default function AccountFrozenModal() {
|
|
@@ -42,8 +47,10 @@ export default function AccountFrozenModal() {
|
|
|
42
47
|
const { accountsUrl } = useWhitelabelUrls();
|
|
43
48
|
const { redirectToExternal } = useExternalContracting();
|
|
44
49
|
|
|
45
|
-
const
|
|
50
|
+
const data = modalData as FrozenModalData | undefined;
|
|
51
|
+
const freezeDate = data?.freezeDate ?? null;
|
|
46
52
|
const isWarning = Boolean(freezeDate);
|
|
53
|
+
const showResources = Boolean(data?.showResources);
|
|
47
54
|
|
|
48
55
|
const title = isWarning
|
|
49
56
|
? translate('common.subscription.frozen.modal.warningTitle', {
|
|
@@ -51,9 +58,18 @@ export default function AccountFrozenModal() {
|
|
|
51
58
|
})
|
|
52
59
|
: translate('common.subscription.frozen.modal.title');
|
|
53
60
|
|
|
61
|
+
/* Sem a lista o texto tem que fechar sozinho; com a lista ele a INTRODUZ (termina em ":"). */
|
|
54
62
|
const description = isWarning
|
|
55
|
-
? translate(
|
|
56
|
-
|
|
63
|
+
? translate(
|
|
64
|
+
showResources
|
|
65
|
+
? 'common.subscription.frozen.modal.warningDescriptionWithResources'
|
|
66
|
+
: 'common.subscription.frozen.modal.warningDescription',
|
|
67
|
+
)
|
|
68
|
+
: translate(
|
|
69
|
+
showResources
|
|
70
|
+
? 'common.subscription.frozen.modal.descriptionWithResources'
|
|
71
|
+
: 'common.subscription.frozen.modal.description',
|
|
72
|
+
);
|
|
57
73
|
|
|
58
74
|
const handleRegularize = () => {
|
|
59
75
|
if (redirectToExternal('plans')) return;
|
|
@@ -62,41 +78,93 @@ export default function AccountFrozenModal() {
|
|
|
62
78
|
|
|
63
79
|
return (
|
|
64
80
|
<Dialog open={isOpen} onOpenChange={() => closeModal()}>
|
|
65
|
-
<DialogContent
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
<DialogContent
|
|
82
|
+
showCloseButton
|
|
83
|
+
/* Sem isto o Radix move o foco para o primeiro focável ao abrir — que aqui é o
|
|
84
|
+
* gatilho do tooltip — e o tooltip abre em FOCO, não só em hover: a modal
|
|
85
|
+
* aparecia com um balão já aberto. O foco segue preso no dialog. */
|
|
86
|
+
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
87
|
+
className="flex flex-col p-0! gap-0! max-w-[calc(100%-2rem)]! w-full sm:max-w-[400px]! lg:max-w-[420px]! rounded-lg border"
|
|
88
|
+
>
|
|
89
|
+
<div className="flex flex-col gap-5 p-4 lg:p-5">
|
|
90
|
+
<div className="flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg">
|
|
91
|
+
<IconLock size={20} className="text-zinc-950" />
|
|
75
92
|
</div>
|
|
93
|
+
|
|
76
94
|
<div className="flex flex-col gap-2">
|
|
77
95
|
<DialogTitle className="paragraph-medium-semibold text-zinc-950">
|
|
78
96
|
{title}
|
|
79
97
|
</DialogTitle>
|
|
80
|
-
<DialogDescription className="paragraph-small-regular text-zinc-
|
|
81
|
-
|
|
82
|
-
<p>{description}</p>
|
|
83
|
-
<ul className="flex flex-col gap-1.5 list-disc pl-4">
|
|
84
|
-
{BLOCKED_RESOURCE_KEYS.map((key) => (
|
|
85
|
-
<li key={key}>
|
|
86
|
-
{translate(`common.subscription.frozen.modal.resources.${key}`)}
|
|
87
|
-
</li>
|
|
88
|
-
))}
|
|
89
|
-
</ul>
|
|
90
|
-
<p>{translate('common.subscription.frozen.modal.keepsWorking')}</p>
|
|
91
|
-
</div>
|
|
98
|
+
<DialogDescription className="paragraph-small-regular text-zinc-500">
|
|
99
|
+
{description}
|
|
92
100
|
</DialogDescription>
|
|
93
101
|
</div>
|
|
94
|
-
</DialogHeader>
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
{showResources && (
|
|
104
|
+
<>
|
|
105
|
+
{/* Um bloco só, grupos separados por linha. A descrição de cada grupo
|
|
106
|
+
* vive no tooltip do ícone de info à direita: na modal ela empilhava
|
|
107
|
+
* três parágrafos e virava um paredão. */}
|
|
108
|
+
<div className="bg-white border border-zinc-100 rounded-lg">
|
|
109
|
+
{RESOURCE_GROUPS.map(({ key, icon: Icon }, index) => (
|
|
110
|
+
<div key={key}>
|
|
111
|
+
{index > 0 && <div className="h-px bg-zinc-100" />}
|
|
112
|
+
<div className="flex items-center justify-between gap-3 p-4">
|
|
113
|
+
<div className="flex items-center gap-3">
|
|
114
|
+
<Icon size={20} className="text-zinc-950 shrink-0" />
|
|
115
|
+
<span className="paragraph-small-semibold text-zinc-950">
|
|
116
|
+
{translate(
|
|
117
|
+
`common.subscription.frozen.modal.resources.${key}.title`,
|
|
118
|
+
)}
|
|
119
|
+
</span>
|
|
120
|
+
</div>
|
|
121
|
+
<Tooltip>
|
|
122
|
+
<TooltipTrigger asChild>
|
|
123
|
+
<button
|
|
124
|
+
type="button"
|
|
125
|
+
aria-label={translate(
|
|
126
|
+
`common.subscription.frozen.modal.resources.${key}.title`,
|
|
127
|
+
)}
|
|
128
|
+
className="flex items-center justify-center shrink-0 cursor-pointer"
|
|
129
|
+
>
|
|
130
|
+
<IconInfoCircle className="size-4 text-zinc-400" />
|
|
131
|
+
</button>
|
|
132
|
+
</TooltipTrigger>
|
|
133
|
+
<TooltipContent
|
|
134
|
+
side="top"
|
|
135
|
+
/* Acima do dialog: o globals.css do gapps-app
|
|
136
|
+
* sobe o [data-slot='dialog-content'] para
|
|
137
|
+
* z-index 1011 !important (o componente
|
|
138
|
+
* declara 1001), então o z-50 padrão do
|
|
139
|
+
* tooltip ficava atrás. */
|
|
140
|
+
className="z-[1100] max-w-[240px]"
|
|
141
|
+
>
|
|
142
|
+
{translate(
|
|
143
|
+
`common.subscription.frozen.modal.resources.${key}.description`,
|
|
144
|
+
)}
|
|
145
|
+
</TooltipContent>
|
|
146
|
+
</Tooltip>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
))}
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
{/* Bloco de informação padrão da plataforma. Ciano fixo: o congelamento
|
|
153
|
+
* é exclusivo da wl 1, então não existe o caso whitelabel/zinc aqui. */}
|
|
154
|
+
<div className="flex items-center gap-3 p-4 rounded-lg bg-cyan-50">
|
|
155
|
+
<IconInfoCircle className="size-4 text-zinc-950 shrink-0" />
|
|
156
|
+
<span className="paragraph-small-regular text-zinc-950">
|
|
157
|
+
{translate('common.subscription.frozen.modal.keepsWorking')}
|
|
158
|
+
</span>
|
|
159
|
+
</div>
|
|
160
|
+
</>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<div className="h-px bg-zinc-200" />
|
|
97
165
|
|
|
98
|
-
<div className="flex items-center gap-2 p-5">
|
|
99
|
-
<Button className="w-fit
|
|
166
|
+
<div className="flex items-center gap-2 p-4 lg:p-5">
|
|
167
|
+
<Button className="h-10 w-fit" onClick={handleRegularize}>
|
|
100
168
|
{translate('common.subscription.frozen.modal.cta')}
|
|
101
169
|
</Button>
|
|
102
170
|
</div>
|
|
@@ -93,7 +93,7 @@ export function SubscriptionBanner({
|
|
|
93
93
|
// que responde outra pergunta. Aqui "Detalhes" significa "o que eu perco".
|
|
94
94
|
if (freezeState === "frozen") {
|
|
95
95
|
return (
|
|
96
|
-
<FrozenAccountBanner onDetails={() => openModal("accountFrozenModal")} />
|
|
96
|
+
<FrozenAccountBanner onDetails={() => openModal("accountFrozenModal", { showResources: true })} />
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
if (freezeState === "warning") {
|
|
@@ -101,7 +101,7 @@ export function SubscriptionBanner({
|
|
|
101
101
|
return (
|
|
102
102
|
<FreezeWarningBanner
|
|
103
103
|
freezeDate={freezeDate}
|
|
104
|
-
onDetails={() => openModal("accountFrozenModal", { freezeDate })}
|
|
104
|
+
onDetails={() => openModal("accountFrozenModal", { freezeDate, showResources: true })}
|
|
105
105
|
/>
|
|
106
106
|
);
|
|
107
107
|
}
|
|
@@ -444,20 +444,25 @@ const messages = {
|
|
|
444
444
|
},
|
|
445
445
|
modal: {
|
|
446
446
|
title: 'Your account resources are blocked',
|
|
447
|
-
description: '
|
|
447
|
+
description: 'Your account resources are blocked due to missing payment. Update your subscription to unlock them.',
|
|
448
|
+
descriptionWithResources: 'We could not identify your payment, so these resources are blocked:',
|
|
449
|
+
warningDescriptionWithResources: 'Your payment is overdue. If we do not identify it by then, these resources will be blocked:',
|
|
448
450
|
warningTitle: 'Your resources will be blocked on {freezeDate}',
|
|
449
|
-
warningDescription: 'Your payment is overdue.
|
|
451
|
+
warningDescription: 'Your payment is overdue. Settle it to keep access to your account resources.',
|
|
450
452
|
keepsWorking: 'Your published pages stay online and your leads keep coming in. Everything is restored automatically once the payment goes through.',
|
|
451
453
|
resources: {
|
|
452
|
-
pages:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
454
|
+
pages: {
|
|
455
|
+
title: 'Manage pages',
|
|
456
|
+
description: 'Publishing, creating and editing pages, settings, A/B tests, file uploads and exporting leads',
|
|
457
|
+
},
|
|
458
|
+
projects: {
|
|
459
|
+
title: 'Manage projects',
|
|
460
|
+
description: 'Creating and editing projects, inviting users and changing team permissions',
|
|
461
|
+
},
|
|
462
|
+
domains: {
|
|
463
|
+
title: 'Manage domains',
|
|
464
|
+
description: 'Connecting new domains and managing integrations',
|
|
465
|
+
},
|
|
461
466
|
},
|
|
462
467
|
cta: 'Update subscription',
|
|
463
468
|
},
|
|
@@ -445,20 +445,25 @@ const messages = {
|
|
|
445
445
|
},
|
|
446
446
|
modal: {
|
|
447
447
|
title: 'Los recursos de tu cuenta están bloqueados',
|
|
448
|
-
description: '
|
|
448
|
+
description: 'Los recursos de tu cuenta están bloqueados por falta de pago. Regulariza la suscripción para liberarlos.',
|
|
449
|
+
descriptionWithResources: 'No identificamos el pago, así que estos recursos están bloqueados:',
|
|
450
|
+
warningDescriptionWithResources: 'El pago está atrasado. Si no lo identificamos hasta entonces, estos recursos se bloquearán:',
|
|
449
451
|
warningTitle: 'Tus recursos se bloquearán el {freezeDate}',
|
|
450
|
-
warningDescription: 'El pago está atrasado.
|
|
452
|
+
warningDescription: 'El pago está atrasado. Regulariza para no perder el acceso a los recursos de tu cuenta.',
|
|
451
453
|
keepsWorking: 'Tus páginas publicadas siguen en línea y tus leads se siguen capturando. Todo vuelve automáticamente en cuanto se identifique el pago.',
|
|
452
454
|
resources: {
|
|
453
|
-
pages:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
455
|
+
pages: {
|
|
456
|
+
title: 'Gestionar páginas',
|
|
457
|
+
description: 'Publicar, crear y editar páginas, configuración, pruebas A/B, subida de archivos y exportar leads',
|
|
458
|
+
},
|
|
459
|
+
projects: {
|
|
460
|
+
title: 'Gestionar proyectos',
|
|
461
|
+
description: 'Crear y editar proyectos, invitar usuarios y cambiar permisos del equipo',
|
|
462
|
+
},
|
|
463
|
+
domains: {
|
|
464
|
+
title: 'Gestionar dominios',
|
|
465
|
+
description: 'Conectar nuevos dominios y gestionar integraciones',
|
|
466
|
+
},
|
|
462
467
|
},
|
|
463
468
|
cta: 'Regularizar suscripción',
|
|
464
469
|
},
|
|
@@ -462,20 +462,25 @@ const messages = {
|
|
|
462
462
|
},
|
|
463
463
|
modal: {
|
|
464
464
|
title: 'Recursos da sua conta bloqueados',
|
|
465
|
-
description: '
|
|
465
|
+
description: 'Sua conta está com os recursos bloqueados por falta de pagamento. Regularize a assinatura para liberar.',
|
|
466
|
+
descriptionWithResources: 'O pagamento não foi identificado, então estes recursos estão bloqueados:',
|
|
467
|
+
warningDescriptionWithResources: 'O pagamento está em atraso. Se não for identificado até lá, estes recursos serão bloqueados:',
|
|
466
468
|
warningTitle: 'Seus recursos serão bloqueados em {freezeDate}',
|
|
467
|
-
warningDescription: 'O pagamento está em atraso.
|
|
469
|
+
warningDescription: 'O pagamento está em atraso. Regularize para não perder o acesso aos recursos da sua conta.',
|
|
468
470
|
keepsWorking: 'Suas páginas publicadas continuam no ar e seus leads seguem sendo capturados. Assim que o pagamento for identificado, tudo volta automaticamente.',
|
|
469
471
|
resources: {
|
|
470
|
-
pages:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
472
|
+
pages: {
|
|
473
|
+
title: 'Gerenciar páginas',
|
|
474
|
+
description: 'Publicar, criar e editar páginas, configurações, testes A/B, upload de arquivos e exportar leads',
|
|
475
|
+
},
|
|
476
|
+
projects: {
|
|
477
|
+
title: 'Gerenciar projetos',
|
|
478
|
+
description: 'Criar e editar projetos, convidar usuários e alterar permissões da equipe',
|
|
479
|
+
},
|
|
480
|
+
domains: {
|
|
481
|
+
title: 'Gerenciar domínios',
|
|
482
|
+
description: 'Conectar novos domínios e gerenciar integrações',
|
|
483
|
+
},
|
|
479
484
|
},
|
|
480
485
|
cta: 'Regularizar assinatura',
|
|
481
486
|
},
|