@djangocfg/layouts 2.1.10 → 2.1.15
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/README.md +53 -161
- package/package.json +6 -6
- package/src/components/RedirectPage/RedirectPage.tsx +1 -1
- package/src/index.ts +0 -6
- package/src/layouts/AppLayout/AppLayout.tsx +1 -1
- package/src/layouts/AppLayout/BaseApp.tsx +1 -1
- package/src/layouts/AuthLayout/AuthContext.tsx +1 -1
- package/src/layouts/AuthLayout/OAuthCallback.tsx +1 -1
- package/src/layouts/AuthLayout/OAuthProviders.tsx +1 -1
- package/src/layouts/PrivateLayout/PrivateLayout.tsx +1 -1
- package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +1 -1
- package/src/layouts/ProfileLayout/ProfileLayout.tsx +2 -2
- package/src/layouts/ProfileLayout/components/AvatarSection.tsx +2 -2
- package/src/layouts/ProfileLayout/components/ProfileForm.tsx +2 -2
- package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
- package/src/layouts/PublicLayout/components/PublicNavigation.tsx +1 -1
- package/src/layouts/_components/UserMenu.tsx +1 -1
- package/src/layouts/index.ts +0 -2
- package/src/snippets/Analytics/useAnalytics.ts +1 -1
- package/src/snippets/index.ts +0 -3
- package/src/auth/README.md +0 -962
- package/src/auth/context/AccountsContext.tsx +0 -240
- package/src/auth/context/AuthContext.tsx +0 -604
- package/src/auth/context/index.ts +0 -4
- package/src/auth/context/types.ts +0 -68
- package/src/auth/hooks/index.ts +0 -17
- package/src/auth/hooks/useAuthForm.ts +0 -332
- package/src/auth/hooks/useAuthGuard.ts +0 -25
- package/src/auth/hooks/useAuthRedirect.ts +0 -51
- package/src/auth/hooks/useAutoAuth.ts +0 -49
- package/src/auth/hooks/useGithubAuth.ts +0 -184
- package/src/auth/hooks/useLocalStorage.ts +0 -214
- package/src/auth/hooks/useProfileCache.ts +0 -146
- package/src/auth/hooks/useSessionStorage.ts +0 -189
- package/src/auth/index.ts +0 -10
- package/src/auth/middlewares/index.ts +0 -1
- package/src/auth/middlewares/proxy.ts +0 -32
- package/src/auth/server.ts +0 -6
- package/src/auth/utils/errors.ts +0 -34
- package/src/auth/utils/index.ts +0 -2
- package/src/auth/utils/validation.ts +0 -14
- package/src/contexts/LeadsContext.tsx +0 -156
- package/src/contexts/NewsletterContext.tsx +0 -263
- package/src/contexts/SupportContext.tsx +0 -256
- package/src/contexts/index.ts +0 -59
- package/src/contexts/knowbase/ChatContext.tsx +0 -174
- package/src/contexts/knowbase/DocumentsContext.tsx +0 -304
- package/src/contexts/knowbase/SessionsContext.tsx +0 -174
- package/src/contexts/knowbase/index.ts +0 -61
- package/src/contexts/payments/BalancesContext.tsx +0 -65
- package/src/contexts/payments/CurrenciesContext.tsx +0 -66
- package/src/contexts/payments/OverviewContext.tsx +0 -174
- package/src/contexts/payments/PaymentsContext.tsx +0 -132
- package/src/contexts/payments/README.md +0 -201
- package/src/contexts/payments/RootPaymentsContext.tsx +0 -68
- package/src/contexts/payments/index.ts +0 -50
- package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +0 -92
- package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +0 -291
- package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +0 -290
- package/src/layouts/PaymentsLayout/components/index.ts +0 -2
- package/src/layouts/PaymentsLayout/events.ts +0 -47
- package/src/layouts/PaymentsLayout/index.ts +0 -16
- package/src/layouts/PaymentsLayout/types.ts +0 -6
- package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +0 -128
- package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +0 -142
- package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
- package/src/layouts/PaymentsLayout/views/overview/index.tsx +0 -20
- package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +0 -276
- package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
- package/src/layouts/PaymentsLayout/views/payments/index.tsx +0 -17
- package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +0 -273
- package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +0 -1
- package/src/layouts/PaymentsLayout/views/transactions/index.tsx +0 -17
- package/src/layouts/SupportLayout/README.md +0 -91
- package/src/layouts/SupportLayout/SupportLayout.tsx +0 -179
- package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +0 -155
- package/src/layouts/SupportLayout/components/MessageInput.tsx +0 -92
- package/src/layouts/SupportLayout/components/MessageList.tsx +0 -314
- package/src/layouts/SupportLayout/components/TicketCard.tsx +0 -96
- package/src/layouts/SupportLayout/components/TicketList.tsx +0 -153
- package/src/layouts/SupportLayout/components/index.ts +0 -6
- package/src/layouts/SupportLayout/context/SupportLayoutContext.tsx +0 -263
- package/src/layouts/SupportLayout/context/index.ts +0 -2
- package/src/layouts/SupportLayout/events.ts +0 -33
- package/src/layouts/SupportLayout/hooks/index.ts +0 -2
- package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +0 -119
- package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +0 -92
- package/src/layouts/SupportLayout/index.ts +0 -8
- package/src/layouts/SupportLayout/types.ts +0 -21
- package/src/snippets/Chat/ChatUIContext.tsx +0 -110
- package/src/snippets/Chat/ChatWidget.tsx +0 -476
- package/src/snippets/Chat/README.md +0 -122
- package/src/snippets/Chat/components/MessageInput.tsx +0 -124
- package/src/snippets/Chat/components/MessageList.tsx +0 -169
- package/src/snippets/Chat/components/SessionList.tsx +0 -192
- package/src/snippets/Chat/components/index.ts +0 -9
- package/src/snippets/Chat/hooks/index.ts +0 -6
- package/src/snippets/Chat/hooks/useInfiniteSessions.ts +0 -82
- package/src/snippets/Chat/index.tsx +0 -45
- package/src/snippets/Chat/types.ts +0 -80
- package/src/snippets/ContactForm/ContactForm.tsx +0 -346
- package/src/snippets/ContactForm/ContactFormProvider.tsx +0 -153
- package/src/snippets/ContactForm/ContactInfo.tsx +0 -114
- package/src/snippets/ContactForm/ContactPage.tsx +0 -131
- package/src/snippets/ContactForm/dynamic.tsx +0 -55
- package/src/snippets/ContactForm/index.ts +0 -34
- package/src/snippets/ContactForm/types.ts +0 -110
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* Create Payment Dialog (v2.0 - Simplified)
|
|
4
|
-
* Dialog for creating new payments
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
'use client';
|
|
8
|
-
|
|
9
|
-
import React, { useState, useEffect, useMemo } from 'react';
|
|
10
|
-
import {
|
|
11
|
-
Dialog,
|
|
12
|
-
DialogContent,
|
|
13
|
-
DialogDescription,
|
|
14
|
-
DialogFooter,
|
|
15
|
-
DialogHeader,
|
|
16
|
-
DialogTitle,
|
|
17
|
-
Form,
|
|
18
|
-
FormControl,
|
|
19
|
-
FormDescription,
|
|
20
|
-
FormField,
|
|
21
|
-
FormItem,
|
|
22
|
-
FormLabel,
|
|
23
|
-
FormMessage,
|
|
24
|
-
Input,
|
|
25
|
-
Select,
|
|
26
|
-
SelectContent,
|
|
27
|
-
SelectItem,
|
|
28
|
-
SelectTrigger,
|
|
29
|
-
SelectValue,
|
|
30
|
-
Button,
|
|
31
|
-
TokenIcon,
|
|
32
|
-
} from '@djangocfg/ui-nextjs';
|
|
33
|
-
import { Plus, RefreshCw } from 'lucide-react';
|
|
34
|
-
import { useForm } from 'react-hook-form';
|
|
35
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
36
|
-
import { z } from 'zod';
|
|
37
|
-
import { usePaymentsContext, useRootPaymentsContext } from '@djangocfg/layouts/contexts';
|
|
38
|
-
import { PAYMENT_EVENTS, closePaymentsDialog } from '../events';
|
|
39
|
-
import { openPaymentDetailsDialog } from '../events';
|
|
40
|
-
import { paymentsLogger } from '../../../utils/logger';
|
|
41
|
-
|
|
42
|
-
// Payment creation schema
|
|
43
|
-
const PaymentCreateSchema = z.object({
|
|
44
|
-
amount_usd: z.number().min(0.01, 'Amount must be at least $0.01'),
|
|
45
|
-
currency_code: z.string().min(1, 'Please select a currency'),
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
type PaymentCreateRequest = z.infer<typeof PaymentCreateSchema>;
|
|
49
|
-
|
|
50
|
-
export const CreatePaymentDialog: React.FC = () => {
|
|
51
|
-
const [open, setOpen] = useState(false);
|
|
52
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
53
|
-
|
|
54
|
-
const { createPayment } = usePaymentsContext();
|
|
55
|
-
const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
|
|
56
|
-
|
|
57
|
-
const form = useForm<PaymentCreateRequest>({
|
|
58
|
-
resolver: zodResolver(PaymentCreateSchema),
|
|
59
|
-
defaultValues: {
|
|
60
|
-
amount_usd: 10,
|
|
61
|
-
currency_code: 'USDT',
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Extract currencies list from response (handle different possible structures)
|
|
66
|
-
const currenciesList = useMemo(() => {
|
|
67
|
-
const data = currencies?.currencies || currencies?.results || currencies || [];
|
|
68
|
-
return Array.isArray(data) ? data : [];
|
|
69
|
-
}, [currencies]);
|
|
70
|
-
|
|
71
|
-
// Get currency options for select
|
|
72
|
-
const currencyOptions = useMemo(() => {
|
|
73
|
-
return currenciesList
|
|
74
|
-
.filter((curr: any) => curr.is_enabled !== false)
|
|
75
|
-
.map((curr: any) => ({
|
|
76
|
-
code: curr.code || curr.currency_code || curr.symbol,
|
|
77
|
-
name: curr.name || curr.code || curr.currency_code,
|
|
78
|
-
usd_rate: curr.usd_rate || curr.rate || 1,
|
|
79
|
-
network: curr.network || null,
|
|
80
|
-
}));
|
|
81
|
-
}, [currenciesList]);
|
|
82
|
-
|
|
83
|
-
// Calculate crypto amount from USD
|
|
84
|
-
const calculateCryptoAmount = useMemo(() => {
|
|
85
|
-
const amountUsd = form.watch('amount_usd');
|
|
86
|
-
const currencyCode = form.watch('currency_code');
|
|
87
|
-
const currency = currencyOptions.find((c: any) => c.code === currencyCode);
|
|
88
|
-
|
|
89
|
-
if (!currency || !currency.usd_rate || !amountUsd) {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const cryptoAmount = amountUsd / currency.usd_rate;
|
|
94
|
-
return {
|
|
95
|
-
amount: cryptoAmount,
|
|
96
|
-
currency: currency.code,
|
|
97
|
-
rate: currency.usd_rate,
|
|
98
|
-
network: currency.network,
|
|
99
|
-
};
|
|
100
|
-
}, [form.watch('amount_usd'), form.watch('currency_code'), currencyOptions]);
|
|
101
|
-
|
|
102
|
-
// Listen for open/close events
|
|
103
|
-
useEffect(() => {
|
|
104
|
-
const handleOpen = () => setOpen(true);
|
|
105
|
-
const handleClose = () => setOpen(false);
|
|
106
|
-
|
|
107
|
-
window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
108
|
-
window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
109
|
-
|
|
110
|
-
return () => {
|
|
111
|
-
window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
112
|
-
window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
113
|
-
};
|
|
114
|
-
}, []);
|
|
115
|
-
|
|
116
|
-
const handleClose = () => {
|
|
117
|
-
setOpen(false);
|
|
118
|
-
form.reset();
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// Initialize default currency if not set
|
|
122
|
-
useEffect(() => {
|
|
123
|
-
if (currencyOptions.length > 0 && !form.getValues('currency_code')) {
|
|
124
|
-
form.setValue('currency_code', currencyOptions[0].code);
|
|
125
|
-
}
|
|
126
|
-
}, [currencyOptions, form]);
|
|
127
|
-
|
|
128
|
-
const handleSubmit = async (data: PaymentCreateRequest) => {
|
|
129
|
-
try {
|
|
130
|
-
setIsSubmitting(true);
|
|
131
|
-
|
|
132
|
-
const result = await createPayment();
|
|
133
|
-
handleClose();
|
|
134
|
-
closePaymentsDialog();
|
|
135
|
-
|
|
136
|
-
// Extract payment ID from result
|
|
137
|
-
const paymentData = result as any;
|
|
138
|
-
const paymentId = paymentData?.payment?.id || paymentData?.id;
|
|
139
|
-
|
|
140
|
-
if (paymentId) {
|
|
141
|
-
openPaymentDetailsDialog(String(paymentId));
|
|
142
|
-
}
|
|
143
|
-
} catch (error) {
|
|
144
|
-
paymentsLogger.error('Failed to create payment:', error);
|
|
145
|
-
} finally {
|
|
146
|
-
setIsSubmitting(false);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
|
|
152
|
-
<DialogContent className="sm:max-w-md">
|
|
153
|
-
<DialogHeader>
|
|
154
|
-
<DialogTitle>Create Payment</DialogTitle>
|
|
155
|
-
<DialogDescription>
|
|
156
|
-
Create a new payment to add funds to your account.
|
|
157
|
-
</DialogDescription>
|
|
158
|
-
</DialogHeader>
|
|
159
|
-
|
|
160
|
-
<Form {...form}>
|
|
161
|
-
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
|
162
|
-
<FormField
|
|
163
|
-
control={form.control}
|
|
164
|
-
name="amount_usd"
|
|
165
|
-
render={({ field }) => (
|
|
166
|
-
<FormItem>
|
|
167
|
-
<FormLabel>Amount (USD)</FormLabel>
|
|
168
|
-
<FormControl>
|
|
169
|
-
<Input
|
|
170
|
-
type="number"
|
|
171
|
-
step="0.01"
|
|
172
|
-
min="0.01"
|
|
173
|
-
placeholder="10.00"
|
|
174
|
-
{...field}
|
|
175
|
-
onChange={(e) => field.onChange(parseFloat(e.target.value) || 0)}
|
|
176
|
-
/>
|
|
177
|
-
</FormControl>
|
|
178
|
-
<FormDescription>
|
|
179
|
-
The amount you want to pay in USD.
|
|
180
|
-
</FormDescription>
|
|
181
|
-
<FormMessage />
|
|
182
|
-
</FormItem>
|
|
183
|
-
)}
|
|
184
|
-
/>
|
|
185
|
-
|
|
186
|
-
<FormField
|
|
187
|
-
control={form.control}
|
|
188
|
-
name="currency_code"
|
|
189
|
-
render={({ field }) => (
|
|
190
|
-
<FormItem>
|
|
191
|
-
<FormLabel>Currency</FormLabel>
|
|
192
|
-
<Select
|
|
193
|
-
onValueChange={field.onChange}
|
|
194
|
-
defaultValue={field.value}
|
|
195
|
-
disabled={isLoadingCurrencies}
|
|
196
|
-
>
|
|
197
|
-
<FormControl>
|
|
198
|
-
<SelectTrigger>
|
|
199
|
-
<SelectValue placeholder="Select currency..." />
|
|
200
|
-
</SelectTrigger>
|
|
201
|
-
</FormControl>
|
|
202
|
-
<SelectContent>
|
|
203
|
-
{currencyOptions.map((curr: any) => (
|
|
204
|
-
<SelectItem key={curr.code} value={curr.code}>
|
|
205
|
-
<div className="flex items-center gap-2">
|
|
206
|
-
<TokenIcon symbol={curr.code} size={16} />
|
|
207
|
-
<span>{curr.code}</span>
|
|
208
|
-
{curr.network && (
|
|
209
|
-
<span className="text-xs text-muted-foreground">
|
|
210
|
-
({curr.network})
|
|
211
|
-
</span>
|
|
212
|
-
)}
|
|
213
|
-
</div>
|
|
214
|
-
</SelectItem>
|
|
215
|
-
))}
|
|
216
|
-
</SelectContent>
|
|
217
|
-
</Select>
|
|
218
|
-
<FormDescription>
|
|
219
|
-
The cryptocurrency to use for payment.
|
|
220
|
-
</FormDescription>
|
|
221
|
-
<FormMessage />
|
|
222
|
-
</FormItem>
|
|
223
|
-
)}
|
|
224
|
-
/>
|
|
225
|
-
|
|
226
|
-
{/* Conversion Information */}
|
|
227
|
-
{calculateCryptoAmount && (
|
|
228
|
-
<div className="rounded-sm bg-muted p-4 space-y-3">
|
|
229
|
-
{/* Amount to Send in Crypto */}
|
|
230
|
-
<div className="flex items-center justify-between">
|
|
231
|
-
<span className="text-sm text-muted-foreground">You will send</span>
|
|
232
|
-
<div className="flex items-center gap-2">
|
|
233
|
-
<TokenIcon symbol={calculateCryptoAmount.currency} size={16} />
|
|
234
|
-
<span className="font-mono font-semibold">
|
|
235
|
-
{calculateCryptoAmount.amount.toFixed(8)} {calculateCryptoAmount.currency}
|
|
236
|
-
</span>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
|
|
240
|
-
{/* USD Amount Received */}
|
|
241
|
-
<div className="flex items-center justify-between">
|
|
242
|
-
<span className="text-sm text-muted-foreground">You will receive</span>
|
|
243
|
-
<span className="text-lg font-bold">
|
|
244
|
-
${form.watch('amount_usd')?.toFixed(2)} USD
|
|
245
|
-
</span>
|
|
246
|
-
</div>
|
|
247
|
-
|
|
248
|
-
{/* Exchange Rate */}
|
|
249
|
-
<div className="flex items-center justify-between text-xs">
|
|
250
|
-
<span className="text-muted-foreground">Rate</span>
|
|
251
|
-
<span className="font-medium">
|
|
252
|
-
1 {calculateCryptoAmount.currency} = ${calculateCryptoAmount.rate?.toFixed(2)}
|
|
253
|
-
</span>
|
|
254
|
-
</div>
|
|
255
|
-
|
|
256
|
-
{/* Network Info */}
|
|
257
|
-
{calculateCryptoAmount.network && (
|
|
258
|
-
<div className="border-t pt-3">
|
|
259
|
-
<div className="flex items-center justify-between">
|
|
260
|
-
<span className="text-sm text-muted-foreground">Network</span>
|
|
261
|
-
<span className="text-sm font-medium">{calculateCryptoAmount.network}</span>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
)}
|
|
265
|
-
</div>
|
|
266
|
-
)}
|
|
267
|
-
|
|
268
|
-
<DialogFooter>
|
|
269
|
-
<Button type="button" variant="outline" onClick={handleClose} disabled={isSubmitting}>
|
|
270
|
-
Cancel
|
|
271
|
-
</Button>
|
|
272
|
-
<Button type="submit" disabled={isSubmitting || currencyOptions.length === 0}>
|
|
273
|
-
{isSubmitting ? (
|
|
274
|
-
<>
|
|
275
|
-
<RefreshCw className="h-4 w-4 mr-2 animate-spin" />
|
|
276
|
-
Creating...
|
|
277
|
-
</>
|
|
278
|
-
) : (
|
|
279
|
-
<>
|
|
280
|
-
<Plus className="h-4 w-4 mr-2" />
|
|
281
|
-
Create Payment
|
|
282
|
-
</>
|
|
283
|
-
)}
|
|
284
|
-
</Button>
|
|
285
|
-
</DialogFooter>
|
|
286
|
-
</form>
|
|
287
|
-
</Form>
|
|
288
|
-
</DialogContent>
|
|
289
|
-
</Dialog>
|
|
290
|
-
);
|
|
291
|
-
};
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payment Details Dialog (v2.0 - Simplified)
|
|
3
|
-
* Shows payment details with QR code, address, and status
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React, { useState, useEffect } from 'react';
|
|
9
|
-
import {
|
|
10
|
-
Dialog,
|
|
11
|
-
DialogContent,
|
|
12
|
-
DialogDescription,
|
|
13
|
-
DialogFooter,
|
|
14
|
-
DialogHeader,
|
|
15
|
-
DialogTitle,
|
|
16
|
-
Button,
|
|
17
|
-
TokenIcon,
|
|
18
|
-
CopyButton,
|
|
19
|
-
} from '@djangocfg/ui-nextjs';
|
|
20
|
-
import { ExternalLink, CheckCircle2, Clock, XCircle, AlertCircle, RefreshCw } from 'lucide-react';
|
|
21
|
-
import { Hooks, api } from '@djangocfg/api';
|
|
22
|
-
import type { API } from '@djangocfg/api';
|
|
23
|
-
import { PAYMENT_EVENTS } from '../events';
|
|
24
|
-
|
|
25
|
-
export const PaymentDetailsDialog: React.FC = () => {
|
|
26
|
-
const [open, setOpen] = useState(false);
|
|
27
|
-
const [paymentId, setPaymentId] = useState<string | null>(null);
|
|
28
|
-
const [timeLeft, setTimeLeft] = useState<string>('');
|
|
29
|
-
|
|
30
|
-
// Load payment data by ID using hook
|
|
31
|
-
const shouldFetch = open && !!paymentId;
|
|
32
|
-
const { data: payment, isLoading, error, mutate } = Hooks.usePaymentsPaymentsRetrieve(
|
|
33
|
-
shouldFetch ? paymentId : '',
|
|
34
|
-
api as unknown as API
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// Listen for open/close events
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const handleOpen = (event: Event) => {
|
|
40
|
-
const customEvent = event as CustomEvent<{ id: string }>;
|
|
41
|
-
setPaymentId(customEvent.detail.id);
|
|
42
|
-
setOpen(true);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const handleClose = () => {
|
|
46
|
-
setOpen(false);
|
|
47
|
-
setPaymentId(null);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
window.addEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
|
|
51
|
-
window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
52
|
-
|
|
53
|
-
return () => {
|
|
54
|
-
window.removeEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
|
|
55
|
-
window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
56
|
-
};
|
|
57
|
-
}, []);
|
|
58
|
-
|
|
59
|
-
const handleClose = () => {
|
|
60
|
-
setOpen(false);
|
|
61
|
-
setPaymentId(null);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Calculate time left until expiration
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (!payment?.expires_at) return;
|
|
67
|
-
|
|
68
|
-
const updateTimeLeft = () => {
|
|
69
|
-
const now = new Date().getTime();
|
|
70
|
-
const expires = new Date(payment.expires_at!).getTime();
|
|
71
|
-
const diff = expires - now;
|
|
72
|
-
|
|
73
|
-
if (diff <= 0) {
|
|
74
|
-
setTimeLeft('Expired');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const hours = Math.floor(diff / (1000 * 60 * 60));
|
|
79
|
-
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
|
80
|
-
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
|
|
81
|
-
|
|
82
|
-
setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
updateTimeLeft();
|
|
86
|
-
const interval = setInterval(updateTimeLeft, 1000);
|
|
87
|
-
|
|
88
|
-
return () => clearInterval(interval);
|
|
89
|
-
}, [payment?.expires_at]);
|
|
90
|
-
|
|
91
|
-
// Get status icon and color
|
|
92
|
-
const getStatusInfo = () => {
|
|
93
|
-
switch (payment?.status?.toLowerCase()) {
|
|
94
|
-
case 'pending':
|
|
95
|
-
return { icon: Clock, color: 'text-yellow-500', bg: 'bg-yellow-500/10' };
|
|
96
|
-
case 'completed':
|
|
97
|
-
case 'success':
|
|
98
|
-
return { icon: CheckCircle2, color: 'text-green-500', bg: 'bg-green-500/10' };
|
|
99
|
-
case 'failed':
|
|
100
|
-
case 'error':
|
|
101
|
-
return { icon: XCircle, color: 'text-red-500', bg: 'bg-red-500/10' };
|
|
102
|
-
case 'expired':
|
|
103
|
-
return { icon: AlertCircle, color: 'text-gray-500', bg: 'bg-gray-500/10' };
|
|
104
|
-
case 'confirming':
|
|
105
|
-
return { icon: RefreshCw, color: 'text-blue-500', bg: 'bg-blue-500/10' };
|
|
106
|
-
default:
|
|
107
|
-
return { icon: Clock, color: 'text-gray-500', bg: 'bg-gray-500/10' };
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
if (!open) return null;
|
|
112
|
-
|
|
113
|
-
// Loading state
|
|
114
|
-
if (isLoading) {
|
|
115
|
-
return (
|
|
116
|
-
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
|
|
117
|
-
<DialogContent className="sm:max-w-lg">
|
|
118
|
-
<DialogHeader>
|
|
119
|
-
<DialogTitle>Payment Details</DialogTitle>
|
|
120
|
-
<DialogDescription>Loading payment information...</DialogDescription>
|
|
121
|
-
</DialogHeader>
|
|
122
|
-
<div className="flex items-center justify-center py-12">
|
|
123
|
-
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
124
|
-
</div>
|
|
125
|
-
</DialogContent>
|
|
126
|
-
</Dialog>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Error state
|
|
131
|
-
if (shouldFetch && !isLoading && (error || !payment)) {
|
|
132
|
-
return (
|
|
133
|
-
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
|
|
134
|
-
<DialogContent className="sm:max-w-lg">
|
|
135
|
-
<DialogHeader>
|
|
136
|
-
<DialogTitle>Payment Details</DialogTitle>
|
|
137
|
-
<DialogDescription>Failed to load payment information</DialogDescription>
|
|
138
|
-
</DialogHeader>
|
|
139
|
-
<div className="flex flex-col items-center justify-center py-12 space-y-4">
|
|
140
|
-
<XCircle className="h-12 w-12 text-destructive" />
|
|
141
|
-
<p className="text-sm text-muted-foreground">
|
|
142
|
-
{error ? `Error: ${error}` : 'Payment not found'}
|
|
143
|
-
</p>
|
|
144
|
-
<Button onClick={() => mutate()}>Try Again</Button>
|
|
145
|
-
</div>
|
|
146
|
-
</DialogContent>
|
|
147
|
-
</Dialog>
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const statusInfo = getStatusInfo();
|
|
152
|
-
const StatusIcon = statusInfo.icon;
|
|
153
|
-
|
|
154
|
-
// Generate QR code URL
|
|
155
|
-
const qrCodeUrl = payment.pay_address
|
|
156
|
-
? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}`
|
|
157
|
-
: null;
|
|
158
|
-
|
|
159
|
-
return (
|
|
160
|
-
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
|
|
161
|
-
<DialogContent className="sm:max-w-lg">
|
|
162
|
-
<DialogHeader>
|
|
163
|
-
<DialogTitle>Payment Details</DialogTitle>
|
|
164
|
-
<DialogDescription>
|
|
165
|
-
Send cryptocurrency to complete your payment
|
|
166
|
-
</DialogDescription>
|
|
167
|
-
</DialogHeader>
|
|
168
|
-
|
|
169
|
-
<div className="space-y-6">
|
|
170
|
-
{/* Status Badge */}
|
|
171
|
-
<div className={`flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`}>
|
|
172
|
-
<StatusIcon className={`h-5 w-5 ${statusInfo.color}`} />
|
|
173
|
-
<div className="flex-1">
|
|
174
|
-
<div className="font-semibold capitalize">{payment.status}</div>
|
|
175
|
-
{payment.status === 'pending' && timeLeft && (
|
|
176
|
-
<div className="text-sm text-muted-foreground">
|
|
177
|
-
Expires in {timeLeft}
|
|
178
|
-
</div>
|
|
179
|
-
)}
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
{/* Amount Information */}
|
|
184
|
-
<div className="space-y-3">
|
|
185
|
-
<div className="flex items-center justify-between p-4 bg-muted rounded-sm">
|
|
186
|
-
<span className="text-sm text-muted-foreground">Amount to send</span>
|
|
187
|
-
<div className="flex items-center gap-2">
|
|
188
|
-
<TokenIcon symbol={String(payment.currency_code || 'BTC')} size={20} />
|
|
189
|
-
<span className="font-mono font-bold text-lg">
|
|
190
|
-
{payment.pay_amount || '0.00000000'} {payment.currency_code}
|
|
191
|
-
</span>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div className="flex items-center justify-between px-4">
|
|
196
|
-
<span className="text-sm text-muted-foreground">Equivalent to</span>
|
|
197
|
-
<span className="font-semibold text-lg">
|
|
198
|
-
${parseFloat(payment.amount_usd || '0').toFixed(2)} USD
|
|
199
|
-
</span>
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
{payment.internal_payment_id && (
|
|
203
|
-
<div className="flex items-center justify-between px-4">
|
|
204
|
-
<span className="text-sm text-muted-foreground">Payment Order #</span>
|
|
205
|
-
<span className="font-mono font-medium">{payment.internal_payment_id}</span>
|
|
206
|
-
</div>
|
|
207
|
-
)}
|
|
208
|
-
|
|
209
|
-
{payment.currency_network && (
|
|
210
|
-
<div className="flex items-center justify-between px-4">
|
|
211
|
-
<span className="text-sm text-muted-foreground">Network</span>
|
|
212
|
-
<span className="font-medium">{payment.currency_network}</span>
|
|
213
|
-
</div>
|
|
214
|
-
)}
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
{/* QR Code */}
|
|
218
|
-
{qrCodeUrl && payment.status === 'pending' && (
|
|
219
|
-
<div className="flex justify-center p-6 bg-white rounded-sm">
|
|
220
|
-
<img src={qrCodeUrl} alt="Payment QR Code" className="w-48 h-48" />
|
|
221
|
-
</div>
|
|
222
|
-
)}
|
|
223
|
-
|
|
224
|
-
{/* Payment Address */}
|
|
225
|
-
{payment.pay_address && payment.status === 'pending' && (
|
|
226
|
-
<div className="space-y-2">
|
|
227
|
-
<label className="text-sm font-medium">Payment Address</label>
|
|
228
|
-
<div className="flex items-center gap-2">
|
|
229
|
-
<div className="flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all">
|
|
230
|
-
{payment.pay_address}
|
|
231
|
-
</div>
|
|
232
|
-
<CopyButton value={payment.pay_address} variant="outline" />
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
)}
|
|
236
|
-
|
|
237
|
-
{/* Transaction Hash */}
|
|
238
|
-
{payment.transaction_hash && (
|
|
239
|
-
<div className="space-y-2">
|
|
240
|
-
<label className="text-sm font-medium">Transaction Hash</label>
|
|
241
|
-
<div className="p-3 bg-muted rounded-sm font-mono text-sm break-all">
|
|
242
|
-
{payment.transaction_hash}
|
|
243
|
-
</div>
|
|
244
|
-
</div>
|
|
245
|
-
)}
|
|
246
|
-
|
|
247
|
-
{/* Payment URL */}
|
|
248
|
-
{payment.payment_url && payment.status === 'pending' && (
|
|
249
|
-
<Button
|
|
250
|
-
variant="outline"
|
|
251
|
-
className="w-full"
|
|
252
|
-
onClick={() => window.open(payment.payment_url!, '_blank')}
|
|
253
|
-
>
|
|
254
|
-
<ExternalLink className="h-4 w-4 mr-2" />
|
|
255
|
-
Open in Payment Provider
|
|
256
|
-
</Button>
|
|
257
|
-
)}
|
|
258
|
-
|
|
259
|
-
{/* Additional Info */}
|
|
260
|
-
<div className="pt-4 border-t space-y-2 text-xs text-muted-foreground">
|
|
261
|
-
<div className="flex justify-between">
|
|
262
|
-
<span>Payment ID</span>
|
|
263
|
-
<span className="font-mono">{payment.id}</span>
|
|
264
|
-
</div>
|
|
265
|
-
<div className="flex justify-between">
|
|
266
|
-
<span>Created</span>
|
|
267
|
-
<span>{new Date(payment.created_at!).toLocaleString()}</span>
|
|
268
|
-
</div>
|
|
269
|
-
{payment.confirmations_count !== undefined && (
|
|
270
|
-
<div className="flex justify-between">
|
|
271
|
-
<span>Confirmations</span>
|
|
272
|
-
<span>{payment.confirmations_count}</span>
|
|
273
|
-
</div>
|
|
274
|
-
)}
|
|
275
|
-
</div>
|
|
276
|
-
</div>
|
|
277
|
-
|
|
278
|
-
<DialogFooter>
|
|
279
|
-
<Button variant="outline" onClick={handleClose}>
|
|
280
|
-
Close
|
|
281
|
-
</Button>
|
|
282
|
-
<Button onClick={() => mutate()} variant="ghost" size="sm">
|
|
283
|
-
<RefreshCw className="h-4 w-4 mr-2" />
|
|
284
|
-
Refresh
|
|
285
|
-
</Button>
|
|
286
|
-
</DialogFooter>
|
|
287
|
-
</DialogContent>
|
|
288
|
-
</Dialog>
|
|
289
|
-
);
|
|
290
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Payment Events System (v2.0 - Simplified)
|
|
5
|
-
*
|
|
6
|
-
* Event-based communication for dialogs using DOM events
|
|
7
|
-
* Removed: API Keys events (deprecated)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
11
|
-
// Event Names
|
|
12
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
export const PAYMENT_EVENTS = {
|
|
15
|
-
OPEN_CREATE_PAYMENT_DIALOG: 'payments:open-create-payment',
|
|
16
|
-
OPEN_PAYMENT_DETAILS_DIALOG: 'payments:open-payment-details',
|
|
17
|
-
CLOSE_DIALOG: 'payments:close-dialog',
|
|
18
|
-
} as const;
|
|
19
|
-
|
|
20
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
21
|
-
// Event Types
|
|
22
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
export type PaymentEvent =
|
|
25
|
-
| { type: 'OPEN_CREATE_PAYMENT' }
|
|
26
|
-
| { type: 'OPEN_PAYMENT_DETAILS'; id: string }
|
|
27
|
-
| { type: 'CLOSE_DIALOG' };
|
|
28
|
-
|
|
29
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
30
|
-
// Helper Functions
|
|
31
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
32
|
-
|
|
33
|
-
export const openCreatePaymentDialog = () => {
|
|
34
|
-
window.dispatchEvent(new Event(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG));
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const openPaymentDetailsDialog = (id: string) => {
|
|
38
|
-
window.dispatchEvent(
|
|
39
|
-
new CustomEvent(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, {
|
|
40
|
-
detail: { id },
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const closePaymentsDialog = () => {
|
|
46
|
-
window.dispatchEvent(new Event(PAYMENT_EVENTS.CLOSE_DIALOG));
|
|
47
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payments Layout (v2.0 - Simplified)
|
|
3
|
-
*
|
|
4
|
-
* Exports:
|
|
5
|
-
* - PaymentsLayout: Main layout component
|
|
6
|
-
* - PaymentTab: Tab type definition
|
|
7
|
-
* - Payment events: openCreatePaymentDialog, openPaymentDetailsDialog, closePaymentsDialog
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export { PaymentsLayout } from './PaymentsLayout';
|
|
11
|
-
export type { PaymentTab } from './types';
|
|
12
|
-
export {
|
|
13
|
-
openCreatePaymentDialog,
|
|
14
|
-
openPaymentDetailsDialog,
|
|
15
|
-
closePaymentsDialog
|
|
16
|
-
} from './events';
|