167 lines
5.6 KiB
TypeScript
167 lines
5.6 KiB
TypeScript
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<string, string>, c: string) => {
|
|
a[c] = c;
|
|
return a;
|
|
},
|
|
init as Record<string, string>,
|
|
);
|
|
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);
|
|
}
|
|
}
|