@agentpaid/paid-nextjs-client 0.3.0-test.2 → 0.3.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 (38) hide show
  1. package/README.md +246 -72
  2. package/dist/components/PaidActivityLog.d.ts +11 -24
  3. package/dist/components/PaidActivityLog.d.ts.map +1 -1
  4. package/dist/components/PaidActivityLog.js +53 -26
  5. package/dist/components/PaidActivityLog.js.map +1 -1
  6. package/dist/components/PaidContainer.d.ts +11 -24
  7. package/dist/components/PaidContainer.d.ts.map +1 -1
  8. package/dist/components/PaidContainer.js +18 -9
  9. package/dist/components/PaidContainer.js.map +1 -1
  10. package/dist/components/PaidInvoiceTable.d.ts +11 -24
  11. package/dist/components/PaidInvoiceTable.d.ts.map +1 -1
  12. package/dist/components/PaidInvoiceTable.js +57 -30
  13. package/dist/components/PaidInvoiceTable.js.map +1 -1
  14. package/dist/components/PaidPaymentsTable.d.ts +11 -24
  15. package/dist/components/PaidPaymentsTable.d.ts.map +1 -1
  16. package/dist/components/PaidPaymentsTable.js +54 -28
  17. package/dist/components/PaidPaymentsTable.js.map +1 -1
  18. package/dist/components/components/PaidActivityLog.js +98 -57
  19. package/dist/components/components/PaidContainer.js +42 -32
  20. package/dist/components/components/PaidInvoiceTable.js +103 -86
  21. package/dist/components/components/PaidPaymentsTable.js +102 -69
  22. package/dist/components/components/ui/Pagination.js +168 -0
  23. package/dist/components/ui/Pagination.d.ts +10 -0
  24. package/dist/components/ui/Pagination.d.ts.map +1 -0
  25. package/dist/components/ui/Pagination.js +111 -0
  26. package/dist/components/ui/Pagination.js.map +1 -0
  27. package/dist/index.d.ts +3 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/styles/activity-log-table.css +94 -78
  32. package/dist/styles/paid-container.css +25 -16
  33. package/dist/styles/paid-invoice-table.css +135 -120
  34. package/dist/styles/paid-payments-table.css +65 -109
  35. package/dist/tsconfig.tsbuildinfo +1 -1
  36. package/dist/utils/cache.js +1 -1
  37. package/dist/utils/cache.js.map +1 -1
  38. package/package.json +1 -1
@@ -3,34 +3,34 @@
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { useIsInContainer } from './PaidContainer';
5
5
  import { cachedFetch, getCacheKey, CACHE_TTL } from '../utils/cache';
6
+ import { Pagination } from './ui/Pagination';
6
7
  import '../styles/activity-log-table.css';
7
8
 
8
9
  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;
10
+ // Global - Font
11
+ fontFamily?: string;
12
+
13
+ // Global - Font Colors
14
+ primaryColor?: string;
15
+ secondaryColor?: string;
16
+
17
+ // Background Colors
18
+ containerBackgroundColor?: string;
19
+ tableBackgroundColor?: string;
20
+ tableHeaderBackgroundColor?: string;
21
+
22
+ // Tab Colors
23
+ tabBackgroundColor?: string;
24
+ tabActiveBackgroundColor?: string;
25
+ tabHoverBackgroundColor?: string;
26
+
27
+ // Table Hover
28
+ tableHoverColor?: string;
29
+
30
+ // Button Background (Status badges & Pagination)
31
+ buttonBgColor?: string;
33
32
  }
33
+
34
34
  interface UsageSummary {
35
35
  id: string;
36
36
  updatedAt: string;
@@ -47,6 +47,7 @@ interface UsageSummary {
47
47
  orderLineAttributeId: string;
48
48
  invoiceId: string | null;
49
49
  invoiceLineId: string | null;
50
+ currency?: string;
50
51
  }
51
52
 
52
53
  interface UsageApiResponse {
@@ -67,29 +68,71 @@ export const PaidActivityLog: React.FC<PaidActivityLogProps> = ({
67
68
  const [usageSummaries, setUsageSummaries] = useState<UsageSummary[]>([]);
68
69
  const [loading, setLoading] = useState(true);
69
70
  const [error, setError] = useState<string | null>(null);
71
+ const [currentPage, setCurrentPage] = useState(1);
72
+ const itemsPerPage = 8;
70
73
  const isInContainer = useIsInContainer();
71
74
 
75
+ // Calculate pagination
76
+ const totalPages = Math.ceil(usageSummaries.length / itemsPerPage);
77
+ const startIndex = (currentPage - 1) * itemsPerPage;
78
+ const endIndex = startIndex + itemsPerPage;
79
+ const currentUsageSummaries = usageSummaries.slice(startIndex, endIndex);
80
+
81
+ const handlePageChange = (page: number) => {
82
+ setCurrentPage(page);
83
+ };
84
+
72
85
  // Convert paidStyle entries into CSS custom properties
73
86
  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}`;
87
+ // Only set CSS variables if they are explicitly provided
88
+ // This allows inheritance from parent PaidContainer
89
+ if (value !== undefined && value !== null && value !== '') {
90
+ // Map simplified properties to CSS custom properties
91
+ const propertyMap: Record<string, string> = {
92
+ fontFamily: '--paid-font-family',
93
+ primaryColor: '--paid-primary-color',
94
+ secondaryColor: '--paid-secondary-color',
95
+ containerBackgroundColor: '--paid-container-background-color',
96
+ tableBackgroundColor: '--paid-table-background-color',
97
+ tableHeaderBackgroundColor: '--paid-table-header-background-color',
98
+ tabBackgroundColor: '--paid-tab-background-color',
99
+ tabActiveBackgroundColor: '--paid-tab-active-background-color',
100
+ tabHoverBackgroundColor: '--paid-tab-hover-background-color',
101
+ tableHoverColor: '--paid-table-hover-color',
102
+ buttonBgColor: '--paid-button-bg-color'
103
+ };
104
+
105
+ const cssProperty = propertyMap[key];
106
+ if (cssProperty) {
107
+ // @ts-ignore allow custom property
108
+ vars[cssProperty] = value;
109
+ }
80
110
  }
81
- // @ts-ignore allow custom property
82
- vars[varName] = value;
111
+
83
112
  return vars;
84
113
  }, {} as React.CSSProperties);
85
114
 
86
- const formatCurrency = (amount: number) => {
115
+ const formatCurrency = (amount: number, currency?: string) => {
116
+ const symbol = getCurrencySymbol(currency || 'USD');
87
117
  return new Intl.NumberFormat("en-US", {
88
118
  style: "currency",
89
119
  currency: "USD",
90
120
  minimumFractionDigits: 2,
91
121
  maximumFractionDigits: 2,
92
- }).format(amount / 100);
122
+ }).format(amount / 100).replace('$', symbol);
123
+ };
124
+
125
+ const getCurrencySymbol = (currency: string) => {
126
+ switch (currency.toUpperCase()) {
127
+ case 'USD':
128
+ return '$';
129
+ case 'EUR':
130
+ return '€';
131
+ case 'GBP':
132
+ return '£';
133
+ default:
134
+ return '$'; // Default to USD symbol
135
+ }
93
136
  };
94
137
 
95
138
  const formatEventName = (eventName: string) => {
@@ -112,20 +155,13 @@ export const PaidActivityLog: React.FC<PaidActivityLogProps> = ({
112
155
  try {
113
156
  setLoading(true);
114
157
 
115
- // TEMPORARILY DISABLED: Use cached fetch for usage data
116
- // const cacheKey = getCacheKey.usage(accountExternalId);
117
- // const data = await cachedFetch<UsageApiResponse>(
118
- // `/api/usage/${accountExternalId}`,
119
- // cacheKey,
120
- // CACHE_TTL.DATA
121
- // );
122
-
123
- // Direct fetch without caching
124
- const response = await fetch(`/api/usage/${accountExternalId}`);
125
- if (!response.ok) {
126
- throw new Error(`Failed to fetch: ${response.statusText}`);
127
- }
128
- const data = await response.json();
158
+ // Use cached fetch for usage data
159
+ const cacheKey = getCacheKey.usage(accountExternalId);
160
+ const data = await cachedFetch<UsageApiResponse>(
161
+ `/api/usage/${accountExternalId}`,
162
+ cacheKey,
163
+ CACHE_TTL.DATA
164
+ );
129
165
 
130
166
  const mappedUsageSummaries = (data.data.usageSummary || []).map((summary: any) => ({
131
167
  ...summary,
@@ -142,8 +178,6 @@ export const PaidActivityLog: React.FC<PaidActivityLogProps> = ({
142
178
  fetchUsageData();
143
179
  }, [accountExternalId]);
144
180
 
145
- const displayedSummaries = usageSummaries;
146
-
147
181
  if (loading) {
148
182
  return <div>Loading usage data...</div>;
149
183
  }
@@ -154,14 +188,14 @@ export const PaidActivityLog: React.FC<PaidActivityLogProps> = ({
154
188
 
155
189
  return (
156
190
  <div className="paid-activity-log-container" style={{ position: 'relative', minWidth: 0, ...cssVariables }}>
157
- <div className="paid-activity-log-table-wrapper" style={{ position: 'static', width: '100%', height: 'auto', left: undefined, top: undefined, boxShadow: undefined, cursor: undefined }}>
191
+ <div className="paid-activity-log-table-wrapper" style={{ position: 'relative', width: '100%', height: 'auto', left: undefined, top: undefined, boxShadow: undefined, cursor: undefined }}>
158
192
  {!isInContainer && (
159
193
  <div className="paid-activity-log-header">
160
- <h3 className="paid-activity-log-title">Paid.ai Activity Log</h3>
194
+ <h3 className="paid-activity-log-title">Activity Log</h3>
161
195
  </div>
162
196
  )}
163
- <div style={{ background: '#fff', overflow: 'auto' }}>
164
- <table className="paid-activity-log-table">
197
+ <div style={{ background: '#fff', overflow: 'auto', width: '100%', boxSizing: 'border-box' }}>
198
+ <table className="paid-activity-log-table" style={{ width: '100%', maxWidth: '100%', tableLayout: 'fixed' }}>
165
199
  <thead>
166
200
  <tr>
167
201
  <th>Event</th>
@@ -172,26 +206,33 @@ export const PaidActivityLog: React.FC<PaidActivityLogProps> = ({
172
206
  </tr>
173
207
  </thead>
174
208
  <tbody>
175
- {displayedSummaries.length === 0 ? (
209
+ {currentUsageSummaries.length === 0 ? (
176
210
  <tr>
177
211
  <td colSpan={5} className="paid-activity-log-empty">
178
212
  No usage data found
179
213
  </td>
180
214
  </tr>
181
215
  ) : (
182
- displayedSummaries.map((summary) => (
216
+ currentUsageSummaries.map((summary) => (
183
217
  <tr key={summary.id}>
184
218
  <td style={{ fontWeight: 500 }}>{formatEventName(summary.eventName)}</td>
185
219
  <td>{formatDate(summary.startDate)}</td>
186
220
  <td>{formatDate(summary.endDate)}</td>
187
221
  <td style={{ textAlign: 'center' }}>{summary.eventsQuantity}</td>
188
- <td style={{ textAlign: 'center', fontWeight: 500 }}>{formatCurrency(summary.subtotal)}</td>
222
+ <td style={{ textAlign: 'center', fontWeight: 500 }}>{formatCurrency(summary.subtotal, summary.currency)}</td>
189
223
  </tr>
190
224
  ))
191
225
  )}
192
226
  </tbody>
193
227
  </table>
194
228
  </div>
229
+
230
+ {/* Pagination */}
231
+ <Pagination
232
+ currentPage={currentPage}
233
+ totalPages={totalPages}
234
+ onPageChange={handlePageChange}
235
+ />
195
236
  </div>
196
237
  </div>
197
238
  );
@@ -10,30 +10,28 @@ const PaidContainerContext = createContext<boolean>(false);
10
10
  export const useIsInContainer = () => useContext(PaidContainerContext);
11
11
 
12
12
  interface PaidStyleProperties {
13
- paidTitleColor?: string;
14
- paidTitleFontWeight?: string;
15
- paidFontFamily?: string;
16
- paidWrapperBorder?: string;
17
- paidHeaderBorderBottom?: string;
18
- paidThBorderBottom?: string;
19
- paidTdBorderBottom?: string;
20
- paidTdBg?: string;
21
- paidTdFontWeight?: string;
22
- paidTitleFontSize?: string;
23
- paidToggleFontSize?: string;
24
- paidToggleFontWeight?: string;
25
- paidToggleColor?: string;
26
- paidThFontSize?: string;
27
- paidThFontWeight?: string;
28
- paidThColor?: string;
29
- paidTdFontSize?: string;
30
- paidTdColor?: string;
31
- paidEmptyColor?: string;
32
- paidWrapperBg?: string;
33
- paidHeaderBg?: string;
34
- paidTableBg?: string;
35
- paidThBg?: string;
36
- paidRowHoverBg?: string;
13
+ // Global - Font
14
+ fontFamily?: string;
15
+
16
+ // Global - Font Colors
17
+ primaryColor?: string;
18
+ secondaryColor?: string;
19
+
20
+ // Background Colors
21
+ containerBackgroundColor?: string;
22
+ tableBackgroundColor?: string;
23
+ tableHeaderBackgroundColor?: string;
24
+
25
+ // Tab Colors
26
+ tabBackgroundColor?: string;
27
+ tabActiveBackgroundColor?: string;
28
+ tabHoverBackgroundColor?: string;
29
+
30
+ // Table Hover
31
+ tableHoverColor?: string;
32
+
33
+ // Button Background (Status badges & Pagination)
34
+ buttonBgColor?: string;
37
35
  }
38
36
 
39
37
  interface PaidContainerTab {
@@ -63,15 +61,27 @@ export const PaidContainer: React.FC<PaidContainerProps> = ({
63
61
 
64
62
  // Convert paidStyle entries into CSS custom properties
65
63
  const cssVariables: React.CSSProperties = Object.entries(paidStyle).reduce((vars, [key, value]) => {
66
- let varName: string;
67
- if (key.startsWith('--')) {
68
- varName = key;
69
- } else {
70
- const raw = key.replace(/([A-Z])/g, '-$1').toLowerCase();
71
- varName = raw.startsWith('--') ? raw : `--${raw}`;
64
+ // Map simplified properties to CSS custom properties
65
+ const propertyMap: Record<string, string> = {
66
+ fontFamily: '--paid-font-family',
67
+ primaryColor: '--paid-primary-color',
68
+ secondaryColor: '--paid-secondary-color',
69
+ containerBackgroundColor: '--paid-container-background-color',
70
+ tableBackgroundColor: '--paid-table-background-color',
71
+ tableHeaderBackgroundColor: '--paid-table-header-background-color',
72
+ tabBackgroundColor: '--paid-tab-background-color',
73
+ tabActiveBackgroundColor: '--paid-tab-active-background-color',
74
+ tabHoverBackgroundColor: '--paid-tab-hover-background-color',
75
+ tableHoverColor: '--paid-table-hover-color',
76
+ buttonBgColor: '--paid-button-bg-color'
77
+ };
78
+
79
+ const cssProperty = propertyMap[key];
80
+ if (cssProperty) {
81
+ // @ts-ignore allow custom property
82
+ vars[cssProperty] = value;
72
83
  }
73
- // @ts-ignore allow custom property
74
- vars[varName] = value;
84
+
75
85
  return vars;
76
86
  }, {} as React.CSSProperties);
77
87
 
@@ -3,33 +3,32 @@
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { useIsInContainer } from './PaidContainer';
5
5
  import { cachedFetch, getCacheKey, CACHE_TTL, dataCache } from '../utils/cache';
6
+ import { Pagination } from './ui/Pagination';
6
7
  import '../styles/paid-invoice-table.css';
7
8
 
8
9
  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;
10
+ // Global - Font
11
+ fontFamily?: string;
12
+
13
+ // Global - Font Colors
14
+ primaryColor?: string;
15
+ secondaryColor?: string;
16
+
17
+ // Background Colors
18
+ containerBackgroundColor?: string;
19
+ tableBackgroundColor?: string;
20
+ tableHeaderBackgroundColor?: string;
21
+
22
+ // Tab Colors
23
+ tabBackgroundColor?: string;
24
+ tabActiveBackgroundColor?: string;
25
+ tabHoverBackgroundColor?: string;
26
+
27
+ // Table Hover
28
+ tableHoverColor?: string;
29
+
30
+ // Button Background (Status badges & Pagination)
31
+ buttonBgColor?: string;
33
32
  }
34
33
 
35
34
  interface Invoice {
@@ -37,7 +36,7 @@ interface Invoice {
37
36
  number: string;
38
37
  issueDate: string;
39
38
  dueDate: string;
40
- status: string;
39
+ paymentStatus: string;
41
40
  invoiceTotal: number;
42
41
  currency: string;
43
42
  customer?: {
@@ -66,30 +65,68 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
66
65
  const [isPreviewOpen, setIsPreviewOpen] = useState(false);
67
66
  const [pdfResponse, setPdfResponse] = useState<string | null>(null);
68
67
  const [selectedInvoice, setSelectedInvoice] = useState<Invoice | null>(null);
69
- const [loadingPdf, setLoadingPdf] = useState(false);
68
+ const [loadingInvoiceId, setLoadingInvoiceId] = useState<string | null>(null);
69
+ const [currentPage, setCurrentPage] = useState(1);
70
+ const itemsPerPage = 8;
70
71
  const isInContainer = useIsInContainer();
71
72
 
73
+ // Calculate pagination
74
+ const totalPages = Math.ceil(invoices.length / itemsPerPage);
75
+ const startIndex = (currentPage - 1) * itemsPerPage;
76
+ const endIndex = startIndex + itemsPerPage;
77
+ const currentInvoices = invoices.slice(startIndex, endIndex);
78
+
72
79
  // Convert paidStyle entries into CSS custom properties
73
80
  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}`;
81
+ // Only set CSS variables if they are explicitly provided
82
+ // This allows inheritance from parent PaidContainer
83
+ if (value !== undefined && value !== null && value !== '') {
84
+ // Map simplified properties to CSS custom properties
85
+ const propertyMap: Record<string, string> = {
86
+ fontFamily: '--paid-font-family',
87
+ primaryColor: '--paid-primary-color',
88
+ secondaryColor: '--paid-secondary-color',
89
+ containerBackgroundColor: '--paid-container-background-color',
90
+ tableBackgroundColor: '--paid-table-background-color',
91
+ tableHeaderBackgroundColor: '--paid-table-header-background-color',
92
+ tabBackgroundColor: '--paid-tab-background-color',
93
+ tabActiveBackgroundColor: '--paid-tab-active-background-color',
94
+ tabHoverBackgroundColor: '--paid-tab-hover-background-color',
95
+ tableHoverColor: '--paid-table-hover-color',
96
+ buttonBgColor: '--paid-button-bg-color'
97
+ };
98
+
99
+ const cssProperty = propertyMap[key];
100
+ if (cssProperty) {
101
+ // @ts-ignore allow custom property
102
+ vars[cssProperty] = value;
103
+ }
80
104
  }
81
- // @ts-ignore allow custom property
82
- vars[varName] = value;
105
+
83
106
  return vars;
84
107
  }, {} as React.CSSProperties);
85
108
 
86
- const formatCurrency = (amount: number) => {
109
+ const formatCurrency = (amount: number, currency: string) => {
110
+ const symbol = getCurrencySymbol(currency);
87
111
  return new Intl.NumberFormat("en-US", {
88
112
  style: "currency",
89
113
  currency: "USD",
90
114
  minimumFractionDigits: 2,
91
115
  maximumFractionDigits: 2,
92
- }).format(amount / 100);
116
+ }).format(amount / 100).replace('$', symbol);
117
+ };
118
+
119
+ const getCurrencySymbol = (currency: string) => {
120
+ switch (currency.toUpperCase()) {
121
+ case 'USD':
122
+ return '$';
123
+ case 'EUR':
124
+ return '€';
125
+ case 'GBP':
126
+ return '£';
127
+ default:
128
+ return '$'; // Default to USD symbol
129
+ }
93
130
  };
94
131
 
95
132
  const formatDate = (dateString: string) => {
@@ -108,7 +145,7 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
108
145
 
109
146
  const handlePreview = async (invoice: Invoice) => {
110
147
  try {
111
- setLoadingPdf(true);
148
+ setLoadingInvoiceId(invoice.id);
112
149
  setSelectedInvoice(invoice);
113
150
 
114
151
  // Check cache first for PDF
@@ -118,7 +155,7 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
118
155
  if (cachedPdf) {
119
156
  setPdfResponse(cachedPdf);
120
157
  setIsPreviewOpen(true);
121
- setLoadingPdf(false);
158
+ setLoadingInvoiceId(null);
122
159
  return;
123
160
  }
124
161
 
@@ -141,7 +178,7 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
141
178
  console.error('Error fetching PDF:', error);
142
179
  alert('Failed to load PDF preview');
143
180
  } finally {
144
- setLoadingPdf(false);
181
+ setLoadingInvoiceId(null);
145
182
  }
146
183
  };
147
184
 
@@ -166,25 +203,22 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
166
203
  URL.revokeObjectURL(url);
167
204
  };
168
205
 
206
+ const handlePageChange = (page: number) => {
207
+ setCurrentPage(page);
208
+ };
209
+
169
210
  useEffect(() => {
170
211
  const fetchInvoiceData = async () => {
171
212
  try {
172
213
  setLoading(true);
173
214
 
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
- // );
181
-
182
- // Direct fetch without caching
183
- const response = await fetch(`/api/invoices/${accountExternalId}`);
184
- if (!response.ok) {
185
- throw new Error(`Failed to fetch: ${response.statusText}`);
186
- }
187
- const data = await response.json();
215
+ // Use cached fetch for invoice data
216
+ const cacheKey = getCacheKey.invoices(accountExternalId);
217
+ const data = await cachedFetch<InvoiceApiResponse>(
218
+ `/api/invoices/${accountExternalId}`,
219
+ cacheKey,
220
+ CACHE_TTL.DATA
221
+ );
188
222
 
189
223
  setInvoices(data.data || []);
190
224
  } catch (err) {
@@ -214,8 +248,8 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
214
248
  <h3 className="paid-invoice-title">Invoices</h3>
215
249
  </div>
216
250
  )}
217
- <div style={{ background: '#fff', overflow: 'auto' }}>
218
- <table className="paid-invoice-table">
251
+ <div style={{ background: '#fff', overflow: 'auto', width: '100%', boxSizing: 'border-box' }}>
252
+ <table className="paid-invoice-table" style={{ width: '100%', maxWidth: '100%', tableLayout: 'fixed' }}>
219
253
  <thead>
220
254
  <tr>
221
255
  <th>Invoice Number</th>
@@ -223,32 +257,32 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
223
257
  <th>Invoice Date</th>
224
258
  <th>Due Date</th>
225
259
  <th style={{ textAlign: 'right' }}>Total amount</th>
226
- <th style={{ textAlign: 'center' }}>Actions</th>
260
+ <th style={{ textAlign: 'center' }}>Preview</th>
227
261
  </tr>
228
262
  </thead>
229
263
  <tbody>
230
- {invoices.length === 0 ? (
264
+ {currentInvoices.length === 0 ? (
231
265
  <tr>
232
266
  <td colSpan={6} className="paid-invoice-empty">
233
267
  No invoices found
234
268
  </td>
235
269
  </tr>
236
270
  ) : (
237
- invoices.map((invoice) => (
271
+ currentInvoices.map((invoice) => (
238
272
  <tr key={invoice.id}>
239
273
  <td style={{ fontWeight: 500 }}>INV-{invoice.number}</td>
240
- <td>{getStatusBadge(invoice.status)}</td>
274
+ <td>{getStatusBadge(invoice.paymentStatus)}</td>
241
275
  <td>{formatDate(invoice.issueDate)}</td>
242
276
  <td>{formatDate(invoice.dueDate)}</td>
243
- <td style={{ textAlign: 'right', fontWeight: 500 }}>{formatCurrency(invoice.invoiceTotal)}</td>
277
+ <td style={{ textAlign: 'right', fontWeight: 500 }}>{formatCurrency(invoice.invoiceTotal, invoice.currency)}</td>
244
278
  <td style={{ textAlign: 'center' }}>
245
279
  <button
246
280
  className="paid-invoice-action-btn"
247
281
  onClick={() => handlePreview(invoice)}
248
- disabled={loadingPdf}
282
+ disabled={loadingInvoiceId === invoice.id}
249
283
  title="Preview Invoice"
250
284
  >
251
- {loadingPdf ? (
285
+ {loadingInvoiceId === invoice.id ? (
252
286
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
253
287
  <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="2" fill="none" strokeDasharray="37.7" strokeDashoffset="37.7">
254
288
  <animateTransform attributeName="transform" type="rotate" values="0 8 8;360 8 8" dur="1s" repeatCount="indefinite"/>
@@ -269,6 +303,13 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
269
303
  </tbody>
270
304
  </table>
271
305
  </div>
306
+
307
+ {/* Pagination */}
308
+ <Pagination
309
+ currentPage={currentPage}
310
+ totalPages={totalPages}
311
+ onPageChange={handlePageChange}
312
+ />
272
313
  </div>
273
314
  </div>
274
315
 
@@ -276,30 +317,6 @@ export const PaidInvoiceTable: React.FC<PaidInvoiceTableProps> = ({
276
317
  {isPreviewOpen && (
277
318
  <div className="paid-invoice-modal-overlay" onClick={() => setIsPreviewOpen(false)}>
278
319
  <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
320
  <div className="paid-invoice-modal-body">
304
321
  {pdfResponse ? (
305
322
  <iframe