import { CommonModule } from '@angular/common'; import { Component, inject, computed, linkedSignal, input } from '@angular/core'; import { form, FormField, required } from '@angular/forms/signals'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; import { Router } from '@angular/router'; import { DateTime } from 'luxon'; import { SaleCategoryService } from '../sale-category/sale-category.service'; import { ErrorStateComponent } from '../shared/error-state/error-state.component'; import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component'; import { ToCsvService } from '../shared/to-csv.service'; import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface'; import { BeerSaleReport } from './beer-sale-report'; import { BeerSaleReportService } from './beer-sale-report.service'; export interface BeerSaleReportFormData { startDate: DateTime; finishDate: DateTime; saleCategory: string; regular: boolean; happy: boolean; staff: boolean; nc: boolean; } @Component({ selector: 'app-beer-sale-report', templateUrl: './beer-sale-report.component.html', styleUrls: ['./beer-sale-report.component.css'], imports: [ CommonModule, MatButtonModule, MatCheckboxModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSelectModule, MatTableModule, FormField, ErrorStateComponent, SkeletonLoaderComponent, ], }) export class BeerSaleReportComponent { private router = inject(Router); private toCsv = inject(ToCsvService); private ser = inject(BeerSaleReportService); private saleCategoryService = inject(SaleCategoryService); startDate = input(null, { transform: (v: string | null | undefined) => v ?? null }); finishDate = input(null, { transform: (v: string | null | undefined) => v ?? null }); saleCategory = input(null, { transform: (v: string | null | undefined) => v ?? null }); regular = input(true, { transform: (v: string | null | undefined) => v !== 'false' }); happy = input(true, { transform: (v: string | null | undefined) => v !== 'false' }); staff = input(true, { transform: (v: string | null | undefined) => v !== 'false' }); nc = input(true, { transform: (v: string | null | undefined) => v !== 'false' }); saleCategoriesResource = this.saleCategoryService.list(); infoResource = this.ser.get( this.startDate, this.finishDate, this.saleCategory, this.regular, this.happy, this.staff, this.nc, ); saleCategories = computed(() => this.saleCategoriesResource.value() ?? []); info = computed(() => this.infoResource.value()); dataSource = computed(() => this.info()?.data ?? []); formModel = linkedSignal({ source: () => this.info(), computation: (info): BeerSaleReportFormData => { if (info) { return { startDate: DateTime.fromFormat(info.startDate, 'dd-MMM-yyyy'), finishDate: DateTime.fromFormat(info.finishDate, 'dd-MMM-yyyy'), saleCategory: info.saleCategory?.id ?? '', regular: info.regular, happy: info.happy, staff: info.staff, nc: info.nc, }; } return { startDate: DateTime.now(), finishDate: DateTime.now(), saleCategory: '', regular: true, happy: true, staff: true, nc: true, }; }, }); form = form(this.formModel, (schemaPath) => { required(schemaPath.saleCategory, { message: 'Sale Category is required' }); }); /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = computed(() => { const headers = this.info()?.headers ?? []; return ['date'].concat(headers); }); show() { const info = this.getInfo(); this.router.navigate(['beer-sale-report'], { queryParams: { startDate: info.startDate, finishDate: info.finishDate, saleCategory: info.saleCategory?.id ?? '', regular: info.regular, happy: info.happy, staff: info.staff, nc: info.nc, }, }); } getInfo(): BeerSaleReport { const formModel = this.formModel(); return new BeerSaleReport({ startDate: formModel.startDate.toFormat('dd-MMM-yyyy'), finishDate: formModel.finishDate.toFormat('dd-MMM-yyyy'), saleCategory: this.saleCategories().find((sc) => sc.id === formModel.saleCategory), regular: formModel.regular, happy: formModel.happy, staff: formModel.staff, nc: formModel.nc, }); } exportCsv() { const currentInfo = this.info(); if (!currentInfo) return; const init: BeerSaleExportHeaderInterface = { Date: 'date' }; const headers = currentInfo.headers.reduce( (a: Record, c: string) => { a[c] = c; return a; }, init as Record, ); const csvData = new Blob([this.toCsv.toCsv(headers, currentInfo.data)], { type: 'text/csv;charset=utf-8;', }); const link = document.createElement('a'); link.href = window.URL.createObjectURL(csvData); link.setAttribute('download', 'beer-sale-report.csv'); document.body.appendChild(link); link.click(); document.body.removeChild(link); } }