@fayz-ai/plugin-financial 0.1.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.
- package/dist/FinancialContext.d.ts +44 -0
- package/dist/FinancialContext.d.ts.map +1 -0
- package/dist/FinancialPage.d.ts +18 -0
- package/dist/FinancialPage.d.ts.map +1 -0
- package/dist/components/FinancialGeneralSettings.d.ts +3 -0
- package/dist/components/FinancialGeneralSettings.d.ts.map +1 -0
- package/dist/components/FinancialOnboarding.d.ts +5 -0
- package/dist/components/FinancialOnboarding.d.ts.map +1 -0
- package/dist/components/FinancialSettings.d.ts +8 -0
- package/dist/components/FinancialSettings.d.ts.map +1 -0
- package/dist/components/PaymentModal.d.ts +8 -0
- package/dist/components/PaymentModal.d.ts.map +1 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.d.ts.map +1 -0
- package/dist/data/mock.d.ts +9 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/supabase.d.ts +3 -0
- package/dist/data/supabase.d.ts.map +1 -0
- package/dist/data/types.d.ts +27 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/index.cjs +4937 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4930 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/tenant.d.ts +3 -0
- package/dist/lib/tenant.d.ts.map +1 -0
- package/dist/locales/en.d.ts +2 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/index.d.ts +2 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/pt-BR.d.ts +2 -0
- package/dist/locales/pt-BR.d.ts.map +1 -0
- package/dist/registries.d.ts +3 -0
- package/dist/registries.d.ts.map +1 -0
- package/dist/store.d.ts +38 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/types.d.ts +302 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/views/CardsView.d.ts +3 -0
- package/dist/views/CardsView.d.ts.map +1 -0
- package/dist/views/CashRegistersView.d.ts +3 -0
- package/dist/views/CashRegistersView.d.ts.map +1 -0
- package/dist/views/CommissionsView.d.ts +3 -0
- package/dist/views/CommissionsView.d.ts.map +1 -0
- package/dist/views/InvoiceDetailView.d.ts +9 -0
- package/dist/views/InvoiceDetailView.d.ts.map +1 -0
- package/dist/views/InvoiceFormView.d.ts +13 -0
- package/dist/views/InvoiceFormView.d.ts.map +1 -0
- package/dist/views/InvoiceListView.d.ts +8 -0
- package/dist/views/InvoiceListView.d.ts.map +1 -0
- package/dist/views/PayablesView.d.ts +7 -0
- package/dist/views/PayablesView.d.ts.map +1 -0
- package/dist/views/ReceivablesView.d.ts +7 -0
- package/dist/views/ReceivablesView.d.ts.map +1 -0
- package/dist/views/StatementsView.d.ts +3 -0
- package/dist/views/StatementsView.d.ts.map +1 -0
- package/dist/views/SummaryView.d.ts +9 -0
- package/dist/views/SummaryView.d.ts.map +1 -0
- package/dist/views/dashboardWidgets.d.ts +11 -0
- package/dist/views/dashboardWidgets.d.ts.map +1 -0
- package/package.json +55 -0
- package/src/FinancialContext.tsx +47 -0
- package/src/FinancialPage.tsx +261 -0
- package/src/README.md +155 -0
- package/src/components/FinancialGeneralSettings.tsx +26 -0
- package/src/components/FinancialOnboarding.tsx +87 -0
- package/src/components/FinancialSettings.tsx +31 -0
- package/src/components/PaymentModal.tsx +322 -0
- package/src/data/index.ts +2 -0
- package/src/data/mock.ts +520 -0
- package/src/data/supabase.ts +509 -0
- package/src/data/types.ts +53 -0
- package/src/index.ts +307 -0
- package/src/lib/tenant.ts +3 -0
- package/src/locales/en.ts +331 -0
- package/src/locales/index.ts +7 -0
- package/src/locales/pt-BR.ts +331 -0
- package/src/migrations/001_financial_base.sql +109 -0
- package/src/migrations/002_chart_of_accounts.sql +28 -0
- package/src/migrations/003_card_brands.sql +12 -0
- package/src/migrations/004_order_to_cash.sql +164 -0
- package/src/migrations/005_seed_defaults.sql +38 -0
- package/src/registries.ts +305 -0
- package/src/store.ts +221 -0
- package/src/types.ts +359 -0
- package/src/views/CardsView.tsx +74 -0
- package/src/views/CashRegistersView.tsx +597 -0
- package/src/views/CommissionsView.tsx +18 -0
- package/src/views/InvoiceDetailView.tsx +595 -0
- package/src/views/InvoiceFormView.tsx +900 -0
- package/src/views/InvoiceListView.tsx +177 -0
- package/src/views/PayablesView.tsx +37 -0
- package/src/views/ReceivablesView.tsx +37 -0
- package/src/views/StatementsView.tsx +123 -0
- package/src/views/SummaryView.tsx +12 -0
- package/src/views/dashboardWidgets.tsx +191 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Financial Module — Pure TypeScript types
|
|
3
|
+
// Zero dependencies. Maps to beautyplace DB schema but with English names.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
// ============================================================
|
|
7
|
+
// ENUMS / LITERALS
|
|
8
|
+
// ============================================================
|
|
9
|
+
|
|
10
|
+
/** Direction: debit (money going out / payable) or credit (money coming in / receivable) */
|
|
11
|
+
export type TransactionDirection = 'debit' | 'credit'
|
|
12
|
+
|
|
13
|
+
/** What kind of financial movement this is */
|
|
14
|
+
export type MovementKind = 'bill' | 'payment' | 'transfer'
|
|
15
|
+
|
|
16
|
+
/** Status of a financial movement */
|
|
17
|
+
export type MovementStatus = 'pending' | 'paid' | 'partial' | 'overdue' | 'cancelled'
|
|
18
|
+
|
|
19
|
+
/** Status of an invoice */
|
|
20
|
+
export type InvoiceStatus = 'draft' | 'open' | 'partial' | 'paid' | 'cancelled' | 'overdue'
|
|
21
|
+
|
|
22
|
+
/** Type of bank account */
|
|
23
|
+
export type BankAccountType = 'bank_account' | 'cash_register' | 'credit_card' | 'digital_wallet'
|
|
24
|
+
|
|
25
|
+
/** Cash session status */
|
|
26
|
+
export type CashSessionStatus = 'open' | 'closed'
|
|
27
|
+
|
|
28
|
+
/** Discount/interest application mode */
|
|
29
|
+
export type AdjustmentMode = 'percentage' | 'fixed'
|
|
30
|
+
|
|
31
|
+
/** Chart of accounts node type */
|
|
32
|
+
export type AccountNodeType = 'group' | 'leaf'
|
|
33
|
+
|
|
34
|
+
/** Item type on an invoice line — parametrizable per vertical */
|
|
35
|
+
export type InvoiceItemKind = string
|
|
36
|
+
|
|
37
|
+
// ============================================================
|
|
38
|
+
// CORE ENTITIES
|
|
39
|
+
// ============================================================
|
|
40
|
+
|
|
41
|
+
export interface Invoice {
|
|
42
|
+
id: string
|
|
43
|
+
direction: TransactionDirection
|
|
44
|
+
invoiceDate: string
|
|
45
|
+
fiscalNumber?: string
|
|
46
|
+
totalAmount: number
|
|
47
|
+
paidAmount: number
|
|
48
|
+
status: InvoiceStatus
|
|
49
|
+
totalInstallments: number
|
|
50
|
+
contactId?: string
|
|
51
|
+
contactName?: string
|
|
52
|
+
cashSessionId?: string
|
|
53
|
+
unitId?: string
|
|
54
|
+
observations?: string
|
|
55
|
+
/** Denormalized summary of item descriptions for list display */
|
|
56
|
+
itemsSummary?: string
|
|
57
|
+
/** If this order has a scheduled time (booking), the start time */
|
|
58
|
+
bookingStartsAt?: string
|
|
59
|
+
metadata?: Record<string, unknown>
|
|
60
|
+
tenantId: string
|
|
61
|
+
createdAt: string
|
|
62
|
+
updatedAt: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface InvoiceItem {
|
|
66
|
+
id: string
|
|
67
|
+
invoiceId: string
|
|
68
|
+
itemKind: InvoiceItemKind
|
|
69
|
+
referenceId?: string
|
|
70
|
+
description: string
|
|
71
|
+
quantity: number
|
|
72
|
+
unitPrice: number
|
|
73
|
+
totalAmount: number
|
|
74
|
+
discount: number
|
|
75
|
+
surcharge: number
|
|
76
|
+
accountId?: string
|
|
77
|
+
costCenterId?: string
|
|
78
|
+
// Service execution tracking (opt-in per vertical)
|
|
79
|
+
isExecuted?: boolean
|
|
80
|
+
executionDate?: string
|
|
81
|
+
executedByProfessionalId?: string
|
|
82
|
+
metadata?: Record<string, unknown>
|
|
83
|
+
createdAt: string
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface FinancialMovement {
|
|
87
|
+
id: string
|
|
88
|
+
invoiceId?: string
|
|
89
|
+
direction: TransactionDirection
|
|
90
|
+
movementKind: MovementKind
|
|
91
|
+
amount: number
|
|
92
|
+
paidAmount: number
|
|
93
|
+
status: MovementStatus
|
|
94
|
+
dueDate: string
|
|
95
|
+
paymentDate?: string
|
|
96
|
+
installmentNumber?: number
|
|
97
|
+
paymentMethodId?: string
|
|
98
|
+
paymentMethodTypeId?: string
|
|
99
|
+
bankAccountId?: string
|
|
100
|
+
cashSessionId?: string
|
|
101
|
+
cardBrand?: string
|
|
102
|
+
cardInstallments?: number
|
|
103
|
+
debitAccountId?: string
|
|
104
|
+
creditAccountId?: string
|
|
105
|
+
notes?: string
|
|
106
|
+
metadata?: Record<string, unknown>
|
|
107
|
+
tenantId: string
|
|
108
|
+
createdAt: string
|
|
109
|
+
updatedAt: string
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface BankAccount {
|
|
113
|
+
id: string
|
|
114
|
+
name: string
|
|
115
|
+
accountType: BankAccountType
|
|
116
|
+
bankName?: string
|
|
117
|
+
accountNumber?: string
|
|
118
|
+
agencyNumber?: string
|
|
119
|
+
currentBalance: number
|
|
120
|
+
initialBalance: number
|
|
121
|
+
creditLimit?: number
|
|
122
|
+
dueDay?: number
|
|
123
|
+
closingDay?: number
|
|
124
|
+
isActive: boolean
|
|
125
|
+
unitId?: string
|
|
126
|
+
tenantId: string
|
|
127
|
+
createdAt: string
|
|
128
|
+
updatedAt: string
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface CashSession {
|
|
132
|
+
id: string
|
|
133
|
+
bankAccountId: string
|
|
134
|
+
bankAccountName?: string
|
|
135
|
+
status: CashSessionStatus
|
|
136
|
+
openedAt: string
|
|
137
|
+
openedByUserId?: string
|
|
138
|
+
openedByName?: string
|
|
139
|
+
openingBalance: number
|
|
140
|
+
closedAt?: string
|
|
141
|
+
closedByUserId?: string
|
|
142
|
+
closedByName?: string
|
|
143
|
+
closingBalance?: number
|
|
144
|
+
expectedBalance?: number
|
|
145
|
+
difference?: number
|
|
146
|
+
notes?: string
|
|
147
|
+
unitId?: string
|
|
148
|
+
tenantId: string
|
|
149
|
+
createdAt: string
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface PaymentMethod {
|
|
153
|
+
id: string
|
|
154
|
+
name: string
|
|
155
|
+
paymentMethodTypeId: string
|
|
156
|
+
isActive: boolean
|
|
157
|
+
discountMode?: AdjustmentMode
|
|
158
|
+
discountValue?: number
|
|
159
|
+
interestMode?: AdjustmentMode
|
|
160
|
+
interestValue?: number
|
|
161
|
+
minInstallments: number
|
|
162
|
+
maxInstallments: number
|
|
163
|
+
serviceFilterMode?: 'all' | 'include' | 'exclude'
|
|
164
|
+
serviceFilterIds?: string[]
|
|
165
|
+
tenantId: string
|
|
166
|
+
createdAt: string
|
|
167
|
+
updatedAt: string
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface PaymentMethodType {
|
|
171
|
+
id: string
|
|
172
|
+
name: string
|
|
173
|
+
transactionType?: string
|
|
174
|
+
isActive: boolean
|
|
175
|
+
allowedAccountTypes?: BankAccountType[]
|
|
176
|
+
tenantId: string
|
|
177
|
+
createdAt: string
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface ChartOfAccountsNode {
|
|
181
|
+
id: string
|
|
182
|
+
code: string
|
|
183
|
+
name: string
|
|
184
|
+
nodeType: AccountNodeType
|
|
185
|
+
parentId?: string
|
|
186
|
+
isActive: boolean
|
|
187
|
+
tenantId: string
|
|
188
|
+
createdAt: string
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface CardTransaction {
|
|
192
|
+
id: string
|
|
193
|
+
movementId: string
|
|
194
|
+
cardBrand: string
|
|
195
|
+
totalAmount: number
|
|
196
|
+
installmentCount: number
|
|
197
|
+
currentInstallment: number
|
|
198
|
+
installmentAmount: number
|
|
199
|
+
expectedDate: string
|
|
200
|
+
receivedDate?: string
|
|
201
|
+
fee?: number
|
|
202
|
+
netAmount?: number
|
|
203
|
+
status: 'pending' | 'received' | 'cancelled'
|
|
204
|
+
tenantId: string
|
|
205
|
+
createdAt: string
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ============================================================
|
|
209
|
+
// INPUT TYPES (create / mutate)
|
|
210
|
+
// ============================================================
|
|
211
|
+
|
|
212
|
+
export interface CreateInvoiceInput {
|
|
213
|
+
direction: TransactionDirection
|
|
214
|
+
invoiceDate: string
|
|
215
|
+
fiscalNumber?: string
|
|
216
|
+
contactId?: string
|
|
217
|
+
contactName?: string
|
|
218
|
+
cashSessionId?: string
|
|
219
|
+
unitId?: string
|
|
220
|
+
observations?: string
|
|
221
|
+
metadata?: Record<string, unknown>
|
|
222
|
+
items: CreateInvoiceItemInput[]
|
|
223
|
+
installments: CreateMovementInput[]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface CreateInvoiceItemInput {
|
|
227
|
+
itemKind: InvoiceItemKind
|
|
228
|
+
referenceId?: string
|
|
229
|
+
description: string
|
|
230
|
+
quantity: number
|
|
231
|
+
unitPrice: number
|
|
232
|
+
discount?: number
|
|
233
|
+
surcharge?: number
|
|
234
|
+
accountId?: string
|
|
235
|
+
costCenterId?: string
|
|
236
|
+
metadata?: Record<string, unknown>
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface CreateMovementInput {
|
|
240
|
+
direction: TransactionDirection
|
|
241
|
+
movementKind: MovementKind
|
|
242
|
+
amount: number
|
|
243
|
+
dueDate: string
|
|
244
|
+
installmentNumber?: number
|
|
245
|
+
paymentMethodId?: string
|
|
246
|
+
bankAccountId?: string
|
|
247
|
+
notes?: string
|
|
248
|
+
metadata?: Record<string, unknown>
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface PayMovementInput {
|
|
252
|
+
movementId: string
|
|
253
|
+
amount: number
|
|
254
|
+
paymentDate: string
|
|
255
|
+
paymentMethodId?: string
|
|
256
|
+
paymentMethodTypeId?: string
|
|
257
|
+
bankAccountId?: string
|
|
258
|
+
cashSessionId?: string
|
|
259
|
+
cardBrand?: string
|
|
260
|
+
cardInstallments?: number
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface OpenCashSessionInput {
|
|
264
|
+
bankAccountId: string
|
|
265
|
+
openingBalance: number
|
|
266
|
+
openedByUserId?: string
|
|
267
|
+
openedByName?: string
|
|
268
|
+
unitId?: string
|
|
269
|
+
notes?: string
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface CloseCashSessionInput {
|
|
273
|
+
sessionId: string
|
|
274
|
+
closingBalance: number
|
|
275
|
+
closedByUserId?: string
|
|
276
|
+
closedByName?: string
|
|
277
|
+
notes?: string
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface CreateBankAccountInput {
|
|
281
|
+
name: string
|
|
282
|
+
accountType: BankAccountType
|
|
283
|
+
bankName?: string
|
|
284
|
+
accountNumber?: string
|
|
285
|
+
agencyNumber?: string
|
|
286
|
+
initialBalance?: number
|
|
287
|
+
creditLimit?: number
|
|
288
|
+
dueDay?: number
|
|
289
|
+
closingDay?: number
|
|
290
|
+
unitId?: string
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ============================================================
|
|
294
|
+
// QUERY / FILTER TYPES
|
|
295
|
+
// ============================================================
|
|
296
|
+
|
|
297
|
+
export interface DateRange {
|
|
298
|
+
from: string
|
|
299
|
+
to: string
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface InvoiceQuery {
|
|
303
|
+
direction?: TransactionDirection
|
|
304
|
+
status?: InvoiceStatus | InvoiceStatus[]
|
|
305
|
+
contactId?: string
|
|
306
|
+
dateRange?: DateRange
|
|
307
|
+
search?: string
|
|
308
|
+
page?: number
|
|
309
|
+
pageSize?: number
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface MovementQuery {
|
|
313
|
+
direction?: TransactionDirection
|
|
314
|
+
status?: MovementStatus | MovementStatus[]
|
|
315
|
+
bankAccountId?: string
|
|
316
|
+
cashSessionId?: string
|
|
317
|
+
dateRange?: DateRange
|
|
318
|
+
page?: number
|
|
319
|
+
pageSize?: number
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export interface StatementQuery {
|
|
323
|
+
bankAccountId: string
|
|
324
|
+
dateRange: DateRange
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export interface PaginatedResult<T> {
|
|
328
|
+
data: T[]
|
|
329
|
+
total: number
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ============================================================
|
|
333
|
+
// AGGREGATION TYPES
|
|
334
|
+
// ============================================================
|
|
335
|
+
|
|
336
|
+
export interface FinancialSummary {
|
|
337
|
+
totalBalance: number
|
|
338
|
+
totalReceivable: number
|
|
339
|
+
totalPayable: number
|
|
340
|
+
monthlyInflow: number
|
|
341
|
+
monthlyOutflow: number
|
|
342
|
+
overdueReceivableCount: number
|
|
343
|
+
overdueReceivableAmount: number
|
|
344
|
+
overduePayableCount: number
|
|
345
|
+
overduePayableAmount: number
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export interface StatementEntry {
|
|
349
|
+
movement: FinancialMovement
|
|
350
|
+
invoice?: Invoice
|
|
351
|
+
runningBalance: number
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export interface CashSessionSummary {
|
|
355
|
+
session: CashSession
|
|
356
|
+
movementCount: number
|
|
357
|
+
totalInflow: number
|
|
358
|
+
totalOutflow: number
|
|
359
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
|
+
import { CreditCard, Check } from 'lucide-react'
|
|
3
|
+
import { useFinancialConfig, useFinancialStore, formatCurrency } from '../FinancialContext'
|
|
4
|
+
import { SubpageHeader } from '@fayz-ai/ui'
|
|
5
|
+
import { useTranslation } from '@fayz-ai/core'
|
|
6
|
+
|
|
7
|
+
export function CardsView() {
|
|
8
|
+
const t = useTranslation()
|
|
9
|
+
const { currency, labels } = useFinancialConfig()
|
|
10
|
+
const cardTransactions = useFinancialStore((s) => s.cardTransactions)
|
|
11
|
+
const cardsLoading = useFinancialStore((s) => s.cardsLoading)
|
|
12
|
+
const fetchCardTransactions = useFinancialStore((s) => s.fetchCardTransactions)
|
|
13
|
+
|
|
14
|
+
useEffect(() => { fetchCardTransactions() }, [])
|
|
15
|
+
|
|
16
|
+
// Group by card brand
|
|
17
|
+
const byBrand: Record<string, typeof cardTransactions> = {}
|
|
18
|
+
for (const tx of cardTransactions) {
|
|
19
|
+
const brand = tx.cardBrand || 'Other'
|
|
20
|
+
if (!byBrand[brand]) byBrand[brand] = []
|
|
21
|
+
byBrand[brand].push(tx)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="space-y-4">
|
|
26
|
+
<SubpageHeader title={t('financial.cards.title')} subtitle={t('financial.cards.subtitle')} />
|
|
27
|
+
{cardsLoading ? (
|
|
28
|
+
<div className="text-center py-12 text-sm text-muted-foreground">Loading...</div>
|
|
29
|
+
) : cardTransactions.length === 0 ? (
|
|
30
|
+
<div className="flex flex-col items-center justify-center py-12 text-center rounded-lg border-2 border-dashed border-muted">
|
|
31
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-50 dark:bg-indigo-500/20 mb-2">
|
|
32
|
+
<CreditCard className="h-5 w-5 text-indigo-500" />
|
|
33
|
+
</div>
|
|
34
|
+
<p className="text-sm text-muted-foreground">{t('financial.cards.noTransactions')}</p>
|
|
35
|
+
<p className="text-xs text-muted-foreground mt-0.5">{t('financial.cards.transactionsAppear')}</p>
|
|
36
|
+
</div>
|
|
37
|
+
) : (
|
|
38
|
+
Object.entries(byBrand).map(([brand, txs]) => (
|
|
39
|
+
<div key={brand} className="rounded-lg border bg-card shadow-sm">
|
|
40
|
+
<div className="flex items-center gap-2 px-4 py-3 border-b">
|
|
41
|
+
<CreditCard className="h-4 w-4 text-indigo-500" />
|
|
42
|
+
<h3 className="text-sm font-semibold">{brand}</h3>
|
|
43
|
+
<span className="text-xs text-muted-foreground">({txs.length} transactions)</span>
|
|
44
|
+
</div>
|
|
45
|
+
<div className="divide-y">
|
|
46
|
+
{txs.map((tx) => (
|
|
47
|
+
<div key={tx.id} className="px-4 py-3 flex items-center justify-between">
|
|
48
|
+
<div>
|
|
49
|
+
<p className="text-sm font-medium">
|
|
50
|
+
Installment {tx.currentInstallment}/{tx.installmentCount}
|
|
51
|
+
</p>
|
|
52
|
+
<p className="text-xs text-muted-foreground">Due: {tx.expectedDate}</p>
|
|
53
|
+
</div>
|
|
54
|
+
<div className="flex items-center gap-3">
|
|
55
|
+
<span className="text-sm font-medium">{formatCurrency(tx.installmentAmount, currency)}</span>
|
|
56
|
+
{tx.status === 'received' ? (
|
|
57
|
+
<span className="inline-flex items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-[10px] font-medium text-success dark:bg-success/20">
|
|
58
|
+
<Check className="h-2.5 w-2.5" /> Received
|
|
59
|
+
</span>
|
|
60
|
+
) : (
|
|
61
|
+
<span className="inline-flex items-center rounded-full bg-warning/15 px-2 py-0.5 text-[10px] font-medium text-warning dark:bg-warning/20">
|
|
62
|
+
Pending
|
|
63
|
+
</span>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
))
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|