@djangocfg/ext-payments 1.0.21 → 1.0.23
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/config.cjs +14 -5
- package/dist/config.js +14 -5
- package/dist/i18n.cjs +434 -0
- package/dist/i18n.d.cts +172 -0
- package/dist/i18n.d.ts +172 -0
- package/dist/i18n.js +406 -0
- package/dist/index.cjs +653 -113
- package/dist/index.js +654 -114
- package/package.json +22 -13
- package/src/components/ActivityList.tsx +15 -4
- package/src/components/AddFundsSheet.tsx +34 -14
- package/src/components/BalanceHero.tsx +17 -5
- package/src/components/CurrencyCombobox.tsx +13 -3
- package/src/components/PaymentSheet.tsx +72 -29
- package/src/components/WithdrawSheet.tsx +36 -15
- package/src/components/WithdrawalSheet.tsx +75 -32
- package/src/i18n/index.ts +26 -0
- package/src/i18n/locales/en.ts +136 -0
- package/src/i18n/locales/ko.ts +136 -0
- package/src/i18n/locales/ru.ts +136 -0
- package/src/i18n/types.ts +169 -0
- package/src/i18n/usePaymentsT.ts +60 -0
|
@@ -13,6 +13,7 @@ import { useForm } from 'react-hook-form';
|
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
15
15
|
|
|
16
|
+
import { usePaymentsT } from '../i18n';
|
|
16
17
|
import {
|
|
17
18
|
Alert,
|
|
18
19
|
AlertDescription,
|
|
@@ -74,10 +75,30 @@ interface WithdrawSaved {
|
|
|
74
75
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
75
76
|
|
|
76
77
|
export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetProps) {
|
|
78
|
+
const pt = usePaymentsT();
|
|
77
79
|
const { currencies, isLoadingCurrencies, withdraw, balanceAmount } = useWallet();
|
|
78
80
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
79
81
|
const [error, setError] = useState<string | null>(null);
|
|
80
82
|
|
|
83
|
+
// Prepare labels before render
|
|
84
|
+
const labels = useMemo(() => ({
|
|
85
|
+
title: pt('sheets.withdrawTitle'),
|
|
86
|
+
description: pt('sheets.withdrawDescription'),
|
|
87
|
+
amountUsd: pt('form.amountUsd'),
|
|
88
|
+
withdrawAs: pt('form.withdrawAs'),
|
|
89
|
+
walletAddress: pt('form.walletAddress'),
|
|
90
|
+
enterWalletAddress: pt('form.enterWalletAddress'),
|
|
91
|
+
amount: pt('form.amount'),
|
|
92
|
+
serviceFee: pt('estimate.serviceFee'),
|
|
93
|
+
networkFee: pt('estimate.networkFee'),
|
|
94
|
+
youWillReceive: pt('estimate.youWillReceive'),
|
|
95
|
+
calculating: pt('estimate.calculating'),
|
|
96
|
+
insufficientBalance: pt('withdraw.insufficientBalance'),
|
|
97
|
+
approvalWarning: pt('withdraw.approvalWarning'),
|
|
98
|
+
submitting: pt('withdraw.submitting'),
|
|
99
|
+
requestWithdrawal: pt('actions.requestWithdrawal'),
|
|
100
|
+
}), [pt]);
|
|
101
|
+
|
|
81
102
|
// Remember last used currency and wallet address
|
|
82
103
|
const [saved, setSaved] = useLocalStorage<WithdrawSaved>(STORAGE_KEY, {
|
|
83
104
|
currency: '',
|
|
@@ -178,9 +199,9 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
178
199
|
<ResponsiveSheet open={open} onOpenChange={handleOpenChange}>
|
|
179
200
|
<ResponsiveSheetContent className="sm:max-w-md">
|
|
180
201
|
<ResponsiveSheetHeader>
|
|
181
|
-
<ResponsiveSheetTitle>
|
|
202
|
+
<ResponsiveSheetTitle>{labels.title}</ResponsiveSheetTitle>
|
|
182
203
|
<ResponsiveSheetDescription>
|
|
183
|
-
|
|
204
|
+
{labels.description}
|
|
184
205
|
</ResponsiveSheetDescription>
|
|
185
206
|
</ResponsiveSheetHeader>
|
|
186
207
|
|
|
@@ -192,7 +213,7 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
192
213
|
name="amount"
|
|
193
214
|
render={({ field }) => (
|
|
194
215
|
<FormItem>
|
|
195
|
-
<FormLabel>
|
|
216
|
+
<FormLabel>{labels.amountUsd}</FormLabel>
|
|
196
217
|
<FormControl>
|
|
197
218
|
<div className="relative">
|
|
198
219
|
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-muted-foreground text-lg">
|
|
@@ -212,7 +233,7 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
212
233
|
<FormMessage />
|
|
213
234
|
{insufficientBalance && (
|
|
214
235
|
<p className="text-sm text-destructive mt-1">
|
|
215
|
-
|
|
236
|
+
{labels.insufficientBalance} (Available: ${formatUsdAmount(balanceAmount)})
|
|
216
237
|
</p>
|
|
217
238
|
)}
|
|
218
239
|
</FormItem>
|
|
@@ -225,7 +246,7 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
225
246
|
name="currency"
|
|
226
247
|
render={({ field }) => (
|
|
227
248
|
<FormItem>
|
|
228
|
-
<FormLabel>
|
|
249
|
+
<FormLabel>{labels.withdrawAs}</FormLabel>
|
|
229
250
|
<FormControl>
|
|
230
251
|
<CurrencyCombobox
|
|
231
252
|
options={currencyOptions}
|
|
@@ -245,10 +266,10 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
245
266
|
name="wallet_address"
|
|
246
267
|
render={({ field }) => (
|
|
247
268
|
<FormItem>
|
|
248
|
-
<FormLabel>
|
|
269
|
+
<FormLabel>{labels.walletAddress}</FormLabel>
|
|
249
270
|
<FormControl>
|
|
250
271
|
<Input
|
|
251
|
-
placeholder=
|
|
272
|
+
placeholder={labels.enterWalletAddress}
|
|
252
273
|
className="font-mono text-sm"
|
|
253
274
|
{...field}
|
|
254
275
|
/>
|
|
@@ -262,33 +283,33 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
262
283
|
{amount >= 10 && selectedCurrency && (
|
|
263
284
|
<div className="bg-muted rounded-xl p-4 space-y-2">
|
|
264
285
|
<div className="flex items-center justify-between text-sm">
|
|
265
|
-
<span className="text-muted-foreground">
|
|
286
|
+
<span className="text-muted-foreground">{labels.amount}</span>
|
|
266
287
|
<span>${formatUsdAmount(amount)}</span>
|
|
267
288
|
</div>
|
|
268
289
|
{isLoadingEstimate ? (
|
|
269
290
|
<div className="flex items-center gap-2 text-sm text-muted-foreground py-2">
|
|
270
291
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
271
|
-
<span>
|
|
292
|
+
<span>{labels.calculating}</span>
|
|
272
293
|
</div>
|
|
273
294
|
) : estimate ? (
|
|
274
295
|
<>
|
|
275
296
|
<div className="flex items-center justify-between text-sm">
|
|
276
297
|
<span className="text-muted-foreground">
|
|
277
|
-
|
|
298
|
+
{labels.serviceFee} ({estimate.serviceFeePercent}%)
|
|
278
299
|
</span>
|
|
279
300
|
<span className="text-destructive">
|
|
280
301
|
-${formatUsdAmount(estimate.serviceFeeUsd)}
|
|
281
302
|
</span>
|
|
282
303
|
</div>
|
|
283
304
|
<div className="flex items-center justify-between text-sm">
|
|
284
|
-
<span className="text-muted-foreground">
|
|
305
|
+
<span className="text-muted-foreground">{labels.networkFee}</span>
|
|
285
306
|
<span className="text-destructive">
|
|
286
307
|
-${formatUsdAmount(estimate.networkFeeUsd)}
|
|
287
308
|
</span>
|
|
288
309
|
</div>
|
|
289
310
|
<div className="border-t pt-2 mt-2">
|
|
290
311
|
<div className="flex items-center justify-between">
|
|
291
|
-
<span className="font-medium">
|
|
312
|
+
<span className="font-medium">{labels.youWillReceive}</span>
|
|
292
313
|
<div className="text-right">
|
|
293
314
|
<div className="font-semibold">
|
|
294
315
|
${formatUsdAmount(estimate.amountToReceive)}
|
|
@@ -313,7 +334,7 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
313
334
|
<Alert>
|
|
314
335
|
<AlertCircle className="h-4 w-4" />
|
|
315
336
|
<AlertDescription>
|
|
316
|
-
|
|
337
|
+
{labels.approvalWarning}
|
|
317
338
|
</AlertDescription>
|
|
318
339
|
</Alert>
|
|
319
340
|
|
|
@@ -341,10 +362,10 @@ export function WithdrawSheet({ open, onOpenChange, onSuccess }: WithdrawSheetPr
|
|
|
341
362
|
{isSubmitting ? (
|
|
342
363
|
<>
|
|
343
364
|
<RefreshCw className="h-5 w-5 mr-2 animate-spin" />
|
|
344
|
-
|
|
365
|
+
{labels.submitting}
|
|
345
366
|
</>
|
|
346
367
|
) : (
|
|
347
|
-
|
|
368
|
+
labels.requestWithdrawal
|
|
348
369
|
)}
|
|
349
370
|
</Button>
|
|
350
371
|
</form>
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import moment from 'moment';
|
|
20
20
|
import useSWR from 'swr';
|
|
21
21
|
|
|
22
|
+
import { usePaymentsT } from '../i18n';
|
|
22
23
|
import {
|
|
23
24
|
Button,
|
|
24
25
|
CopyButton,
|
|
@@ -49,43 +50,37 @@ interface WithdrawalSheetProps {
|
|
|
49
50
|
// Status Config
|
|
50
51
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
51
52
|
|
|
52
|
-
const statusConfig: Record<string, { icon: any; color: string; bg: string;
|
|
53
|
+
const statusConfig: Record<string, { icon: any; color: string; bg: string; animate?: boolean }> = {
|
|
53
54
|
pending: {
|
|
54
55
|
icon: Clock,
|
|
55
56
|
color: 'text-yellow-500',
|
|
56
57
|
bg: 'bg-yellow-500/10',
|
|
57
|
-
label: 'Pending Approval',
|
|
58
58
|
},
|
|
59
59
|
approved: {
|
|
60
60
|
icon: CheckCircle2,
|
|
61
61
|
color: 'text-blue-500',
|
|
62
62
|
bg: 'bg-blue-500/10',
|
|
63
|
-
label: 'Approved',
|
|
64
63
|
},
|
|
65
64
|
processing: {
|
|
66
65
|
icon: RefreshCw,
|
|
67
66
|
color: 'text-blue-500',
|
|
68
67
|
bg: 'bg-blue-500/10',
|
|
69
|
-
label: 'Processing',
|
|
70
68
|
animate: true,
|
|
71
69
|
},
|
|
72
70
|
completed: {
|
|
73
71
|
icon: CheckCircle2,
|
|
74
72
|
color: 'text-green-500',
|
|
75
73
|
bg: 'bg-green-500/10',
|
|
76
|
-
label: 'Completed',
|
|
77
74
|
},
|
|
78
75
|
rejected: {
|
|
79
76
|
icon: XCircle,
|
|
80
77
|
color: 'text-red-500',
|
|
81
78
|
bg: 'bg-red-500/10',
|
|
82
|
-
label: 'Rejected',
|
|
83
79
|
},
|
|
84
80
|
cancelled: {
|
|
85
81
|
icon: Ban,
|
|
86
82
|
color: 'text-muted-foreground',
|
|
87
83
|
bg: 'bg-muted',
|
|
88
|
-
label: 'Cancelled',
|
|
89
84
|
},
|
|
90
85
|
};
|
|
91
86
|
|
|
@@ -94,8 +89,45 @@ const statusConfig: Record<string, { icon: any; color: string; bg: string; label
|
|
|
94
89
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
95
90
|
|
|
96
91
|
export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: WithdrawalSheetProps) {
|
|
92
|
+
const pt = usePaymentsT();
|
|
97
93
|
const { getWithdrawalDetails, cancelWithdrawal, refreshWallet } = useWallet();
|
|
98
94
|
|
|
95
|
+
// Prepare labels before render
|
|
96
|
+
const labels = useMemo(() => ({
|
|
97
|
+
title: pt('sheets.withdrawalTitle'),
|
|
98
|
+
// Status labels
|
|
99
|
+
pending: pt('withdrawalStatus.pending'),
|
|
100
|
+
approved: pt('withdrawalStatus.approved'),
|
|
101
|
+
processing: pt('withdrawalStatus.processing'),
|
|
102
|
+
completed: pt('withdrawalStatus.completed'),
|
|
103
|
+
rejected: pt('withdrawalStatus.rejected'),
|
|
104
|
+
cancelled: pt('withdrawalStatus.cancelled'),
|
|
105
|
+
// Descriptions
|
|
106
|
+
pendingApproval: pt('withdrawalDescriptions.pendingApproval'),
|
|
107
|
+
processingDesc: pt('withdrawalDescriptions.processing'),
|
|
108
|
+
completedDesc: pt('withdrawalDescriptions.completed'),
|
|
109
|
+
rejectedDesc: pt('withdrawalDescriptions.rejected'),
|
|
110
|
+
cancelledDesc: pt('withdrawalDescriptions.cancelled'),
|
|
111
|
+
// Form
|
|
112
|
+
amount: pt('form.amount'),
|
|
113
|
+
totalFees: pt('estimate.serviceFee'),
|
|
114
|
+
youReceive: pt('estimate.youWillReceive'),
|
|
115
|
+
cryptoAmount: pt('form.amount'),
|
|
116
|
+
destinationWallet: pt('form.walletAddress'),
|
|
117
|
+
transactionHash: pt('form.transactionHash'),
|
|
118
|
+
withdrawalId: pt('form.paymentId'),
|
|
119
|
+
reference: pt('form.orderId'),
|
|
120
|
+
created: pt('form.created'),
|
|
121
|
+
network: pt('form.network'),
|
|
122
|
+
// Actions
|
|
123
|
+
viewOnExplorer: pt('actions.openInPaymentProvider'),
|
|
124
|
+
cancel: pt('actions.cancel'),
|
|
125
|
+
refreshStatus: pt('actions.refreshStatus'),
|
|
126
|
+
tryAgain: pt('actions.tryAgain'),
|
|
127
|
+
// Messages
|
|
128
|
+
failedToLoad: pt('messages.failedToLoadPayment'),
|
|
129
|
+
}), [pt]);
|
|
130
|
+
|
|
99
131
|
// Fetch withdrawal details when sheet is open
|
|
100
132
|
const { data: withdrawal, isLoading, error, mutate } = useSWR<WithdrawalDetail>(
|
|
101
133
|
open && withdrawalId ? ['withdrawal-details', withdrawalId] : null,
|
|
@@ -115,13 +147,23 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
115
147
|
const isProcessing = s === 'processing' || s === 'approved';
|
|
116
148
|
const canCancel = isPending;
|
|
117
149
|
|
|
150
|
+
// Status label from translations
|
|
151
|
+
const statusLabels: Record<string, string> = {
|
|
152
|
+
pending: labels.pending,
|
|
153
|
+
approved: labels.approved,
|
|
154
|
+
processing: labels.processing,
|
|
155
|
+
completed: labels.completed,
|
|
156
|
+
rejected: labels.rejected,
|
|
157
|
+
cancelled: labels.cancelled,
|
|
158
|
+
};
|
|
159
|
+
|
|
118
160
|
// Description text
|
|
119
161
|
let description = '';
|
|
120
|
-
if (isPending) description =
|
|
121
|
-
else if (isProcessing) description =
|
|
122
|
-
else if (isCompleted) description =
|
|
123
|
-
else if (isRejected) description =
|
|
124
|
-
else if (isCancelled) description =
|
|
162
|
+
if (isPending) description = labels.pendingApproval;
|
|
163
|
+
else if (isProcessing) description = labels.processingDesc;
|
|
164
|
+
else if (isCompleted) description = labels.completedDesc;
|
|
165
|
+
else if (isRejected) description = labels.rejectedDesc;
|
|
166
|
+
else if (isCancelled) description = labels.cancelledDesc;
|
|
125
167
|
|
|
126
168
|
// Formatted values
|
|
127
169
|
const amountUsd = withdrawal?.amount_usd ? `$${parseFloat(withdrawal.amount_usd).toFixed(2)}` : '';
|
|
@@ -137,6 +179,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
137
179
|
return {
|
|
138
180
|
status: s,
|
|
139
181
|
config,
|
|
182
|
+
statusLabel: statusLabels[s] || statusLabels.pending,
|
|
140
183
|
isPending,
|
|
141
184
|
isCompleted,
|
|
142
185
|
isRejected,
|
|
@@ -150,9 +193,9 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
150
193
|
createdAt,
|
|
151
194
|
completedAt,
|
|
152
195
|
};
|
|
153
|
-
}, [withdrawal]);
|
|
196
|
+
}, [withdrawal, labels]);
|
|
154
197
|
|
|
155
|
-
const { config, canCancel, description, amountUsd, finalAmountUsd, totalFeeUsd, createdAt, completedAt } = displayData;
|
|
198
|
+
const { config, statusLabel, canCancel, description, amountUsd, finalAmountUsd, totalFeeUsd, createdAt, completedAt } = displayData;
|
|
156
199
|
const StatusIcon = config.icon;
|
|
157
200
|
|
|
158
201
|
// Handle cancel
|
|
@@ -171,7 +214,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
171
214
|
<ResponsiveSheet open={open} onOpenChange={onOpenChange}>
|
|
172
215
|
<ResponsiveSheetContent className="sm:max-w-lg">
|
|
173
216
|
<ResponsiveSheetHeader>
|
|
174
|
-
<ResponsiveSheetTitle>
|
|
217
|
+
<ResponsiveSheetTitle>{labels.title}</ResponsiveSheetTitle>
|
|
175
218
|
<ResponsiveSheetDescription>{description}</ResponsiveSheetDescription>
|
|
176
219
|
</ResponsiveSheetHeader>
|
|
177
220
|
|
|
@@ -187,8 +230,8 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
187
230
|
{error && (
|
|
188
231
|
<div className="flex flex-col items-center justify-center py-12">
|
|
189
232
|
<XCircle className="h-12 w-12 text-destructive mb-4" />
|
|
190
|
-
<p className="text-sm text-muted-foreground mb-4">
|
|
191
|
-
<Button onClick={() => mutate()}>
|
|
233
|
+
<p className="text-sm text-muted-foreground mb-4">{labels.failedToLoad}</p>
|
|
234
|
+
<Button onClick={() => mutate()}>{labels.tryAgain}</Button>
|
|
192
235
|
</div>
|
|
193
236
|
)}
|
|
194
237
|
|
|
@@ -198,7 +241,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
198
241
|
<div className={cn('flex items-center gap-3 p-4 rounded-xl', config.bg)}>
|
|
199
242
|
<StatusIcon className={cn('h-6 w-6', config.color, config.animate && 'animate-spin')} />
|
|
200
243
|
<div className="flex-1">
|
|
201
|
-
<div className="font-semibold">{
|
|
244
|
+
<div className="font-semibold">{statusLabel}</div>
|
|
202
245
|
{withdrawal.admin_notes && (
|
|
203
246
|
<div className="text-sm text-muted-foreground">{withdrawal.admin_notes}</div>
|
|
204
247
|
)}
|
|
@@ -208,17 +251,17 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
208
251
|
{/* Amount Breakdown */}
|
|
209
252
|
<div className="bg-muted rounded-xl p-4 space-y-3">
|
|
210
253
|
<div className="flex items-center justify-between">
|
|
211
|
-
<span className="text-muted-foreground">
|
|
254
|
+
<span className="text-muted-foreground">{labels.amount}</span>
|
|
212
255
|
<span className="font-semibold">{amountUsd}</span>
|
|
213
256
|
</div>
|
|
214
257
|
{totalFeeUsd && (
|
|
215
258
|
<div className="flex items-center justify-between text-sm">
|
|
216
|
-
<span className="text-muted-foreground">
|
|
259
|
+
<span className="text-muted-foreground">{labels.totalFees}</span>
|
|
217
260
|
<span className="text-destructive">-{totalFeeUsd}</span>
|
|
218
261
|
</div>
|
|
219
262
|
)}
|
|
220
263
|
<div className="flex items-center justify-between pt-2 border-t">
|
|
221
|
-
<span className="text-muted-foreground">
|
|
264
|
+
<span className="text-muted-foreground">{labels.youReceive}</span>
|
|
222
265
|
<div className="flex items-center gap-2">
|
|
223
266
|
<TokenIcon symbol={withdrawal.currency_code} size={24} />
|
|
224
267
|
<span className="font-mono font-bold text-lg">
|
|
@@ -228,7 +271,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
228
271
|
</div>
|
|
229
272
|
{withdrawal.crypto_amount && (
|
|
230
273
|
<div className="flex items-center justify-between text-sm">
|
|
231
|
-
<span className="text-muted-foreground">
|
|
274
|
+
<span className="text-muted-foreground">{labels.cryptoAmount}</span>
|
|
232
275
|
<span className="font-mono">{withdrawal.crypto_amount} {withdrawal.currency_token}</span>
|
|
233
276
|
</div>
|
|
234
277
|
)}
|
|
@@ -237,7 +280,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
237
280
|
{/* Wallet Address */}
|
|
238
281
|
{withdrawal.wallet_address && (
|
|
239
282
|
<div className="space-y-2">
|
|
240
|
-
<label className="text-sm font-medium">
|
|
283
|
+
<label className="text-sm font-medium">{labels.destinationWallet}</label>
|
|
241
284
|
<div className="flex items-center gap-2">
|
|
242
285
|
<div className="flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all">
|
|
243
286
|
{withdrawal.wallet_address}
|
|
@@ -250,7 +293,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
250
293
|
{/* Transaction Hash (if completed) */}
|
|
251
294
|
{withdrawal.transaction_hash && (
|
|
252
295
|
<div className="space-y-2">
|
|
253
|
-
<label className="text-sm font-medium">
|
|
296
|
+
<label className="text-sm font-medium">{labels.transactionHash}</label>
|
|
254
297
|
<div className="flex items-center gap-2">
|
|
255
298
|
<div className="flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all">
|
|
256
299
|
{withdrawal.transaction_hash}
|
|
@@ -268,7 +311,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
268
311
|
onClick={() => window.open(withdrawal.explorer_link!, '_blank')}
|
|
269
312
|
>
|
|
270
313
|
<ExternalLink className="h-4 w-4 mr-2" />
|
|
271
|
-
|
|
314
|
+
{labels.viewOnExplorer}
|
|
272
315
|
</Button>
|
|
273
316
|
)}
|
|
274
317
|
|
|
@@ -280,35 +323,35 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
280
323
|
onClick={handleCancel}
|
|
281
324
|
>
|
|
282
325
|
<Ban className="h-4 w-4 mr-2" />
|
|
283
|
-
|
|
326
|
+
{labels.cancel}
|
|
284
327
|
</Button>
|
|
285
328
|
)}
|
|
286
329
|
|
|
287
330
|
{/* Metadata */}
|
|
288
331
|
<div className="space-y-2 text-xs text-muted-foreground pt-4 border-t">
|
|
289
332
|
<div className="flex justify-between">
|
|
290
|
-
<span>
|
|
333
|
+
<span>{labels.withdrawalId}</span>
|
|
291
334
|
<span className="font-mono">{withdrawal.id}</span>
|
|
292
335
|
</div>
|
|
293
336
|
{withdrawal.internal_withdrawal_id && (
|
|
294
337
|
<div className="flex justify-between">
|
|
295
|
-
<span>
|
|
338
|
+
<span>{labels.reference}</span>
|
|
296
339
|
<span className="font-mono">{withdrawal.internal_withdrawal_id}</span>
|
|
297
340
|
</div>
|
|
298
341
|
)}
|
|
299
342
|
<div className="flex justify-between">
|
|
300
|
-
<span>
|
|
343
|
+
<span>{labels.created}</span>
|
|
301
344
|
<span>{createdAt}</span>
|
|
302
345
|
</div>
|
|
303
346
|
{completedAt && (
|
|
304
347
|
<div className="flex justify-between">
|
|
305
|
-
<span>
|
|
348
|
+
<span>{labels.completed}</span>
|
|
306
349
|
<span>{completedAt}</span>
|
|
307
350
|
</div>
|
|
308
351
|
)}
|
|
309
352
|
{withdrawal.currency_network && (
|
|
310
353
|
<div className="flex justify-between">
|
|
311
|
-
<span>
|
|
354
|
+
<span>{labels.network}</span>
|
|
312
355
|
<span>{withdrawal.currency_network}</span>
|
|
313
356
|
</div>
|
|
314
357
|
)}
|
|
@@ -321,7 +364,7 @@ export function WithdrawalSheet({ withdrawalId, open, onOpenChange }: Withdrawal
|
|
|
321
364
|
onClick={() => mutate()}
|
|
322
365
|
>
|
|
323
366
|
<RefreshCw className="h-4 w-4 mr-2" />
|
|
324
|
-
|
|
367
|
+
{labels.refreshStatus}
|
|
325
368
|
</Button>
|
|
326
369
|
</div>
|
|
327
370
|
)}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payments Extension I18n
|
|
3
|
+
*
|
|
4
|
+
* Self-contained translations - no app configuration needed.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { usePaymentsT } from '@djangocfg/ext-payments/i18n';
|
|
9
|
+
*
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const t = usePaymentsT();
|
|
12
|
+
* return <span>{t('balance.available')}</span>;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Self-contained hook (recommended)
|
|
18
|
+
export { usePaymentsT } from './usePaymentsT';
|
|
19
|
+
|
|
20
|
+
// Types
|
|
21
|
+
export type { PaymentsTranslations, PaymentsLocalKeys } from './types';
|
|
22
|
+
|
|
23
|
+
// Locales (for direct access if needed)
|
|
24
|
+
export { en } from './locales/en';
|
|
25
|
+
export { ru } from './locales/ru';
|
|
26
|
+
export { ko } from './locales/ko';
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { PaymentsTranslations } from '../types';
|
|
2
|
+
|
|
3
|
+
export const en: PaymentsTranslations = {
|
|
4
|
+
balance: {
|
|
5
|
+
available: 'Available Balance',
|
|
6
|
+
totalDeposited: 'Total Deposited',
|
|
7
|
+
totalWithdrawn: 'Total Withdrawn',
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
actions: {
|
|
11
|
+
addFunds: 'Add Funds',
|
|
12
|
+
withdraw: 'Withdraw',
|
|
13
|
+
continue: 'Continue',
|
|
14
|
+
requestWithdrawal: 'Request Withdrawal',
|
|
15
|
+
cancel: 'Cancel',
|
|
16
|
+
close: 'Close',
|
|
17
|
+
copyAddress: 'Copy Address',
|
|
18
|
+
copied: 'Copied!',
|
|
19
|
+
viewAll: 'View All',
|
|
20
|
+
tryAgain: 'Try Again',
|
|
21
|
+
refreshStatus: 'Refresh Status',
|
|
22
|
+
createNewPayment: 'Create New Payment',
|
|
23
|
+
openInPaymentProvider: 'Open in Payment Provider',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
paymentStatus: {
|
|
27
|
+
waiting: 'Waiting for payment',
|
|
28
|
+
confirming: 'Confirming',
|
|
29
|
+
completed: 'Completed',
|
|
30
|
+
failed: 'Failed',
|
|
31
|
+
expired: 'Expired',
|
|
32
|
+
paymentExpired: 'Payment Expired',
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
withdrawalStatus: {
|
|
36
|
+
pending: 'Pending Approval',
|
|
37
|
+
approved: 'Approved',
|
|
38
|
+
processing: 'Processing',
|
|
39
|
+
completed: 'Completed',
|
|
40
|
+
rejected: 'Rejected',
|
|
41
|
+
cancelled: 'Cancelled',
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
paymentDescriptions: {
|
|
45
|
+
sendCrypto: 'Send cryptocurrency to complete payment',
|
|
46
|
+
expired: 'This payment has expired',
|
|
47
|
+
completed: 'Payment completed successfully',
|
|
48
|
+
failed: 'Payment failed',
|
|
49
|
+
confirming: 'Confirming your payment',
|
|
50
|
+
createNew: 'Please create a new payment to continue',
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
withdrawalDescriptions: {
|
|
54
|
+
pendingApproval: 'Waiting for admin approval',
|
|
55
|
+
processing: 'Your withdrawal is being processed',
|
|
56
|
+
completed: 'Withdrawal completed successfully',
|
|
57
|
+
rejected: 'Withdrawal was rejected',
|
|
58
|
+
cancelled: 'Withdrawal was cancelled',
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
form: {
|
|
62
|
+
amount: 'Amount',
|
|
63
|
+
amountUsd: 'Amount (USD)',
|
|
64
|
+
currency: 'Currency',
|
|
65
|
+
walletAddress: 'Wallet Address',
|
|
66
|
+
selectCurrency: 'Select currency...',
|
|
67
|
+
enterWalletAddress: 'Enter your wallet address',
|
|
68
|
+
search: 'Search...',
|
|
69
|
+
payWith: 'Pay with',
|
|
70
|
+
withdrawAs: 'Withdraw as',
|
|
71
|
+
amountToSend: 'Amount to send',
|
|
72
|
+
equivalent: 'Equivalent',
|
|
73
|
+
network: 'Network',
|
|
74
|
+
paymentAddress: 'Payment Address',
|
|
75
|
+
transactionHash: 'Transaction Hash',
|
|
76
|
+
paymentId: 'Payment ID',
|
|
77
|
+
orderId: 'Order #',
|
|
78
|
+
created: 'Created',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
validation: {
|
|
82
|
+
minimumDeposit: 'Minimum $1',
|
|
83
|
+
minimumWithdrawal: 'Minimum $10',
|
|
84
|
+
selectCurrency: 'Select a currency',
|
|
85
|
+
invalidWalletAddress: 'Invalid wallet address',
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
messages: {
|
|
89
|
+
paymentCreated: 'Payment created successfully',
|
|
90
|
+
paymentFailed: 'Failed to create payment',
|
|
91
|
+
withdrawalCreated: 'Withdrawal request created',
|
|
92
|
+
withdrawalFailed: 'Failed to create withdrawal request',
|
|
93
|
+
withdrawalCancelled: 'Withdrawal cancelled',
|
|
94
|
+
addressCopied: 'Address copied to clipboard',
|
|
95
|
+
failedToLoadPayment: 'Failed to load payment',
|
|
96
|
+
failedToCreateWithdrawal: 'Failed to create withdrawal request',
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
sheets: {
|
|
100
|
+
addFundsTitle: 'Add Funds',
|
|
101
|
+
addFundsDescription: 'Add funds to your wallet using cryptocurrency',
|
|
102
|
+
withdrawTitle: 'Withdraw',
|
|
103
|
+
withdrawDescription: 'Withdraw funds to your cryptocurrency wallet',
|
|
104
|
+
paymentTitle: 'Payment Details',
|
|
105
|
+
withdrawalTitle: 'Withdrawal Details',
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
activity: {
|
|
109
|
+
title: 'Recent Activity',
|
|
110
|
+
noActivity: 'No Activity Yet',
|
|
111
|
+
deposit: 'Deposit',
|
|
112
|
+
withdrawal: 'Withdrawal',
|
|
113
|
+
payment: 'Payment',
|
|
114
|
+
transactionsWillAppear: 'Your transactions will appear here',
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
estimate: {
|
|
118
|
+
gettingRate: 'Getting rate...',
|
|
119
|
+
calculating: 'Calculating fees...',
|
|
120
|
+
enterAmountToSee: 'Enter amount to see conversion',
|
|
121
|
+
youWillSend: 'You will send',
|
|
122
|
+
youWillReceive: 'You will receive',
|
|
123
|
+
serviceFee: 'Service fee',
|
|
124
|
+
networkFee: 'Network fee',
|
|
125
|
+
rate: 'Rate',
|
|
126
|
+
minimumAmount: 'Minimum amount',
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
withdraw: {
|
|
130
|
+
insufficientBalance: 'Insufficient balance',
|
|
131
|
+
approvalWarning: 'Withdrawal requests require admin approval. Processing may take 24-48 hours.',
|
|
132
|
+
submitting: 'Submitting...',
|
|
133
|
+
creating: 'Creating...',
|
|
134
|
+
expiresIn: 'Expires in',
|
|
135
|
+
},
|
|
136
|
+
};
|