Locker module UI: dashboard, class master, locker list, waiting list, allotment form
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
<!--
|
||||
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="container">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'Locker List' | translate }}</h2>
|
||||
<div class="header-actions">
|
||||
<button mat-raised-button [routerLink]="['/locker']">{{ 'labels.buttons.Back' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tiles">
|
||||
<button type="button" class="tile" [class.active]="statusFilter === ''" (click)="filterByStatus('')">
|
||||
<span class="tile-label">{{ 'Total' | translate }}</span>
|
||||
<span class="tile-value">{{ summary.total }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="tile vacant"
|
||||
[class.active]="statusFilter === 'VACANT'"
|
||||
(click)="filterByStatus('VACANT')"
|
||||
>
|
||||
<span class="tile-label">{{ 'Vacant' | translate }}</span>
|
||||
<span class="tile-value">{{ summary.vacant }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="tile allotted"
|
||||
[class.active]="statusFilter === 'ALLOTTED'"
|
||||
(click)="filterByStatus('ALLOTTED')"
|
||||
>
|
||||
<span class="tile-label">{{ 'Allotted' | translate }}</span>
|
||||
<span class="tile-value">{{ summary.allotted }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="tile blocked"
|
||||
[class.active]="statusFilter === 'BLOCKED'"
|
||||
(click)="filterByStatus('BLOCKED')"
|
||||
>
|
||||
<span class="tile-label">{{ 'Blocked' | translate }}</span>
|
||||
<span class="tile-value">{{ summary.blocked }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="filter-row">
|
||||
@if (isSuperUser) {
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'Branch' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="officeFilter" (selectionChange)="refresh()">
|
||||
<mat-option value="">{{ 'All Branches' | translate }}</mat-option>
|
||||
@for (office of offices; track office.id) {
|
||||
<mat-option [value]="office.id">{{ office.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
}
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'Class' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="classFilter" (selectionChange)="applyFilters()">
|
||||
<mat-option value="">{{ 'All Classes' | translate }}</mat-option>
|
||||
@for (code of classCodes; track code) {
|
||||
<mat-option [value]="code">{{ code }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'Status' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="statusFilter" (selectionChange)="applyFilters()">
|
||||
<mat-option value="">{{ 'All' | translate }}</mat-option>
|
||||
@for (s of statuses; track s) {
|
||||
<mat-option [value]="s">{{ s }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'Locker No' | translate }}</mat-label>
|
||||
<input matInput type="number" min="1" [(ngModel)]="lockerNoFilter" (keyup.enter)="applyFilters()" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" (click)="applyFilters()">
|
||||
<fa-icon icon="search"></fa-icon> {{ 'Search' | translate }}
|
||||
</button>
|
||||
<button mat-stroked-button (click)="clearFilters()">{{ 'Clear' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper mat-elevation-z1">
|
||||
<table mat-table [dataSource]="lockers">
|
||||
<ng-container matColumnDef="office">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'Branch' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l">{{ l.officeName }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="classCode">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'Class' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l">
|
||||
<strong>{{ l.classCode }}</strong>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="className">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'Class Name' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l">
|
||||
<span class="pill neutral">{{ l.className }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="lockerNo">
|
||||
<th mat-header-cell *matHeaderCellDef class="num">{{ 'Locker No' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l" class="num">{{ l.lockerNo }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="keyNo">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'Key No' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l">{{ l.keyNo || '-' }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Status' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let l">
|
||||
<span class="pill" [ngClass]="l.status === 'VACANT' ? 'ok' : l.status === 'ALLOTTED' ? 'info' : 'warn'">{{
|
||||
l.status
|
||||
}}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="columns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: columns"></tr>
|
||||
</table>
|
||||
@if (loadFailed) {
|
||||
<div class="empty-state">{{ 'Could not load lockers.' }}</div>
|
||||
} @else if (lockers.length === 0) {
|
||||
<div class="empty-state">
|
||||
{{ 'No lockers found. Lockers are created from Class Master.' }}
|
||||
</div>
|
||||
}
|
||||
@if (totalRecords > 0) {
|
||||
<mat-paginator
|
||||
[length]="totalRecords"
|
||||
[pageSize]="pageSize"
|
||||
[pageSizeOptions]="pageSizeOptions"
|
||||
[pageIndex]="pageIndex"
|
||||
showFirstLastButtons
|
||||
(page)="onPageChange($event)"
|
||||
></mat-paginator>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user