- KYC tab: fix Verify (PAN) and Send OTP (Aadhaar) being disabled in edit mode; unmask Aadhaar input and show on-file masked value as hint; resolve kycId from id/kycId/resourceId fallbacks. - Client stepper/view: add familyAllowed / nomineeAllowed predicates + CanActivate route guards. Family tab hidden for non-individuals, Nominee tab hidden for non-proprietor entities. Family-members step accepts a nomineeOnly input for proprietorship clients. Add/Edit/Delete buttons inside family-members and nominee tabs gated by canAdd. - cfcfrms: add cfcfrms-shell wrapper, restyle complaint/fraud/mule/escalate pages and dashboard. - Savings: identity-verify and transaction-confirm dialogs, manage / activate / add-charge flows, account preview styling. - Tasks, core shell, account-nominees, icons: minor style and behaviour updates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
67 lines
2.5 KiB
TypeScript
67 lines
2.5 KiB
TypeScript
/**
|
|
* 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/.
|
|
*/
|
|
|
|
import { inject } from '@angular/core';
|
|
import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router';
|
|
import { Observable, of } from 'rxjs';
|
|
import { catchError, map } from 'rxjs/operators';
|
|
|
|
import { ClientsService } from '../clients.service';
|
|
import { familyAllowed, nomineeAllowed } from './client-rules';
|
|
|
|
/**
|
|
* Walk up the route snapshot tree until we find a `clientId` path param. The
|
|
* family-members / nominees routes are nested two levels under the client
|
|
* shell, so simple `route.params['clientId']` returns undefined.
|
|
*/
|
|
function findClientId(route: ActivatedRouteSnapshot): string | null {
|
|
let cur: ActivatedRouteSnapshot | null = route;
|
|
while (cur) {
|
|
const id = cur.params?.['clientId'];
|
|
if (id) return id;
|
|
cur = cur.parent;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Build a guard that redirects to the client's General tab when the client
|
|
* isn't eligible for the section. Resolves the client lazily so we don't
|
|
* couple the guard to any specific parent resolver.
|
|
*/
|
|
function makeEligibilityGuard(
|
|
predicate: (legalFormId: number | null | undefined, constitutionLabel?: string | null) => boolean
|
|
): CanActivateFn {
|
|
return (route) => {
|
|
const router = inject(Router);
|
|
const clientsService = inject(ClientsService);
|
|
const clientId = findClientId(route);
|
|
// No clientId in the URL — let the framework's own missing-param handling kick in.
|
|
if (!clientId) return true;
|
|
|
|
return clientsService.getClientData(clientId).pipe(
|
|
map((client: any) => {
|
|
const legalFormId = client?.legalForm?.id;
|
|
const constitutionLabel = client?.clientNonPersonDetails?.constitution?.name || '';
|
|
if (predicate(legalFormId, constitutionLabel)) return true;
|
|
return router.createUrlTree([
|
|
'/clients',
|
|
clientId,
|
|
'general'
|
|
]);
|
|
}),
|
|
// If the client lookup fails, fail open and let downstream handle it
|
|
// rather than redirecting users into an infinite loop on a stale URL.
|
|
catchError(() => of(true))
|
|
) as Observable<boolean | ReturnType<Router['createUrlTree']>>;
|
|
};
|
|
}
|
|
|
|
export const familyAllowedGuard: CanActivateFn = makeEligibilityGuard(familyAllowed);
|
|
export const nomineeAllowedGuard: CanActivateFn = makeEligibilityGuard(nomineeAllowed);
|