import { CommonModule, isPlatformBrowser } from '@angular/common'; import { Component, ElementRef, Inject, PLATFORM_ID, ViewChild, AfterViewInit, OnInit } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; import Chart from 'chart.js/auto'; import { ParcelamentoService, ParcelamentoKpis, ParcelamentoMonthlyPoint, ParcelamentoTopLine } from '../../services/parcelamento.service'; @Component({ selector: 'app-parcelamento', standalone: true, imports: [CommonModule, FormsModule, HttpClientModule], templateUrl: './parcelamento.html', styleUrl: './parcelamento.scss' }) export class Parcelamento implements OnInit, AfterViewInit { @ViewChild('monthlyCanvas') monthlyCanvas!: ElementRef; @ViewChild('topLinesCanvas') topLinesCanvas!: ElementRef; private monthlyChart?: Chart; private topLinesChart?: Chart; loading = false; clients: string[] = []; selectedClient: string = ''; lineSearch: string = ''; kpis: ParcelamentoKpis = { linhas: 0, clientes: 0, totalValorCheio: 0, totalDesconto: 0, totalComDesconto: 0, meses: 0 }; monthlySeries: ParcelamentoMonthlyPoint[] = []; topLines: ParcelamentoTopLine[] = []; constructor( private parcelamentoService: ParcelamentoService, @Inject(PLATFORM_ID) private platformId: Object ) {} async ngOnInit() { await this.loadClients(); await this.refreshAll(); } ngAfterViewInit() { if (isPlatformBrowser(this.platformId)) { this.renderCharts(); } } private buildOpts() { const cliente = this.selectedClient?.trim() || undefined; const linha = this.onlyDigits(this.lineSearch) || undefined; return { cliente, linha }; } async loadClients() { try { this.clients = await firstValueFrom(this.parcelamentoService.getClients()); } catch { this.clients = []; } } async refreshAll() { this.loading = true; try { const opts = this.buildOpts(); this.kpis = await firstValueFrom(this.parcelamentoService.getKpis(opts)); this.monthlySeries = await firstValueFrom(this.parcelamentoService.getMonthlySeries(opts)); this.topLines = await firstValueFrom( this.parcelamentoService.getTopLines({ cliente: opts.cliente, take: 10 }) ); this.renderCharts(); } finally { this.loading = false; } } onClearFilters() { this.selectedClient = ''; this.lineSearch = ''; this.refreshAll(); } onApplyFilters() { this.refreshAll(); } private renderCharts() { if (!isPlatformBrowser(this.platformId)) return; if (!this.monthlyCanvas || !this.topLinesCanvas) return; this.renderMonthlyChart(); this.renderTopLinesChart(); } private renderMonthlyChart() { const labels = this.monthlySeries.map(x => x.label); const values = this.monthlySeries.map(x => x.total ?? 0); if (this.monthlyChart) this.monthlyChart.destroy(); this.monthlyChart = new Chart(this.monthlyCanvas.nativeElement.getContext('2d')!, { type: 'bar', data: { labels, datasets: [{ label: 'Valor por mês (R$)', data: values }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true }, tooltip: { callbacks: { label: (ctx) => { const y = (ctx.parsed as any)?.y; return ` ${this.money(typeof y === 'number' ? y : 0)}`; } } } }, scales: { y: { ticks: { callback: (v: any) => this.money(Number(v) || 0) } } } } }); } private renderTopLinesChart() { const labels = this.topLines.map(x => (x.linha ?? '').toString()); const values = this.topLines.map(x => x.total ?? 0); if (this.topLinesChart) this.topLinesChart.destroy(); this.topLinesChart = new Chart(this.topLinesCanvas.nativeElement.getContext('2d')!, { type: 'bar', data: { labels, datasets: [{ label: 'Top 10 linhas (Total R$)', data: values }] }, options: { indexAxis: 'y', responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true }, tooltip: { callbacks: { label: (ctx) => { const x = (ctx.parsed as any)?.x; return ` ${this.money(typeof x === 'number' ? x : 0)}`; } } } }, scales: { x: { ticks: { callback: (v: any) => this.money(Number(v) || 0) } } } } }); } money(v: number) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(v ?? 0); } private onlyDigits(s: string) { return (s ?? '').replace(/\D/g, ''); } }