import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common'; import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core'; import { Chart, LineController, LineElement, PointElement, CategoryScale, LinearScale, Tooltip, Legend } from 'chart.js'; import { StatsService } from '../../core/services/stats.service'; import { UiService } from '../../core/services/ui.service'; import type { CashflowResponse } from '../../shared/models'; Chart.register(LineController, LineElement, PointElement, CategoryScale, LinearScale, Tooltip, Legend); @Component({ selector: 'app-cashflow', standalone: true, imports: [CommonModule, CurrencyPipe, DatePipe], template: `
{{ ui.t('cashflow.actual') }}
{{ (data()?.actualCurrent || 0) | currency:'PLN':'symbol':'1.2-2' }}
{{ ui.t('cashflow.budget') }}
{{ (data()?.totalBudget || 0) | currency:'PLN':'symbol':'1.2-2' }}
{{ ui.t('cashflow.forecast') }}
{{ (data()?.forecastCurrentMonth || 0) | currency:'PLN':'symbol':'1.2-2' }}
{{ ui.t('cashflow.pending') }}
{{ data()?.pendingApproval || 0 }}

{{ ui.t('cashflow.trend') }}

{{ ui.t('budget.alerts') }}

@for (alert of data()?.alerts || []; track alert.id) {
{{ alert.name }} ยท {{ alert.usagePercent }}%
} @empty {
{{ ui.t('common.noData') }}
}

{{ ui.t('cashflow.statusSummary') }}

@for (item of data()?.statusSummary || []; track item.status) { } @empty { }
{{ ui.t('expenses.field.status') }}{{ ui.t('table.count') }}
{{ ui.t('status.' + item.status.toLowerCase()) }}{{ item.count }}
{{ ui.t('common.noData') }}

{{ ui.t('cashflow.upcomingRecurring') }}

@for (item of data()?.upcomingRecurring || []; track item.id) { } @empty { }
{{ ui.t('table.title') }}{{ ui.t('table.date') }}{{ ui.t('table.amount') }}
{{ item.title }}{{ item.nextRunDate | date:'yyyy-MM-dd' }}{{ item.amount | currency:'PLN':'symbol':'1.2-2' }}
{{ ui.t('common.noData') }}
` }) export class CashflowComponent implements OnInit, OnDestroy { readonly ui = inject(UiService); private readonly statsService = inject(StatsService); readonly data = signal(null); private chart?: Chart; ngOnInit() { this.statsService.cashflow().subscribe({ next: (response) => { this.data.set(response); requestAnimationFrame(() => this.renderChart()); } }); } ngOnDestroy() { this.chart?.destroy(); } private renderChart() { const canvas = document.getElementById('cashflowTrendChart') as HTMLCanvasElement | null; const data = this.data(); if (!canvas || !data?.trend?.length) { this.chart?.destroy(); return; } this.chart?.destroy(); this.chart = new Chart(canvas, { type: 'line', data: { labels: data.trend.map((item) => item.label), datasets: [ { label: this.ui.t('cashflow.actual'), data: data.trend.map((item) => item.actual), borderColor: '#206bc4', backgroundColor: '#206bc4', tension: 0.25 }, { label: this.ui.t('cashflow.budget'), data: data.trend.map((item) => item.budget), borderColor: '#2fb344', backgroundColor: '#2fb344', tension: 0.25 } ] }, options: { maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { color: '#9ca3af' } } }, scales: { x: { ticks: { color: '#9ca3af' } }, y: { ticks: { color: '#9ca3af' } } } } }); } }