@fayz-ai/plugin-financial 0.9.0 → 0.9.2
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/README.md +3 -3
- package/dist/components/PersonStatementWidget.d.ts +1 -1
- package/dist/components/PersonStatementWidget.d.ts.map +1 -1
- package/dist/{FinancialContext.d.ts → context.d.ts} +4 -2
- package/dist/context.d.ts.map +1 -0
- package/dist/data/registries.d.ts.map +1 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1426 -1426
- package/dist/index.js.map +1 -1
- package/dist/integrations/stripe/connectorDef.d.ts +14 -0
- package/dist/integrations/stripe/connectorDef.d.ts.map +1 -0
- package/dist/integrations/stripe/data.d.ts +43 -0
- package/dist/integrations/stripe/data.d.ts.map +1 -0
- package/dist/lib/message-events.d.ts +12 -0
- package/dist/lib/message-events.d.ts.map +1 -0
- package/dist/{quick-add.d.ts → lib/quick-add.d.ts} +1 -1
- package/dist/lib/quick-add.d.ts.map +1 -0
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/{FinancialPage.d.ts → views/FinancialPage.d.ts} +3 -3
- package/dist/views/FinancialPage.d.ts.map +1 -0
- package/dist/views/InvoiceDetailView.d.ts.map +1 -1
- package/dist/views/InvoiceFormView.d.ts.map +1 -1
- package/dist/views/InvoiceListView.d.ts.map +1 -1
- package/dist/views/PayablesView.d.ts +1 -1
- package/dist/views/PayablesView.d.ts.map +1 -1
- package/dist/views/ReceivablesView.d.ts +1 -1
- package/dist/views/ReceivablesView.d.ts.map +1 -1
- package/dist/views/StatementsView.d.ts.map +1 -1
- package/dist/views/dashboardWidgets.d.ts +1 -1
- package/dist/views/dashboardWidgets.d.ts.map +1 -1
- package/package.json +12 -14
- package/dist/FinancialContext.d.ts.map +0 -1
- package/dist/FinancialPage.d.ts.map +0 -1
- package/dist/contract.test.d.ts +0 -2
- package/dist/contract.test.d.ts.map +0 -1
- package/dist/quick-add.d.ts.map +0 -1
- package/dist/registries.d.ts.map +0 -1
- package/src/FinancialContext.tsx +0 -59
- package/src/FinancialPage.tsx +0 -413
- package/src/README.md +0 -155
- package/src/components/FinancialGeneralSettings.tsx +0 -39
- package/src/components/FinancialOnboarding.tsx +0 -87
- package/src/components/FinancialSettings.tsx +0 -31
- package/src/components/PaymentModal.tsx +0 -369
- package/src/components/PersonStatementWidget.tsx +0 -133
- package/src/components/TransferModal.tsx +0 -150
- package/src/contract.test.ts +0 -58
- package/src/data/capability.test.ts +0 -135
- package/src/data/index.ts +0 -3
- package/src/data/mock.ts +0 -842
- package/src/data/supabase.ts +0 -968
- package/src/data/tables.ts +0 -13
- package/src/data/types.ts +0 -86
- package/src/index.ts +0 -487
- package/src/lib/tenant.ts +0 -3
- package/src/locales/en.ts +0 -493
- package/src/locales/index.ts +0 -7
- package/src/locales/pt-BR.ts +0 -493
- package/src/migrations/000_plg_rename.sql +0 -30
- package/src/migrations/001_financial_base.sql +0 -109
- package/src/migrations/002_chart_of_accounts.sql +0 -28
- package/src/migrations/003_card_brands.sql +0 -12
- package/src/migrations/004_order_to_cash.sql +0 -178
- package/src/migrations/005_seed_defaults.sql +0 -38
- package/src/migrations/006_rls_policies.sql +0 -37
- package/src/migrations/006b_extract_fee_amount.sql +0 -20
- package/src/migrations/007_reconciliation.sql +0 -32
- package/src/migrations/007b_movement_payment_method_type.sql +0 -6
- package/src/migrations/008_split_payment_movements.sql +0 -29
- package/src/migrations/009_agent_rpcs.sql +0 -165
- package/src/migrations/010_invoice_internal.sql +0 -133
- package/src/migrations/011_nfe.sql +0 -58
- package/src/migrations/index.ts +0 -923
- package/src/quick-add.ts +0 -58
- package/src/registries.ts +0 -308
- package/src/store.ts +0 -329
- package/src/types.ts +0 -592
- package/src/views/CardsView.tsx +0 -213
- package/src/views/CashRegistersView.tsx +0 -597
- package/src/views/CommissionsView.tsx +0 -18
- package/src/views/InvoiceDetailView.tsx +0 -616
- package/src/views/InvoiceFormView.tsx +0 -945
- package/src/views/InvoiceListView.tsx +0 -323
- package/src/views/NotasFiscaisView.tsx +0 -209
- package/src/views/PayablesView.tsx +0 -48
- package/src/views/QuickTransactionForm.tsx +0 -548
- package/src/views/ReceivablesView.tsx +0 -48
- package/src/views/ReconciliationView.tsx +0 -211
- package/src/views/StatementsView.tsx +0 -335
- package/src/views/SummaryView.tsx +0 -203
- package/src/views/dashboardWidgets.tsx +0 -437
- package/src/views/navReferrer.ts +0 -24
- /package/dist/{registries.d.ts → data/registries.d.ts} +0 -0
package/src/views/CardsView.tsx
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react'
|
|
2
|
-
import { CreditCard, Plus, CalendarClock } from 'lucide-react'
|
|
3
|
-
import { useFinancialConfig, useFinancialStore, formatCurrency } from '../FinancialContext'
|
|
4
|
-
import { SubpageHeader } from '@fayz-ai/ui'
|
|
5
|
-
import { PermissionGate } from '@fayz-ai/saas'
|
|
6
|
-
import { useTranslation } from '@fayz-ai/core'
|
|
7
|
-
import type { BankAccount } from '../types'
|
|
8
|
-
import { QuickTransactionForm } from './QuickTransactionForm'
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// Per-card money math. Credit-card balances are stored as debt (negative), so
|
|
12
|
-
// the current bill (fatura) is the magnitude owed; the available limit is what
|
|
13
|
-
// remains of the credit line.
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
function cardMath(acc: BankAccount) {
|
|
17
|
-
const limit = acc.creditLimit ?? 0
|
|
18
|
-
const used = Math.max(0, -acc.currentBalance)
|
|
19
|
-
const available = Math.max(0, limit - used)
|
|
20
|
-
const pct = limit > 0 ? Math.min(100, (used / limit) * 100) : 0
|
|
21
|
-
return { limit, used, available, pct }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function CardsView() {
|
|
25
|
-
const t = useTranslation()
|
|
26
|
-
const { currency } = useFinancialConfig()
|
|
27
|
-
const bankAccounts = useFinancialStore((s) => s.bankAccounts)
|
|
28
|
-
const bankAccountsLoading = useFinancialStore((s) => s.bankAccountsLoading)
|
|
29
|
-
const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts)
|
|
30
|
-
|
|
31
|
-
const [tab, setTab] = useState<'open' | 'closed'>('open')
|
|
32
|
-
const [addOpen, setAddOpen] = useState(false)
|
|
33
|
-
const [addCardId, setAddCardId] = useState<string | undefined>()
|
|
34
|
-
|
|
35
|
-
useEffect(() => { fetchBankAccounts() }, [])
|
|
36
|
-
|
|
37
|
-
const cards = useMemo(
|
|
38
|
-
() => bankAccounts.filter((a) => a.accountType === 'credit_card'),
|
|
39
|
-
[bankAccounts],
|
|
40
|
-
)
|
|
41
|
-
const openCards = useMemo(() => cards.filter((c) => c.isActive), [cards])
|
|
42
|
-
const closedCards = useMemo(() => cards.filter((c) => !c.isActive), [cards])
|
|
43
|
-
const visibleCards = tab === 'open' ? openCards : closedCards
|
|
44
|
-
|
|
45
|
-
// Summary strip is computed over the active (open) cards — the money that is
|
|
46
|
-
// actually in play this cycle.
|
|
47
|
-
const summary = useMemo(() => {
|
|
48
|
-
let totalAvailable = 0
|
|
49
|
-
let totalBills = 0
|
|
50
|
-
for (const c of openCards) {
|
|
51
|
-
const { available, used } = cardMath(c)
|
|
52
|
-
totalAvailable += available
|
|
53
|
-
totalBills += used
|
|
54
|
-
}
|
|
55
|
-
return { totalAvailable, totalBills }
|
|
56
|
-
}, [openCards])
|
|
57
|
-
|
|
58
|
-
function openAddExpense(cardId: string) {
|
|
59
|
-
setAddCardId(cardId)
|
|
60
|
-
setAddOpen(true)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div className="space-y-4">
|
|
65
|
-
<SubpageHeader title={t('financial.cards.title')} subtitle={t('financial.cards.subtitle')} />
|
|
66
|
-
|
|
67
|
-
{bankAccountsLoading && cards.length === 0 ? (
|
|
68
|
-
<div className="text-center py-12 text-sm text-muted-foreground">Loading...</div>
|
|
69
|
-
) : cards.length === 0 ? (
|
|
70
|
-
<div className="flex flex-col items-center justify-center py-12 text-center rounded-2xl border-2 border-dashed border-muted">
|
|
71
|
-
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-gradient-to-br from-amber-300 to-yellow-600 mb-3 text-white shadow-sm">
|
|
72
|
-
<CreditCard className="h-6 w-6" />
|
|
73
|
-
</div>
|
|
74
|
-
<p className="text-sm font-medium">{t('financial.cards.noCards')}</p>
|
|
75
|
-
<p className="text-xs text-muted-foreground mt-0.5 max-w-xs">{t('financial.cards.noCardsHint')}</p>
|
|
76
|
-
</div>
|
|
77
|
-
) : (
|
|
78
|
-
<>
|
|
79
|
-
{/* Summary strip — available limit + total bills across open cards */}
|
|
80
|
-
<div className="grid grid-cols-2 gap-px overflow-hidden rounded-2xl border bg-border shadow-sm">
|
|
81
|
-
<div className="bg-card px-4 py-3">
|
|
82
|
-
<p className="text-xs text-muted-foreground">{t('financial.cards.availableLimit')}</p>
|
|
83
|
-
<p className="mt-0.5 text-lg font-bold tabular-nums text-success">
|
|
84
|
-
{formatCurrency(summary.totalAvailable, currency)}
|
|
85
|
-
</p>
|
|
86
|
-
</div>
|
|
87
|
-
<div className="bg-card px-4 py-3">
|
|
88
|
-
<p className="text-xs text-muted-foreground">{t('financial.cards.allBillsValue')}</p>
|
|
89
|
-
<p className="mt-0.5 text-lg font-bold tabular-nums">
|
|
90
|
-
{formatCurrency(summary.totalBills, currency)}
|
|
91
|
-
</p>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
{/* Open / Closed tabs (only when there are closed cards to switch to) */}
|
|
96
|
-
{closedCards.length > 0 && (
|
|
97
|
-
<div className="flex gap-1 rounded-full bg-muted p-1 w-full max-w-xs">
|
|
98
|
-
{(['open', 'closed'] as const).map((k) => (
|
|
99
|
-
<button
|
|
100
|
-
key={k}
|
|
101
|
-
onClick={() => setTab(k)}
|
|
102
|
-
className={`flex-1 rounded-full px-3 py-1.5 text-xs font-medium transition-colors ${
|
|
103
|
-
tab === k ? 'bg-card text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'
|
|
104
|
-
}`}
|
|
105
|
-
>
|
|
106
|
-
{k === 'open' ? t('financial.cards.tabOpen') : t('financial.cards.tabClosed')}
|
|
107
|
-
</button>
|
|
108
|
-
))}
|
|
109
|
-
</div>
|
|
110
|
-
)}
|
|
111
|
-
|
|
112
|
-
{/* Card tiles — stacked on mobile, grid on desktop */}
|
|
113
|
-
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
114
|
-
{visibleCards.map((card) => {
|
|
115
|
-
const { limit, used, available, pct } = cardMath(card)
|
|
116
|
-
const over = pct >= 90
|
|
117
|
-
// Per-brand color so cards match the bank (and the Home card), not a uniform gold.
|
|
118
|
-
const brand = `${card.bankName ?? ''} ${card.name ?? ''}`.toLowerCase()
|
|
119
|
-
const headerGrad =
|
|
120
|
-
brand.includes('nubank') || brand.includes('nu ') ? 'from-purple-500 via-purple-600 to-indigo-700'
|
|
121
|
-
: brand.includes('ita') ? 'from-orange-400 via-orange-500 to-amber-600'
|
|
122
|
-
: brand.includes('inter') ? 'from-orange-500 via-orange-600 to-orange-700'
|
|
123
|
-
: 'from-indigo-500 via-indigo-600 to-violet-700'
|
|
124
|
-
const barGrad =
|
|
125
|
-
brand.includes('nubank') || brand.includes('nu ') ? 'from-purple-500 to-indigo-600'
|
|
126
|
-
: brand.includes('ita') ? 'from-orange-400 to-amber-500'
|
|
127
|
-
: brand.includes('inter') ? 'from-orange-500 to-orange-600'
|
|
128
|
-
: 'from-indigo-500 to-violet-600'
|
|
129
|
-
return (
|
|
130
|
-
<div key={card.id} className="overflow-hidden rounded-2xl border bg-card shadow-sm">
|
|
131
|
-
{/* Per-brand header */}
|
|
132
|
-
<div className={`bg-gradient-to-br ${headerGrad} px-4 py-4 text-white`}>
|
|
133
|
-
<div className="flex items-start justify-between">
|
|
134
|
-
<div className="flex items-center gap-2">
|
|
135
|
-
<CreditCard className="h-5 w-5" />
|
|
136
|
-
<span className="text-sm font-semibold">{card.name}</span>
|
|
137
|
-
</div>
|
|
138
|
-
{card.bankName && (
|
|
139
|
-
<span className="text-[11px] font-medium uppercase tracking-wide opacity-80">
|
|
140
|
-
{card.bankName}
|
|
141
|
-
</span>
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
<div className="mt-4">
|
|
145
|
-
<p className="text-[11px] uppercase tracking-wide opacity-80">
|
|
146
|
-
{t('financial.cards.currentBill')}
|
|
147
|
-
</p>
|
|
148
|
-
<p className="text-2xl font-bold tabular-nums leading-tight">
|
|
149
|
-
{formatCurrency(used, currency)}
|
|
150
|
-
</p>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
|
|
154
|
-
{/* Body */}
|
|
155
|
-
<div className="space-y-3 px-4 py-3">
|
|
156
|
-
{/* Usage progress bar */}
|
|
157
|
-
<div>
|
|
158
|
-
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
159
|
-
<span>{t('financial.cards.usedOfLimit', { percent: String(Math.round(pct)) })}</span>
|
|
160
|
-
<span className="tabular-nums">{formatCurrency(limit, currency)}</span>
|
|
161
|
-
</div>
|
|
162
|
-
<div className="mt-1 h-2 overflow-hidden rounded-full bg-muted">
|
|
163
|
-
<div
|
|
164
|
-
className={`h-full rounded-full ${
|
|
165
|
-
over ? 'bg-destructive' : `bg-gradient-to-r ${barGrad}`
|
|
166
|
-
}`}
|
|
167
|
-
style={{ width: `${pct}%` }}
|
|
168
|
-
/>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
{/* Available limit + due date */}
|
|
173
|
-
<div className="flex items-center justify-between">
|
|
174
|
-
<div>
|
|
175
|
-
<p className="text-[11px] text-muted-foreground">{t('financial.cards.availableLimit')}</p>
|
|
176
|
-
<p className="text-sm font-semibold tabular-nums">{formatCurrency(available, currency)}</p>
|
|
177
|
-
</div>
|
|
178
|
-
{card.dueDay != null && (
|
|
179
|
-
<div className="flex items-center gap-1.5 text-right text-xs text-muted-foreground">
|
|
180
|
-
<CalendarClock className="h-3.5 w-3.5" />
|
|
181
|
-
<span>{t('financial.cards.dueOn', { day: String(card.dueDay) })}</span>
|
|
182
|
-
</div>
|
|
183
|
-
)}
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Add expense against this card — gated on the role's create action */}
|
|
187
|
-
<PermissionGate feature="financial" action="create">
|
|
188
|
-
<button
|
|
189
|
-
type="button"
|
|
190
|
-
onClick={() => openAddExpense(card.id)}
|
|
191
|
-
className="flex w-full items-center justify-center gap-1.5 rounded-input border border-input bg-card px-3 py-2 text-xs font-medium text-foreground transition-colors hover:bg-muted/40"
|
|
192
|
-
>
|
|
193
|
-
<Plus className="h-3.5 w-3.5" />
|
|
194
|
-
{t('financial.cards.addExpense')}
|
|
195
|
-
</button>
|
|
196
|
-
</PermissionGate>
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
)
|
|
200
|
-
})}
|
|
201
|
-
</div>
|
|
202
|
-
</>
|
|
203
|
-
)}
|
|
204
|
-
|
|
205
|
-
<QuickTransactionForm
|
|
206
|
-
open={addOpen}
|
|
207
|
-
onOpenChange={setAddOpen}
|
|
208
|
-
defaultType="expense"
|
|
209
|
-
defaultAccountId={addCardId}
|
|
210
|
-
/>
|
|
211
|
-
</div>
|
|
212
|
-
)
|
|
213
|
-
}
|