77 lines
3.3 KiB
TypeScript
77 lines
3.3 KiB
TypeScript
import { Component, OnInit } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { GridModule } from '@progress/kendo-angular-grid';
|
|
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
|
import { ExpenseApiService } from '../../services/expense-api.service';
|
|
import { ExpenseFormDialogComponent, ExpenseFormResult } from '../../components/expense-form-dialog/expense-form-dialog.component';
|
|
import { ExpenseListItemDto } from '../../models/expense.model';
|
|
import { switchMap, of } from 'rxjs';
|
|
import { PageHeaderActionsDirective } from '../../../../shared/directives/page-header-actions.directive';
|
|
|
|
@Component({
|
|
selector: 'app-my-reimbursements-page',
|
|
standalone: true,
|
|
imports: [CommonModule, GridModule, ButtonsModule, ExpenseFormDialogComponent, PageHeaderActionsDirective],
|
|
templateUrl: './my-reimbursements-page.component.html',
|
|
styleUrls: ['./my-reimbursements-page.component.scss'],
|
|
})
|
|
export class MyReimbursementsPageComponent implements OnInit {
|
|
rows: ExpenseListItemDto[] = [];
|
|
loading = false;
|
|
dialogOpen = false;
|
|
editRow: ExpenseListItemDto | null = null;
|
|
|
|
constructor(private api: ExpenseApiService) {}
|
|
|
|
ngOnInit(): void { this.load(); }
|
|
|
|
load(): void {
|
|
this.loading = true;
|
|
this.api.getMine().subscribe({
|
|
next: r => { this.rows = r.items; this.loading = false; },
|
|
error: () => { this.loading = false; },
|
|
});
|
|
}
|
|
|
|
openNew(): void { this.editRow = null; this.dialogOpen = true; }
|
|
openEdit(row: ExpenseListItemDto): void { this.editRow = row; this.dialogOpen = true; }
|
|
closeDialog(): void { this.dialogOpen = false; this.editRow = null; }
|
|
|
|
onSave(result: ExpenseFormResult): void {
|
|
if (this.editRow) {
|
|
const id = this.editRow.id;
|
|
this.api.update(id, result.request).pipe(
|
|
switchMap(() => result.receipt ? this.api.uploadReceipt(id, result.receipt) : of(void 0)),
|
|
).subscribe(() => { this.closeDialog(); this.load(); });
|
|
} else {
|
|
this.api.create(result.request).pipe(
|
|
switchMap(created => result.receipt
|
|
? this.api.uploadReceipt(created.id, result.receipt).pipe(switchMap(() => of(created)))
|
|
: of(created)),
|
|
).subscribe(() => { this.closeDialog(); this.load(); });
|
|
}
|
|
}
|
|
|
|
submit(row: ExpenseListItemDto): void { this.api.submit(row.id).subscribe(() => this.load()); }
|
|
remove(row: ExpenseListItemDto): void {
|
|
if (!confirm('Delete this reimbursement?')) return;
|
|
this.api.delete(row.id).subscribe(() => this.load());
|
|
}
|
|
|
|
openReceipt(id: number): void {
|
|
this.api.downloadReceipt(id).subscribe(blob => {
|
|
const url = URL.createObjectURL(blob);
|
|
window.open(url, '_blank');
|
|
setTimeout(() => URL.revokeObjectURL(url), 60_000);
|
|
});
|
|
}
|
|
|
|
/** Editing (and reuploading the photo) is allowed while a reimbursement is still Draft or awaiting review. */
|
|
canEdit(row: ExpenseListItemDto): boolean { return row.status === 'Draft' || row.status === 'PendingApproval'; }
|
|
/** Submit and Delete only apply before the reimbursement has been submitted. */
|
|
isDraft(row: ExpenseListItemDto): boolean { return row.status === 'Draft'; }
|
|
statusClass(status: string): string {
|
|
return ({ Draft: 'badge-draft', PendingApproval: 'badge-pending', Approved: 'badge-approved', Paid: 'badge-paid', Rejected: 'badge-rejected' } as Record<string, string>)[status] ?? '';
|
|
}
|
|
}
|