import { CurrencyPipe, DecimalPipe } from '@angular/common'; import { Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormArray, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; 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 { ActivatedRoute, Router } from '@angular/router'; import moment from 'moment'; import { BehaviorSubject } from 'rxjs'; import { map } from 'rxjs/operators'; 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'; import { IncentiveDataSource } from './incentive-datasource'; @Component({ selector: 'app-incentive', templateUrl: './incentive.component.html', styleUrls: ['./incentive.component.css'], imports: [ MatCardModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatTableModule, MatIconModule, MatButtonModule, DecimalPipe, CurrencyPipe, LocalTimePipe, ], }) export class IncentiveComponent implements OnInit { private route = inject(ActivatedRoute); private router = inject(Router); private dialog = inject(MatDialog); private snackBar = inject(MatSnackBar); auth = inject(AuthService); private ser = inject(VoucherService); @ViewChild('dateElement', { static: true }) dateElement!: ElementRef; public incentiveObservable = new BehaviorSubject([]); dataSource: IncentiveDataSource = new IncentiveDataSource(this.incentiveObservable); form: FormGroup<{ date: FormControl; incentives: FormArray< FormGroup<{ points: FormControl; }> >; }>; voucher: Voucher = new Voucher(); account: Account = new Account(); accBal: AccountBalance | null = null; displayedColumns = ['name', 'designation', 'department', 'daysWorked', 'points', 'amount']; @HostListener('window:keydown.f2', ['$event']) focusDate(event: KeyboardEvent) { event.preventDefault(); this.dateElement.nativeElement.focus(); this.dateElement.nativeElement.select(); } constructor() { this.form = new FormGroup({ date: new FormControl(new Date(), { nonNullable: true }), incentives: new FormArray }>>([]), }); // Listen to Date Change this.form.controls.date.valueChanges.pipe(map((x) => moment(x).format('DD-MMM-YYYY'))).subscribe((x) => { if (x !== this.voucher.date && !this.voucher.id) { return this.ser.getIncentive(x).subscribe((voucher: Voucher) => { this.loadVoucher(voucher); }); } return ''; }); } ngOnInit() { this.route.data.subscribe((value) => { const data = value as { voucher: Voucher }; this.loadVoucher(data.voucher); }); } loadVoucher(voucher: Voucher) { this.voucher = voucher; this.form.controls.date.setValue(moment(this.voucher.date, 'DD-MMM-YYYY').toDate()); this.form.controls.incentives.clear(); this.voucher.incentives.forEach((x) => this.form.controls.incentives.push( new FormGroup({ points: new FormControl(x.points, { nonNullable: true }), }), ), ); this.dataSource = new IncentiveDataSource(this.incentiveObservable); this.incentiveObservable.next(this.voucher.incentives); } totalPoints() { return this.voucher.incentives.map((item) => item.daysWorked * item.points).reduce((sum, item) => sum + item); } pointValue() { return Math.round(((this.voucher.incentive as number) * 100) / this.totalPoints()) / 100; } less(row: Incentive, i: number) { if (row.points >= 1) { row.points -= 1; this.form.controls.incentives.controls[i].setValue({ points: row.points, }); } } change(row: Incentive, i: number) { row.points = this.form.controls.incentives.controls[i].value.points ?? 0; this.form.controls.incentives.controls[i].setValue({ points: row.points }); } more(row: Incentive, i: number) { row.points += 1; this.form.controls.incentives.controls[i].setValue({ points: row.points }); } amount(row: Incentive) { return row.points * 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) => { this.loadVoucher(result); this.snackBar.open('Voucher Posted', 'Success'); }, error: (error) => { this.snackBar.open(error, 'Danger'); }, }); } save() { const voucher: Voucher = this.getVoucher(); this.ser.saveOrUpdate(voucher).subscribe({ next: (result) => { if (voucher.id === result.id) { this.loadVoucher(result); } else { this.router.navigate(['/incentive', result.id]); } }, error: (error) => { this.snackBar.open(error, 'Danger'); }, }); } getVoucher(): Voucher { const formModel = this.form.value; this.voucher.date = moment(formModel.date).format('DD-MMM-YYYY'); const array = this.form.controls.incentives; this.voucher.incentives.forEach((item, index) => { item.points = array.controls[index].value.points ?? 0; }); return this.voucher; } 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, '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(); } }); } }