@agentpaid/paid-nextjs-client 0.3.0-test.2 → 0.3.1

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 (72) hide show
  1. package/README.md +184 -79
  2. package/dist/api/api/handleBlocks.ts +144 -0
  3. package/dist/api/handleBlocks.d.ts +9 -0
  4. package/dist/api/handleBlocks.d.ts.map +1 -0
  5. package/dist/api/handleBlocks.js +107 -0
  6. package/dist/api/handleBlocks.js.map +1 -0
  7. package/dist/components/PaidActivityLog.d.ts +13 -26
  8. package/dist/components/PaidActivityLog.d.ts.map +1 -1
  9. package/dist/components/PaidActivityLog.js +70 -26
  10. package/dist/components/PaidActivityLog.js.map +1 -1
  11. package/dist/components/PaidContainer.d.ts +11 -24
  12. package/dist/components/PaidContainer.d.ts.map +1 -1
  13. package/dist/components/PaidContainer.js +18 -9
  14. package/dist/components/PaidContainer.js.map +1 -1
  15. package/dist/components/PaidInvoiceTable.d.ts +12 -25
  16. package/dist/components/PaidInvoiceTable.d.ts.map +1 -1
  17. package/dist/components/PaidInvoiceTable.js +78 -30
  18. package/dist/components/PaidInvoiceTable.js.map +1 -1
  19. package/dist/components/PaidPaymentsTable.d.ts +12 -25
  20. package/dist/components/PaidPaymentsTable.d.ts.map +1 -1
  21. package/dist/components/PaidPaymentsTable.js +63 -29
  22. package/dist/components/PaidPaymentsTable.js.map +1 -1
  23. package/dist/components/components/PaidActivityLog.js +115 -58
  24. package/dist/components/components/PaidContainer.js +42 -32
  25. package/dist/components/components/PaidInvoiceTable.js +126 -89
  26. package/dist/components/components/PaidPaymentsTable.js +111 -72
  27. package/dist/components/components/ui/Pagination.js +168 -0
  28. package/dist/components/ui/Pagination.d.ts +10 -0
  29. package/dist/components/ui/Pagination.d.ts.map +1 -0
  30. package/dist/components/ui/Pagination.js +111 -0
  31. package/dist/components/ui/Pagination.js.map +1 -0
  32. package/dist/hooks/useCache.d.ts +2 -2
  33. package/dist/hooks/useCache.d.ts.map +1 -1
  34. package/dist/hooks/useCache.js +10 -17
  35. package/dist/hooks/useCache.js.map +1 -1
  36. package/dist/index.d.ts +4 -4
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +4 -4
  39. package/dist/index.js.map +1 -1
  40. package/dist/styles/paid-activity-log.css +154 -0
  41. package/dist/styles/paid-container.css +25 -16
  42. package/dist/styles/paid-invoice-table.css +135 -120
  43. package/dist/styles/paid-payments-table.css +65 -109
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/dist/utils/apiClient.d.ts +17 -0
  46. package/dist/utils/apiClient.d.ts.map +1 -0
  47. package/dist/utils/apiClient.js +60 -0
  48. package/dist/utils/apiClient.js.map +1 -0
  49. package/dist/utils/cache.js +1 -1
  50. package/dist/utils/cache.js.map +1 -1
  51. package/package.json +1 -1
  52. package/dist/api/api/handlePaidInvoicePdf.ts +0 -79
  53. package/dist/api/api/handlePaidInvoices.ts +0 -77
  54. package/dist/api/api/handlePaidPayments.ts +0 -77
  55. package/dist/api/api/handlePaidUsage.ts +0 -52
  56. package/dist/api/handlePaidInvoicePdf.d.ts +0 -6
  57. package/dist/api/handlePaidInvoicePdf.d.ts.map +0 -1
  58. package/dist/api/handlePaidInvoicePdf.js +0 -60
  59. package/dist/api/handlePaidInvoicePdf.js.map +0 -1
  60. package/dist/api/handlePaidInvoices.d.ts +0 -6
  61. package/dist/api/handlePaidInvoices.d.ts.map +0 -1
  62. package/dist/api/handlePaidInvoices.js +0 -56
  63. package/dist/api/handlePaidInvoices.js.map +0 -1
  64. package/dist/api/handlePaidPayments.d.ts +0 -6
  65. package/dist/api/handlePaidPayments.d.ts.map +0 -1
  66. package/dist/api/handlePaidPayments.js +0 -56
  67. package/dist/api/handlePaidPayments.js.map +0 -1
  68. package/dist/api/handlePaidUsage.d.ts +0 -6
  69. package/dist/api/handlePaidUsage.d.ts.map +0 -1
  70. package/dist/api/handlePaidUsage.js +0 -35
  71. package/dist/api/handlePaidUsage.js.map +0 -1
  72. package/dist/styles/activity-log-table.css +0 -138
@@ -2,34 +2,34 @@
2
2
 
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { useIsInContainer } from './PaidContainer';
5
- import { cachedFetch, getCacheKey, CACHE_TTL, dataCache } from '../utils/cache';
5
+ import { getCacheKey, CACHE_TTL, dataCache } from '../utils/cache';
6
+ import { Pagination } from './ui/Pagination';
7
+ import { fetchPaidData } from '../utils/apiClient';
6
8
  import '../styles/paid-invoice-table.css';
7
9
 
8
10
  interface PaidStyleProperties {
9
- paidTitleColor?: string;
10
- paidTitleFontWeight?: string;
11
- paidFontFamily?: string;
12
- paidWrapperBorder?: string;
13
- paidHeaderBorderBottom?: string;
14
- paidThBorderBottom?: string;
15
- paidTdBorderBottom?: string;
16
- paidTdBg?: string;
17
- paidTdFontWeight?: string;
18
- paidTitleFontSize?: string;
19
- paidToggleFontSize?: string;
20
- paidToggleFontWeight?: string;
21
- paidToggleColor?: string;
22
- paidThFontSize?: string;
23
- paidThFontWeight?: string;
24
- paidThColor?: string;
25
- paidTdFontSize?: string;
26
- paidTdColor?: string;
27
- paidEmptyColor?: string;
28
- paidWrapperBg?: string;
29
- paidHeaderBg?: string;
30
- paidTableBg?: string;
31
- paidThBg?: string;
32
- paidRowHoverBg?: string;
11
+ // Global - Font
12
+ fontFamily?: string;
13
+
14
+ // Global - Font Colors
15
+ primaryColor?: string;
16
+ secondaryColor?: string;
17
+
18
+ // Background Colors
19
+ containerBackgroundColor?: string;
20
+ tableBackgroundColor?: string;
21
+ tableHeaderBackgroundColor?: string;
22
+
23
+ // Tab Colors
24
+ tabBackgroundColor?: string;
25
+ tabActiveBackgroundColor?: string;
26
+ tabHoverBackgroundColor?: string;
27
+
28
+ // Table Hover
29
+ tableHoverColor?: string;
30
+
31
+ // Button Background (Status badges & Pagination)
32
+ buttonBgColor?: string;
33
33
  }
34
34
 
35
35
  interface Invoice {
@@ -37,7 +37,7 @@ interface Invoice {
37
37
  number: string;
38
38
  issueDate: string;
39
39
  dueDate: string;
40
- status: string;
40
+ paymentStatus: string;
41
41
  invoiceTotal: number;
42
42
  currency: string;
43
43
  customer?: {
@@ -52,12 +52,12 @@ interface InvoiceApiResponse {
52
52
  }
53
53
 
54
54
  interface PaidInvoiceTableProps {
55
- accountExternalId: string;
55
+ customerExternalId: string;
56
56
  paidStyle?: PaidStyleProperties;
57
57
  }
58
58
 
59
59
  export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
60
- accountExternalId,
60
+ customerExternalId,
61
61
  paidStyle = {}
62
62
  }) => {
63
63
  const [invoices, setInvoices] = useState<Invoice[]>([]);
@@ -66,30 +66,68 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
66
66
  const [isPreviewOpen, setIsPreviewOpen] = useState(false);
67
67
  const [pdfResponse, setPdfResponse] = useState<string | null>(null);
68
68
  const [selectedInvoice, setSelectedInvoice] = useState<Invoice | null>(null);
69
- const [loadingPdf, setLoadingPdf] = useState(false);
69
+ const [loadingInvoiceId, setLoadingInvoiceId] = useState<string | null>(null);
70
+ const [currentPage, setCurrentPage] = useState(1);
71
+ const itemsPerPage = 8;
70
72
  const isInContainer = useIsInContainer();
71
73
 
74
+ // Calculate pagination
75
+ const totalPages = Math.ceil(invoices.length / itemsPerPage);
76
+ const startIndex = (currentPage - 1) * itemsPerPage;
77
+ const endIndex = startIndex + itemsPerPage;
78
+ const currentInvoices = invoices.slice(startIndex, endIndex);
79
+
72
80
  // Convert paidStyle entries into CSS custom properties
73
81
  const cssVariables: React.CSSProperties = Object.entries(paidStyle).reduce((vars, [key, value]) => {
74
- let varName: string;
75
- if (key.startsWith('--')) {
76
- varName = key;
77
- } else {
78
- const raw = key.replace(/([A-Z])/g, '-$1').toLowerCase();
79
- varName = raw.startsWith('--') ? raw : `--${raw}`;
82
+ // Only set CSS variables if they are explicitly provided
83
+ // This allows inheritance from parent PaidContainer
84
+ if (value !== undefined && value !== null && value !== '') {
85
+ // Map simplified properties to CSS custom properties
86
+ const propertyMap: Record<string, string> = {
87
+ fontFamily: '--paid-font-family',
88
+ primaryColor: '--paid-primary-color',
89
+ secondaryColor: '--paid-secondary-color',
90
+ containerBackgroundColor: '--paid-container-background-color',
91
+ tableBackgroundColor: '--paid-table-background-color',
92
+ tableHeaderBackgroundColor: '--paid-table-header-background-color',
93
+ tabBackgroundColor: '--paid-tab-background-color',
94
+ tabActiveBackgroundColor: '--paid-tab-active-background-color',
95
+ tabHoverBackgroundColor: '--paid-tab-hover-background-color',
96
+ tableHoverColor: '--paid-table-hover-color',
97
+ buttonBgColor: '--paid-button-bg-color'
98
+ };
99
+
100
+ const cssProperty = propertyMap[key];
101
+ if (cssProperty) {
102
+ // @ts-ignore allow custom property
103
+ vars[cssProperty] = value;
104
+ }
80
105
  }
81
- // @ts-ignore allow custom property
82
- vars[varName] = value;
106
+
83
107
  return vars;
84
108
  }, {} as React.CSSProperties);
85
109
 
86
- const formatCurrency = (amount: number) => {
110
+ const formatCurrency = (amount: number, currency: string) => {
111
+ const symbol = getCurrencySymbol(currency);
87
112
  return new Intl.NumberFormat("en-US", {
88
113
  style: "currency",
89
114
  currency: "USD",
90
115
  minimumFractionDigits: 2,
91
116
  maximumFractionDigits: 2,
92
- }).format(amount / 100);
117
+ }).format(amount / 100).replace('$', symbol);
118
+ };
119
+
120
+ const getCurrencySymbol = (currency: string) => {
121
+ switch (currency.toUpperCase()) {
122
+ case 'USD':
123
+ return '$';
124
+ case 'EUR':
125
+ return '€';
126
+ case 'GBP':
127
+ return '£';
128
+ default:
129
+ return '$'; // Default to USD symbol
130
+ }
93
131
  };
94
132
 
95
133
  const formatDate = (dateString: string) => {
@@ -108,7 +146,7 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
108
146
 
109
147
  const handlePreview = async (invoice: Invoice) => {
110
148
  try {
111
- setLoadingPdf(true);
149
+ setLoadingInvoiceId(invoice.id);
112
150
  setSelectedInvoice(invoice);
113
151
 
114
152
  // Check cache first for PDF
@@ -118,12 +156,15 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
118
156
  if (cachedPdf) {
119
157
  setPdfResponse(cachedPdf);
120
158
  setIsPreviewOpen(true);
121
- setLoadingPdf(false);
159
+ setLoadingInvoiceId(null);
122
160
  return;
123
161
  }
124
162
 
125
- // Fetch PDF if not cached
126
- const response = await fetch(`/api/invoice-pdf/${invoice.id}`);
163
+ // Fetch PDF if not cached using new API client
164
+ const response = await fetchPaidData({
165
+ paidEndpoint: 'invoice-pdf',
166
+ invoiceId: invoice.id
167
+ });
127
168
 
128
169
  if (!response.ok) {
129
170
  throw new Error('Failed to fetch PDF');
@@ -141,7 +182,7 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
141
182
  console.error('Error fetching PDF:', error);
142
183
  alert('Failed to load PDF preview');
143
184
  } finally {
144
- setLoadingPdf(false);
185
+ setLoadingInvoiceId(null);
145
186
  }
146
187
  };
147
188
 
@@ -166,26 +207,26 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
166
207
  URL.revokeObjectURL(url);
167
208
  };
168
209
 
210
+ const handlePageChange = (page: number) => {
211
+ setCurrentPage(page);
212
+ };
213
+
169
214
  useEffect(() => {
170
215
  const fetchInvoiceData = async () => {
171
216
  try {
172
217
  setLoading(true);
173
218
 
174
- // TEMPORARILY DISABLED: Use cached fetch for invoice data
175
- // const cacheKey = getCacheKey.invoices(accountExternalId);
176
- // const data = await cachedFetch<InvoiceApiResponse>(
177
- // `/api/invoices/${accountExternalId}`,
178
- // cacheKey,
179
- // CACHE_TTL.DATA
180
- // );
219
+ // Use new API client for invoice data
220
+ const response = await fetchPaidData({
221
+ paidEndpoint: 'invoices',
222
+ customerExternalId
223
+ });
181
224
 
182
- // Direct fetch without caching
183
- const response = await fetch(`/api/invoices/${accountExternalId}`);
184
225
  if (!response.ok) {
185
- throw new Error(`Failed to fetch: ${response.statusText}`);
226
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
186
227
  }
187
- const data = await response.json();
188
228
 
229
+ const data = await response.json() as InvoiceApiResponse;
189
230
  setInvoices(data.data || []);
190
231
  } catch (err) {
191
232
  setError(err instanceof Error ? err.message : 'An error occurred');
@@ -195,7 +236,20 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
195
236
  };
196
237
 
197
238
  fetchInvoiceData();
198
- }, [accountExternalId]);
239
+
240
+ // Listen for cache refresh events
241
+ const handleCacheRefresh = (event: CustomEvent) => {
242
+ if (event.detail?.customerId === customerExternalId || event.detail?.type === 'all') {
243
+ fetchInvoiceData();
244
+ }
245
+ };
246
+
247
+ window.addEventListener('cache-refresh', handleCacheRefresh as EventListener);
248
+
249
+ return () => {
250
+ window.removeEventListener('cache-refresh', handleCacheRefresh as EventListener);
251
+ };
252
+ }, [customerExternalId]);
199
253
 
200
254
  if (loading) {
201
255
  return <div>Loading invoice data...</div>;
@@ -214,8 +268,8 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
214
268
  <h3 className="paid-invoice-title">Invoices</h3>
215
269
  </div>
216
270
  )}
217
- <div style={{ background: '#fff', overflow: 'auto' }}>
218
- <table className="paid-invoice-table">
271
+ <div style={{ background: '#fff', overflow: 'auto', width: '100%', boxSizing: 'border-box' }}>
272
+ <table className="paid-invoice-table" style={{ width: '100%', maxWidth: '100%', tableLayout: 'fixed' }}>
219
273
  <thead>
220
274
  <tr>
221
275
  <th>Invoice Number</th>
@@ -223,32 +277,32 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
223
277
  <th>Invoice Date</th>
224
278
  <th>Due Date</th>
225
279
  <th style={{ textAlign: 'right' }}>Total amount</th>
226
- <th style={{ textAlign: 'center' }}>Actions</th>
280
+ <th style={{ textAlign: 'center' }}>Preview</th>
227
281
  </tr>
228
282
  </thead>
229
283
  <tbody>
230
- {invoices.length === 0 ? (
284
+ {currentInvoices.length === 0 ? (
231
285
  <tr>
232
286
  <td colSpan={6} className="paid-invoice-empty">
233
287
  No invoices found
234
288
  </td>
235
289
  </tr>
236
290
  ) : (
237
- invoices.map((invoice) => (
291
+ currentInvoices.map((invoice) => (
238
292
  <tr key={invoice.id}>
239
293
  <td style={{ fontWeight: 500 }}>INV-{invoice.number}</td>
240
- <td>{getStatusBadge(invoice.status)}</td>
294
+ <td>{getStatusBadge(invoice.paymentStatus)}</td>
241
295
  <td>{formatDate(invoice.issueDate)}</td>
242
296
  <td>{formatDate(invoice.dueDate)}</td>
243
- <td style={{ textAlign: 'right', fontWeight: 500 }}>{formatCurrency(invoice.invoiceTotal)}</td>
297
+ <td style={{ textAlign: 'right', fontWeight: 500 }}>{formatCurrency(invoice.invoiceTotal, invoice.currency)}</td>
244
298
  <td style={{ textAlign: 'center' }}>
245
299
  <button
246
300
  className="paid-invoice-action-btn"
247
301
  onClick={() => handlePreview(invoice)}
248
- disabled={loadingPdf}
302
+ disabled={loadingInvoiceId === invoice.id}
249
303
  title="Preview Invoice"
250
304
  >
251
- {loadingPdf ? (
305
+ {loadingInvoiceId === invoice.id ? (
252
306
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
253
307
  <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="2" fill="none" strokeDasharray="37.7" strokeDashoffset="37.7">
254
308
  <animateTransform attributeName="transform" type="rotate" values="0 8 8;360 8 8" dur="1s" repeatCount="indefinite"/>
@@ -269,6 +323,13 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
269
323
  </tbody>
270
324
  </table>
271
325
  </div>
326
+
327
+ {/* Pagination */}
328
+ <Pagination
329
+ currentPage={currentPage}
330
+ totalPages={totalPages}
331
+ onPageChange={handlePageChange}
332
+ />
272
333
  </div>
273
334
  </div>
274
335
 
@@ -276,30 +337,6 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
276
337
  {isPreviewOpen && (
277
338
  <div className="paid-invoice-modal-overlay" onClick={() => setIsPreviewOpen(false)}>
278
339
  <div className="paid-invoice-modal-content" onClick={(e) => e.stopPropagation()}>
279
- <div className="paid-invoice-modal-header">
280
- <h3>Invoice Preview - INV-{selectedInvoice?.number}</h3>
281
- <div className="paid-invoice-modal-actions">
282
- <button
283
- className="paid-invoice-modal-btn paid-invoice-modal-btn-download"
284
- onClick={handleDownload}
285
- title="Download PDF"
286
- >
287
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
288
- <path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
289
- </svg>
290
- </button>
291
- <button
292
- className="paid-invoice-modal-btn paid-invoice-modal-btn-close"
293
- onClick={() => setIsPreviewOpen(false)}
294
- title="Close"
295
- >
296
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
297
- <line x1="18" y1="6" x2="6" y2="18"></line>
298
- <line x1="6" y1="6" x2="18" y2="18"></line>
299
- </svg>
300
- </button>
301
- </div>
302
- </div>
303
340
  <div className="paid-invoice-modal-body">
304
341
  {pdfResponse ? (
305
342
  <iframe
@@ -2,41 +2,41 @@
2
2
 
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { useIsInContainer } from './PaidContainer';
5
- import { cachedFetch, getCacheKey, CACHE_TTL } from '../utils/cache';
5
+ import { getCacheKey } from '../utils/cache';
6
+ import { Pagination } from './ui/Pagination';
6
7
  import '../styles/paid-payments-table.css';
8
+ import { fetchPaidData } from '../utils/apiClient';
7
9
 
8
10
  interface PaidStyleProperties {
9
- paidTitleColor?: string;
10
- paidTitleFontWeight?: string;
11
- paidFontFamily?: string;
12
- paidWrapperBorder?: string;
13
- paidHeaderBorderBottom?: string;
14
- paidThBorderBottom?: string;
15
- paidTdBorderBottom?: string;
16
- paidTdBg?: string;
17
- paidTdFontWeight?: string;
18
- paidTitleFontSize?: string;
19
- paidToggleFontSize?: string;
20
- paidToggleFontWeight?: string;
21
- paidToggleColor?: string;
22
- paidThFontSize?: string;
23
- paidThFontWeight?: string;
24
- paidThColor?: string;
25
- paidTdFontSize?: string;
26
- paidTdColor?: string;
27
- paidEmptyColor?: string;
28
- paidWrapperBg?: string;
29
- paidHeaderBg?: string;
30
- paidTableBg?: string;
31
- paidThBg?: string;
32
- paidRowHoverBg?: string;
11
+ // Global - Font
12
+ fontFamily?: string;
13
+
14
+ // Global - Font Colors
15
+ primaryColor?: string;
16
+ secondaryColor?: string;
17
+
18
+ // Background Colors
19
+ containerBackgroundColor?: string;
20
+ tableBackgroundColor?: string;
21
+ tableHeaderBackgroundColor?: string;
22
+
23
+ // Tab Colors
24
+ tabBackgroundColor?: string;
25
+ tabActiveBackgroundColor?: string;
26
+ tabHoverBackgroundColor?: string;
27
+
28
+ // Table Hover
29
+ tableHoverColor?: string;
30
+
31
+ // Button Background (Status badges & Pagination)
32
+ buttonBgColor?: string;
33
33
  }
34
34
 
35
35
  interface Payment {
36
36
  id: string;
37
37
  paymentType: string;
38
38
  paymentDate: string;
39
- status: string;
39
+ paymentStatus: string;
40
40
  amount: number;
41
41
  currency: string;
42
42
  }
@@ -46,40 +46,80 @@ interface PaymentApiResponse {
46
46
  }
47
47
 
48
48
  interface PaidPaymentsTableProps {
49
- accountExternalId: string;
49
+ customerExternalId: string;
50
50
  paidStyle?: PaidStyleProperties;
51
51
  }
52
52
 
53
53
  export const PaidPaymentsTable: React.FC<PaidPaymentsTableProps> = ({
54
- accountExternalId,
54
+ customerExternalId,
55
55
  paidStyle = {}
56
56
  }) => {
57
57
  const [payments, setPayments] = useState<Payment[]>([]);
58
58
  const [loading, setLoading] = useState(true);
59
59
  const [error, setError] = useState<string | null>(null);
60
+ const [currentPage, setCurrentPage] = useState(1);
61
+ const itemsPerPage = 8;
60
62
  const isInContainer = useIsInContainer();
61
63
 
64
+ // Calculate pagination
65
+ const totalPages = Math.ceil(payments.length / itemsPerPage);
66
+ const startIndex = (currentPage - 1) * itemsPerPage;
67
+ const endIndex = startIndex + itemsPerPage;
68
+ const currentPayments = payments.slice(startIndex, endIndex);
69
+
70
+ const handlePageChange = (page: number) => {
71
+ setCurrentPage(page);
72
+ };
73
+
62
74
  // Convert paidStyle entries into CSS custom properties
63
75
  const cssVariables: React.CSSProperties = Object.entries(paidStyle).reduce((vars, [key, value]) => {
64
- let varName: string;
65
- if (key.startsWith('--')) {
66
- varName = key;
67
- } else {
68
- const raw = key.replace(/([A-Z])/g, '-$1').toLowerCase();
69
- varName = raw.startsWith('--') ? raw : `--${raw}`;
76
+ if (value !== undefined && value !== null && value !== '') {
77
+ // Map simplified properties to CSS custom properties
78
+ const propertyMap: Record<string, string> = {
79
+ fontFamily: '--paid-font-family',
80
+ primaryColor: '--paid-primary-color',
81
+ secondaryColor: '--paid-secondary-color',
82
+ containerBackgroundColor: '--paid-container-background-color',
83
+ tableBackgroundColor: '--paid-table-background-color',
84
+ tableHeaderBackgroundColor: '--paid-table-header-background-color',
85
+ tabBackgroundColor: '--paid-tab-background-color',
86
+ tabActiveBackgroundColor: '--paid-tab-active-background-color',
87
+ tabHoverBackgroundColor: '--paid-tab-hover-background-color',
88
+ tableHoverColor: '--paid-table-hover-color',
89
+ buttonBgColor: '--paid-button-bg-color'
90
+ };
91
+
92
+ const cssProperty = propertyMap[key];
93
+ if (cssProperty) {
94
+ // @ts-ignore allow custom property
95
+ vars[cssProperty] = value;
96
+ }
70
97
  }
71
- // @ts-ignore allow custom property
72
- vars[varName] = value;
98
+
73
99
  return vars;
74
100
  }, {} as React.CSSProperties);
75
101
 
76
- const formatCurrency = (amount: number) => {
102
+ const formatCurrency = (amount: number, currency: string) => {
103
+ const symbol = getCurrencySymbol(currency);
77
104
  return new Intl.NumberFormat("en-US", {
78
105
  style: "currency",
79
106
  currency: "USD",
80
- minimumFractionDigits: 0,
81
- maximumFractionDigits: 0,
82
- }).format(amount / 100);
107
+ minimumFractionDigits: 2,
108
+ maximumFractionDigits: 2,
109
+ }).format(amount / 100).replace('$', symbol);
110
+ };
111
+
112
+ const getCurrencySymbol = (currency: string) => {
113
+ switch (currency.toUpperCase()) {
114
+ case 'USD':
115
+ return '$';
116
+ case 'EUR':
117
+ return '€';
118
+ case 'GBP':
119
+ return '£';
120
+ default:
121
+ return '$'; // Default to USD symbol
122
+ }
83
123
  };
84
124
 
85
125
  const formatDate = (dateString: string) => {
@@ -105,24 +145,22 @@ export const PaidPaymentsTable: React.FC<PaidPaymentsTableProps> = ({
105
145
  const fetchPaymentData = async () => {
106
146
  try {
107
147
  setLoading(true);
108
- console.log('PaidPaymentsTable: Fetching payment data for', accountExternalId);
148
+ console.log('PaidPaymentsTable: Fetching payment data for', customerExternalId);
109
149
 
110
- // TEMPORARILY DISABLED: Use cached fetch for payment data
111
- // const cacheKey = getCacheKey.payments(accountExternalId);
112
- // console.log('PaidPaymentsTable: Using cache key', cacheKey);
113
- // const data = await cachedFetch<PaymentApiResponse>(
114
- // `/api/payments/${accountExternalId}`,
115
- // cacheKey,
116
- // CACHE_TTL.DATA
117
- // );
150
+ // Use cached fetch for payment data
151
+ const cacheKey = getCacheKey.payments(customerExternalId);
152
+ console.log('PaidPaymentsTable: Using cache key', cacheKey);
153
+
154
+ const response = await fetchPaidData({
155
+ paidEndpoint: 'payments',
156
+ customerExternalId
157
+ });
118
158
 
119
- // Direct fetch without caching
120
- const response = await fetch(`/api/payments/${accountExternalId}`);
121
159
  if (!response.ok) {
122
- throw new Error(`Failed to fetch: ${response.statusText}`);
160
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
123
161
  }
124
- const data = await response.json();
125
162
 
163
+ const data = await response.json() as PaymentApiResponse;
126
164
  console.log('PaidPaymentsTable: Received data', data);
127
165
  setPayments(data.data || []);
128
166
  } catch (err) {
@@ -138,7 +176,7 @@ export const PaidPaymentsTable: React.FC<PaidPaymentsTableProps> = ({
138
176
  // Listen for cache refresh events
139
177
  const handleCacheRefresh = (event: CustomEvent) => {
140
178
  console.log('PaidPaymentsTable: Cache refresh event received', event.detail);
141
- if (event.detail?.accountId === accountExternalId || event.detail?.type === 'all') {
179
+ if (event.detail?.customerId === customerExternalId || event.detail?.type === 'all') {
142
180
  console.log('PaidPaymentsTable: Refetching data due to cache refresh');
143
181
  fetchPaymentData();
144
182
  }
@@ -149,7 +187,7 @@ export const PaidPaymentsTable: React.FC<PaidPaymentsTableProps> = ({
149
187
  return () => {
150
188
  window.removeEventListener('cache-refresh', handleCacheRefresh as EventListener);
151
189
  };
152
- }, [accountExternalId]);
190
+ }, [customerExternalId]);
153
191
 
154
192
  if (loading) {
155
193
  return <div>Loading payment data...</div>;
@@ -161,58 +199,59 @@ export const PaidPaymentsTable: React.FC<PaidPaymentsTableProps> = ({
161
199
 
162
200
  return (
163
201
  <div className="paid-payment-container" style={{ position: 'relative', minWidth: 0, ...cssVariables }}>
164
- <div className="paid-payment-table-wrapper" style={{ position: 'static', width: '100%', height: 'auto', left: undefined, top: undefined, boxShadow: undefined, cursor: undefined }}>
202
+ <div className="paid-payment-table-wrapper" style={{ position: 'relative', width: '100%', height: 'auto', left: undefined, top: undefined, boxShadow: undefined, cursor: undefined }}>
165
203
  {!isInContainer && (
166
204
  <div className="paid-payment-header">
167
205
  <h3 className="paid-payment-title">Payments</h3>
168
206
  </div>
169
207
  )}
170
- <div style={{ background: '#fff', overflow: 'auto' }}>
171
- <table className="paid-payment-table">
208
+ <div style={{ background: '#fff', overflow: 'auto', width: '100%', boxSizing: 'border-box' }}>
209
+ <table className="paid-payment-table" style={{ width: '100%', maxWidth: '100%', tableLayout: 'fixed' }}>
172
210
  <thead>
173
211
  <tr>
174
212
  <th>Payment Number</th>
175
213
  <th>Payment type</th>
176
214
  <th>Due date</th>
177
215
  <th>Status</th>
178
- <th style={{ textAlign: 'right' }}>Amount</th>
179
- <th></th>
216
+ <th style={{ textAlign: 'center' }}>Amount</th>
180
217
  </tr>
181
218
  </thead>
182
219
  <tbody>
183
- {payments.length === 0 ? (
220
+ {currentPayments.length === 0 ? (
184
221
  <tr>
185
- <td colSpan={6} className="paid-payment-empty">
222
+ <td colSpan={5} className="paid-payment-empty">
186
223
  No payments found
187
224
  </td>
188
225
  </tr>
189
226
  ) : (
190
- payments.map((payment) => (
227
+ currentPayments.map((payment) => (
191
228
  <tr key={payment.id}>
192
- <td>
229
+ <td style={{ fontWeight: 500 }}>
193
230
  <div className="paid-payment-number">
194
- <span className="paid-payment-dollar">$</span>
195
231
  <span>PAY-1</span>
196
232
  </div>
197
233
  </td>
198
234
  <td>{payment.paymentType}</td>
199
235
  <td>{formatDate(payment.paymentDate)}</td>
200
- <td>{getStatusBadge(payment.status)}</td>
201
- <td style={{ textAlign: 'right' }}>
236
+ <td>{getStatusBadge(payment.paymentStatus)}</td>
237
+ <td style={{ textAlign: 'center' }}>
202
238
  <div className="paid-payment-amount">
203
- <span>{formatCurrency(payment.amount)}</span>
204
- <span className="paid-payment-dollar-right">$</span>
239
+ <span className="amount-number">{formatCurrency(payment.amount, payment.currency)}</span>
205
240
  </div>
206
241
  </td>
207
- <td style={{ textAlign: 'center' }}>
208
- <span className="paid-payment-currency">{payment.currency}</span>
209
- </td>
210
242
  </tr>
211
243
  ))
212
244
  )}
213
245
  </tbody>
214
246
  </table>
215
247
  </div>
248
+
249
+ {/* Pagination */}
250
+ <Pagination
251
+ currentPage={currentPage}
252
+ totalPages={totalPages}
253
+ onPageChange={handlePageChange}
254
+ />
216
255
  </div>
217
256
  </div>
218
257
  );