@djangocfg/ext-payments 1.0.14 → 1.0.19

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.
Files changed (76) hide show
  1. package/dist/config.cjs +5 -8
  2. package/dist/config.js +5 -8
  3. package/dist/index.cjs +1906 -1043
  4. package/dist/index.d.cts +644 -59
  5. package/dist/index.d.ts +644 -59
  6. package/dist/index.js +1886 -1040
  7. package/package.json +13 -16
  8. package/src/WalletPage.tsx +100 -0
  9. package/src/api/generated/ext_payments/CLAUDE.md +10 -4
  10. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +268 -5
  11. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +102 -3
  12. package/src/api/generated/ext_payments/_utils/schemas/Balance.schema.ts +1 -1
  13. package/src/api/generated/ext_payments/_utils/schemas/PaginatedWithdrawalListList.schema.ts +24 -0
  14. package/src/api/generated/ext_payments/_utils/schemas/PaymentCreateRequest.schema.ts +21 -0
  15. package/src/api/generated/ext_payments/_utils/schemas/PaymentCreateResponse.schema.ts +22 -0
  16. package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +3 -3
  17. package/src/api/generated/ext_payments/_utils/schemas/PaymentList.schema.ts +2 -2
  18. package/src/api/generated/ext_payments/_utils/schemas/Transaction.schema.ts +1 -1
  19. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCancelResponse.schema.ts +22 -0
  20. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCreateRequest.schema.ts +21 -0
  21. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCreateResponse.schema.ts +22 -0
  22. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalDetail.schema.ts +42 -0
  23. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalList.schema.ts +29 -0
  24. package/src/api/generated/ext_payments/_utils/schemas/index.ts +8 -0
  25. package/src/api/generated/ext_payments/client.ts +1 -1
  26. package/src/api/generated/ext_payments/enums.ts +36 -0
  27. package/src/api/generated/ext_payments/ext_payments__payments/client.ts +104 -6
  28. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +168 -8
  29. package/src/api/generated/ext_payments/index.ts +1 -1
  30. package/src/api/generated/ext_payments/schema.json +752 -42
  31. package/src/components/ActivityItem.tsx +118 -0
  32. package/src/components/ActivityList.tsx +93 -0
  33. package/src/components/AddFundsSheet.tsx +342 -0
  34. package/src/components/BalanceHero.tsx +102 -0
  35. package/src/components/CurrencyCombobox.tsx +49 -0
  36. package/src/components/PaymentSheet.tsx +352 -0
  37. package/src/components/WithdrawSheet.tsx +355 -0
  38. package/src/components/WithdrawalSheet.tsx +332 -0
  39. package/src/components/index.ts +11 -0
  40. package/src/config.ts +1 -0
  41. package/src/contexts/WalletContext.tsx +356 -0
  42. package/src/contexts/index.ts +13 -42
  43. package/src/contexts/types.ts +43 -37
  44. package/src/hooks/index.ts +3 -20
  45. package/src/hooks/useCurrencyOptions.ts +79 -0
  46. package/src/hooks/useEstimate.ts +113 -0
  47. package/src/hooks/useWithdrawalEstimate.ts +117 -0
  48. package/src/index.ts +9 -18
  49. package/src/types/index.ts +78 -0
  50. package/src/utils/errors.ts +36 -0
  51. package/src/utils/format.ts +65 -0
  52. package/src/utils/index.ts +3 -0
  53. package/src/contexts/BalancesContext.tsx +0 -63
  54. package/src/contexts/CurrenciesContext.tsx +0 -64
  55. package/src/contexts/OverviewContext.tsx +0 -173
  56. package/src/contexts/PaymentsContext.tsx +0 -122
  57. package/src/contexts/PaymentsExtensionProvider.tsx +0 -56
  58. package/src/contexts/README.md +0 -201
  59. package/src/contexts/RootPaymentsContext.tsx +0 -66
  60. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +0 -90
  61. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +0 -274
  62. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +0 -287
  63. package/src/layouts/PaymentsLayout/components/index.ts +0 -2
  64. package/src/layouts/PaymentsLayout/events.ts +0 -47
  65. package/src/layouts/PaymentsLayout/index.ts +0 -16
  66. package/src/layouts/PaymentsLayout/types.ts +0 -6
  67. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +0 -121
  68. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +0 -139
  69. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
  70. package/src/layouts/PaymentsLayout/views/overview/index.tsx +0 -21
  71. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +0 -279
  72. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
  73. package/src/layouts/PaymentsLayout/views/payments/index.tsx +0 -18
  74. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +0 -260
  75. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +0 -1
  76. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +0 -18
@@ -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';
@@ -1,6 +0,0 @@
1
- /**
2
- * Payments Layout Types (v2.0 - Simplified)
3
- */
4
-
5
- // Tab types for navigation (removed apikeys and tariffs)
6
- export type PaymentTab = 'overview' | 'payments' | 'transactions';
@@ -1,121 +0,0 @@
1
- /**
2
- * Balance Card Component (v2.0 - Simplified)
3
- * Display user balance with quick actions
4
- */
5
-
6
- 'use client';
7
-
8
- import { Plus, RefreshCw, Wallet } from 'lucide-react';
9
- import moment from 'moment';
10
- import React from 'react';
11
-
12
- import {
13
- Badge, Button, Card, CardContent, CardHeader, CardTitle, Skeleton
14
- } from '@djangocfg/ui-core';
15
-
16
- import { useOverviewContext } from '../../../../../contexts';
17
- import { openCreatePaymentDialog } from '../../../events';
18
-
19
- export const BalanceCard: React.FC = () => {
20
- const {
21
- balance,
22
- isLoadingBalance,
23
- refreshBalance
24
- } = useOverviewContext();
25
-
26
- const formatCurrency = (amount?: number | null) => {
27
- if (amount === null || amount === undefined) return '$0.00';
28
- return new Intl.NumberFormat('en-US', {
29
- style: 'currency',
30
- currency: 'USD',
31
- minimumFractionDigits: 2,
32
- }).format(amount);
33
- };
34
-
35
- const formatDate = (dateStr?: string) => {
36
- if (!dateStr) return 'No transactions yet';
37
- try {
38
- return moment.utc(dateStr).local().format('MMM D, YYYY');
39
- } catch {
40
- return 'Invalid date';
41
- }
42
- };
43
-
44
- if (isLoadingBalance) {
45
- return (
46
- <Card>
47
- <CardHeader>
48
- <CardTitle className="flex items-center justify-between">
49
- <div className="flex items-center gap-2">
50
- <Wallet className="h-5 w-5" />
51
- Account Balance
52
- </div>
53
- <Skeleton className="h-8 w-20" />
54
- </CardTitle>
55
- </CardHeader>
56
- <CardContent className="space-y-4">
57
- <Skeleton className="h-10 w-32" />
58
- <Skeleton className="h-4 w-48" />
59
- </CardContent>
60
- </Card>
61
- );
62
- }
63
-
64
- // Extract balance data from response: { success, balance: { amount_usd, total_deposited, total_withdrawn, last_transaction_at } }
65
- const balanceData = balance?.balance || balance;
66
- const amountUsd = balanceData?.amount_usd ?? 0;
67
- const totalDeposited = balanceData?.total_deposited ?? 0;
68
- const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
69
- const lastTransactionAt = balanceData?.last_transaction_at;
70
- const isEmpty = amountUsd === 0 && totalDeposited === 0;
71
-
72
- return (
73
- <Card>
74
- <CardHeader>
75
- <CardTitle className="flex items-center justify-between">
76
- <div className="flex items-center gap-2">
77
- <Wallet className="h-5 w-5" />
78
- Account Balance
79
- </div>
80
- <div className="flex items-center gap-2">
81
- <Button variant="ghost" size="sm" onClick={refreshBalance}>
82
- <RefreshCw className="h-4 w-4" />
83
- </Button>
84
- <Button size="sm" onClick={() => openCreatePaymentDialog()}>
85
- <Plus className="h-4 w-4 mr-2" />
86
- Add Funds
87
- </Button>
88
- </div>
89
- </CardTitle>
90
- </CardHeader>
91
- <CardContent className="space-y-4">
92
- <div>
93
- <div className="text-4xl font-bold">
94
- {formatCurrency(amountUsd)}
95
- </div>
96
- <p className="text-sm text-muted-foreground mt-1">
97
- Available balance • Last updated {formatDate(lastTransactionAt)}
98
- </p>
99
- </div>
100
-
101
- <div className="grid grid-cols-2 gap-4 pt-4 border-t">
102
- <div>
103
- <p className="text-xs text-muted-foreground">Total Deposited</p>
104
- <p className="text-lg font-semibold text-green-600">{formatCurrency(totalDeposited)}</p>
105
- </div>
106
- <div>
107
- <p className="text-xs text-muted-foreground">Total Withdrawn</p>
108
- <p className="text-lg font-semibold text-red-600">{formatCurrency(totalWithdrawn)}</p>
109
- </div>
110
- </div>
111
-
112
- <div className="flex items-center gap-2">
113
- <Badge variant={!isEmpty ? 'default' : 'secondary'}>
114
- {!isEmpty ? 'Active' : 'New Account'}
115
- </Badge>
116
- {isEmpty && <Badge variant="outline">Empty Balance</Badge>}
117
- </div>
118
- </CardContent>
119
- </Card>
120
- );
121
- };
@@ -1,139 +0,0 @@
1
- /**
2
- * Recent Payments Component (v2.0 - Simplified)
3
- * Display recent payment transactions from payments list
4
- */
5
-
6
- 'use client';
7
-
8
- import { ExternalLink, History } from 'lucide-react';
9
- import moment from 'moment';
10
- import React from 'react';
11
-
12
- import {
13
- Badge, Button, Card, CardContent, CardHeader, CardTitle, Skeleton
14
- } from '@djangocfg/ui-core';
15
-
16
- import { useOverviewContext } from '../../../../../contexts';
17
- import { openPaymentDetailsDialog } from '../../../events';
18
-
19
- export const RecentPayments: React.FC = () => {
20
- const { payments, isLoadingPayments } = useOverviewContext();
21
-
22
- const formatCurrency = (amount?: number | string | null) => {
23
- if (amount === null || amount === undefined) return '$0.00';
24
- const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
25
- return new Intl.NumberFormat('en-US', {
26
- style: 'currency',
27
- currency: 'USD',
28
- minimumFractionDigits: 2,
29
- }).format(numAmount);
30
- };
31
-
32
- const getRelativeTime = (date: string | null | undefined): string => {
33
- if (!date) return 'N/A';
34
-
35
- const m = moment.utc(date).local();
36
- const now = moment();
37
- const diffInSeconds = now.diff(m, 'seconds');
38
-
39
- if (diffInSeconds < 60) return 'Just now';
40
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
41
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
42
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
43
- };
44
-
45
- const getStatusVariant = (
46
- status: string | null | undefined
47
- ): 'default' | 'destructive' | 'outline' | 'secondary' => {
48
- switch (status?.toLowerCase()) {
49
- case 'completed':
50
- case 'success':
51
- return 'default';
52
- case 'pending':
53
- case 'confirming':
54
- return 'secondary';
55
- case 'failed':
56
- case 'error':
57
- case 'expired':
58
- return 'destructive';
59
- default:
60
- return 'outline';
61
- }
62
- };
63
-
64
- if (isLoadingPayments) {
65
- return (
66
- <Card>
67
- <CardHeader>
68
- <CardTitle className="flex items-center gap-2">
69
- <History className="h-5 w-5" />
70
- Recent Payments
71
- </CardTitle>
72
- </CardHeader>
73
- <CardContent className="space-y-3">
74
- {Array.from({ length: 5 }).map((_, i) => (
75
- <div key={i} className="flex items-center justify-between p-3 border rounded-sm">
76
- <div className="space-y-2">
77
- <Skeleton className="h-4 w-32" />
78
- <Skeleton className="h-3 w-24" />
79
- </div>
80
- <Skeleton className="h-6 w-16" />
81
- </div>
82
- ))}
83
- </CardContent>
84
- </Card>
85
- );
86
- }
87
-
88
- // Get first 5 payments for recent list
89
- const recentPaymentsList = payments?.results?.slice(0, 5) || [];
90
-
91
- return (
92
- <Card>
93
- <CardHeader>
94
- <CardTitle className="flex items-center justify-between">
95
- <div className="flex items-center gap-2">
96
- <History className="h-5 w-5" />
97
- Recent Payments
98
- </div>
99
- <Button variant="ghost" size="sm">
100
- View All
101
- <ExternalLink className="h-4 w-4 ml-2" />
102
- </Button>
103
- </CardTitle>
104
- </CardHeader>
105
- <CardContent>
106
- {recentPaymentsList.length === 0 ? (
107
- <div className="text-center py-8 text-muted-foreground">
108
- <History className="h-12 w-12 mx-auto mb-4 opacity-50" />
109
- <p>No recent payments</p>
110
- <p className="text-sm mt-2">Create your first payment to get started</p>
111
- </div>
112
- ) : (
113
- <div className="space-y-3">
114
- {recentPaymentsList.map((payment) => (
115
- <div
116
- key={payment.id}
117
- className="flex items-center justify-between p-3 border rounded-sm hover:bg-accent cursor-pointer transition-colors"
118
- onClick={() => openPaymentDetailsDialog(String(payment.id))}
119
- >
120
- <div className="flex-1">
121
- <div className="flex items-center gap-2">
122
- <span className="font-medium">{formatCurrency(payment.amount_usd)}</span>
123
- <Badge variant={getStatusVariant(payment.status)} className="text-xs">
124
- {payment.status}
125
- </Badge>
126
- </div>
127
- <p className="text-sm text-muted-foreground">
128
- {getRelativeTime(payment.created_at)} • {payment.currency_code || 'USD'}
129
- </p>
130
- </div>
131
- <ExternalLink className="h-4 w-4 text-muted-foreground" />
132
- </div>
133
- ))}
134
- </div>
135
- )}
136
- </CardContent>
137
- </Card>
138
- );
139
- };
@@ -1,2 +0,0 @@
1
- export { BalanceCard } from './BalanceCard';
2
- export { RecentPayments } from './RecentPayments';
@@ -1,21 +0,0 @@
1
- /**
2
- * Overview View (v2.0 - Simplified)
3
- * Dashboard with balance and recent payments
4
- */
5
-
6
- 'use client';
7
-
8
- import React from 'react';
9
-
10
- import { BalanceCard, RecentPayments } from './components';
11
-
12
- export const OverviewView: React.FC = () => {
13
- return (
14
- <div className="space-y-6">
15
- <div className="grid gap-6 lg:grid-cols-2">
16
- <BalanceCard />
17
- <RecentPayments />
18
- </div>
19
- </div>
20
- );
21
- };
@@ -1,279 +0,0 @@
1
- /**
2
- * Payments List Component (v2.0 - Simplified)
3
- * Display paginated list of payments with filters
4
- */
5
-
6
- 'use client';
7
-
8
- import { ExternalLink, Filter, Plus, RefreshCw, Search } from 'lucide-react';
9
- import moment from 'moment';
10
- import React, { useState } from 'react';
11
-
12
- import {
13
- Badge, Button, Card, CardContent, CardHeader, CardTitle, Input, Select, SelectContent,
14
- SelectItem, SelectTrigger, SelectValue, Skeleton, Table, TableBody, TableCell,
15
- TableHead, TableHeader, TableRow,
16
- } from '@djangocfg/ui-core';
17
- import { useDRFPagination, StaticPagination } from '@djangocfg/ui-nextjs/components';
18
-
19
- import { apiPayments } from '../../../../../api';
20
- import { usePaymentsPaymentsList } from '../../../../../api/generated/ext_payments/_utils/hooks';
21
- import { openCreatePaymentDialog, openPaymentDetailsDialog } from '../../../events';
22
-
23
- export const PaymentsList: React.FC = () => {
24
- // Local pagination state
25
- const pagination = useDRFPagination(1, 20);
26
-
27
- // Fetch payments with pagination
28
- const {
29
- data: payments,
30
- error,
31
- isLoading: isLoadingPayments,
32
- mutate: refreshPayments,
33
- } = usePaymentsPaymentsList(pagination.params, apiPayments);
34
-
35
- const paymentsList = payments?.results || [];
36
- const totalCount = payments?.count || 0;
37
-
38
- const [searchTerm, setSearchTerm] = useState('');
39
- const [statusFilter, setStatusFilter] = useState<string>('all');
40
-
41
- const formatCurrency = (amount?: number | string | null) => {
42
- if (amount === null || amount === undefined) return '$0.00';
43
- const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
44
- return new Intl.NumberFormat('en-US', {
45
- style: 'currency',
46
- currency: 'USD',
47
- minimumFractionDigits: 2,
48
- }).format(numAmount);
49
- };
50
-
51
- const getRelativeTime = (date: string | null | undefined): string => {
52
- if (!date) return 'N/A';
53
-
54
- const m = moment.utc(date).local();
55
- const now = moment();
56
- const diffInSeconds = now.diff(m, 'seconds');
57
-
58
- if (diffInSeconds < 60) return 'Just now';
59
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
60
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
61
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
62
- };
63
-
64
- const formatDate = (date: string | null | undefined): string => {
65
- if (!date) return 'N/A';
66
- return moment.utc(date).local().format('MMM D, YYYY');
67
- };
68
-
69
- const getStatusVariant = (
70
- status: string | null | undefined
71
- ): 'default' | 'destructive' | 'outline' | 'secondary' => {
72
- switch (status?.toLowerCase()) {
73
- case 'completed':
74
- case 'success':
75
- return 'default';
76
- case 'pending':
77
- case 'confirming':
78
- return 'secondary';
79
- case 'failed':
80
- case 'error':
81
- case 'expired':
82
- return 'destructive';
83
- default:
84
- return 'outline';
85
- }
86
- };
87
-
88
- const handleSearch = (value: string) => {
89
- setSearchTerm(value);
90
- // Client-side filtering only
91
- };
92
-
93
- const handleStatusFilter = (status: string) => {
94
- setStatusFilter(status);
95
- // Client-side filtering only
96
- };
97
-
98
- // Helper to truncate ID
99
- const truncateId = (id: string | number | null | undefined): string => {
100
- if (!id) return 'N/A';
101
- const str = id.toString();
102
- return str.length > 8 ? `${str.slice(0, 8)}...` : str;
103
- };
104
-
105
- // Filter and prepare payments with pre-computed fields
106
- const filteredPayments = paymentsList
107
- .filter((payment) => {
108
- const matchesSearch = searchTerm
109
- ? payment.id?.toLowerCase().includes(searchTerm.toLowerCase()) ||
110
- payment.status?.toLowerCase().includes(searchTerm.toLowerCase()) ||
111
- payment.currency_code?.toLowerCase().includes(searchTerm.toLowerCase())
112
- : true;
113
-
114
- const matchesStatus = statusFilter !== 'all'
115
- ? payment.status?.toLowerCase() === statusFilter.toLowerCase()
116
- : true;
117
-
118
- return matchesSearch && matchesStatus;
119
- })
120
- .map((payment) => ({
121
- ...payment,
122
- formattedDate: formatDate(payment.created_at),
123
- relativeTime: getRelativeTime(payment.created_at),
124
- truncatedId: truncateId(payment.id),
125
- }));
126
-
127
- return (
128
- <Card>
129
- <CardHeader>
130
- <CardTitle className="flex items-center justify-between">
131
- <span>Payment History</span>
132
- <div className="flex items-center gap-2">
133
- <Button variant="outline" size="sm" onClick={() => refreshPayments()} disabled={isLoadingPayments}>
134
- <RefreshCw className={`h-4 w-4 mr-2 ${isLoadingPayments ? 'animate-spin' : ''}`} />
135
- Refresh
136
- </Button>
137
- <Button size="sm" onClick={() => openCreatePaymentDialog()}>
138
- <Plus className="h-4 w-4 mr-2" />
139
- New Payment
140
- </Button>
141
- </div>
142
- </CardTitle>
143
- </CardHeader>
144
-
145
- <CardContent className="space-y-4">
146
- {/* Filters */}
147
- <div className="flex flex-col sm:flex-row gap-4">
148
- <div className="relative flex-1">
149
- <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
150
- <Input
151
- placeholder="Search by ID, status, or currency..."
152
- value={searchTerm}
153
- onChange={(e) => handleSearch(e.target.value)}
154
- className="pl-10"
155
- />
156
- </div>
157
-
158
- <Select value={statusFilter} onValueChange={handleStatusFilter}>
159
- <SelectTrigger className="w-full sm:w-48">
160
- <Filter className="h-4 w-4 mr-2" />
161
- <SelectValue placeholder="Filter by status" />
162
- </SelectTrigger>
163
- <SelectContent>
164
- <SelectItem value="all">All Statuses</SelectItem>
165
- <SelectItem value="completed">Completed</SelectItem>
166
- <SelectItem value="pending">Pending</SelectItem>
167
- <SelectItem value="confirming">Confirming</SelectItem>
168
- <SelectItem value="failed">Failed</SelectItem>
169
- <SelectItem value="expired">Expired</SelectItem>
170
- </SelectContent>
171
- </Select>
172
- </div>
173
-
174
- {/* Payments Table */}
175
- {isLoadingPayments ? (
176
- <div className="space-y-3">
177
- {Array.from({ length: 5 }).map((_, i) => (
178
- <div key={i} className="flex items-center justify-between p-4 border rounded-sm">
179
- <div className="space-y-2">
180
- <Skeleton className="h-4 w-32" />
181
- <Skeleton className="h-3 w-24" />
182
- </div>
183
- <Skeleton className="h-6 w-16" />
184
- </div>
185
- ))}
186
- </div>
187
- ) : filteredPayments.length === 0 ? (
188
- <div className="text-center py-12">
189
- <div className="w-16 h-16 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center">
190
- <Search className="w-8 h-8 text-muted-foreground" />
191
- </div>
192
- <h3 className="text-lg font-semibold mb-2">No Payments Found</h3>
193
- <p className="text-muted-foreground mb-4">
194
- {searchTerm || statusFilter !== 'all'
195
- ? 'No payments match your current filters'
196
- : "You haven't made any payments yet"}
197
- </p>
198
- <Button onClick={() => openCreatePaymentDialog()}>
199
- <Plus className="h-4 w-4 mr-2" />
200
- Create Payment
201
- </Button>
202
- </div>
203
- ) : (
204
- <>
205
- <div className="rounded-md border">
206
- <Table>
207
- <TableHeader>
208
- <TableRow>
209
- <TableHead>Date</TableHead>
210
- <TableHead>Amount</TableHead>
211
- <TableHead>Currency</TableHead>
212
- <TableHead>Status</TableHead>
213
- <TableHead>Provider</TableHead>
214
- <TableHead>Payment ID</TableHead>
215
- <TableHead className="text-right">Actions</TableHead>
216
- </TableRow>
217
- </TableHeader>
218
- <TableBody>
219
- {filteredPayments.map((payment) => (
220
- <TableRow
221
- key={payment.id}
222
- className="cursor-pointer hover:bg-accent"
223
- onClick={() => openPaymentDetailsDialog(String(payment.id))}
224
- >
225
- <TableCell>
226
- <div>
227
- <div className="font-medium">
228
- {payment.formattedDate}
229
- </div>
230
- <div className="text-sm text-muted-foreground">
231
- {payment.relativeTime}
232
- </div>
233
- </div>
234
- </TableCell>
235
- <TableCell className="font-mono font-semibold">
236
- {formatCurrency(payment.amount_usd)}
237
- </TableCell>
238
- <TableCell>
239
- <Badge variant="outline">{payment.currency_code || 'USD'}</Badge>
240
- </TableCell>
241
- <TableCell>
242
- <Badge variant={getStatusVariant(payment.status)}>{payment.status}</Badge>
243
- </TableCell>
244
- <TableCell className="text-sm text-muted-foreground">
245
- NowPayments
246
- </TableCell>
247
- <TableCell className="font-mono text-sm text-muted-foreground">
248
- {payment.truncatedId}
249
- </TableCell>
250
- <TableCell className="text-right">
251
- <Button
252
- variant="ghost"
253
- size="sm"
254
- onClick={(e) => {
255
- e.stopPropagation();
256
- openPaymentDetailsDialog(String(payment.id));
257
- }}
258
- >
259
- <ExternalLink className="h-4 w-4" />
260
- </Button>
261
- </TableCell>
262
- </TableRow>
263
- ))}
264
- </TableBody>
265
- </Table>
266
- </div>
267
-
268
- {/* DRF Pagination */}
269
- <StaticPagination
270
- data={payments}
271
- onPageChange={pagination.setPage}
272
- className="mt-4"
273
- />
274
- </>
275
- )}
276
- </CardContent>
277
- </Card>
278
- );
279
- };
@@ -1 +0,0 @@
1
- export { PaymentsList } from './PaymentsList';
@@ -1,18 +0,0 @@
1
- /**
2
- * Payments View (v2.0 - Simplified)
3
- * List and manage payment transactions
4
- */
5
-
6
- 'use client';
7
-
8
- import React from 'react';
9
-
10
- import { PaymentsList } from './components';
11
-
12
- export const PaymentsView: React.FC = () => {
13
- return (
14
- <div className="space-y-6">
15
- <PaymentsList />
16
- </div>
17
- );
18
- };