163 lines
7.5 KiB
HTML
163 lines
7.5 KiB
HTML
<!--
|
|
Copyright since 2025 Mifos Initiative
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
-->
|
|
|
|
<div class="complaint-list-page">
|
|
<div class="page-header">
|
|
<div>
|
|
<h2>{{ 'labels.menus.Complaint Management' | translate }}</h2>
|
|
<p class="subtitle">{{ 'labels.text.I4C/MHA CFCFRMS Complaint Tickets' | translate }}</p>
|
|
</div>
|
|
<button mat-raised-button color="accent" (click)="exportCsv()" [disabled]="complaints.length === 0">
|
|
<fa-icon icon="file-csv" class="mr-05"></fa-icon> {{ 'labels.text.Export CSV' | translate }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Filter Chips -->
|
|
<div class="filter-chips">
|
|
<button mat-stroked-button [class.active-chip]="activeChip === 'ALL'" (click)="onChipClick('ALL')">
|
|
{{ 'labels.text.All' | translate }}
|
|
</button>
|
|
<button mat-stroked-button [class.active-chip]="activeChip === 'PENDING'" (click)="onChipClick('PENDING')">
|
|
<span class="chip-dot pending"></span> {{ 'labels.text.Pending' | translate }}
|
|
</button>
|
|
<button mat-stroked-button [class.active-chip]="activeChip === 'ACTIVE'" (click)="onChipClick('ACTIVE')">
|
|
<span class="chip-dot active"></span> {{ 'labels.text.Active' | translate }}
|
|
</button>
|
|
<button mat-stroked-button [class.active-chip]="activeChip === 'RESOLVED'" (click)="onChipClick('RESOLVED')">
|
|
<span class="chip-dot resolved"></span> {{ 'labels.text.Resolved' | translate }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Filter Bar -->
|
|
<mat-card class="filter-bar">
|
|
<mat-card-content>
|
|
<div class="filter-row">
|
|
<mat-form-field appearance="outline" class="filter-field">
|
|
<mat-label>{{ 'labels.text.Search by Ticket ID / Mobile' | translate }}</mat-label>
|
|
<input
|
|
matInput
|
|
[(ngModel)]="searchQuery"
|
|
(keyup.enter)="onSearch()"
|
|
placeholder="{{ 'labels.text.Enter ticket ID or mobile...' | translate }}"
|
|
/>
|
|
<button mat-icon-button matSuffix (click)="onSearch()">
|
|
<fa-icon icon="search"></fa-icon>
|
|
</button>
|
|
</mat-form-field>
|
|
|
|
<mat-form-field appearance="outline" class="filter-field">
|
|
<mat-label>{{ 'labels.text.Status' | translate }}</mat-label>
|
|
<mat-select [(ngModel)]="statusFilter" (selectionChange)="onStatusFilterChange()">
|
|
<mat-option value="">{{ 'labels.text.All Statuses' | translate }}</mat-option>
|
|
@for (s of statuses; track s) {
|
|
<mat-option [value]="s">{{ s.replace('_', ' ') }}</mat-option>
|
|
}
|
|
</mat-select>
|
|
</mat-form-field>
|
|
|
|
<mat-form-field appearance="outline" class="filter-field">
|
|
<mat-label>{{ 'labels.text.From Date' | translate }}</mat-label>
|
|
<input matInput [matDatepicker]="fromPicker" [(ngModel)]="dateFrom" (dateChange)="onSearch()" />
|
|
<mat-datepicker-toggle matSuffix [for]="fromPicker"></mat-datepicker-toggle>
|
|
<mat-datepicker #fromPicker></mat-datepicker>
|
|
</mat-form-field>
|
|
|
|
<mat-form-field appearance="outline" class="filter-field">
|
|
<mat-label>{{ 'labels.text.To Date' | translate }}</mat-label>
|
|
<input matInput [matDatepicker]="toPicker" [(ngModel)]="dateTo" (dateChange)="onSearch()" />
|
|
<mat-datepicker-toggle matSuffix [for]="toPicker"></mat-datepicker-toggle>
|
|
<mat-datepicker #toPicker></mat-datepicker>
|
|
</mat-form-field>
|
|
|
|
<button mat-icon-button matTooltip="{{ 'labels.text.Clear Filters' | translate }}" (click)="clearFilters()">
|
|
<fa-icon icon="times-circle"></fa-icon>
|
|
</button>
|
|
</div>
|
|
</mat-card-content>
|
|
</mat-card>
|
|
|
|
<!-- Table -->
|
|
<mat-card class="table-card">
|
|
<mat-card-content>
|
|
@if (isLoading) {
|
|
<div class="loading-container">
|
|
<mat-spinner diameter="40"></mat-spinner>
|
|
</div>
|
|
} @else if (complaints.length === 0) {
|
|
<div class="empty-state">
|
|
<fa-icon icon="inbox" size="3x"></fa-icon>
|
|
<p>{{ 'labels.text.No complaints match your filters' | translate }}</p>
|
|
<button mat-stroked-button (click)="clearFilters()">{{ 'labels.text.Clear Filters' | translate }}</button>
|
|
</div>
|
|
} @else {
|
|
<div class="table-responsive">
|
|
<table mat-table [dataSource]="complaints" class="full-width">
|
|
<ng-container matColumnDef="ticketId">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Ticket ID' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">
|
|
<a [routerLink]="['/cfcfrms/complaints', row.ticketId]" class="ticket-link">{{ row.ticketId }}</a>
|
|
</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="complainantName">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Complainant' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">{{ row.complainantName }}</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="complainantMobile">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Mobile' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">{{ row.complainantMobile }}</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="fraudAmount">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Fraud Amount' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row" class="amount-cell">{{ formatCurrency(row.fraudAmount) }}</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="suspectAccountNumber">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Suspect Account' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row" class="mono">{{ row.suspectAccountNumber }}</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="status">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Status' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">
|
|
<mifosx-cfcfrms-status-badge [status]="row.status"></mifosx-cfcfrms-status-badge>
|
|
</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="createdAt">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Created At' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">{{ formatDate(row.createdAt) }}</td>
|
|
</ng-container>
|
|
<ng-container matColumnDef="actions">
|
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Actions' | translate }}</th>
|
|
<td mat-cell *matCellDef="let row">
|
|
<a
|
|
mat-icon-button
|
|
color="primary"
|
|
[routerLink]="['/cfcfrms/complaints', row.ticketId]"
|
|
matTooltip="{{ 'labels.text.View Details' | translate }}"
|
|
>
|
|
<fa-icon icon="eye"></fa-icon>
|
|
</a>
|
|
</td>
|
|
</ng-container>
|
|
|
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
|
</table>
|
|
</div>
|
|
<mat-paginator
|
|
[length]="totalElements"
|
|
[pageSize]="pageSize"
|
|
[pageIndex]="pageIndex"
|
|
[pageSizeOptions]="[10, 25, 50]"
|
|
(page)="onPageChange($event)"
|
|
showFirstLastButtons
|
|
>
|
|
</mat-paginator>
|
|
}
|
|
</mat-card-content>
|
|
</mat-card>
|
|
</div>
|