import { Component, OnInit, OnDestroy, inject, signal, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatCardModule } from '@angular/material/card';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule, PageEvent } from '@angular/material/paginator';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { PageHeaderComponent } from '../../../shared/components/page-header/page-header.component';
import { StatusBadgeComponent } from '../../../shared/components/status-badge/status-badge.component';
import { EmptyStateComponent } from '../../../shared/components/empty-state/empty-state.component';
import { ApprovalActionComponent } from '../approval-action/approval-action.component';
import { ApprovalService } from '../services/approval.service';
import { NotificationService } from '../../../core/services/notification.service';
import { ApprovalResponseDto } from '../../../api/models';
@Component({
selector: 'app-pending-list',
standalone: true,
imports: [
CommonModule,
RouterModule,
MatCardModule,
MatTableModule,
MatPaginatorModule,
MatButtonModule,
MatIconModule,
MatProgressSpinnerModule,
MatDialogModule,
PageHeaderComponent,
StatusBadgeComponent,
EmptyStateComponent,
],
template: `
@if (loading()) {
} @else if (approvals().length === 0) {
} @else {
}
`,
styles: [
`
.loading-container {
display: flex;
justify-content: center;
padding: 48px;
}
table {
width: 100%;
}
.request-link {
color: #1976d2;
text-decoration: none;
font-weight: 500;
&:hover {
text-decoration: underline;
}
}
.mat-column-actions {
width: 300px;
text-align: right;
}
`,
],
})
export class PendingListComponent implements OnInit, OnDestroy {
private readonly approvalService = inject(ApprovalService);
private readonly notification = inject(NotificationService);
private readonly dialog = inject(MatDialog);
private readonly destroyRef = inject(DestroyRef);
readonly loading = signal(true);
readonly hasError = signal(false);
readonly approvals = signal([]);
readonly totalItems = signal(0);
readonly pageSize = signal(10);
readonly pageIndex = signal(0);
readonly displayedColumns = ['requestId', 'status', 'createdAt', 'actions'];
ngOnInit(): void {
this.loadApprovals();
}
loadApprovals(): void {
this.loading.set(true);
this.hasError.set(false);
this.approvalService
.getPendingApprovals(this.pageIndex() + 1, this.pageSize())
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: (response) => {
this.approvals.set(response?.data ?? []);
this.totalItems.set(response?.total ?? 0);
this.loading.set(false);
},
error: () => {
this.hasError.set(true);
this.loading.set(false);
},
});
}
onPageChange(event: PageEvent): void {
this.pageIndex.set(event.pageIndex);
this.pageSize.set(event.pageSize);
this.loadApprovals();
}
openApprovalDialog(
approval: ApprovalResponseDto,
action: 'approve' | 'reject' | 'changes'
): void {
if (!approval) return;
const dialogRef = this.dialog.open(ApprovalActionComponent, {
data: { approval, action },
width: '500px',
});
dialogRef.afterClosed()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((result) => {
if (result) {
this.loadApprovals();
}
});
}
ngOnDestroy(): void {
// Cleanup handled by DestroyRef/takeUntilDestroyed
}
/** Retry loading data - clears error state */
retryLoad(): void {
this.loadApprovals();
}
}