Files
Goa-gel-fullstack/frontend/src/app/features/approvals/pending-list/pending-list.component.ts

209 lines
6.6 KiB
TypeScript
Raw Normal View History

import { Component, OnInit, inject, signal } from '@angular/core';
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: `
<div class="page-container">
<app-page-header
title="Pending Approvals"
subtitle="Review and approve license requests"
/>
<mat-card>
<mat-card-content>
@if (loading()) {
<div class="loading-container">
<mat-spinner diameter="48"></mat-spinner>
</div>
} @else if (approvals().length === 0) {
<app-empty-state
icon="check_circle"
title="No pending approvals"
message="You have no requests pending your approval."
/>
} @else {
<table mat-table [dataSource]="approvals()">
<ng-container matColumnDef="requestId">
<th mat-header-cell *matHeaderCellDef>Request</th>
<td mat-cell *matCellDef="let row">
<a [routerLink]="['/requests', row.requestId]" class="request-link">
{{ row.requestId.slice(0, 8) }}...
</a>
</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>Status</th>
<td mat-cell *matCellDef="let row">
<app-status-badge [status]="row.status" />
</td>
</ng-container>
<ng-container matColumnDef="createdAt">
<th mat-header-cell *matHeaderCellDef>Received</th>
<td mat-cell *matCellDef="let row">{{ row.createdAt | date: 'medium' }}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>Actions</th>
<td mat-cell *matCellDef="let row">
<button
mat-raised-button
color="primary"
(click)="openApprovalDialog(row, 'approve')"
>
<mat-icon>check</mat-icon>
Approve
</button>
<button
mat-raised-button
color="warn"
(click)="openApprovalDialog(row, 'reject')"
style="margin-left: 8px"
>
<mat-icon>close</mat-icon>
Reject
</button>
<button
mat-button
(click)="openApprovalDialog(row, 'changes')"
style="margin-left: 8px"
>
Request Changes
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<mat-paginator
[length]="totalItems()"
[pageSize]="pageSize()"
[pageIndex]="pageIndex()"
[pageSizeOptions]="[5, 10, 25]"
(page)="onPageChange($event)"
showFirstLastButtons
/>
}
</mat-card-content>
</mat-card>
</div>
`,
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 {
private readonly approvalService = inject(ApprovalService);
private readonly notification = inject(NotificationService);
private readonly dialog = inject(MatDialog);
readonly loading = signal(true);
readonly approvals = signal<ApprovalResponseDto[]>([]);
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.approvalService
.getPendingApprovals(this.pageIndex() + 1, this.pageSize())
.subscribe({
next: (response) => {
this.approvals.set(response.data);
this.totalItems.set(response.total);
this.loading.set(false);
},
error: () => {
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 {
const dialogRef = this.dialog.open(ApprovalActionComponent, {
data: { approval, action },
width: '500px',
});
dialogRef.afterClosed().subscribe((result) => {
if (result) {
this.loadApprovals();
}
});
}
}