feat(clerk): add dedicated nav pages, state restore, and fullscreen ESC fix
- Add ClerkUiStateService with full account state save/restore (no double network call on back navigation) - Add Photo & Signature, Standing Instructions, Today's Activity as dedicated nav pages - Remove photo/signature, standing instructions, linked accounts, today's activity panels from main dashboard - Add ESC key to exit fullscreen; clicking Clerk nav immediately restores fullscreen without re-navigating - Compact clerk dashboard UI with reduced font sizes and padding throughout - Add CashierOnlyGuard for route protection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f7d9259eb7
commit
40a436dabe
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
@@ -14,6 +14,8 @@ import { catchError } from 'rxjs/operators';
|
||||
import { forkJoin, of } from 'rxjs';
|
||||
import { MatDialog, MatDialogModule, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { CashierService } from '../cashier.service';
|
||||
import { AuthenticationService } from '../../core/authentication/authentication.service';
|
||||
import { ClerkUiStateService, ClerkSavedAccount } from '../clerk-ui-state.service';
|
||||
|
||||
interface TxnRow {
|
||||
typ: string;
|
||||
@@ -621,10 +623,12 @@ export class ImagePreviewDialogComponent {
|
||||
MatDialogModule
|
||||
]
|
||||
})
|
||||
export class TransactionEntryComponent implements OnInit {
|
||||
export class TransactionEntryComponent implements OnInit, OnDestroy {
|
||||
private http = inject(HttpClient);
|
||||
private cashierService = inject(CashierService);
|
||||
private authService = inject(AuthenticationService);
|
||||
private dialog = inject(MatDialog);
|
||||
private clerkUiState = inject(ClerkUiStateService);
|
||||
|
||||
today = '';
|
||||
rows: TxnRow[] = [];
|
||||
@@ -748,6 +752,56 @@ export class TransactionEntryComponent implements OnInit {
|
||||
.getPaymentTypes()
|
||||
.pipe(catchError(() => of([])))
|
||||
.subscribe((types: any[]) => (this.paymentTypes = types ?? []));
|
||||
|
||||
if (this.isClerk) {
|
||||
const saved = this.clerkUiState.snapshot.savedAccount;
|
||||
if (saved) {
|
||||
this.accountDetails = saved.accountDetails;
|
||||
this.clientDetails = saved.clientDetails;
|
||||
this.kycDetails = saved.kycDetails;
|
||||
this.nominees = saved.nominees;
|
||||
this.jointHolders = saved.jointHolders;
|
||||
this.clientAddresses = saved.clientAddresses;
|
||||
this.nonPersonDetails = saved.nonPersonDetails;
|
||||
this.clientPhotoUrl = saved.clientPhotoUrl;
|
||||
this.signatureUrl = saved.signatureUrl;
|
||||
this.accountNotes = saved.accountNotes;
|
||||
this.standingInstructions = saved.standingInstructions;
|
||||
this.todayTransactions = saved.todayTransactions;
|
||||
this.linkedAccounts = saved.linkedAccounts;
|
||||
this.sameDayNeftRtgs = saved.sameDayNeftRtgs;
|
||||
this.sameDayChequeClearing = saved.sameDayChequeClearing;
|
||||
this.selectedRow = saved.selectedRow;
|
||||
if (saved.accountDetails) {
|
||||
const acNo = saved.accountDetails.accountNo ?? '';
|
||||
const acTyp = this.clerkUiState.snapshot.savedRow?.acTyp ?? '';
|
||||
this.rows[0] = { ...this.rows[0], acNo, acTyp };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.isClerk && this.accountDetails) {
|
||||
this.clerkUiState.saveFullState({
|
||||
accountDetails: this.accountDetails,
|
||||
clientDetails: this.clientDetails,
|
||||
kycDetails: this.kycDetails,
|
||||
nominees: this.nominees,
|
||||
jointHolders: this.jointHolders,
|
||||
clientAddresses: this.clientAddresses,
|
||||
nonPersonDetails: this.nonPersonDetails,
|
||||
clientPhotoUrl: this.clientPhotoUrl,
|
||||
signatureUrl: this.signatureUrl,
|
||||
accountNotes: this.accountNotes,
|
||||
standingInstructions: this.standingInstructions,
|
||||
todayTransactions: this.todayTransactions,
|
||||
linkedAccounts: this.linkedAccounts,
|
||||
sameDayNeftRtgs: this.sameDayNeftRtgs,
|
||||
sameDayChequeClearing: this.sameDayChequeClearing,
|
||||
selectedRow: this.selectedRow
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private loadDenominations(): void {
|
||||
@@ -1010,7 +1064,7 @@ export class TransactionEntryComponent implements OnInit {
|
||||
// returns all accounts as an array (e.g. recurringdepositaccounts)
|
||||
const match = allItems.find((x: any) => x.accountNo === acNo) ?? allItems[0];
|
||||
if (match?.id) {
|
||||
this.fetchAllDetails(match.id, acNo, cfg, token);
|
||||
this.fetchAllDetails(match.id, acNo, cfg, token, acTyp);
|
||||
return;
|
||||
}
|
||||
// Fallback: global search
|
||||
@@ -1021,7 +1075,7 @@ export class TransactionEntryComponent implements OnInit {
|
||||
if (token !== this.searchToken) return;
|
||||
const list: any[] = Array.isArray(found) ? found : [];
|
||||
if (list.length > 0 && list[0].entityId) {
|
||||
this.fetchAllDetails(list[0].entityId, acNo, cfg, token);
|
||||
this.fetchAllDetails(list[0].entityId, acNo, cfg, token, acTyp);
|
||||
} else {
|
||||
this.loadingAccount = false;
|
||||
this.accountError = 'Account not found for: ' + acNo;
|
||||
@@ -1107,7 +1161,8 @@ export class TransactionEntryComponent implements OnInit {
|
||||
txnBase: string;
|
||||
txnSearchSupported: boolean;
|
||||
},
|
||||
token: number
|
||||
token: number,
|
||||
acTyp: string = ''
|
||||
): void {
|
||||
this.http
|
||||
.get<any>(`${cfg.detail}/${accountId}?associations=all`)
|
||||
@@ -1127,6 +1182,7 @@ export class TransactionEntryComponent implements OnInit {
|
||||
}
|
||||
this.accountDetails = acc;
|
||||
this.jointHolders = acc.jointHolders ?? [];
|
||||
if (this.isClerk) this.clerkUiState.setFacilities(this.facilities, acNo, acTyp);
|
||||
// Compute same-day compliance indicators from included transactions
|
||||
this.computeSameDayNeftRtgs(acc.transactions);
|
||||
this.computeSameDayChequeClearing(acc.transactions);
|
||||
@@ -1263,11 +1319,6 @@ export class TransactionEntryComponent implements OnInit {
|
||||
if (acc.withHoldTax)
|
||||
alerts.push({ type: 'info', message: `TDS Applicable — Tax Group: ${acc.taxGroupData?.name ?? ''}` });
|
||||
|
||||
// Notes
|
||||
(this.accountNotes ?? []).forEach((n: any) => {
|
||||
if (n.note) alerts.push({ type: 'info', message: n.note });
|
||||
});
|
||||
|
||||
// Sanctions (from KYC) — DB stores 'YES'/'NO' strings, not booleans
|
||||
const isYes = (v: any) => v === true || v === 'YES' || v === 'yes' || v === 'Y';
|
||||
if (isYes(this.kycDetails?.bannedEntityMatch))
|
||||
@@ -1423,6 +1474,10 @@ export class TransactionEntryComponent implements OnInit {
|
||||
if (this.selectedRow && !this.rows.includes(this.selectedRow)) this.selectedRow = null;
|
||||
}
|
||||
|
||||
get isClerk(): boolean {
|
||||
return this.authService.isClerkUser();
|
||||
}
|
||||
|
||||
get isNonIndividual(): boolean {
|
||||
// legalForm.id=1 → Individual, legalForm.id=2 → Non-Individual (Entity)
|
||||
const lf = this.clientDetails?.legalForm?.id ?? this.clientDetails?.legalFormId;
|
||||
@@ -1996,6 +2051,7 @@ export class TransactionEntryComponent implements OnInit {
|
||||
}
|
||||
|
||||
onCancel(): void {
|
||||
this.clerkUiState.clear();
|
||||
this.accountDetails = null;
|
||||
this.clientDetails = null;
|
||||
this.kycDetails = null;
|
||||
|
||||
Reference in New Issue
Block a user