/** * 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 { Component, OnDestroy, inject } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog'; import { MatIconButton } from '@angular/material/button'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { Dates } from 'app/core/utils/dates'; import { ProofType } from '../../../shared/kyc-proof-types'; export interface CkycUploadDialogData { title: string; isProofKind: boolean; accept: string; proofOptions?: ProofType[]; initialProofType?: ProofType | null; initialDocumentKey?: string; initialIssueDate?: Date | null; initialExpiryDate?: Date | null; } export interface CkycUploadDialogResult { proofType?: ProofType | null; front: File; back?: File; /** Document number (Aadhaar/PAN/Passport number, etc.) — same field client creation collects. */ documentKey?: string; /** 'yyyy-MM-dd', same as the rest of this app's date fields. */ issueDate?: string | null; expiryDate?: string | null; } /** * A focused popup for replacing/uploading one CKYC artefact at a time — opened from each card on * the CKYC tab instead of expanding a form inline underneath it. Collects the same details * client creation does for an identity/address proof (document type, number, issue + expiry * date) and shows a client-side preview of whatever image is picked before it's ever sent to the * server; the actual upload still happens back in CkycTabComponent (this dialog only collects * the type, number, dates and file(s), then hands them back). */ @Component({ selector: 'mifosx-ckyc-upload-dialog', templateUrl: './ckyc-upload-dialog.component.html', styleUrls: ['./ckyc-upload-dialog.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, FormsModule, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose, MatIconButton, FaIconComponent ] }) export class CkycUploadDialogComponent implements OnDestroy { private dates = inject(Dates); dialogRef = inject>(MatDialogRef); data = inject(MAT_DIALOG_DATA); selectedProofType: ProofType | null = this.data.initialProofType || null; documentKey = this.data.initialDocumentKey || ''; issueDate: Date | null = this.data.initialIssueDate || null; expiryDate: Date | null = this.data.initialExpiryDate || null; front: File | null = null; back: File | null = null; frontPreview: string | null = null; backPreview: string | null = null; get sides(): number { return this.data.isProofKind ? (this.selectedProofType?.sides ?? 1) : 1; } get canSubmit(): boolean { if (this.data.isProofKind) { if (!this.selectedProofType) return false; if (!this.documentKey.trim()) return false; } if (!this.front) return false; if (this.sides === 2 && !this.back) return false; return true; } compareProofType = (a: ProofType | null, b: ProofType | null): boolean => (a?.id ?? null) === (b?.id ?? null); onProofTypeChange(proof: ProofType | null): void { this.selectedProofType = proof; this.clearSlot('front'); this.clearSlot('back'); } onFilePick(slot: 'front' | 'back', event: any): void { const file = event?.target?.files?.[0]; if (event?.target) event.target.value = ''; if (!file) return; this.clearSlot(slot); const preview = file.type?.startsWith('image/') ? URL.createObjectURL(file) : null; if (slot === 'front') { this.front = file; this.frontPreview = preview; } else { this.back = file; this.backPreview = preview; } } private clearSlot(slot: 'front' | 'back'): void { if (slot === 'front') { if (this.frontPreview) URL.revokeObjectURL(this.frontPreview); this.front = null; this.frontPreview = null; } else { if (this.backPreview) URL.revokeObjectURL(this.backPreview); this.back = null; this.backPreview = null; } } submit(): void { if (!this.canSubmit) return; this.dialogRef.close({ proofType: this.selectedProofType, front: this.front!, back: this.sides === 2 ? this.back! : undefined, documentKey: this.data.isProofKind ? this.documentKey.trim() : undefined, issueDate: this.issueDate ? this.dates.getDate(this.issueDate) : null, expiryDate: this.expiryDate ? this.dates.getDate(this.expiryDate) : null }); } cancel(): void { this.dialogRef.close(null); } ngOnDestroy(): void { if (this.frontPreview) URL.revokeObjectURL(this.frontPreview); if (this.backPreview) URL.revokeObjectURL(this.backPreview); } }