create-bluecopa-react-app 1.0.11 → 1.0.12

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 (28) hide show
  1. package/bin/create-bluecopa-react-app.js +1 -1
  2. package/package.json +1 -1
  3. package/templates/latest/.dockerignore +5 -1
  4. package/templates/latest/Agent.md +577 -0
  5. package/templates/latest/Dockerfile +2 -2
  6. package/templates/latest/app/app.tsx +3 -1
  7. package/templates/latest/app/components/app-sidebar.tsx +14 -16
  8. package/templates/latest/app/components/nav-main.tsx +6 -22
  9. package/templates/latest/app/data/mock-payments.json +122 -0
  10. package/templates/latest/app/data/mock-transactions.json +128 -0
  11. package/templates/latest/app/routes/comments.tsx +552 -0
  12. package/templates/latest/app/routes/home.tsx +1 -1
  13. package/templates/latest/app/routes/payments.tsx +342 -0
  14. package/templates/latest/app/routes/websocket.tsx +449 -0
  15. package/templates/latest/app/routes.tsx +6 -0
  16. package/templates/latest/dist/assets/{__federation_expose_App-C8_sl1dD.js → __federation_expose_App-B2IoFaIA.js} +15 -4
  17. package/templates/latest/dist/assets/client-LFBsfOjG.js +2775 -0
  18. package/templates/latest/dist/assets/{home-DhyEFlEc.js → home-BBY02MnI.js} +87 -59
  19. package/templates/latest/dist/assets/{index-DkyIpbj3.js → index-CNNS7Foy.js} +4 -3
  20. package/templates/latest/dist/assets/{client-Hh38T4k9.js → index-D5og7-RT-BA7DwZw1.js} +46 -2789
  21. package/templates/latest/dist/assets/remoteEntry.css +4 -4
  22. package/templates/latest/dist/assets/remoteEntry.js +1 -1
  23. package/templates/latest/dist/index.html +3 -2
  24. package/templates/latest/package-lock.json +11 -11
  25. package/templates/latest/package.json +1 -1
  26. package/templates/latest/public/favicon.ico +0 -0
  27. package/templates/latest/public/avatars/shadcn.svg +0 -6
  28. /package/templates/latest/app/{dashboard → data}/data.json +0 -0
@@ -0,0 +1,342 @@
1
+ import { useDataset } from "@bluecopa/react";
2
+ import { AppSidebar } from "~/components/app-sidebar";
3
+ import { SiteHeader } from "~/components/site-header";
4
+ import { SidebarInset, SidebarProvider } from "~/components/ui/sidebar";
5
+ import { Badge } from "~/components/ui/badge";
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
7
+ import {
8
+ Table,
9
+ TableBody,
10
+ TableCell,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ } from "~/components/ui/table";
15
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
16
+ import { Skeleton } from "~/components/ui/skeleton";
17
+ import mockTransactions from "~/data/mock-transactions.json";
18
+ import mockPayments from "~/data/mock-payments.json";
19
+
20
+ export default function PaymentsPage() {
21
+ // Fetch customers dataset (bank transactions)
22
+ const {
23
+ data: customersData,
24
+ isLoading: customersLoading,
25
+ error: customersError
26
+ } = useDataset("0Uz7OdcTzoofrHA9vPDb_mt940_a_tr_tr610012300123100101128200_pc000018202_2023050302584600720230502_225853_55320230502_225911_654_csv");
27
+
28
+ // Fetch invoices dataset (payments received)
29
+ const {
30
+ data: invoicesData,
31
+ isLoading: invoicesLoading,
32
+ error: invoicesError
33
+ } = useDataset("0Uz7OOjMvou8FWTdMYov_home_depot__us__20230501_112012951_parsed_csv");
34
+
35
+ // Use mock data as fallback if there's an error or no data
36
+ const transactions = customersError || !customersData?.data
37
+ ? mockTransactions
38
+ : customersData.data;
39
+
40
+ const invoices = invoicesError || !invoicesData?.data
41
+ ? mockPayments
42
+ : invoicesData.data;
43
+
44
+ // Calculate payment statistics from invoices
45
+ const totalInvoices = invoices.length;
46
+ const totalTransactions = transactions.length;
47
+
48
+ // Calculate totals from invoices (payments received)
49
+ const totalPaymentAmount = invoices.reduce((sum: number, inv: any) => sum + (Number(inv.paymentamount) || 0), 0);
50
+ const totalGrossAmount = invoices.reduce((sum: number, inv: any) => sum + (Number(inv.grossamount) || 0), 0);
51
+ const totalNetAmount = invoices.reduce((sum: number, inv: any) => sum + (Number(inv.netamountpaid) || 0), 0);
52
+ const totalDeductions = invoices.reduce((sum: number, inv: any) => sum + (Number(inv.deductionamount) || 0), 0);
53
+
54
+ // Calculate totals from transactions
55
+ const totalTransactionAmount = transactions.reduce((sum: number, txn: any) => sum + (Number(txn.amount) || 0), 0);
56
+ const creditTransactions = transactions.filter((txn: any) => txn.debit_credit_mark === "C").length;
57
+ const debitTransactions = transactions.filter((txn: any) => txn.debit_credit_mark === "D").length;
58
+
59
+ return (
60
+ <SidebarProvider
61
+ style={
62
+ {
63
+ "--sidebar-width": "calc(var(--spacing) * 72)",
64
+ "--header-height": "calc(var(--spacing) * 12)",
65
+ } as React.CSSProperties
66
+ }
67
+ >
68
+ <AppSidebar variant="inset" />
69
+ <SidebarInset>
70
+ <SiteHeader />
71
+ <div className="flex flex-1 flex-col">
72
+ <div className="@container/main flex flex-1 flex-col gap-2">
73
+ <div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
74
+ {/* Stats Cards */}
75
+ <div className="grid gap-4 px-4 md:grid-cols-2 lg:grid-cols-4 lg:px-6">
76
+ <Card>
77
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
78
+ <CardTitle className="text-sm font-medium">
79
+ Total Payments Received
80
+ </CardTitle>
81
+ </CardHeader>
82
+ <CardContent>
83
+ <div className="text-2xl font-bold">
84
+ ${totalPaymentAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
85
+ </div>
86
+ <p className="text-xs text-muted-foreground">
87
+ From {totalInvoices} payments
88
+ </p>
89
+ </CardContent>
90
+ </Card>
91
+ <Card>
92
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
93
+ <CardTitle className="text-sm font-medium">
94
+ Net Amount
95
+ </CardTitle>
96
+ </CardHeader>
97
+ <CardContent>
98
+ <div className="text-2xl font-bold">
99
+ ${totalNetAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
100
+ </div>
101
+ <p className="text-xs text-muted-foreground">
102
+ After deductions
103
+ </p>
104
+ </CardContent>
105
+ </Card>
106
+ <Card>
107
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
108
+ <CardTitle className="text-sm font-medium">
109
+ Total Deductions
110
+ </CardTitle>
111
+ </CardHeader>
112
+ <CardContent>
113
+ <div className="text-2xl font-bold text-orange-600">
114
+ ${totalDeductions.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
115
+ </div>
116
+ <p className="text-xs text-muted-foreground">
117
+ From {totalInvoices} payments
118
+ </p>
119
+ </CardContent>
120
+ </Card>
121
+ <Card>
122
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
123
+ <CardTitle className="text-sm font-medium">
124
+ Transactions
125
+ </CardTitle>
126
+ </CardHeader>
127
+ <CardContent>
128
+ <div className="text-2xl font-bold">
129
+ {totalTransactions}
130
+ </div>
131
+ <p className="text-xs text-muted-foreground">
132
+ {creditTransactions} credits / {debitTransactions} debits
133
+ </p>
134
+ </CardContent>
135
+ </Card>
136
+ </div>
137
+
138
+ {/* Tabs for Invoices and Transactions */}
139
+ <div className="px-4 lg:px-6">
140
+ <Tabs defaultValue="payments" className="w-full">
141
+ <TabsList>
142
+ <TabsTrigger value="payments">
143
+ Payments Received
144
+ {invoicesLoading && <Skeleton className="ml-2 h-4 w-8" />}
145
+ </TabsTrigger>
146
+ <TabsTrigger value="transactions">
147
+ Bank Transactions
148
+ {customersLoading && <Skeleton className="ml-2 h-4 w-8" />}
149
+ </TabsTrigger>
150
+ </TabsList>
151
+
152
+ {/* Payments Tab */}
153
+ <TabsContent value="payments" className="space-y-4">
154
+ <Card>
155
+ <CardHeader>
156
+ <CardTitle>Payments Received</CardTitle>
157
+ <CardDescription>
158
+ {invoicesError
159
+ ? "Using mock data (dataset unavailable)"
160
+ : "View all customer payments and deductions"}
161
+ </CardDescription>
162
+ </CardHeader>
163
+ <CardContent>
164
+ {invoicesLoading ? (
165
+ <div className="space-y-2">
166
+ {[...Array(5)].map((_, i) => (
167
+ <Skeleton key={i} className="h-12 w-full" />
168
+ ))}
169
+ </div>
170
+ ) : invoices.length === 0 ? (
171
+ <div className="text-center py-8 text-muted-foreground">
172
+ No payments found
173
+ </div>
174
+ ) : (
175
+ <div className="rounded-md border overflow-x-auto">
176
+ <Table>
177
+ <TableHeader>
178
+ <TableRow>
179
+ <TableHead>Payer Name</TableHead>
180
+ <TableHead>Payer ID</TableHead>
181
+ <TableHead>Payment Amount</TableHead>
182
+ <TableHead>Gross Amount</TableHead>
183
+ <TableHead>Net Paid</TableHead>
184
+ <TableHead>Deduction</TableHead>
185
+ <TableHead>Effective Date</TableHead>
186
+ <TableHead>ACH Trace #</TableHead>
187
+ <TableHead>PO Number</TableHead>
188
+ </TableRow>
189
+ </TableHeader>
190
+ <TableBody>
191
+ {invoices.map((payment: any, index: number) => (
192
+ <TableRow key={payment.achtracenumber || index}>
193
+ <TableCell className="font-medium">
194
+ {payment.payername || "N/A"}
195
+ </TableCell>
196
+ <TableCell>
197
+ {payment.payerid || "N/A"}
198
+ </TableCell>
199
+ <TableCell>
200
+ ${Number(payment.paymentamount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
201
+ </TableCell>
202
+ <TableCell>
203
+ ${Number(payment.grossamount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
204
+ </TableCell>
205
+ <TableCell>
206
+ ${Number(payment.netamountpaid || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
207
+ </TableCell>
208
+ <TableCell>
209
+ {payment.deductionamount > 0 ? (
210
+ <div className="flex flex-col">
211
+ <span className="text-orange-600 font-medium">
212
+ ${Number(payment.deductionamount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
213
+ </span>
214
+ {payment.deductionreasontext && (
215
+ <span className="text-xs text-muted-foreground">
216
+ {payment.deductionreasontext}
217
+ </span>
218
+ )}
219
+ </div>
220
+ ) : (
221
+ <span className="text-muted-foreground">-</span>
222
+ )}
223
+ </TableCell>
224
+ <TableCell>
225
+ {payment.paymenteffectivedate || "N/A"}
226
+ </TableCell>
227
+ <TableCell className="font-mono text-xs">
228
+ {payment.achtracenumber || "N/A"}
229
+ </TableCell>
230
+ <TableCell>
231
+ {payment.purchaseordernumber || "N/A"}
232
+ </TableCell>
233
+ </TableRow>
234
+ ))}
235
+ </TableBody>
236
+ </Table>
237
+ </div>
238
+ )}
239
+ </CardContent>
240
+ </Card>
241
+ </TabsContent>
242
+
243
+ {/* Transactions Tab */}
244
+ <TabsContent value="transactions" className="space-y-4">
245
+ <Card>
246
+ <CardHeader>
247
+ <CardTitle>Bank Transactions</CardTitle>
248
+ <CardDescription>
249
+ {customersError
250
+ ? "Using mock data (dataset unavailable)"
251
+ : "View all bank account transactions and statements"}
252
+ </CardDescription>
253
+ </CardHeader>
254
+ <CardContent>
255
+ {customersLoading ? (
256
+ <div className="space-y-2">
257
+ {[...Array(5)].map((_, i) => (
258
+ <Skeleton key={i} className="h-12 w-full" />
259
+ ))}
260
+ </div>
261
+ ) : transactions.length === 0 ? (
262
+ <div className="text-center py-8 text-muted-foreground">
263
+ No transactions found
264
+ </div>
265
+ ) : (
266
+ <div className="rounded-md border overflow-x-auto">
267
+ <Table>
268
+ <TableHeader>
269
+ <TableRow>
270
+ <TableHead>Transaction Ref</TableHead>
271
+ <TableHead>Value Date</TableHead>
272
+ <TableHead>Type</TableHead>
273
+ <TableHead>Description</TableHead>
274
+ <TableHead>Debit/Credit</TableHead>
275
+ <TableHead>Amount</TableHead>
276
+ <TableHead>Balance</TableHead>
277
+ <TableHead>Customer Ref</TableHead>
278
+ <TableHead>Bank Ref</TableHead>
279
+ </TableRow>
280
+ </TableHeader>
281
+ <TableBody>
282
+ {transactions.map((txn: any, index: number) => (
283
+ <TableRow key={txn.transaction_reference || index}>
284
+ <TableCell className="font-medium font-mono text-xs">
285
+ {txn.transaction_reference || "N/A"}
286
+ </TableCell>
287
+ <TableCell>
288
+ {txn.value_date || "N/A"}
289
+ </TableCell>
290
+ <TableCell>
291
+ <Badge variant="outline">
292
+ {txn.transaction_type || "N/A"}
293
+ </Badge>
294
+ </TableCell>
295
+ <TableCell className="max-w-xs truncate">
296
+ {txn.description || "N/A"}
297
+ </TableCell>
298
+ <TableCell>
299
+ <Badge
300
+ variant={
301
+ txn.debit_credit_mark === "C"
302
+ ? "default"
303
+ : txn.debit_credit_mark === "D"
304
+ ? "secondary"
305
+ : "outline"
306
+ }
307
+ >
308
+ {txn.debit_credit_mark === "C" ? "Credit" : txn.debit_credit_mark === "D" ? "Debit" : "N/A"}
309
+ </Badge>
310
+ </TableCell>
311
+ <TableCell className="font-medium">
312
+ {txn.debit_credit_mark === "D" && "-"}
313
+ ${Number(txn.amount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
314
+ </TableCell>
315
+ <TableCell>
316
+ ${Number(txn.closing_balance_amount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
317
+ </TableCell>
318
+ <TableCell className="font-mono text-xs">
319
+ {txn.customer_reference || "-"}
320
+ </TableCell>
321
+ <TableCell className="font-mono text-xs">
322
+ {txn.bank_reference || "-"}
323
+ </TableCell>
324
+ </TableRow>
325
+ ))}
326
+ </TableBody>
327
+ </Table>
328
+ </div>
329
+ )}
330
+ </CardContent>
331
+ </Card>
332
+ </TabsContent>
333
+ </Tabs>
334
+ </div>
335
+ </div>
336
+ </div>
337
+ </div>
338
+ </SidebarInset>
339
+ </SidebarProvider>
340
+ );
341
+ }
342
+