@greatapps/common 1.1.805 → 1.1.806
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/account/sections/subscription/PixDetailsDialog.mjs +4 -6
- package/dist/components/account/sections/subscription/PixDetailsDialog.mjs.map +1 -1
- package/dist/components/account/sections/subscription/PixPaymentDialog.mjs +17 -24
- package/dist/components/account/sections/subscription/PixPaymentDialog.mjs.map +1 -1
- package/dist/hooks/useSecondsUntil.mjs +17 -0
- package/dist/hooks/useSecondsUntil.mjs.map +1 -0
- package/dist/i18n/messages/en-us.mjs +2 -0
- package/dist/i18n/messages/en-us.mjs.map +1 -1
- package/dist/i18n/messages/es-es.mjs +2 -0
- package/dist/i18n/messages/es-es.mjs.map +1 -1
- package/dist/i18n/messages/pt-br.mjs +2 -0
- package/dist/i18n/messages/pt-br.mjs.map +1 -1
- package/dist/modules/subscriptions/types/pending-pix-status.type.mjs +1 -0
- package/dist/modules/subscriptions/types/pending-pix-status.type.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/account/sections/subscription/PixDetailsDialog.tsx +4 -9
- package/src/components/account/sections/subscription/PixPaymentDialog.tsx +18 -29
- package/src/hooks/useSecondsUntil.ts +17 -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/modules/subscriptions/types/pending-pix-status.type.ts +1 -0
|
@@ -10,7 +10,7 @@ import { Toast } from '../../../ui/feedback/Toast';
|
|
|
10
10
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../../ui/overlay/Dialog';
|
|
11
11
|
import { useCurrencyFormatter } from '../../../../modules/accounts/hooks/use-currency-formatter.hook';
|
|
12
12
|
import { usePendingPixStatus } from '../../../../modules/subscriptions/hooks/pending-pix-status.hook';
|
|
13
|
-
import
|
|
13
|
+
import useSecondsUntil from '../../../../hooks/useSecondsUntil';
|
|
14
14
|
import { copyToClipboard } from '../../../../utils/browser/clipboard';
|
|
15
15
|
import { qrCodeToDataUrl } from '../../../../utils/qrcode/to-data-url';
|
|
16
16
|
import { useSubscriptionFlows } from '../../../../store/useSubscriptionFlows';
|
|
@@ -39,20 +39,11 @@ export function PixPaymentDialog() {
|
|
|
39
39
|
const close = useSubscriptionFlows((state) => state.closePixPayment);
|
|
40
40
|
const openPlansCatalog = useSubscriptionFlows((state) => state.openPlansCatalog);
|
|
41
41
|
|
|
42
|
-
const [mountedAt, setMountedAt] = useState<number | null>(null);
|
|
43
42
|
const [generatedQrImage, setGeneratedQrImage] = useState<string | null>(null);
|
|
44
43
|
|
|
45
44
|
const { data: statusData } = usePendingPixStatus(pixPayment?.correlationId);
|
|
46
45
|
const phase = statusData?.data?.phase;
|
|
47
46
|
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (!pixPayment) {
|
|
50
|
-
setMountedAt(null);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
setMountedAt(Date.now());
|
|
54
|
-
}, [pixPayment]);
|
|
55
|
-
|
|
56
47
|
useEffect(() => {
|
|
57
48
|
const qrCode = pixPayment?.qrCode;
|
|
58
49
|
if (!qrCode) {
|
|
@@ -79,19 +70,22 @@ export function PixPaymentDialog() {
|
|
|
79
70
|
};
|
|
80
71
|
}, [pixPayment?.qrCode]);
|
|
81
72
|
|
|
82
|
-
const
|
|
73
|
+
const isCompleted = phase === 'completed';
|
|
74
|
+
const isAuthorizedOnly = statusData?.data?.payment_collected === false;
|
|
75
|
+
const completedTitle = isAuthorizedOnly ? translate('authorizedTitle') : translate('paidTitle');
|
|
76
|
+
const completedMessage = isAuthorizedOnly ? translate('authorizedMessage') : translate('paidToast');
|
|
83
77
|
const isRejected = phase === 'rejected';
|
|
84
78
|
const isExpired = phase === 'expired';
|
|
85
79
|
|
|
86
80
|
// Pago avisa uma vez; a janela fica com a confirmação na tela, como a página do gapps fazia.
|
|
87
81
|
const paidNotifiedRef = useRef(false);
|
|
88
82
|
useEffect(() => {
|
|
89
|
-
if (!
|
|
83
|
+
if (!isCompleted || paidNotifiedRef.current) return;
|
|
90
84
|
paidNotifiedRef.current = true;
|
|
91
85
|
toast.custom((toastId) => (
|
|
92
|
-
<Toast variant="success" message={
|
|
86
|
+
<Toast variant="success" message={completedMessage} toastId={toastId} />
|
|
93
87
|
));
|
|
94
|
-
}, [
|
|
88
|
+
}, [isCompleted, completedMessage]);
|
|
95
89
|
|
|
96
90
|
useEffect(() => {
|
|
97
91
|
if (!pixPayment) paidNotifiedRef.current = false;
|
|
@@ -102,12 +96,7 @@ export function PixPaymentDialog() {
|
|
|
102
96
|
openPlansCatalog();
|
|
103
97
|
};
|
|
104
98
|
|
|
105
|
-
const
|
|
106
|
-
pixPayment?.expiresAt && mountedAt
|
|
107
|
-
? Math.max(0, Math.floor((new Date(pixPayment.expiresAt).getTime() - mountedAt) / 1000))
|
|
108
|
-
: null;
|
|
109
|
-
const shouldShowCountdown = typeof expiresInSeconds === 'number' && expiresInSeconds > 0;
|
|
110
|
-
const { seconds } = useCountdownTimer({ initialSeconds: shouldShowCountdown ? expiresInSeconds : 1 });
|
|
99
|
+
const secondsUntilExpiry = useSecondsUntil(pixPayment?.expiresAt);
|
|
111
100
|
|
|
112
101
|
const handleCopyCode = async () => {
|
|
113
102
|
if (!pixPayment?.qrCode) return;
|
|
@@ -141,15 +130,15 @@ export function PixPaymentDialog() {
|
|
|
141
130
|
|
|
142
131
|
{/* Fechado o ciclo (pago, recusado ou expirado), o QR perde a função: a janela vira o
|
|
143
132
|
desfecho, como a página de pix do gapps. */}
|
|
144
|
-
{
|
|
133
|
+
{isCompleted || isRejected || isExpired ? (
|
|
145
134
|
<div className="flex flex-col items-center justify-center gap-4 p-8 text-center">
|
|
146
135
|
<div
|
|
147
136
|
className={cn(
|
|
148
137
|
'size-12 rounded-full flex items-center justify-center',
|
|
149
|
-
|
|
138
|
+
isCompleted ? 'bg-green-50' : 'bg-red-50'
|
|
150
139
|
)}
|
|
151
140
|
>
|
|
152
|
-
{
|
|
141
|
+
{isCompleted ? (
|
|
153
142
|
<IconCircleCheck size={24} className="text-green-500" />
|
|
154
143
|
) : (
|
|
155
144
|
<IconAlertTriangle size={24} className="text-red-500" />
|
|
@@ -158,18 +147,18 @@ export function PixPaymentDialog() {
|
|
|
158
147
|
|
|
159
148
|
<div className="flex flex-col gap-1">
|
|
160
149
|
<span className="paragraph-xlarge-semibold text-zinc-950">
|
|
161
|
-
{
|
|
162
|
-
?
|
|
150
|
+
{isCompleted
|
|
151
|
+
? completedTitle
|
|
163
152
|
: isRejected
|
|
164
153
|
? translate('rejectedTitle')
|
|
165
154
|
: translate('expiredTitle')}
|
|
166
155
|
</span>
|
|
167
156
|
<span className="paragraph-small-regular text-zinc-500">
|
|
168
|
-
{
|
|
157
|
+
{isCompleted ? completedMessage : translate('rejectedOrExpiredDescription')}
|
|
169
158
|
</span>
|
|
170
159
|
</div>
|
|
171
160
|
|
|
172
|
-
{
|
|
161
|
+
{isCompleted ? (
|
|
173
162
|
<Button variant="secondary" className="h-10" onClick={close}>
|
|
174
163
|
{translateActions('common.actions.close')}
|
|
175
164
|
</Button>
|
|
@@ -189,9 +178,9 @@ export function PixPaymentDialog() {
|
|
|
189
178
|
)}
|
|
190
179
|
|
|
191
180
|
<div className="flex flex-col gap-6 p-5 border border-zinc-200 rounded-lg bg-white items-center">
|
|
192
|
-
{
|
|
181
|
+
{!!secondsUntilExpiry && (
|
|
193
182
|
<p className="paragraph-small-semibold text-zinc-950 text-center">
|
|
194
|
-
{translate('payIn')} <span className="text-red-600">{formatCountdown(
|
|
183
|
+
{translate('payIn')} <span className="text-red-600">{formatCountdown(secondsUntilExpiry)}</span>
|
|
195
184
|
</p>
|
|
196
185
|
)}
|
|
197
186
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export default function useSecondsUntil(deadline: string | null | undefined): number | null {
|
|
6
|
+
const [now, setNow] = useState<number | null>(null);
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!deadline) return;
|
|
10
|
+
setNow(Date.now());
|
|
11
|
+
const interval = setInterval(() => setNow(Date.now()), 1000);
|
|
12
|
+
return () => clearInterval(interval);
|
|
13
|
+
}, [deadline]);
|
|
14
|
+
|
|
15
|
+
if (!deadline || now === null) return null;
|
|
16
|
+
return Math.max(0, Math.floor((new Date(deadline).getTime() - now) / 1000));
|
|
17
|
+
}
|
|
@@ -1092,6 +1092,8 @@ const messages = {
|
|
|
1092
1092
|
paidToast: 'Payment processed successfully.',
|
|
1093
1093
|
waitingPayment: 'Waiting for payment confirmation...',
|
|
1094
1094
|
paidTitle: 'PIX paid',
|
|
1095
|
+
authorizedTitle: 'Automatic PIX authorized',
|
|
1096
|
+
authorizedMessage: 'The charge will be made automatically on the due date.',
|
|
1095
1097
|
rejectedTitle: 'PIX rejected',
|
|
1096
1098
|
expiredTitle: 'PIX code expired',
|
|
1097
1099
|
rejectedOrExpiredDescription: 'Click below to generate a new PIX code',
|
|
@@ -1098,6 +1098,8 @@ const messages = {
|
|
|
1098
1098
|
paidToast: 'Pago realizado exitosamente.',
|
|
1099
1099
|
waitingPayment: 'Esperando la confirmación del pago...',
|
|
1100
1100
|
paidTitle: 'PIX pagado',
|
|
1101
|
+
authorizedTitle: 'PIX automático autorizado',
|
|
1102
|
+
authorizedMessage: 'El cobro se realizará automáticamente en la fecha de vencimiento.',
|
|
1101
1103
|
rejectedTitle: 'PIX rechazado',
|
|
1102
1104
|
expiredTitle: 'Código PIX expirado',
|
|
1103
1105
|
rejectedOrExpiredDescription: 'Haz clic abajo para generar un nuevo código PIX',
|
|
@@ -1105,6 +1105,8 @@ const messages = {
|
|
|
1105
1105
|
paidToast: 'Pagamento efetuado com sucesso.',
|
|
1106
1106
|
waitingPayment: 'Aguardando a confirmação do pagamento...',
|
|
1107
1107
|
paidTitle: 'PIX pago',
|
|
1108
|
+
authorizedTitle: 'PIX automático autorizado',
|
|
1109
|
+
authorizedMessage: 'A cobrança será feita automaticamente na data de vencimento.',
|
|
1108
1110
|
rejectedTitle: 'Pix recusado',
|
|
1109
1111
|
expiredTitle: 'Código PIX expirado',
|
|
1110
1112
|
rejectedOrExpiredDescription: 'Clique abaixo para gerar um novo código PIX',
|
|
@@ -16,6 +16,7 @@ export const PendingPixStatusDataSchema = z
|
|
|
16
16
|
payment_method: z.number().nullable().optional(),
|
|
17
17
|
subscription_id: z.union([z.number(), z.string()]).optional(),
|
|
18
18
|
completed_at: z.string().nullable().optional(),
|
|
19
|
+
payment_collected: z.boolean().optional(),
|
|
19
20
|
pix: z
|
|
20
21
|
.object({
|
|
21
22
|
qr_code: z.string().nullable().optional(),
|