Updated ruff and mypy, accepted all changes Central exception management and injected the Session. This removed a lot of duplicated boilerplate code. Added health check Updated to Angular 21
222 lines
6.8 KiB
TypeScript
222 lines
6.8 KiB
TypeScript
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 { 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: [
|
|
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<HTMLInputElement>;
|
|
public incentiveObservable = new BehaviorSubject<Incentive[]>([]);
|
|
dataSource: IncentiveDataSource = new IncentiveDataSource(this.incentiveObservable);
|
|
form: FormGroup<{
|
|
date: FormControl<moment.Moment>;
|
|
incentives: FormArray<
|
|
FormGroup<{
|
|
points: FormControl<number>;
|
|
}>
|
|
>;
|
|
}>;
|
|
|
|
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: Event) {
|
|
event.preventDefault();
|
|
this.dateElement.nativeElement.focus();
|
|
this.dateElement.nativeElement.select();
|
|
}
|
|
|
|
constructor() {
|
|
this.form = new FormGroup({
|
|
date: new FormControl(moment(new Date()), { nonNullable: true }),
|
|
incentives: new FormArray<FormGroup<{ points: FormControl<number> }>>([]),
|
|
});
|
|
// 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'));
|
|
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();
|
|
}
|
|
});
|
|
}
|
|
}
|