diff --git a/src/app/accounts/page.tsx b/src/app/accounts/page.tsx index fdb58d9..e1a4c25 100644 --- a/src/app/accounts/page.tsx +++ b/src/app/accounts/page.tsx @@ -442,7 +442,7 @@ export default function AccountsPage() {
- {isEmi ? 'REMAINING BALANCE' : 'OUTSTANDING PRINCIPAL'} + {isEmi ? 'REMAINING BALANCE' : 'OUTSTANDING BALANCE'}
- +
@@ -469,8 +470,8 @@ export default function LoansPage() {
- Principal Repaid: ₹{Math.round(loan.paidPrincipal / 100).toLocaleString('en-IN')} of ₹ - {Math.round(loan.principal / 100).toLocaleString('en-IN')} + Repaid: ₹{Math.round((loan.totalPaid ?? loan.paidPrincipal) / 100).toLocaleString('en-IN')} of ₹ + {Math.round((loan.totalPayable ?? loan.principal) / 100).toLocaleString('en-IN')} {loan.progressPercent}% Completed
@@ -501,27 +502,42 @@ export default function LoansPage() { Principal Interest Remaining Balance + Status - {amort.schedule.map((row: any) => ( - - #{row.monthNumber} - {row.paymentDate} - - ₹{Math.round(row.emi / 100).toLocaleString('en-IN')} - - - ₹{Math.round(row.principalComponent / 100).toLocaleString('en-IN')} - - - ₹{Math.round(row.interestComponent / 100).toLocaleString('en-IN')} - - - ₹{Math.round(row.remainingPrincipal / 100).toLocaleString('en-IN')} - - - ))} + {amort.schedule.map((row: any) => { + const isPaid = Boolean(row.isPaid); + return ( + + #{row.monthNumber} + {row.paymentDate} + + ₹{Math.round(row.emi / 100).toLocaleString('en-IN')} + + + ₹{Math.round(row.principalComponent / 100).toLocaleString('en-IN')} + + + ₹{Math.round(row.interestComponent / 100).toLocaleString('en-IN')} + + + ₹{Math.round((row.remainingBalance ?? row.remainingPrincipal) / 100).toLocaleString('en-IN')} + + + {isPaid ? ( + + ✓ Paid + + ) : ( + + Upcoming + + )} + + + ); + })}
@@ -828,9 +844,30 @@ export default function LoansPage() {
+ {payModalLoan.account_name && ( +
+
+ + Target Account: {payModalLoan.account_name} +
+ Repayment Transfer +
+ )} +

- This will record an expense transaction and automatically deduct ₹{Math.round(payModalLoan.emi_amount / 100).toLocaleString('en-IN')} from your liquid cash. + This will record a repayment transfer from your selected account to {payModalLoan.account_name || 'the linked debt account'}, reducing both your liquid cash and debt.

diff --git a/src/app/reports/page.tsx b/src/app/reports/page.tsx index 4afcca2..a2b0708 100644 --- a/src/app/reports/page.tsx +++ b/src/app/reports/page.tsx @@ -356,7 +356,7 @@ function ExpenseDonutChart({ letterSpacing="0.04em" style={{ textTransform: 'uppercase' }} > - {activeSlice ? (activeSlice.name.length > 14 ? activeSlice.name.substring(0, 12) + '…' : activeSlice.name) : 'TOTAL SPENT'} + {activeSlice ? (activeSlice.name.length > 14 ? activeSlice.name.substring(0, 12) + '…' : activeSlice.name) : (analyticsLabel === 'Tag' ? 'TOTAL TAGGED' : 'TOTAL SPENT')} - {activeSlice ? `${activeSlice.percentage}% of total` : `${slices.length} ${analyticsLabel.toLowerCase()}s`} + {activeSlice ? `${activeSlice.percentage}% of ${analyticsLabel === 'Tag' ? 'tagged' : 'total'}` : `${slices.length} ${analyticsLabel.toLowerCase()}s`} @@ -493,7 +493,9 @@ export default function ReportsPage() { const savingsRate = totalMonthIncome > 0 ? Math.round(((totalMonthIncome - totalMonthSpend) / totalMonthIncome) * 100) : 0; // Active analytics data based on view mode + const totalTaggedSpend = useMemo(() => spendingByTag.reduce((acc: number, t: any) => acc + (t.total || 0), 0), [spendingByTag]); const activeAnalytics = analyticsView === 'category' ? spendingByCategory : spendingByTag; + const activeAnalyticsTotal = analyticsView === 'category' ? totalMonthSpend : totalTaggedSpend; const analyticsLabel = analyticsView === 'category' ? 'Category' : 'Tag'; return ( @@ -1101,7 +1103,7 @@ export default function ReportsPage() { > { setAccounts(d.accounts); if (!editingTransaction) { if (preselectedAccountId) { - setAccountId(preselectedAccountId); + const preselectedAcc = d.accounts.find((a: any) => a.id === preselectedAccountId); + if (preselectedAcc && preselectedAcc.type === 'credit_card' && transactionModalType === 'transfer') { + const defaultBank = d.accounts.find((a: any) => a.id !== preselectedAcc.id && a.type !== 'credit_card') || d.accounts.find((a: any) => a.id !== preselectedAcc.id); + if (defaultBank) setAccountId(defaultBank.id); + setDestinationAccountId(preselectedAcc.id); + setSelectedTags(prev => prev.some(t => t.name.toLowerCase() === 'cc-repayment') ? prev : [...prev, { id: 'cc-repayment', name: 'cc-repayment', color: '#3B82F6' }]); + } else { + setAccountId(preselectedAccountId); + const otherAcc = d.accounts.find((a: any) => a.id !== preselectedAccountId); + if (otherAcc) setDestinationAccountId(otherAcc.id); + } } else { const defaultAcc = d.accounts.find((a: any) => Boolean(a.is_default)) || d.accounts[0]; if (defaultAcc) { setAccountId(defaultAcc.id); const otherAcc = d.accounts.find((a: any) => a.id !== defaultAcc.id); - if (otherAcc) setDestinationAccountId(otherAcc.id); + if (otherAcc) { + setDestinationAccountId(otherAcc.id); + if (otherAcc.type === 'credit_card' && transactionModalType === 'transfer') { + setSelectedTags(prev => prev.some(t => t.name.toLowerCase() === 'cc-repayment') ? prev : [...prev, { id: 'cc-repayment', name: 'cc-repayment', color: '#3B82F6' }]); + } + } } } } @@ -517,6 +532,7 @@ export const TransactionModal = () => { amount: minorAmount, date, notes, + tags: selectedTags.map(t => t.name), }), }); const data = await res.json(); @@ -1006,7 +1022,14 @@ export const TransactionModal = () => {