@djangocfg/layouts 1.0.3 → 1.0.5
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/package.json +5 -5
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +2 -2
- package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +6 -6
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/DesktopUserMenu.tsx +6 -6
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +43 -133
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenuUserCard.tsx +150 -0
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +2 -2
- package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +47 -65
- package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +121 -144
- package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +103 -48
- package/src/layouts/PaymentsLayout/components/index.ts +1 -4
- package/src/layouts/PaymentsLayout/events.ts +23 -84
- package/src/layouts/PaymentsLayout/index.ts +7 -11
- package/src/layouts/PaymentsLayout/types.ts +3 -16
- package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +45 -16
- package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +18 -14
- package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
- package/src/layouts/PaymentsLayout/views/overview/index.tsx +3 -6
- package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +51 -31
- package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
- package/src/layouts/PaymentsLayout/views/payments/index.tsx +1 -2
- package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +273 -0
- package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +1 -0
- package/src/layouts/PaymentsLayout/views/transactions/index.tsx +5 -17
- package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -3
- package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -3
- package/src/snippets/Chat/components/SessionList.tsx +1 -1
- package/src/snippets/Chat/hooks/useInfiniteSessions.ts +2 -2
- package/src/snippets/VideoPlayer/VideoPlayer.tsx +1 -1
- package/src/layouts/PaymentsLayout/README.md +0 -133
- package/src/layouts/PaymentsLayout/components/CreateApiKeyDialog.tsx +0 -172
- package/src/layouts/PaymentsLayout/components/DeleteApiKeyDialog.tsx +0 -100
- package/src/layouts/PaymentsLayout/context/RootPaymentsContext.tsx +0 -134
- package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeyMetrics.tsx +0 -109
- package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeysList.tsx +0 -194
- package/src/layouts/PaymentsLayout/views/apikeys/components/index.ts +0 -3
- package/src/layouts/PaymentsLayout/views/apikeys/index.tsx +0 -19
- package/src/layouts/PaymentsLayout/views/overview/components/MetricsCards.tsx +0 -103
- package/src/layouts/PaymentsLayout/views/tariffs/index.tsx +0 -29
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Payments Layout
|
|
3
|
-
*
|
|
2
|
+
* Payments Layout (v2.0 - Simplified)
|
|
3
|
+
*
|
|
4
|
+
* Simplified layout with 3 tabs: Overview, Payments, Transactions
|
|
5
|
+
* Removed: API Keys, Tariffs (deprecated in v2.0)
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
8
|
'use client';
|
|
@@ -8,18 +10,15 @@
|
|
|
8
10
|
import React from 'react';
|
|
9
11
|
import {
|
|
10
12
|
PaymentsProvider,
|
|
11
|
-
ApiKeysProvider,
|
|
12
13
|
OverviewProvider,
|
|
13
14
|
RootPaymentsProvider,
|
|
14
15
|
} from '@djangocfg/api/cfg/contexts';
|
|
15
16
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@djangocfg/ui';
|
|
16
|
-
import { Wallet, CreditCard, History
|
|
17
|
+
import { Wallet, CreditCard, History } from 'lucide-react';
|
|
17
18
|
import { OverviewView } from './views/overview';
|
|
18
19
|
import { PaymentsView } from './views/payments';
|
|
19
20
|
import { TransactionsView } from './views/transactions';
|
|
20
|
-
import {
|
|
21
|
-
import { TariffsView } from './views/tariffs';
|
|
22
|
-
import { CreateApiKeyDialog, DeleteApiKeyDialog, CreatePaymentDialog, PaymentDetailsDialog } from './components';
|
|
21
|
+
import { CreatePaymentDialog, PaymentDetailsDialog } from './components';
|
|
23
22
|
|
|
24
23
|
// ─────────────────────────────────────────────────────────────────────────
|
|
25
24
|
// Payments Layout
|
|
@@ -35,75 +34,58 @@ export const PaymentsLayout: React.FC<PaymentsLayoutProps> = () => {
|
|
|
35
34
|
<div className="h-full p-6 space-y-6">
|
|
36
35
|
{/* Page Header */}
|
|
37
36
|
<div>
|
|
38
|
-
<h1 className="text-3xl font-bold tracking-tight">Payments
|
|
37
|
+
<h1 className="text-3xl font-bold tracking-tight">Payments</h1>
|
|
39
38
|
<p className="text-muted-foreground">
|
|
40
|
-
Manage your payments,
|
|
39
|
+
Manage your payments, balance, and transaction history
|
|
41
40
|
</p>
|
|
42
41
|
</div>
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<Key className="h-4 w-4" />
|
|
61
|
-
<span className="hidden sm:inline">API Keys</span>
|
|
62
|
-
</TabsTrigger>
|
|
63
|
-
<TabsTrigger value="tariffs" className="inline-flex items-center gap-2 px-3 py-1.5">
|
|
64
|
-
<Crown className="h-4 w-4" />
|
|
65
|
-
<span className="hidden sm:inline">Tariffs</span>
|
|
66
|
-
</TabsTrigger>
|
|
67
|
-
</TabsList>
|
|
43
|
+
{/* Main Content with Tabs */}
|
|
44
|
+
<Tabs defaultValue="overview" className="space-y-6">
|
|
45
|
+
<TabsList className="inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground">
|
|
46
|
+
<TabsTrigger value="overview" className="inline-flex items-center gap-2 px-3 py-1.5">
|
|
47
|
+
<Wallet className="h-4 w-4" />
|
|
48
|
+
<span className="hidden sm:inline">Overview</span>
|
|
49
|
+
</TabsTrigger>
|
|
50
|
+
<TabsTrigger value="payments" className="inline-flex items-center gap-2 px-3 py-1.5">
|
|
51
|
+
<CreditCard className="h-4 w-4" />
|
|
52
|
+
<span className="hidden sm:inline">Payments</span>
|
|
53
|
+
</TabsTrigger>
|
|
54
|
+
<TabsTrigger value="transactions" className="inline-flex items-center gap-2 px-3 py-1.5">
|
|
55
|
+
<History className="h-4 w-4" />
|
|
56
|
+
<span className="hidden sm:inline">Transactions</span>
|
|
57
|
+
</TabsTrigger>
|
|
58
|
+
</TabsList>
|
|
68
59
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
{/* Overview Tab - Balance + Recent Payments */}
|
|
61
|
+
<TabsContent value="overview" className="space-y-6">
|
|
62
|
+
<OverviewProvider>
|
|
63
|
+
<PaymentsProvider>
|
|
64
|
+
<OverviewView />
|
|
65
|
+
<CreatePaymentDialog />
|
|
66
|
+
</PaymentsProvider>
|
|
67
|
+
</OverviewProvider>
|
|
68
|
+
</TabsContent>
|
|
69
|
+
|
|
70
|
+
{/* Payments Tab - Full Payment List */}
|
|
71
|
+
<TabsContent value="payments" className="space-y-6">
|
|
72
72
|
<PaymentsProvider>
|
|
73
|
-
<
|
|
73
|
+
<PaymentsView />
|
|
74
74
|
<CreatePaymentDialog />
|
|
75
75
|
</PaymentsProvider>
|
|
76
|
-
</
|
|
77
|
-
</TabsContent>
|
|
78
|
-
|
|
79
|
-
<TabsContent value="payments" className="space-y-6">
|
|
80
|
-
<PaymentsProvider>
|
|
81
|
-
<PaymentsView />
|
|
82
|
-
<CreatePaymentDialog />
|
|
83
|
-
</PaymentsProvider>
|
|
84
|
-
</TabsContent>
|
|
85
|
-
|
|
86
|
-
<TabsContent value="transactions" className="space-y-6">
|
|
87
|
-
<TransactionsView />
|
|
88
|
-
</TabsContent>
|
|
76
|
+
</TabsContent>
|
|
89
77
|
|
|
90
|
-
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
</
|
|
96
|
-
</
|
|
78
|
+
{/* Transactions Tab - Transaction History */}
|
|
79
|
+
<TabsContent value="transactions" className="space-y-6">
|
|
80
|
+
<OverviewProvider>
|
|
81
|
+
<TransactionsView />
|
|
82
|
+
</OverviewProvider>
|
|
83
|
+
</TabsContent>
|
|
84
|
+
</Tabs>
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
</TabsContent>
|
|
101
|
-
</Tabs>
|
|
102
|
-
|
|
103
|
-
{/* Global Payment Details Dialog */}
|
|
104
|
-
<PaymentDetailsDialog />
|
|
86
|
+
{/* Global Payment Details Dialog */}
|
|
87
|
+
<PaymentDetailsDialog />
|
|
105
88
|
</div>
|
|
106
89
|
</RootPaymentsProvider>
|
|
107
90
|
);
|
|
108
91
|
};
|
|
109
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Create Payment Dialog
|
|
2
|
+
* Create Payment Dialog (v2.0 - Simplified)
|
|
3
3
|
* Dialog for creating new payments
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -21,95 +21,95 @@ import {
|
|
|
21
21
|
FormLabel,
|
|
22
22
|
FormMessage,
|
|
23
23
|
Input,
|
|
24
|
-
|
|
24
|
+
Select,
|
|
25
|
+
SelectContent,
|
|
26
|
+
SelectItem,
|
|
27
|
+
SelectTrigger,
|
|
28
|
+
SelectValue,
|
|
25
29
|
Button,
|
|
26
30
|
TokenIcon,
|
|
27
|
-
useEventListener,
|
|
28
31
|
} from '@djangocfg/ui';
|
|
29
32
|
import { Plus, RefreshCw } from 'lucide-react';
|
|
30
33
|
import { useForm } from 'react-hook-form';
|
|
31
34
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
35
|
+
import { z } from 'zod';
|
|
32
36
|
import { usePaymentsContext, useRootPaymentsContext } from '@djangocfg/api/cfg/contexts';
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import { PAYMENTS_DIALOG_EVENTS, closePaymentsDialog } from '../events';
|
|
36
|
-
import { openPaymentDetails } from './PaymentDetailsDialog';
|
|
37
|
-
import type { ProviderCurrency } from '@djangocfg/api/cfg/contexts';
|
|
38
|
-
import type { ComboboxOption } from '@djangocfg/ui';
|
|
37
|
+
import { PAYMENT_EVENTS, closePaymentsDialog } from '../events';
|
|
38
|
+
import { openPaymentDetailsDialog } from '../events';
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// Payment creation schema
|
|
41
|
+
const PaymentCreateSchema = z.object({
|
|
42
|
+
amount_usd: z.number().min(0.01, 'Amount must be at least $0.01'),
|
|
43
|
+
currency_code: z.string().min(1, 'Please select a currency'),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
type PaymentCreateRequest = z.infer<typeof PaymentCreateSchema>;
|
|
43
47
|
|
|
44
48
|
export const CreatePaymentDialog: React.FC = () => {
|
|
45
49
|
const [open, setOpen] = useState(false);
|
|
46
50
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
47
51
|
|
|
48
52
|
const { createPayment } = usePaymentsContext();
|
|
49
|
-
const {
|
|
50
|
-
providerCurrencies,
|
|
51
|
-
isLoadingProviderCurrencies,
|
|
52
|
-
} = useRootPaymentsContext();
|
|
53
|
+
const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
|
|
53
54
|
|
|
54
55
|
const form = useForm<PaymentCreateRequest>({
|
|
55
|
-
resolver: zodResolver(
|
|
56
|
+
resolver: zodResolver(PaymentCreateSchema),
|
|
56
57
|
defaultValues: {
|
|
57
58
|
amount_usd: 10,
|
|
58
|
-
currency_code:
|
|
59
|
+
currency_code: 'USDT',
|
|
59
60
|
},
|
|
60
61
|
});
|
|
61
62
|
|
|
62
|
-
//
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return enabledCurrencies.map((pc) => {
|
|
69
|
-
const networkInfo = pc.network ? ` (${pc.network.name})` : '';
|
|
70
|
-
const label = `${pc.currency.code} - ${pc.currency.name}${networkInfo}`;
|
|
71
|
-
const description = pc.network ? pc.network.code : 'No network';
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
value: pc.provider_currency_code,
|
|
75
|
-
label,
|
|
76
|
-
description,
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
}, [providerCurrencies]);
|
|
63
|
+
// Extract currencies list from response (handle different possible structures)
|
|
64
|
+
const currenciesList = useMemo(() => {
|
|
65
|
+
const data = currencies?.currencies || currencies?.results || currencies || [];
|
|
66
|
+
return Array.isArray(data) ? data : [];
|
|
67
|
+
}, [currencies]);
|
|
80
68
|
|
|
81
|
-
// Get
|
|
82
|
-
const
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
// Get currency options for select
|
|
70
|
+
const currencyOptions = useMemo(() => {
|
|
71
|
+
return currenciesList
|
|
72
|
+
.filter((curr: any) => curr.is_enabled !== false)
|
|
73
|
+
.map((curr: any) => ({
|
|
74
|
+
code: curr.code || curr.currency_code || curr.symbol,
|
|
75
|
+
name: curr.name || curr.code || curr.currency_code,
|
|
76
|
+
usd_rate: curr.usd_rate || curr.rate || 1,
|
|
77
|
+
network: curr.network || null,
|
|
78
|
+
}));
|
|
79
|
+
}, [currenciesList]);
|
|
87
80
|
|
|
88
81
|
// Calculate crypto amount from USD
|
|
89
82
|
const calculateCryptoAmount = useMemo(() => {
|
|
90
83
|
const amountUsd = form.watch('amount_usd');
|
|
91
84
|
const currencyCode = form.watch('currency_code');
|
|
92
|
-
const
|
|
85
|
+
const currency = currencyOptions.find((c: any) => c.code === currencyCode);
|
|
93
86
|
|
|
94
|
-
if (!
|
|
87
|
+
if (!currency || !currency.usd_rate || !amountUsd) {
|
|
95
88
|
return null;
|
|
96
89
|
}
|
|
97
90
|
|
|
98
|
-
const cryptoAmount = amountUsd /
|
|
91
|
+
const cryptoAmount = amountUsd / currency.usd_rate;
|
|
99
92
|
return {
|
|
100
93
|
amount: cryptoAmount,
|
|
101
|
-
currency:
|
|
102
|
-
|
|
94
|
+
currency: currency.code,
|
|
95
|
+
rate: currency.usd_rate,
|
|
96
|
+
network: currency.network,
|
|
103
97
|
};
|
|
104
|
-
}, [form.watch('amount_usd'), form.watch('currency_code'),
|
|
98
|
+
}, [form.watch('amount_usd'), form.watch('currency_code'), currencyOptions]);
|
|
105
99
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
// Listen for open/close events
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const handleOpen = () => setOpen(true);
|
|
103
|
+
const handleClose = () => setOpen(false);
|
|
109
104
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
106
|
+
window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
107
|
+
|
|
108
|
+
return () => {
|
|
109
|
+
window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
110
|
+
window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose);
|
|
111
|
+
};
|
|
112
|
+
}, []);
|
|
113
113
|
|
|
114
114
|
const handleClose = () => {
|
|
115
115
|
setOpen(false);
|
|
@@ -119,7 +119,7 @@ export const CreatePaymentDialog: React.FC = () => {
|
|
|
119
119
|
// Initialize default currency if not set
|
|
120
120
|
useEffect(() => {
|
|
121
121
|
if (currencyOptions.length > 0 && !form.getValues('currency_code')) {
|
|
122
|
-
form.setValue('currency_code', currencyOptions[0].
|
|
122
|
+
form.setValue('currency_code', currencyOptions[0].code);
|
|
123
123
|
}
|
|
124
124
|
}, [currencyOptions, form]);
|
|
125
125
|
|
|
@@ -127,16 +127,19 @@ export const CreatePaymentDialog: React.FC = () => {
|
|
|
127
127
|
try {
|
|
128
128
|
setIsSubmitting(true);
|
|
129
129
|
|
|
130
|
-
const
|
|
130
|
+
const result = await createPayment();
|
|
131
131
|
handleClose();
|
|
132
132
|
closePaymentsDialog();
|
|
133
133
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
// Extract payment ID from result
|
|
135
|
+
const paymentData = result as any;
|
|
136
|
+
const paymentId = paymentData?.payment?.id || paymentData?.id;
|
|
137
|
+
|
|
138
|
+
if (paymentId) {
|
|
139
|
+
openPaymentDetailsDialog(String(paymentId));
|
|
137
140
|
}
|
|
138
141
|
} catch (error) {
|
|
139
|
-
|
|
142
|
+
console.error('Failed to create payment:', error);
|
|
140
143
|
} finally {
|
|
141
144
|
setIsSubmitting(false);
|
|
142
145
|
}
|
|
@@ -184,51 +187,32 @@ export const CreatePaymentDialog: React.FC = () => {
|
|
|
184
187
|
render={({ field }) => (
|
|
185
188
|
<FormItem>
|
|
186
189
|
<FormLabel>Currency</FormLabel>
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (!pc) return option.label;
|
|
201
|
-
return (
|
|
190
|
+
<Select
|
|
191
|
+
onValueChange={field.onChange}
|
|
192
|
+
defaultValue={field.value}
|
|
193
|
+
disabled={isLoadingCurrencies}
|
|
194
|
+
>
|
|
195
|
+
<FormControl>
|
|
196
|
+
<SelectTrigger>
|
|
197
|
+
<SelectValue placeholder="Select currency..." />
|
|
198
|
+
</SelectTrigger>
|
|
199
|
+
</FormControl>
|
|
200
|
+
<SelectContent>
|
|
201
|
+
{currencyOptions.map((curr: any) => (
|
|
202
|
+
<SelectItem key={curr.code} value={curr.code}>
|
|
202
203
|
<div className="flex items-center gap-2">
|
|
203
|
-
<TokenIcon symbol={
|
|
204
|
-
<span>{
|
|
205
|
-
{
|
|
204
|
+
<TokenIcon symbol={curr.code} size={16} />
|
|
205
|
+
<span>{curr.code}</span>
|
|
206
|
+
{curr.network && (
|
|
206
207
|
<span className="text-xs text-muted-foreground">
|
|
207
|
-
({
|
|
208
|
+
({curr.network})
|
|
208
209
|
</span>
|
|
209
210
|
)}
|
|
210
211
|
</div>
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (!pc) return option.label;
|
|
216
|
-
return (
|
|
217
|
-
<div className="flex items-center gap-2 flex-1">
|
|
218
|
-
<TokenIcon symbol={pc.currency.code} size={24} />
|
|
219
|
-
<div className="flex flex-col flex-1">
|
|
220
|
-
<span className="font-medium">{pc.currency.code} - {pc.currency.name}</span>
|
|
221
|
-
{pc.network && (
|
|
222
|
-
<span className="text-xs text-muted-foreground">
|
|
223
|
-
Network: {pc.network.name} ({pc.network.code})
|
|
224
|
-
</span>
|
|
225
|
-
)}
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
);
|
|
229
|
-
}}
|
|
230
|
-
/>
|
|
231
|
-
</FormControl>
|
|
212
|
+
</SelectItem>
|
|
213
|
+
))}
|
|
214
|
+
</SelectContent>
|
|
215
|
+
</Select>
|
|
232
216
|
<FormDescription>
|
|
233
217
|
The cryptocurrency to use for payment.
|
|
234
218
|
</FormDescription>
|
|
@@ -237,59 +221,53 @@ export const CreatePaymentDialog: React.FC = () => {
|
|
|
237
221
|
)}
|
|
238
222
|
/>
|
|
239
223
|
|
|
240
|
-
{/* Conversion
|
|
241
|
-
{calculateCryptoAmount && (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
<span className="text-sm text-muted-foreground">You will send</span>
|
|
251
|
-
<div className="flex items-center gap-2">
|
|
252
|
-
<TokenIcon symbol={calculateCryptoAmount.currency} size={16} />
|
|
253
|
-
<span className="font-mono font-semibold">
|
|
254
|
-
{calculateCryptoAmount.amount.toFixed(8)} {calculateCryptoAmount.currency}
|
|
255
|
-
</span>
|
|
256
|
-
</div>
|
|
257
|
-
</div>
|
|
258
|
-
|
|
259
|
-
{/* USD Amount Received */}
|
|
260
|
-
<div className="flex items-center justify-between">
|
|
261
|
-
<span className="text-sm text-muted-foreground">You will receive</span>
|
|
262
|
-
<span className="text-lg font-bold">
|
|
263
|
-
${amountUsd?.toFixed(2)} USD
|
|
224
|
+
{/* Conversion Information */}
|
|
225
|
+
{calculateCryptoAmount && (
|
|
226
|
+
<div className="rounded-sm bg-muted p-4 space-y-3">
|
|
227
|
+
{/* Amount to Send in Crypto */}
|
|
228
|
+
<div className="flex items-center justify-between">
|
|
229
|
+
<span className="text-sm text-muted-foreground">You will send</span>
|
|
230
|
+
<div className="flex items-center gap-2">
|
|
231
|
+
<TokenIcon symbol={calculateCryptoAmount.currency} size={16} />
|
|
232
|
+
<span className="font-mono font-semibold">
|
|
233
|
+
{calculateCryptoAmount.amount.toFixed(8)} {calculateCryptoAmount.currency}
|
|
264
234
|
</span>
|
|
265
235
|
</div>
|
|
236
|
+
</div>
|
|
266
237
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
238
|
+
{/* USD Amount Received */}
|
|
239
|
+
<div className="flex items-center justify-between">
|
|
240
|
+
<span className="text-sm text-muted-foreground">You will receive</span>
|
|
241
|
+
<span className="text-lg font-bold">
|
|
242
|
+
${form.watch('amount_usd')?.toFixed(2)} USD
|
|
243
|
+
</span>
|
|
244
|
+
</div>
|
|
274
245
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
)}
|
|
246
|
+
{/* Exchange Rate */}
|
|
247
|
+
<div className="flex items-center justify-between text-xs">
|
|
248
|
+
<span className="text-muted-foreground">Rate</span>
|
|
249
|
+
<span className="font-medium">
|
|
250
|
+
1 {calculateCryptoAmount.currency} = ${calculateCryptoAmount.rate?.toFixed(2)}
|
|
251
|
+
</span>
|
|
284
252
|
</div>
|
|
285
|
-
|
|
286
|
-
|
|
253
|
+
|
|
254
|
+
{/* Network Info */}
|
|
255
|
+
{calculateCryptoAmount.network && (
|
|
256
|
+
<div className="border-t pt-3">
|
|
257
|
+
<div className="flex items-center justify-between">
|
|
258
|
+
<span className="text-sm text-muted-foreground">Network</span>
|
|
259
|
+
<span className="text-sm font-medium">{calculateCryptoAmount.network}</span>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
)}
|
|
263
|
+
</div>
|
|
264
|
+
)}
|
|
287
265
|
|
|
288
266
|
<DialogFooter>
|
|
289
267
|
<Button type="button" variant="outline" onClick={handleClose} disabled={isSubmitting}>
|
|
290
268
|
Cancel
|
|
291
269
|
</Button>
|
|
292
|
-
<Button type="submit" disabled={isSubmitting}>
|
|
270
|
+
<Button type="submit" disabled={isSubmitting || currencyOptions.length === 0}>
|
|
293
271
|
{isSubmitting ? (
|
|
294
272
|
<>
|
|
295
273
|
<RefreshCw className="h-4 w-4 mr-2 animate-spin" />
|
|
@@ -309,4 +287,3 @@ export const CreatePaymentDialog: React.FC = () => {
|
|
|
309
287
|
</Dialog>
|
|
310
288
|
);
|
|
311
289
|
};
|
|
312
|
-
|