@djangocfg/ext-payments 1.0.0

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 (67) hide show
  1. package/README.md +206 -0
  2. package/dist/chunk-5KY6HVXF.js +2593 -0
  3. package/dist/hooks.cjs +2666 -0
  4. package/dist/hooks.d.cts +186 -0
  5. package/dist/hooks.d.ts +186 -0
  6. package/dist/hooks.js +1 -0
  7. package/dist/index.cjs +2590 -0
  8. package/dist/index.d.cts +1287 -0
  9. package/dist/index.d.ts +1287 -0
  10. package/dist/index.js +1 -0
  11. package/package.json +79 -0
  12. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +408 -0
  13. package/src/api/generated/ext_payments/_utils/fetchers/index.ts +28 -0
  14. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +147 -0
  15. package/src/api/generated/ext_payments/_utils/hooks/index.ts +28 -0
  16. package/src/api/generated/ext_payments/_utils/schemas/Balance.schema.ts +23 -0
  17. package/src/api/generated/ext_payments/_utils/schemas/Currency.schema.ts +28 -0
  18. package/src/api/generated/ext_payments/_utils/schemas/PaginatedPaymentListList.schema.ts +24 -0
  19. package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +44 -0
  20. package/src/api/generated/ext_payments/_utils/schemas/PaymentList.schema.ts +28 -0
  21. package/src/api/generated/ext_payments/_utils/schemas/Transaction.schema.ts +28 -0
  22. package/src/api/generated/ext_payments/_utils/schemas/index.ts +24 -0
  23. package/src/api/generated/ext_payments/api-instance.ts +131 -0
  24. package/src/api/generated/ext_payments/client.ts +301 -0
  25. package/src/api/generated/ext_payments/enums.ts +64 -0
  26. package/src/api/generated/ext_payments/errors.ts +116 -0
  27. package/src/api/generated/ext_payments/ext_payments__payments/client.ts +118 -0
  28. package/src/api/generated/ext_payments/ext_payments__payments/index.ts +2 -0
  29. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +135 -0
  30. package/src/api/generated/ext_payments/http.ts +103 -0
  31. package/src/api/generated/ext_payments/index.ts +273 -0
  32. package/src/api/generated/ext_payments/logger.ts +259 -0
  33. package/src/api/generated/ext_payments/retry.ts +175 -0
  34. package/src/api/generated/ext_payments/schema.json +850 -0
  35. package/src/api/generated/ext_payments/storage.ts +161 -0
  36. package/src/api/generated/ext_payments/validation-events.ts +133 -0
  37. package/src/api/index.ts +9 -0
  38. package/src/config.ts +20 -0
  39. package/src/contexts/BalancesContext.tsx +62 -0
  40. package/src/contexts/CurrenciesContext.tsx +63 -0
  41. package/src/contexts/OverviewContext.tsx +173 -0
  42. package/src/contexts/PaymentsContext.tsx +121 -0
  43. package/src/contexts/PaymentsExtensionProvider.tsx +55 -0
  44. package/src/contexts/README.md +201 -0
  45. package/src/contexts/RootPaymentsContext.tsx +65 -0
  46. package/src/contexts/index.ts +45 -0
  47. package/src/contexts/types.ts +40 -0
  48. package/src/hooks/index.ts +20 -0
  49. package/src/index.ts +36 -0
  50. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +92 -0
  51. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +291 -0
  52. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +290 -0
  53. package/src/layouts/PaymentsLayout/components/index.ts +2 -0
  54. package/src/layouts/PaymentsLayout/events.ts +47 -0
  55. package/src/layouts/PaymentsLayout/index.ts +16 -0
  56. package/src/layouts/PaymentsLayout/types.ts +6 -0
  57. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +128 -0
  58. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +142 -0
  59. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +2 -0
  60. package/src/layouts/PaymentsLayout/views/overview/index.tsx +20 -0
  61. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +277 -0
  62. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +1 -0
  63. package/src/layouts/PaymentsLayout/views/payments/index.tsx +17 -0
  64. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +273 -0
  65. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +1 -0
  66. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +17 -0
  67. package/src/utils/logger.ts +9 -0
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Transactions List Component (v2.0 - Simplified)
3
+ * Display transaction history with balance changes
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React, { useState } from 'react';
9
+ import {
10
+ Card,
11
+ CardContent,
12
+ CardHeader,
13
+ CardTitle,
14
+ Table,
15
+ TableBody,
16
+ TableCell,
17
+ TableHead,
18
+ TableHeader,
19
+ TableRow,
20
+ Button,
21
+ Badge,
22
+ Input,
23
+ Select,
24
+ SelectContent,
25
+ SelectItem,
26
+ SelectTrigger,
27
+ SelectValue,
28
+ Skeleton,
29
+ } from '@djangocfg/ui-nextjs';
30
+ import { History, Search, Filter, RefreshCw, ArrowUpRight, ArrowDownLeft } from 'lucide-react';
31
+ import { useOverviewContext } from '../../../../../contexts';
32
+
33
+ export const TransactionsList: React.FC = () => {
34
+ const {
35
+ transactions,
36
+ isLoadingTransactions,
37
+ refreshTransactions,
38
+ } = useOverviewContext();
39
+
40
+ const [searchTerm, setSearchTerm] = useState('');
41
+ const [typeFilter, setTypeFilter] = useState<string>('all');
42
+
43
+ // Extract transactions array from response (handle different possible structures)
44
+ const transactionsList = transactions?.results || transactions?.transactions || [];
45
+
46
+ const formatCurrency = (amount?: number | null) => {
47
+ if (amount === null || amount === undefined) return '$0.00';
48
+ return new Intl.NumberFormat('en-US', {
49
+ style: 'currency',
50
+ currency: 'USD',
51
+ minimumFractionDigits: 2,
52
+ }).format(amount);
53
+ };
54
+
55
+ const formatDate = (date: string | null | undefined): string => {
56
+ if (!date) return 'N/A';
57
+ try {
58
+ return new Date(date).toLocaleString('en-US', {
59
+ year: 'numeric',
60
+ month: 'short',
61
+ day: 'numeric',
62
+ hour: '2-digit',
63
+ minute: '2-digit',
64
+ });
65
+ } catch {
66
+ return 'Invalid date';
67
+ }
68
+ };
69
+
70
+ const getRelativeTime = (date: string | null | undefined): string => {
71
+ if (!date) return 'N/A';
72
+
73
+ const now = new Date();
74
+ const target = new Date(date);
75
+ const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1000);
76
+
77
+ if (diffInSeconds < 60) return 'Just now';
78
+ if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
79
+ if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
80
+ return `${Math.floor(diffInSeconds / 86400)}d ago`;
81
+ };
82
+
83
+ const getTypeVariant = (
84
+ type: string | null | undefined
85
+ ): 'default' | 'destructive' | 'outline' | 'secondary' => {
86
+ switch (type?.toLowerCase()) {
87
+ case 'deposit':
88
+ case 'credit':
89
+ return 'default';
90
+ case 'withdrawal':
91
+ case 'debit':
92
+ return 'destructive';
93
+ default:
94
+ return 'outline';
95
+ }
96
+ };
97
+
98
+ const getTypeIcon = (type: string | null | undefined) => {
99
+ const isDeposit = type?.toLowerCase() === 'deposit' || type?.toLowerCase() === 'credit';
100
+ return isDeposit ? (
101
+ <ArrowDownLeft className="h-4 w-4 text-green-600" />
102
+ ) : (
103
+ <ArrowUpRight className="h-4 w-4 text-red-600" />
104
+ );
105
+ };
106
+
107
+ const handleSearch = async (value: string) => {
108
+ setSearchTerm(value);
109
+ await refreshTransactions();
110
+ };
111
+
112
+ const handleTypeFilter = async (type: string) => {
113
+ setTypeFilter(type);
114
+ await refreshTransactions();
115
+ };
116
+
117
+ // Filter transactions client-side
118
+ const filteredTransactions = transactionsList.filter((transaction: any) => {
119
+ const matchesSearch = searchTerm
120
+ ? transaction.id?.toString().toLowerCase().includes(searchTerm.toLowerCase()) ||
121
+ transaction.description?.toLowerCase().includes(searchTerm.toLowerCase()) ||
122
+ transaction.type?.toLowerCase().includes(searchTerm.toLowerCase())
123
+ : true;
124
+
125
+ const matchesType = typeFilter !== 'all'
126
+ ? transaction.type?.toLowerCase() === typeFilter.toLowerCase()
127
+ : true;
128
+
129
+ return matchesSearch && matchesType;
130
+ });
131
+
132
+ if (isLoadingTransactions) {
133
+ return (
134
+ <Card>
135
+ <CardHeader>
136
+ <CardTitle className="flex items-center gap-2">
137
+ <History className="h-5 w-5" />
138
+ Transaction History
139
+ </CardTitle>
140
+ </CardHeader>
141
+ <CardContent className="space-y-3">
142
+ {Array.from({ length: 5 }).map((_, i) => (
143
+ <div key={i} className="flex items-center justify-between p-4 border rounded-sm">
144
+ <div className="space-y-2">
145
+ <Skeleton className="h-4 w-32" />
146
+ <Skeleton className="h-3 w-24" />
147
+ </div>
148
+ <Skeleton className="h-6 w-16" />
149
+ </div>
150
+ ))}
151
+ </CardContent>
152
+ </Card>
153
+ );
154
+ }
155
+
156
+ return (
157
+ <Card>
158
+ <CardHeader>
159
+ <CardTitle className="flex items-center justify-between">
160
+ <div className="flex items-center gap-2">
161
+ <History className="h-5 w-5" />
162
+ Transaction History
163
+ </div>
164
+ <Button variant="outline" size="sm" onClick={refreshTransactions} disabled={isLoadingTransactions}>
165
+ <RefreshCw className={`h-4 w-4 mr-2 ${isLoadingTransactions ? 'animate-spin' : ''}`} />
166
+ Refresh
167
+ </Button>
168
+ </CardTitle>
169
+ </CardHeader>
170
+
171
+ <CardContent className="space-y-4">
172
+ {/* Filters */}
173
+ <div className="flex flex-col sm:flex-row gap-4">
174
+ <div className="relative flex-1">
175
+ <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
176
+ <Input
177
+ placeholder="Search by ID, description, or type..."
178
+ value={searchTerm}
179
+ onChange={(e) => handleSearch(e.target.value)}
180
+ className="pl-10"
181
+ />
182
+ </div>
183
+
184
+ <Select value={typeFilter} onValueChange={handleTypeFilter}>
185
+ <SelectTrigger className="w-full sm:w-48">
186
+ <Filter className="h-4 w-4 mr-2" />
187
+ <SelectValue placeholder="Filter by type" />
188
+ </SelectTrigger>
189
+ <SelectContent>
190
+ <SelectItem value="all">All Types</SelectItem>
191
+ <SelectItem value="deposit">Deposits</SelectItem>
192
+ <SelectItem value="withdrawal">Withdrawals</SelectItem>
193
+ </SelectContent>
194
+ </Select>
195
+ </div>
196
+
197
+ {/* Transactions Table */}
198
+ {filteredTransactions.length === 0 ? (
199
+ <div className="text-center py-12">
200
+ <div className="w-16 h-16 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center">
201
+ <History className="w-8 h-8 text-muted-foreground" />
202
+ </div>
203
+ <h3 className="text-lg font-semibold mb-2">No Transactions Found</h3>
204
+ <p className="text-muted-foreground">
205
+ {searchTerm || typeFilter !== 'all'
206
+ ? 'No transactions match your current filters'
207
+ : "You don't have any transactions yet"}
208
+ </p>
209
+ </div>
210
+ ) : (
211
+ <div className="rounded-md border">
212
+ <Table>
213
+ <TableHeader>
214
+ <TableRow>
215
+ <TableHead>Date & Time</TableHead>
216
+ <TableHead>Type</TableHead>
217
+ <TableHead>Amount</TableHead>
218
+ <TableHead>Balance After</TableHead>
219
+ <TableHead>Description</TableHead>
220
+ <TableHead>Reference</TableHead>
221
+ </TableRow>
222
+ </TableHeader>
223
+ <TableBody>
224
+ {filteredTransactions.map((transaction: any, index: number) => {
225
+ const isDeposit = transaction.type?.toLowerCase() === 'deposit' || transaction.type?.toLowerCase() === 'credit';
226
+ return (
227
+ <TableRow key={transaction.id || index}>
228
+ <TableCell>
229
+ <div>
230
+ <div className="font-medium">
231
+ {formatDate(transaction.created_at || transaction.timestamp)}
232
+ </div>
233
+ <div className="text-sm text-muted-foreground">
234
+ {getRelativeTime(transaction.created_at || transaction.timestamp)}
235
+ </div>
236
+ </div>
237
+ </TableCell>
238
+ <TableCell>
239
+ <div className="flex items-center gap-2">
240
+ {getTypeIcon(transaction.type)}
241
+ <Badge variant={getTypeVariant(transaction.type)}>
242
+ {transaction.type || 'Unknown'}
243
+ </Badge>
244
+ </div>
245
+ </TableCell>
246
+ <TableCell className="font-mono font-semibold">
247
+ <span className={isDeposit ? 'text-green-600' : 'text-red-600'}>
248
+ {isDeposit ? '+' : '-'}
249
+ {formatCurrency(Math.abs(transaction.amount || transaction.amount_usd || 0))}
250
+ </span>
251
+ </TableCell>
252
+ <TableCell className="font-mono">
253
+ {formatCurrency(transaction.balance_after || 0)}
254
+ </TableCell>
255
+ <TableCell className="text-sm">
256
+ {transaction.description || transaction.note || 'No description'}
257
+ </TableCell>
258
+ <TableCell className="font-mono text-sm text-muted-foreground">
259
+ {transaction.reference || transaction.payment_id
260
+ ? `${(transaction.reference || transaction.payment_id).toString().slice(0, 8)}...`
261
+ : 'N/A'}
262
+ </TableCell>
263
+ </TableRow>
264
+ );
265
+ })}
266
+ </TableBody>
267
+ </Table>
268
+ </div>
269
+ )}
270
+ </CardContent>
271
+ </Card>
272
+ );
273
+ };
@@ -0,0 +1 @@
1
+ export { TransactionsList } from './TransactionsList';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Transactions View (v2.0 - Simplified)
3
+ * View transaction history and balance changes
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React from 'react';
9
+ import { TransactionsList } from './components';
10
+
11
+ export const TransactionsView: React.FC = () => {
12
+ return (
13
+ <div className="space-y-6">
14
+ <TransactionsList />
15
+ </div>
16
+ );
17
+ };
@@ -0,0 +1,9 @@
1
+ import { createConsola } from 'consola';
2
+
3
+ const isDevelopment = process.env.NODE_ENV === 'development';
4
+
5
+ export const logger = createConsola({
6
+ level: isDevelopment ? 4 : 1,
7
+ }).withTag('ext-payments');
8
+
9
+ export const paymentsLogger = logger;