import { CurrencyPipe, DecimalPipe } from '@angular/common'; import { signal, Component, inject, input, computed, linkedSignal } from '@angular/core'; import { form as createForm, FormField, FormRoot } from '@angular/forms/signals'; import { MatButtonModule } from '@angular/material/button'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatTableModule } from '@angular/material/table'; import { Router } from '@angular/router'; import moment from 'moment'; import { AuthService } from '../auth/auth.service'; import { Account } from '../core/account'; import { AccountBalance } from '../core/account-balance'; import { Incentive } from '../core/incentive'; import { User } from '../core/user'; import { Voucher } from '../core/voucher'; import { VoucherService } from '../core/voucher.service'; import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component'; import { LocalTimePipe } from '../shared/local-time.pipe'; export interface IncentiveFormData { date: Date; incentives: { points: number }[]; } @Component({ selector: 'app-incentive', templateUrl: './incentive.component.html', styleUrls: ['./incentive.component.css'], host: { '(window:keydown.f2)': 'focusDate($event)', }, imports: [ FormField, FormRoot, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatTableModule, MatIconModule, MatButtonModule, DecimalPipe, CurrencyPipe, LocalTimePipe, ], }) export class IncentiveComponent { private router = inject(Router); private dialog = inject(MatDialog); private snackBar = inject(MatSnackBar); auth = inject(AuthService); private ser = inject(VoucherService); id = input(null, { transform: (v: string | null | undefined) => v ?? null }); voucherResource = this.ser.getVoucher(this.id, signal('Incentive'), signal(null), signal(null)); voucher = computed(() => this.voucherResource.value() ?? new Voucher()); model = linkedSignal({ source: this.voucher, computation: (v): IncentiveFormData => ({ date: moment(v.date, 'DD-MMM-YYYY').toDate(), incentives: v.incentives.map((x) => ({ points: x.points })), }), }); form = createForm(this.model); incentives = linkedSignal(() => this.voucher().incentives); account: Account = new Account(); accBal: AccountBalance | null = null; displayedColumns = ['name', 'designation', 'department', 'daysWorked', 'points', 'amount']; focusDate(event: Event) { event.preventDefault(); this.form().focusBoundControl(); } totalPoints = computed(() => { return this.incentives() .map((item: Incentive, i: number) => item.daysWorked * (this.model().incentives[i]?.points ?? 0)) .reduce((sum: number, item: number) => sum + item, 0); }); pointValue = computed(() => { const tp = this.totalPoints(); if (!tp) return 0; return Math.round(((this.voucher().incentive as number) * 100) / tp) / 100; }); less(i: number) { const currentPoints = this.model().incentives[i]?.points ?? 0; if (currentPoints >= 1) { this.model.update((m) => { const arr = [...m.incentives]; if (arr[i]) { arr[i] = { ...arr[i], points: currentPoints - 1 }; } return { ...m, incentives: arr }; }); } } more(i: number) { const currentPoints = this.model().incentives[i]?.points ?? 0; this.model.update((m) => { const arr = [...m.incentives]; if (arr[i]) { arr[i] = { ...arr[i], points: currentPoints + 1 }; } return { ...m, incentives: arr }; }); } amount(row: Incentive, i: number) { const currentPoints = this.model().incentives[i]?.points ?? 0; return currentPoints * row.daysWorked * this.pointValue(); } canSave() { if (!this.voucher().id) { return true; } if (this.voucher().posted && this.auth.allowed('edit-posted-vouchers')) { return true; } return this.voucher().user.id === (this.auth.user as User).id || this.auth.allowed("edit-other-user's-vouchers"); } post() { this.ser.post(this.voucher().id as string).subscribe({ next: (result: Voucher) => { this.snackBar.open('Voucher Posted', 'Success'); this.router.navigate(['/incentive', (result as Voucher).id], { replaceUrl: true }); }, error: (error) => { this.snackBar.open(error as string, 'Danger'); }, }); } save() { const voucher: Voucher = this.getVoucher(); this.ser.saveOrUpdate(voucher).subscribe({ next: (result: Voucher) => { this.router.navigate(['/incentive', (result as Voucher).id], { replaceUrl: true }); }, error: (error) => { this.snackBar.open(error as string, 'Danger'); }, }); } getVoucher(): Voucher { const formModel = this.model(); const v = this.voucher(); v.date = moment(formModel.date).format('DD-MMM-YYYY'); const array = formModel.incentives; v.incentives.forEach((item: Incentive, index: number) => { item.points = array[index]?.points ?? 0; }); return v; } delete() { this.ser.delete(this.voucher().id as string).subscribe({ next: () => { this.snackBar.open('', 'Success'); this.router.navigate(['/incentive'], { replaceUrl: true }); }, error: (error) => { this.snackBar.open(error as string, 'Danger'); }, }); } confirmDelete(): void { const dialogRef = this.dialog.open(ConfirmDialogComponent, { width: '250px', data: { title: 'Delete Voucher?', content: 'Are you sure? This cannot be undone.' }, }); dialogRef.afterClosed().subscribe((result: boolean) => { if (result) { this.delete(); } }); } }