fix(letter-mgmt): make share certificate bank identity dynamic and fix broken printing

- Certificate PDFs, the preview dialog, and both share-certificate list views
  (demo + live) now pull bank name/address/reg no/seal text from the
  Institution Profile instead of a hardcoded "Nexora" identity.
- Certificate preview dialog print CSS was clipped to the dialog's on-screen
  scroll viewport (maxHeight config); switched to position:fixed + unclipped
  overlay ancestors so the full certificate prints, not just a border sliver.
- Global print stylesheet now also hides the app shell's real 2-row nav menu
  (.main-header/.kpi-ticker, not routed through <mifosx-toolbar>) and frees
  the CDK sidenav/tab-body scroll clipping, so printing any page no longer
  captures the nav chrome or gets cut off to one screen's height.
This commit is contained in:
2026-09-14 16:58:18 +05:30
parent ee5a430b17
commit b03efef84e
11 changed files with 279 additions and 41 deletions
@@ -6,12 +6,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Component, inject } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MatTooltip } from '@angular/material/tooltip';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { OrganizationService } from 'app/organization/organization.service';
import { FyInterestBreakup, LoanInterestRecord } from '../loan-interest/loan-interest.component';
import { ShareCertificateRecord } from '../share-certificate/share-certificate.component';
@@ -27,7 +28,8 @@ import {
downloadHypothecationPdf,
downloadLoanInterestPdf,
downloadNocPdf,
downloadShareCertificatePdf
downloadShareCertificatePdf,
setBankIdentity
} from '../certificate-pdf';
export interface InterestPreviewPayload {
@@ -70,14 +72,52 @@ export interface CertificatePreviewDialogData {
MatTooltip
]
})
export class CertificatePreviewDialogComponent {
export class CertificatePreviewDialogComponent implements OnInit {
private dialogRef = inject(MatDialogRef<CertificatePreviewDialogComponent>);
private organizationService = inject(OrganizationService);
data: CertificatePreviewDialogData = inject(MAT_DIALOG_DATA);
readonly bankName = 'Nexora Co-operative Bank Ltd.';
readonly bankAddress = 'Head Office, 4th Floor, Nexora Tower, Mumbai 400051';
readonly bankRegNo = 'RBI Lic. No. NX-2018/MH/482';
readonly bankContact = 'info@nexorabank.in · 022 6789 0000';
/** The issuing bank's own details, fetched from the Institution Profile — this dialog is shared
* by every certificate type and every tenant, so nothing here is a fixed name. */
bankName = 'Bank';
bankAddress = '';
bankRegNo = '';
bankContact = '';
bankSealPrimary = 'BANK';
bankSealSecondary = '';
ngOnInit(): void {
this.organizationService.getInstitutionProfile().subscribe({
next: (profile: any) => {
this.bankName = profile?.statementHeaderName || profile?.bankName || this.bankName;
this.bankAddress = [
profile?.addressLine1,
profile?.addressLine2,
profile?.city
]
.filter((p: any) => !!p && String(p).trim())
.join(', ');
this.bankRegNo = profile?.licenseNumber ? `RBI Lic. No. ${profile.licenseNumber}` : '';
this.bankContact = [
profile?.contactEmail,
profile?.contactPhone
]
.filter((p: any) => !!p && String(p).trim())
.join(' · ');
this.bankSealPrimary = (profile?.shortName || this.bankName).toUpperCase();
this.bankSealSecondary = profile?.bankType
? profile.bankType.replace(/_/g, ' ').toUpperCase() + (/BANK$/i.test(profile.bankType) ? '' : ' BANK')
: '';
// Every certificate PDF this dialog can build (Download button below, or the list page's
// own download icon opened without previewing first) reads the same shared identity, so
// set it here once the real profile is in — never leave a PDF carrying the placeholder.
setBankIdentity(profile || {});
},
// A missing/incomplete profile must not stop the certificate from rendering.
error: () => {}
});
}
get isInterest(): boolean {
return this.data.kind === 'interest';