@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.
Files changed (41) hide show
  1. package/package.json +5 -5
  2. package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +2 -2
  3. package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +6 -6
  4. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +1 -1
  5. package/src/layouts/AppLayout/layouts/PublicLayout/components/DesktopUserMenu.tsx +6 -6
  6. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
  7. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +43 -133
  8. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenuUserCard.tsx +150 -0
  9. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +2 -2
  10. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +47 -65
  11. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +121 -144
  12. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +103 -48
  13. package/src/layouts/PaymentsLayout/components/index.ts +1 -4
  14. package/src/layouts/PaymentsLayout/events.ts +23 -84
  15. package/src/layouts/PaymentsLayout/index.ts +7 -11
  16. package/src/layouts/PaymentsLayout/types.ts +3 -16
  17. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +45 -16
  18. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +18 -14
  19. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
  20. package/src/layouts/PaymentsLayout/views/overview/index.tsx +3 -6
  21. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +51 -31
  22. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
  23. package/src/layouts/PaymentsLayout/views/payments/index.tsx +1 -2
  24. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +273 -0
  25. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +1 -0
  26. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +5 -17
  27. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -3
  28. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -3
  29. package/src/snippets/Chat/components/SessionList.tsx +1 -1
  30. package/src/snippets/Chat/hooks/useInfiniteSessions.ts +2 -2
  31. package/src/snippets/VideoPlayer/VideoPlayer.tsx +1 -1
  32. package/src/layouts/PaymentsLayout/README.md +0 -133
  33. package/src/layouts/PaymentsLayout/components/CreateApiKeyDialog.tsx +0 -172
  34. package/src/layouts/PaymentsLayout/components/DeleteApiKeyDialog.tsx +0 -100
  35. package/src/layouts/PaymentsLayout/context/RootPaymentsContext.tsx +0 -134
  36. package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeyMetrics.tsx +0 -109
  37. package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeysList.tsx +0 -194
  38. package/src/layouts/PaymentsLayout/views/apikeys/components/index.ts +0 -3
  39. package/src/layouts/PaymentsLayout/views/apikeys/index.tsx +0 -19
  40. package/src/layouts/PaymentsLayout/views/overview/components/MetricsCards.tsx +0 -103
  41. package/src/layouts/PaymentsLayout/views/tariffs/index.tsx +0 -29
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Payment Details Dialog
2
+ * Payment Details Dialog (v2.0 - Simplified)
3
3
  * Shows payment details with QR code, address, and status
4
4
  */
5
5
 
@@ -15,37 +15,50 @@ import {
15
15
  DialogTitle,
16
16
  Button,
17
17
  TokenIcon,
18
- useEventListener,
19
18
  } from '@djangocfg/ui';
20
- import { Copy, ExternalLink, CheckCircle2, Clock, XCircle, AlertCircle } from 'lucide-react';
21
- import type { Payment } from '@djangocfg/api/cfg/contexts';
19
+ import { Copy, ExternalLink, CheckCircle2, Clock, XCircle, AlertCircle, RefreshCw } from 'lucide-react';
20
+ import { Hooks, api } from '@djangocfg/api';
21
+ import type { API } from '@djangocfg/api';
22
+ import { PAYMENT_EVENTS } from '../events';
22
23
 
23
- export const PAYMENT_DETAILS_EVENTS = {
24
- OPEN_PAYMENT_DETAILS: 'open-payment-details',
25
- CLOSE_PAYMENT_DETAILS: 'close-payment-details',
26
- } as const;
27
-
28
- export interface PaymentDetailsDialogProps {
29
- payment?: Payment | null;
30
- }
31
-
32
- export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ payment: initialPayment }) => {
24
+ export const PaymentDetailsDialog: React.FC = () => {
33
25
  const [open, setOpen] = useState(false);
34
- const [payment, setPayment] = useState<Payment | null>(initialPayment || null);
26
+ const [paymentId, setPaymentId] = useState<string | null>(null);
35
27
  const [copied, setCopied] = useState(false);
36
28
  const [timeLeft, setTimeLeft] = useState<string>('');
37
29
 
38
- useEventListener(PAYMENT_DETAILS_EVENTS.OPEN_PAYMENT_DETAILS, (event: CustomEvent<{ payment: Payment }>) => {
39
- setPayment(event.detail.payment);
40
- setOpen(true);
41
- });
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
+ );
42
36
 
43
- useEventListener(PAYMENT_DETAILS_EVENTS.CLOSE_PAYMENT_DETAILS, () => {
44
- setOpen(false);
45
- });
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
+ }, []);
46
58
 
47
59
  const handleClose = () => {
48
60
  setOpen(false);
61
+ setPaymentId(null);
49
62
  };
50
63
 
51
64
  const handleCopyAddress = async () => {
@@ -85,26 +98,68 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
85
98
 
86
99
  // Get status icon and color
87
100
  const getStatusInfo = () => {
88
- switch (payment?.status) {
101
+ switch (payment?.status?.toLowerCase()) {
89
102
  case 'pending':
90
103
  return { icon: Clock, color: 'text-yellow-500', bg: 'bg-yellow-500/10' };
91
104
  case 'completed':
105
+ case 'success':
92
106
  return { icon: CheckCircle2, color: 'text-green-500', bg: 'bg-green-500/10' };
93
107
  case 'failed':
108
+ case 'error':
94
109
  return { icon: XCircle, color: 'text-red-500', bg: 'bg-red-500/10' };
95
110
  case 'expired':
96
111
  return { icon: AlertCircle, color: 'text-gray-500', bg: 'bg-gray-500/10' };
112
+ case 'confirming':
113
+ return { icon: RefreshCw, color: 'text-blue-500', bg: 'bg-blue-500/10' };
97
114
  default:
98
115
  return { icon: Clock, color: 'text-gray-500', bg: 'bg-gray-500/10' };
99
116
  }
100
117
  };
101
118
 
102
- if (!payment) return null;
119
+ if (!open) return null;
120
+
121
+ // Loading state
122
+ if (isLoading) {
123
+ return (
124
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
125
+ <DialogContent className="sm:max-w-lg">
126
+ <DialogHeader>
127
+ <DialogTitle>Payment Details</DialogTitle>
128
+ <DialogDescription>Loading payment information...</DialogDescription>
129
+ </DialogHeader>
130
+ <div className="flex items-center justify-center py-12">
131
+ <RefreshCw className="h-8 w-8 animate-spin text-muted-foreground" />
132
+ </div>
133
+ </DialogContent>
134
+ </Dialog>
135
+ );
136
+ }
137
+
138
+ // Error state
139
+ if (shouldFetch && !isLoading && (error || !payment)) {
140
+ return (
141
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
142
+ <DialogContent className="sm:max-w-lg">
143
+ <DialogHeader>
144
+ <DialogTitle>Payment Details</DialogTitle>
145
+ <DialogDescription>Failed to load payment information</DialogDescription>
146
+ </DialogHeader>
147
+ <div className="flex flex-col items-center justify-center py-12 space-y-4">
148
+ <XCircle className="h-12 w-12 text-destructive" />
149
+ <p className="text-sm text-muted-foreground">
150
+ {error ? `Error: ${error}` : 'Payment not found'}
151
+ </p>
152
+ <Button onClick={() => mutate()}>Try Again</Button>
153
+ </div>
154
+ </DialogContent>
155
+ </Dialog>
156
+ );
157
+ }
103
158
 
104
159
  const statusInfo = getStatusInfo();
105
160
  const StatusIcon = statusInfo.icon;
106
161
 
107
- // Generate QR code URL (using simple data URL)
162
+ // Generate QR code URL
108
163
  const qrCodeUrl = payment.pay_address
109
164
  ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}`
110
165
  : null;
@@ -121,7 +176,7 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
121
176
 
122
177
  <div className="space-y-6">
123
178
  {/* Status Badge */}
124
- <div className={`flex items-center gap-3 p-4 rounded-lg ${statusInfo.bg}`}>
179
+ <div className={`flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`}>
125
180
  <StatusIcon className={`h-5 w-5 ${statusInfo.color}`} />
126
181
  <div className="flex-1">
127
182
  <div className="font-semibold capitalize">{payment.status}</div>
@@ -135,32 +190,41 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
135
190
 
136
191
  {/* Amount Information */}
137
192
  <div className="space-y-3">
138
- <div className="flex items-center justify-between p-4 bg-muted rounded-lg">
193
+ <div className="flex items-center justify-between p-4 bg-muted rounded-sm">
139
194
  <span className="text-sm text-muted-foreground">Amount to send</span>
140
195
  <div className="flex items-center gap-2">
141
- <TokenIcon symbol={payment.currency || 'BTC'} size={20} />
196
+ <TokenIcon symbol={String(payment.currency_code || 'BTC')} size={20} />
142
197
  <span className="font-mono font-bold text-lg">
143
- {payment.amount_crypto?.toFixed(8)} {payment.currency}
198
+ {payment.pay_amount || '0.00000000'} {payment.currency_code}
144
199
  </span>
145
200
  </div>
146
201
  </div>
147
202
 
148
203
  <div className="flex items-center justify-between px-4">
149
204
  <span className="text-sm text-muted-foreground">Equivalent to</span>
150
- <span className="font-semibold text-lg">${payment.amount_usd?.toFixed(2)} USD</span>
205
+ <span className="font-semibold text-lg">
206
+ ${parseFloat(payment.amount_usd || '0').toFixed(2)} USD
207
+ </span>
151
208
  </div>
152
209
 
153
- {payment.network && (
210
+ {payment.internal_payment_id && (
211
+ <div className="flex items-center justify-between px-4">
212
+ <span className="text-sm text-muted-foreground">Payment Order #</span>
213
+ <span className="font-mono font-medium">{payment.internal_payment_id}</span>
214
+ </div>
215
+ )}
216
+
217
+ {payment.currency_network && (
154
218
  <div className="flex items-center justify-between px-4">
155
219
  <span className="text-sm text-muted-foreground">Network</span>
156
- <span className="font-medium">{payment.network}</span>
220
+ <span className="font-medium">{payment.currency_network}</span>
157
221
  </div>
158
222
  )}
159
223
  </div>
160
224
 
161
225
  {/* QR Code */}
162
226
  {qrCodeUrl && payment.status === 'pending' && (
163
- <div className="flex justify-center p-6 bg-white rounded-lg">
227
+ <div className="flex justify-center p-6 bg-white rounded-sm">
164
228
  <img src={qrCodeUrl} alt="Payment QR Code" className="w-48 h-48" />
165
229
  </div>
166
230
  )}
@@ -170,7 +234,7 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
170
234
  <div className="space-y-2">
171
235
  <label className="text-sm font-medium">Payment Address</label>
172
236
  <div className="flex items-center gap-2">
173
- <div className="flex-1 p-3 bg-muted rounded-lg font-mono text-sm break-all">
237
+ <div className="flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all">
174
238
  {payment.pay_address}
175
239
  </div>
176
240
  <Button
@@ -193,7 +257,7 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
193
257
  {payment.transaction_hash && (
194
258
  <div className="space-y-2">
195
259
  <label className="text-sm font-medium">Transaction Hash</label>
196
- <div className="p-3 bg-muted rounded-lg font-mono text-sm break-all">
260
+ <div className="p-3 bg-muted rounded-sm font-mono text-sm break-all">
197
261
  {payment.transaction_hash}
198
262
  </div>
199
263
  </div>
@@ -234,21 +298,12 @@ export const PaymentDetailsDialog: React.FC<PaymentDetailsDialogProps> = ({ paym
234
298
  <Button variant="outline" onClick={handleClose}>
235
299
  Close
236
300
  </Button>
301
+ <Button onClick={() => mutate()} variant="ghost" size="sm">
302
+ <RefreshCw className="h-4 w-4 mr-2" />
303
+ Refresh
304
+ </Button>
237
305
  </DialogFooter>
238
306
  </DialogContent>
239
307
  </Dialog>
240
308
  );
241
309
  };
242
-
243
- // Helper function to open payment details dialog
244
- export const openPaymentDetails = (payment: Payment) => {
245
- window.dispatchEvent(
246
- new CustomEvent(PAYMENT_DETAILS_EVENTS.OPEN_PAYMENT_DETAILS, {
247
- detail: { payment },
248
- })
249
- );
250
- };
251
-
252
- export const closePaymentDetails = () => {
253
- window.dispatchEvent(new Event(PAYMENT_DETAILS_EVENTS.CLOSE_PAYMENT_DETAILS));
254
- };
@@ -1,5 +1,2 @@
1
- export { CreateApiKeyDialog } from './CreateApiKeyDialog';
2
- export { DeleteApiKeyDialog } from './DeleteApiKeyDialog';
3
1
  export { CreatePaymentDialog } from './CreatePaymentDialog';
4
- export { PaymentDetailsDialog, openPaymentDetails, closePaymentDetails } from './PaymentDetailsDialog';
5
-
2
+ export { PaymentDetailsDialog } from './PaymentDetailsDialog';
@@ -1,106 +1,45 @@
1
1
  /**
2
- * Payments Layout Events
3
- * Event-based communication for dialogs and actions
2
+ * Payment Events System (v2.0 - Simplified)
3
+ *
4
+ * Event-based communication for dialogs using DOM events
5
+ * Removed: API Keys events (deprecated)
4
6
  */
5
7
 
6
- import { events } from '@djangocfg/ui';
7
- import type { APIKeyDetail, Payment } from './types';
8
-
9
8
  // ─────────────────────────────────────────────────────────────────────────
10
- // Dialog Events
9
+ // Event Names
11
10
  // ─────────────────────────────────────────────────────────────────────────
12
11
 
13
- export const PAYMENTS_DIALOG_EVENTS = {
14
- // API Keys
15
- OPEN_CREATE_APIKEY_DIALOG: 'OPEN_CREATE_APIKEY_DIALOG',
16
- OPEN_EDIT_APIKEY_DIALOG: 'OPEN_EDIT_APIKEY_DIALOG',
17
- OPEN_DELETE_APIKEY_DIALOG: 'OPEN_DELETE_APIKEY_DIALOG',
18
-
19
- // Payments
20
- OPEN_CREATE_PAYMENT_DIALOG: 'OPEN_CREATE_PAYMENT_DIALOG',
21
- OPEN_PAYMENT_DETAILS_DIALOG: 'OPEN_PAYMENT_DETAILS_DIALOG',
22
- OPEN_CANCEL_PAYMENT_DIALOG: 'OPEN_CANCEL_PAYMENT_DIALOG',
23
-
24
- // Close
25
- CLOSE_PAYMENTS_DIALOG: 'CLOSE_PAYMENTS_DIALOG',
12
+ export const PAYMENT_EVENTS = {
13
+ OPEN_CREATE_PAYMENT_DIALOG: 'payments:open-create-payment',
14
+ OPEN_PAYMENT_DETAILS_DIALOG: 'payments:open-payment-details',
15
+ CLOSE_DIALOG: 'payments:close-dialog',
26
16
  } as const;
27
17
 
28
18
  // ─────────────────────────────────────────────────────────────────────────
29
19
  // Event Types
30
20
  // ─────────────────────────────────────────────────────────────────────────
31
21
 
32
- export interface PaymentsDialogEvent {
33
- type: typeof PAYMENTS_DIALOG_EVENTS[keyof typeof PAYMENTS_DIALOG_EVENTS];
34
- payload?: {
35
- // API Keys
36
- keyId?: string;
37
- keyData?: APIKeyDetail;
38
- initialKeyData?: Partial<APIKeyDetail>;
39
-
40
- // Payments
41
- paymentId?: string;
42
- paymentData?: Payment;
43
- initialPaymentData?: Partial<Payment>;
44
- };
45
- }
46
-
47
- // ─────────────────────────────────────────────────────────────────────────
48
- // API Keys Events
49
- // ─────────────────────────────────────────────────────────────────────────
50
-
51
- export const openCreateApiKeyDialog = (initialData?: Partial<APIKeyDetail>) => {
52
- events.publish({
53
- type: PAYMENTS_DIALOG_EVENTS.OPEN_CREATE_APIKEY_DIALOG,
54
- payload: { initialKeyData: initialData },
55
- });
56
- };
57
-
58
- export const openEditApiKeyDialog = (keyId: string, keyData?: APIKeyDetail) => {
59
- events.publish({
60
- type: PAYMENTS_DIALOG_EVENTS.OPEN_EDIT_APIKEY_DIALOG,
61
- payload: { keyId, keyData },
62
- });
63
- };
64
-
65
- export const openDeleteApiKeyDialog = (keyId: string, keyData?: APIKeyDetail) => {
66
- events.publish({
67
- type: PAYMENTS_DIALOG_EVENTS.OPEN_DELETE_APIKEY_DIALOG,
68
- payload: { keyId, keyData },
69
- });
70
- };
22
+ export type PaymentEvent =
23
+ | { type: 'OPEN_CREATE_PAYMENT' }
24
+ | { type: 'OPEN_PAYMENT_DETAILS'; id: string }
25
+ | { type: 'CLOSE_DIALOG' };
71
26
 
72
27
  // ─────────────────────────────────────────────────────────────────────────
73
- // Payments Events
28
+ // Helper Functions
74
29
  // ─────────────────────────────────────────────────────────────────────────
75
30
 
76
- export const openCreatePaymentDialog = (initialData?: Partial<Payment>) => {
77
- events.publish({
78
- type: PAYMENTS_DIALOG_EVENTS.OPEN_CREATE_PAYMENT_DIALOG,
79
- payload: { initialPaymentData: initialData },
80
- });
81
- };
82
-
83
- export const openPaymentDetailsDialog = (paymentId: string, paymentData?: Payment) => {
84
- events.publish({
85
- type: PAYMENTS_DIALOG_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG,
86
- payload: { paymentId, paymentData },
87
- });
31
+ export const openCreatePaymentDialog = () => {
32
+ window.dispatchEvent(new Event(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG));
88
33
  };
89
34
 
90
- export const openCancelPaymentDialog = (paymentId: string, paymentData?: Payment) => {
91
- events.publish({
92
- type: PAYMENTS_DIALOG_EVENTS.OPEN_CANCEL_PAYMENT_DIALOG,
93
- payload: { paymentId, paymentData },
94
- });
35
+ export const openPaymentDetailsDialog = (id: string) => {
36
+ window.dispatchEvent(
37
+ new CustomEvent(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, {
38
+ detail: { id },
39
+ })
40
+ );
95
41
  };
96
42
 
97
- // ─────────────────────────────────────────────────────────────────────────
98
- // Close Events
99
- // ─────────────────────────────────────────────────────────────────────────
100
-
101
43
  export const closePaymentsDialog = () => {
102
- events.publish({
103
- type: PAYMENTS_DIALOG_EVENTS.CLOSE_PAYMENTS_DIALOG,
104
- });
44
+ window.dispatchEvent(new Event(PAYMENT_EVENTS.CLOSE_DIALOG));
105
45
  };
106
-
@@ -1,20 +1,16 @@
1
1
  /**
2
- * Payments Layout
3
- * Export main layout and types
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
4
8
  */
5
9
 
6
10
  export { PaymentsLayout } from './PaymentsLayout';
7
- export type { PaymentsLayoutProps } from './PaymentsLayout';
8
11
  export type { PaymentTab } from './types';
9
-
10
- // Re-export events for convenience
11
12
  export {
12
- openCreateApiKeyDialog,
13
- openEditApiKeyDialog,
14
- openDeleteApiKeyDialog,
15
13
  openCreatePaymentDialog,
16
14
  openPaymentDetailsDialog,
17
- openCancelPaymentDialog,
18
- closePaymentsDialog,
15
+ closePaymentsDialog
19
16
  } from './events';
20
-
@@ -1,19 +1,6 @@
1
1
  /**
2
- * Payments Layout Types
2
+ * Payments Layout Types (v2.0 - Simplified)
3
3
  */
4
4
 
5
- // Tab types for navigation
6
- export type PaymentTab = 'overview' | 'payments' | 'transactions' | 'apikeys' | 'tariffs';
7
-
8
- // Re-export API types for convenience
9
- export type {
10
- Payment,
11
- UserBalance,
12
- Currency,
13
- APIKeyDetail,
14
- PaginatedPaymentListList,
15
- PaginatedUserBalanceList,
16
- PaginatedCurrencyListList,
17
- PaginatedAPIKeyListList,
18
- } from '@djangocfg/api/cfg/contexts';
19
-
5
+ // Tab types for navigation (removed apikeys and tariffs)
6
+ export type PaymentTab = 'overview' | 'payments' | 'transactions';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Balance Card Component
2
+ * Balance Card Component (v2.0 - Simplified)
3
3
  * Display user balance with quick actions
4
4
  */
5
5
 
@@ -21,9 +21,9 @@ import { openCreatePaymentDialog } from '../../../events';
21
21
 
22
22
  export const BalanceCard: React.FC = () => {
23
23
  const {
24
- balanceSummary,
25
- isLoadingSummary,
26
- refreshSummary
24
+ balance,
25
+ isLoadingBalance,
26
+ refreshBalance
27
27
  } = useOverviewContext();
28
28
 
29
29
  const formatCurrency = (amount?: number | null) => {
@@ -35,7 +35,20 @@ export const BalanceCard: React.FC = () => {
35
35
  }).format(amount);
36
36
  };
37
37
 
38
- if (isLoadingSummary) {
38
+ const formatDate = (dateStr?: string) => {
39
+ if (!dateStr) return 'No transactions yet';
40
+ try {
41
+ return new Date(dateStr).toLocaleDateString('en-US', {
42
+ year: 'numeric',
43
+ month: 'short',
44
+ day: 'numeric',
45
+ });
46
+ } catch {
47
+ return 'Invalid date';
48
+ }
49
+ };
50
+
51
+ if (isLoadingBalance) {
39
52
  return (
40
53
  <Card>
41
54
  <CardHeader>
@@ -55,6 +68,14 @@ export const BalanceCard: React.FC = () => {
55
68
  );
56
69
  }
57
70
 
71
+ // Extract balance data from response: { success, balance: { amount_usd, total_deposited, total_withdrawn, last_transaction_at } }
72
+ const balanceData = balance?.balance || balance;
73
+ const amountUsd = balanceData?.amount_usd ?? 0;
74
+ const totalDeposited = balanceData?.total_deposited ?? 0;
75
+ const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
76
+ const lastTransactionAt = balanceData?.last_transaction_at;
77
+ const isEmpty = amountUsd === 0 && totalDeposited === 0;
78
+
58
79
  return (
59
80
  <Card>
60
81
  <CardHeader>
@@ -64,7 +85,7 @@ export const BalanceCard: React.FC = () => {
64
85
  Account Balance
65
86
  </div>
66
87
  <div className="flex items-center gap-2">
67
- <Button variant="ghost" size="sm" onClick={refreshSummary}>
88
+ <Button variant="ghost" size="sm" onClick={refreshBalance}>
68
89
  <RefreshCw className="h-4 w-4" />
69
90
  </Button>
70
91
  <Button size="sm" onClick={() => openCreatePaymentDialog()}>
@@ -77,23 +98,31 @@ export const BalanceCard: React.FC = () => {
77
98
  <CardContent className="space-y-4">
78
99
  <div>
79
100
  <div className="text-4xl font-bold">
80
- {balanceSummary ? formatCurrency(balanceSummary.balance_usd) : '$0.00'}
101
+ {formatCurrency(amountUsd)}
81
102
  </div>
82
103
  <p className="text-sm text-muted-foreground mt-1">
83
- {balanceSummary?.balance_display || 'No balance available'}
104
+ Available balance Last updated {formatDate(lastTransactionAt)}
84
105
  </p>
85
106
  </div>
86
107
 
87
- {balanceSummary && (
88
- <div className="flex items-center gap-2">
89
- <Badge variant={balanceSummary.has_transactions ? 'default' : 'secondary'}>
90
- {balanceSummary.has_transactions ? 'Active' : 'New Account'}
91
- </Badge>
92
- {balanceSummary.is_empty && <Badge variant="outline">Empty Balance</Badge>}
108
+ <div className="grid grid-cols-2 gap-4 pt-4 border-t">
109
+ <div>
110
+ <p className="text-xs text-muted-foreground">Total Deposited</p>
111
+ <p className="text-lg font-semibold text-green-600">{formatCurrency(totalDeposited)}</p>
112
+ </div>
113
+ <div>
114
+ <p className="text-xs text-muted-foreground">Total Withdrawn</p>
115
+ <p className="text-lg font-semibold text-red-600">{formatCurrency(totalWithdrawn)}</p>
93
116
  </div>
94
- )}
117
+ </div>
118
+
119
+ <div className="flex items-center gap-2">
120
+ <Badge variant={!isEmpty ? 'default' : 'secondary'}>
121
+ {!isEmpty ? 'Active' : 'New Account'}
122
+ </Badge>
123
+ {isEmpty && <Badge variant="outline">Empty Balance</Badge>}
124
+ </div>
95
125
  </CardContent>
96
126
  </Card>
97
127
  );
98
128
  };
99
-
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Recent Payments Component
3
- * Display recent payment transactions
2
+ * Recent Payments Component (v2.0 - Simplified)
3
+ * Display recent payment transactions from payments list
4
4
  */
5
5
 
6
6
  'use client';
@@ -20,15 +20,16 @@ import { useOverviewContext } from '@djangocfg/api/cfg/contexts';
20
20
  import { openPaymentDetailsDialog } from '../../../events';
21
21
 
22
22
  export const RecentPayments: React.FC = () => {
23
- const { recentPayments, isLoadingOverview } = useOverviewContext();
23
+ const { payments, isLoadingPayments } = useOverviewContext();
24
24
 
25
- const formatCurrency = (amount?: number | null) => {
25
+ const formatCurrency = (amount?: number | string | null) => {
26
26
  if (amount === null || amount === undefined) return '$0.00';
27
+ const numAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
27
28
  return new Intl.NumberFormat('en-US', {
28
29
  style: 'currency',
29
30
  currency: 'USD',
30
31
  minimumFractionDigits: 2,
31
- }).format(amount);
32
+ }).format(numAmount);
32
33
  };
33
34
 
34
35
  const getRelativeTime = (date: string | null | undefined): string => {
@@ -52,16 +53,18 @@ export const RecentPayments: React.FC = () => {
52
53
  case 'success':
53
54
  return 'default';
54
55
  case 'pending':
56
+ case 'confirming':
55
57
  return 'secondary';
56
58
  case 'failed':
57
59
  case 'error':
60
+ case 'expired':
58
61
  return 'destructive';
59
62
  default:
60
63
  return 'outline';
61
64
  }
62
65
  };
63
66
 
64
- if (isLoadingOverview) {
67
+ if (isLoadingPayments) {
65
68
  return (
66
69
  <Card>
67
70
  <CardHeader>
@@ -72,7 +75,7 @@ export const RecentPayments: React.FC = () => {
72
75
  </CardHeader>
73
76
  <CardContent className="space-y-3">
74
77
  {Array.from({ length: 5 }).map((_, i) => (
75
- <div key={i} className="flex items-center justify-between p-3 border rounded-lg">
78
+ <div key={i} className="flex items-center justify-between p-3 border rounded-sm">
76
79
  <div className="space-y-2">
77
80
  <Skeleton className="h-4 w-32" />
78
81
  <Skeleton className="h-3 w-24" />
@@ -85,7 +88,8 @@ export const RecentPayments: React.FC = () => {
85
88
  );
86
89
  }
87
90
 
88
- const payments = recentPayments?.results || [];
91
+ // Get first 5 payments for recent list
92
+ const recentPaymentsList = payments?.results?.slice(0, 5) || [];
89
93
 
90
94
  return (
91
95
  <Card>
@@ -102,18 +106,19 @@ export const RecentPayments: React.FC = () => {
102
106
  </CardTitle>
103
107
  </CardHeader>
104
108
  <CardContent>
105
- {payments.length === 0 ? (
109
+ {recentPaymentsList.length === 0 ? (
106
110
  <div className="text-center py-8 text-muted-foreground">
107
111
  <History className="h-12 w-12 mx-auto mb-4 opacity-50" />
108
112
  <p>No recent payments</p>
113
+ <p className="text-sm mt-2">Create your first payment to get started</p>
109
114
  </div>
110
115
  ) : (
111
116
  <div className="space-y-3">
112
- {payments.map((payment) => (
117
+ {recentPaymentsList.map((payment) => (
113
118
  <div
114
119
  key={payment.id}
115
- className="flex items-center justify-between p-3 border rounded-lg hover:bg-accent cursor-pointer transition-colors"
116
- onClick={() => openPaymentDetailsDialog(payment.id)}
120
+ className="flex items-center justify-between p-3 border rounded-sm hover:bg-accent cursor-pointer transition-colors"
121
+ onClick={() => openPaymentDetailsDialog(String(payment.id))}
117
122
  >
118
123
  <div className="flex-1">
119
124
  <div className="flex items-center gap-2">
@@ -123,7 +128,7 @@ export const RecentPayments: React.FC = () => {
123
128
  </Badge>
124
129
  </div>
125
130
  <p className="text-sm text-muted-foreground">
126
- {getRelativeTime(payment.created_at)} • {payment.provider || 'Unknown provider'}
131
+ {getRelativeTime(payment.created_at)} • {payment.currency_code || 'USD'}
127
132
  </p>
128
133
  </div>
129
134
  <ExternalLink className="h-4 w-4 text-muted-foreground" />
@@ -135,4 +140,3 @@ export const RecentPayments: React.FC = () => {
135
140
  </Card>
136
141
  );
137
142
  };
138
-
@@ -1,4 +1,2 @@
1
- export { MetricsCards } from './MetricsCards';
2
1
  export { BalanceCard } from './BalanceCard';
3
2
  export { RecentPayments } from './RecentPayments';
4
-