Client-stepper: pre-fill existing KYC/address proofs in edit, fix identifier saves
Edit-mode now shows the previously selected KYC document type + uploaded file thumbnail
(loads from /clients/{id}/identifiers + /client_identifiers/{id}/documents). Same for
address proof on the India address step. Closes the gap where editing a client showed
an empty file picker even when proof had been uploaded on create.
Identifier-save hardened across all three callsites (create-client, edit-client,
identities-tab.createIdentifierWithDocs) - the KYC chip picker proofId is a CODE
string ('AADHAAR'), but backend ClientIdentifierRequest.documentTypeId is Long, which
Spring rejects with HttpMessageNotReadableException -> 400. resolveDocumentTypeId
helper looks up the code against /kyc/proof-types?type=id and substitutes the numeric
CodeValue id before posting. Skips silently for constitution-specific non-individual
docs that have no CodeValue mapping.
KYC payload normalises panNumber / enterprisePan / gstinNumber / cinNumber via
toUpperCase + whitespace strip so user-typed lowercase or trailing spaces don't trip
the backend regex (validation.msg.CLIENTKYC.panNumber.does.not.match.regexp).
State name match in client-address save now normalises both sides (lowercase, collapse
underscores + spaces) so legacy MADHYA_PRADESH resolves to 'Madhya Pradesh' returned
by api.postalpincode.in. Backed by tenant migration 0297.
Identities-tab resolver flattened - was returning identifiers before the per-row
forkJoin(getClientIdentificationDocuments) completed, so the view rendered empty
documents arrays. Now uses switchMap + forkJoin so the resolver awaits completion.
Also bundles concurrent work-in-progress on letter-mgmt, organization, users,
bank-calendar, shell, nominee/notes/identifier dialogs, and theming.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
325228c514
commit
83ea57ccf0
@@ -28,9 +28,30 @@
|
||||
<div class="form-grid">
|
||||
<!-- ══ INDIVIDUAL KYC ══ -->
|
||||
@if (!isNonIndividual) {
|
||||
<div class="form-field checkbox-field full-width">
|
||||
<mat-checkbox formControlName="hasPan">Client has PAN Card</mat-checkbox>
|
||||
</div>
|
||||
@if (readOnly) {
|
||||
<!-- In view mode the mat-checkbox renders as a faded grey square
|
||||
that reads as "blurry". Show a clean Yes/No pill instead. -->
|
||||
<div class="form-field checkbox-field full-width">
|
||||
<div class="ro-flag">
|
||||
<span class="ro-flag__label">Client has PAN Card</span>
|
||||
@if (kycForm.get('hasPan')?.value) {
|
||||
<span class="ro-flag__chip ro-flag__chip--yes">
|
||||
<mat-icon>check_circle</mat-icon>
|
||||
Yes
|
||||
</span>
|
||||
} @else {
|
||||
<span class="ro-flag__chip ro-flag__chip--no">
|
||||
<mat-icon>cancel</mat-icon>
|
||||
No
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="form-field checkbox-field full-width">
|
||||
<mat-checkbox formControlName="hasPan">Client has PAN Card</mat-checkbox>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Individual PAN with inline verify -->
|
||||
@if (kycForm.get('hasPan')?.value) {
|
||||
@@ -83,40 +104,6 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@if (panVerifyStatus === 'VERIFIED') {
|
||||
<div class="pan-result-card full-width">
|
||||
<div class="pan-result-header">
|
||||
<fa-icon icon="check-circle" class="pan-result-ok-icon"></fa-icon>
|
||||
<span>PAN Verified Successfully</span>
|
||||
</div>
|
||||
<div class="pan-result-body">
|
||||
<div class="pan-result-row">
|
||||
<span class="pan-result-label">Full Name (as per PAN)</span>
|
||||
<span class="pan-result-value name">{{ panVerifyName }}</span>
|
||||
</div>
|
||||
<div class="pan-result-row">
|
||||
<span class="pan-result-label">PAN–Aadhaar Link Status</span>
|
||||
<span
|
||||
class="pan-result-value"
|
||||
[class.seeded]="panAadhaarSeedingStatus?.toUpperCase() === 'Y'"
|
||||
[class.not-seeded]="panAadhaarSeedingStatus?.toUpperCase() === 'N'"
|
||||
>
|
||||
@if (panAadhaarSeedingStatus?.toUpperCase() === 'Y') {
|
||||
Linked
|
||||
} @else if (panAadhaarSeedingStatus?.toUpperCase() === 'N') {
|
||||
Not Linked
|
||||
} @else {
|
||||
—
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pan-result-row">
|
||||
<span class="pan-result-label">Verified On</span>
|
||||
<span class="pan-result-value date">{{ panVerifiedOn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<!-- Aadhaar with independent verify (Individual only) -->
|
||||
@@ -251,45 +238,140 @@
|
||||
<fa-icon icon="exclamation-circle"></fa-icon> {{ aadhaarVerifyError }}
|
||||
</div>
|
||||
}
|
||||
@if (aadhaarVerifyStatus === 'VERIFIED' && aadhaarVerifyName) {
|
||||
<div class="aadhaar-result-card full-width">
|
||||
<div class="aadhaar-result-card__header">
|
||||
<fa-icon icon="check-circle" class="aadhaar-result-card__icon"></fa-icon>
|
||||
<span>Aadhaar Verified Successfully</span>
|
||||
</div>
|
||||
<div class="aadhaar-result-card__body">
|
||||
<span class="aadhaar-result-card__label">Name as per Aadhaar</span>
|
||||
<span class="aadhaar-result-card__name">{{ aadhaarVerifyName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- PAN-Aadhaar Seeding Status -->
|
||||
@if (kycForm.get('hasPan')?.value && panAadhaarSeedingStatus) {
|
||||
<div class="form-field pan-link-status full-width">
|
||||
<div
|
||||
class="pan-link-box"
|
||||
[class.linked]="panAadhaarSeedingStatus === 'Y'"
|
||||
[class.not-linked]="panAadhaarSeedingStatus === 'N'"
|
||||
[class.exempt]="panAadhaarSeedingStatus === 'E'"
|
||||
>
|
||||
<fa-icon icon="link" class="pan-link-icon"></fa-icon>
|
||||
<div class="pan-link-info">
|
||||
<span class="pan-link-label">PAN–Aadhaar Link Status</span>
|
||||
<span class="pan-link-value">
|
||||
@if (panAadhaarSeedingStatus === 'Y') {
|
||||
Linked (Seeded)
|
||||
<!-- ─── Unified Identity Verification Summary ─── -->
|
||||
<!-- One polished card that consolidates PAN result, Aadhaar result, and -->
|
||||
<!-- the PAN–Aadhaar link status into a single, scannable panel. -->
|
||||
@if (panVerifyStatus === 'VERIFIED' || aadhaarVerifyStatus === 'VERIFIED') {
|
||||
<div
|
||||
class="idv-summary full-width"
|
||||
[class.both]="panVerifyStatus === 'VERIFIED' && aadhaarVerifyStatus === 'VERIFIED'"
|
||||
[class.partial]="
|
||||
!(panVerifyStatus === 'VERIFIED' && aadhaarVerifyStatus === 'VERIFIED') &&
|
||||
(panVerifyStatus === 'VERIFIED' || aadhaarVerifyStatus === 'VERIFIED')
|
||||
"
|
||||
>
|
||||
<!-- Hero strip -->
|
||||
<div class="idv-hero">
|
||||
<div class="idv-hero__ic"><fa-icon icon="shield-alt"></fa-icon></div>
|
||||
<div class="idv-hero__txt">
|
||||
<div class="idv-hero__title">
|
||||
@if (panVerifyStatus === 'VERIFIED' && aadhaarVerifyStatus === 'VERIFIED') {
|
||||
Identity Verified
|
||||
} @else if (panVerifyStatus === 'VERIFIED') {
|
||||
PAN Verified
|
||||
} @else {
|
||||
Aadhaar Verified
|
||||
}
|
||||
@if (panAadhaarSeedingStatus === 'N') {
|
||||
Not Linked
|
||||
</div>
|
||||
<div class="idv-hero__sub">
|
||||
@if (panVerifyStatus === 'VERIFIED' && aadhaarVerifyStatus === 'VERIFIED') {
|
||||
Both PAN & Aadhaar confirmed against NSDL & UIDAI records.
|
||||
} @else if (panVerifyStatus === 'VERIFIED') {
|
||||
PAN confirmed against NSDL records. Aadhaar verification pending.
|
||||
} @else {
|
||||
Aadhaar confirmed via UIDAI OTP. PAN verification pending.
|
||||
}
|
||||
@if (panAadhaarSeedingStatus === 'E') {
|
||||
Exempt
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="idv-hero__count">
|
||||
<span class="idv-hero__count-num">
|
||||
{{ (panVerifyStatus === 'VERIFIED' ? 1 : 0) + (aadhaarVerifyStatus === 'VERIFIED' ? 1 : 0) }}
|
||||
</span>
|
||||
<span class="idv-hero__count-of">/ 2</span>
|
||||
</div>
|
||||
<span class="pan-link-hint">As per Income Tax Portal — Section 139AA</span>
|
||||
</div>
|
||||
|
||||
<!-- Two-column body: PAN | Aadhaar -->
|
||||
<div class="idv-body">
|
||||
<!-- PAN column -->
|
||||
<div class="idv-col" [class.muted]="panVerifyStatus !== 'VERIFIED'">
|
||||
<div class="idv-col__head">
|
||||
<fa-icon icon="id-card" class="idv-col__ic"></fa-icon>
|
||||
<span class="idv-col__label">PAN</span>
|
||||
@if (panVerifyStatus === 'VERIFIED') {
|
||||
<span class="idv-chip ok"> <fa-icon icon="check-circle"></fa-icon> Verified </span>
|
||||
} @else {
|
||||
<span class="idv-chip pending">Pending</span>
|
||||
}
|
||||
</div>
|
||||
@if (panVerifyStatus === 'VERIFIED') {
|
||||
<div class="idv-col__rows">
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">Name on PAN</span>
|
||||
<span class="idv-row__v name">{{ panVerifyName }}</span>
|
||||
</div>
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">PAN Number</span>
|
||||
<span class="idv-row__v mono">{{ kycForm.get('panNumber')?.value }}</span>
|
||||
</div>
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">Verified On</span>
|
||||
<span class="idv-row__v">{{ panVerifiedOn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="idv-col__empty">Enter PAN above and click <strong>Verify PAN</strong>.</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Aadhaar column -->
|
||||
<div class="idv-col" [class.muted]="aadhaarVerifyStatus !== 'VERIFIED'">
|
||||
<div class="idv-col__head">
|
||||
<fa-icon icon="fingerprint" class="idv-col__ic"></fa-icon>
|
||||
<span class="idv-col__label">Aadhaar</span>
|
||||
@if (aadhaarVerifyStatus === 'VERIFIED') {
|
||||
<span class="idv-chip ok"> <fa-icon icon="check-circle"></fa-icon> Verified </span>
|
||||
} @else {
|
||||
<span class="idv-chip pending">Pending</span>
|
||||
}
|
||||
</div>
|
||||
@if (aadhaarVerifyStatus === 'VERIFIED') {
|
||||
<div class="idv-col__rows">
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">Name on Aadhaar</span>
|
||||
<span class="idv-row__v name">{{ aadhaarVerifyName }}</span>
|
||||
</div>
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">Aadhaar Number</span>
|
||||
<span class="idv-row__v mono"
|
||||
>XXXX XXXX {{ (kycForm.get('aadhaarNumber')?.value || '').slice(-4) }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="idv-row">
|
||||
<span class="idv-row__k">Channel</span>
|
||||
<span class="idv-row__v">UIDAI OTP</span>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="idv-col__empty">Enter Aadhaar above and click <strong>Verify Aadhaar</strong>.</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PAN ↔ Aadhaar link footer -->
|
||||
@if (panAadhaarSeedingStatus) {
|
||||
<div
|
||||
class="idv-link"
|
||||
[class.linked]="panAadhaarSeedingStatus === 'Y'"
|
||||
[class.not-linked]="panAadhaarSeedingStatus === 'N'"
|
||||
[class.exempt]="panAadhaarSeedingStatus === 'E'"
|
||||
>
|
||||
<fa-icon icon="link" class="idv-link__ic"></fa-icon>
|
||||
<div class="idv-link__txt">
|
||||
<span class="idv-link__label">PAN — Aadhaar Link</span>
|
||||
<span class="idv-link__value">
|
||||
@if (panAadhaarSeedingStatus === 'Y') {
|
||||
Linked (Seeded)
|
||||
} @else if (panAadhaarSeedingStatus === 'N') {
|
||||
Not Linked
|
||||
} @else if (panAadhaarSeedingStatus === 'E') {
|
||||
Exempt
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<span class="idv-link__hint">Income Tax Portal — Section 139AA</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -652,7 +734,7 @@
|
||||
|
||||
<div class="kyc-doc-field">
|
||||
<label class="kyc-doc-label"><mat-icon>description</mat-icon> Document type</label>
|
||||
<div class="kyc-doc-chip-wrap">
|
||||
<div class="kyc-doc-chip-wrap" [class.kyc-doc-chip-wrap--locked]="readOnly">
|
||||
@for (group of kycDocGroups; track group.label; let last = $last) {
|
||||
<div class="kyc-doc-chip-group-label"><mat-icon>folder_open</mat-icon> {{ group.label }}</div>
|
||||
<div class="kyc-doc-chip-grid">
|
||||
@@ -660,9 +742,11 @@
|
||||
<span
|
||||
class="kyc-doc-chip"
|
||||
[class.kyc-doc-chip--sel]="isKycDocSelected(p)"
|
||||
(click)="selectKycDoc(p)"
|
||||
(keydown.enter)="selectKycDoc(p)"
|
||||
tabindex="0"
|
||||
[class.kyc-doc-chip--locked]="readOnly && !isKycDocSelected(p)"
|
||||
[attr.aria-disabled]="readOnly ? 'true' : null"
|
||||
(click)="readOnly ? null : selectKycDoc(p)"
|
||||
(keydown.enter)="readOnly ? null : selectKycDoc(p)"
|
||||
[attr.tabindex]="readOnly ? -1 : 0"
|
||||
role="button"
|
||||
>
|
||||
<mat-icon class="kyc-doc-chip__icon">
|
||||
@@ -699,59 +783,78 @@
|
||||
</span>
|
||||
<span class="kyc-doc-upload-req">Required</span>
|
||||
</div>
|
||||
<label
|
||||
class="kyc-doc-dropzone"
|
||||
[class.kyc-doc-dropzone--has]="kycDocFiles.front"
|
||||
[class.kyc-doc-dropzone--req]="!kycDocFiles.front"
|
||||
>
|
||||
<input type="file" accept=".jpg,.jpeg,.png,.pdf" hidden (change)="onKycDocFile($event, 'front')" />
|
||||
@if (kycDocFiles.front) {
|
||||
<div class="kyc-doc-dropzone__file">
|
||||
<mat-icon>insert_drive_file</mat-icon>
|
||||
<span class="kyc-doc-dropzone__name">{{ kycDocFiles.front.name }}</span>
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
class="kyc-doc-dropzone__remove"
|
||||
(click)="$event.preventDefault(); removeKycDocFile('front')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<!-- Existing saved ID-proof doc — locked by default. Replace flow
|
||||
unlocks automatically when the section-level Edit button toggles
|
||||
`readOnly` off. -->
|
||||
@if (existingKycDocuments.length > 0 && !kycDocFiles.front && readOnly) {
|
||||
<div class="kyc-doc-dropzone kyc-doc-dropzone--has kyc-doc-dropzone--locked">
|
||||
<div class="kyc-doc-dropzone__existing">
|
||||
@if (kycDocMergedPreview) {
|
||||
<img [src]="kycDocMergedPreview" alt="Saved KYC document" class="kyc-doc-dropzone__thumb" />
|
||||
} @else {
|
||||
<mat-icon class="kyc-doc-dropzone__doc-ic">description</mat-icon>
|
||||
}
|
||||
<div class="kyc-doc-dropzone__existing-meta">
|
||||
<span class="kyc-doc-dropzone__existing-name">
|
||||
{{ existingKycDocuments[0].fileName || existingKycDocuments[0].name }}
|
||||
</span>
|
||||
<button type="button" class="kyc-doc-dropzone__view" (click)="viewExistingKycDoc()">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
Click here to view
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="kyc-doc-dropzone__hint">
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
<span>Click to upload (JPG / PNG / PDF · max 5 MB)</span>
|
||||
</div>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (selectedKycDoc.sides === 2) {
|
||||
<div class="kyc-doc-upload-slot">
|
||||
<div class="kyc-doc-upload-head">
|
||||
<span class="kyc-doc-upload-title"> <mat-icon>image</mat-icon> Back side </span>
|
||||
<span class="kyc-doc-upload-req">Required</span>
|
||||
</div>
|
||||
} @else {
|
||||
<label
|
||||
class="kyc-doc-dropzone"
|
||||
[class.kyc-doc-dropzone--has]="kycDocFiles.back"
|
||||
[class.kyc-doc-dropzone--req]="!kycDocFiles.back"
|
||||
[class.kyc-doc-dropzone--has]="kycDocFiles.front || existingKycDocuments.length > 0"
|
||||
[class.kyc-doc-dropzone--req]="!kycDocFiles.front && existingKycDocuments.length === 0"
|
||||
>
|
||||
<input type="file" accept=".jpg,.jpeg,.png,.pdf" hidden (change)="onKycDocFile($event, 'back')" />
|
||||
@if (kycDocFiles.back) {
|
||||
<input type="file" accept=".jpg,.jpeg,.png,.pdf" hidden (change)="onKycDocFile($event, 'front')" />
|
||||
@if (kycDocFiles.front) {
|
||||
<div class="kyc-doc-dropzone__file">
|
||||
<mat-icon>insert_drive_file</mat-icon>
|
||||
<span class="kyc-doc-dropzone__name">{{ kycDocFiles.back.name }}</span>
|
||||
<span class="kyc-doc-dropzone__name">{{ kycDocFiles.front.name }}</span>
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
class="kyc-doc-dropzone__remove"
|
||||
(click)="$event.preventDefault(); removeKycDocFile('back')"
|
||||
(click)="$event.preventDefault(); removeKycDocFile('front')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
} @else if (existingKycDocuments.length > 0) {
|
||||
<!-- Edit mode WITH existing doc — let the user view it OR
|
||||
click anywhere to replace. -->
|
||||
<div class="kyc-doc-dropzone__existing">
|
||||
@if (kycDocMergedPreview) {
|
||||
<img [src]="kycDocMergedPreview" alt="Saved KYC document" class="kyc-doc-dropzone__thumb" />
|
||||
} @else {
|
||||
<mat-icon class="kyc-doc-dropzone__doc-ic">description</mat-icon>
|
||||
}
|
||||
<div class="kyc-doc-dropzone__existing-meta">
|
||||
<span class="kyc-doc-dropzone__existing-name">
|
||||
{{ existingKycDocuments[0].fileName || existingKycDocuments[0].name }}
|
||||
</span>
|
||||
<div class="kyc-doc-dropzone__existing-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="kyc-doc-dropzone__view"
|
||||
(click)="$event.preventDefault(); $event.stopPropagation(); viewExistingKycDoc()"
|
||||
>
|
||||
<mat-icon>visibility</mat-icon>
|
||||
View
|
||||
</button>
|
||||
<span class="kyc-doc-dropzone__sep">·</span>
|
||||
<span class="kyc-doc-dropzone__existing-hint">
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
Click here to replace
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="kyc-doc-dropzone__hint">
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
@@ -759,11 +862,104 @@
|
||||
</div>
|
||||
}
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (selectedKycDoc.sides === 2) {
|
||||
<div class="kyc-doc-upload-slot">
|
||||
<div class="kyc-doc-upload-head">
|
||||
<span class="kyc-doc-upload-title"> <mat-icon>image</mat-icon> Back side </span>
|
||||
<!-- Hide Required pill when saved combined doc covers both sides -->
|
||||
@if (!(existingKycDocuments.length > 0 && !kycDocFiles.back)) {
|
||||
<span class="kyc-doc-upload-req">Required</span>
|
||||
}
|
||||
</div>
|
||||
<!-- Locked view: saved combined doc covers the back side too. -->
|
||||
@if (existingKycDocuments.length > 0 && !kycDocFiles.back && readOnly) {
|
||||
<div class="kyc-doc-dropzone kyc-doc-dropzone--has kyc-doc-dropzone--locked">
|
||||
<div class="kyc-doc-dropzone__existing">
|
||||
@if (kycDocMergedPreview) {
|
||||
<img [src]="kycDocMergedPreview" alt="Saved KYC document" class="kyc-doc-dropzone__thumb" />
|
||||
} @else {
|
||||
<mat-icon class="kyc-doc-dropzone__doc-ic">description</mat-icon>
|
||||
}
|
||||
<div class="kyc-doc-dropzone__existing-meta">
|
||||
<span class="kyc-doc-dropzone__existing-name">
|
||||
{{ existingKycDocuments[0].fileName || existingKycDocuments[0].name }}
|
||||
</span>
|
||||
<button type="button" class="kyc-doc-dropzone__view" (click)="viewExistingKycDoc()">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
Click here to view
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<label
|
||||
class="kyc-doc-dropzone"
|
||||
[class.kyc-doc-dropzone--has]="kycDocFiles.back || existingKycDocuments.length > 0"
|
||||
[class.kyc-doc-dropzone--req]="!kycDocFiles.back && existingKycDocuments.length === 0"
|
||||
>
|
||||
<input type="file" accept=".jpg,.jpeg,.png,.pdf" hidden (change)="onKycDocFile($event, 'back')" />
|
||||
@if (kycDocFiles.back) {
|
||||
<div class="kyc-doc-dropzone__file">
|
||||
<mat-icon>insert_drive_file</mat-icon>
|
||||
<span class="kyc-doc-dropzone__name">{{ kycDocFiles.back.name }}</span>
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
class="kyc-doc-dropzone__remove"
|
||||
(click)="$event.preventDefault(); removeKycDocFile('back')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
} @else if (existingKycDocuments.length > 0) {
|
||||
<!-- Edit mode WITH existing combined doc — view + replace. -->
|
||||
<div class="kyc-doc-dropzone__existing">
|
||||
@if (kycDocMergedPreview) {
|
||||
<img [src]="kycDocMergedPreview" alt="Saved KYC document" class="kyc-doc-dropzone__thumb" />
|
||||
} @else {
|
||||
<mat-icon class="kyc-doc-dropzone__doc-ic">description</mat-icon>
|
||||
}
|
||||
<div class="kyc-doc-dropzone__existing-meta">
|
||||
<span class="kyc-doc-dropzone__existing-name">
|
||||
{{ existingKycDocuments[0].fileName || existingKycDocuments[0].name }}
|
||||
</span>
|
||||
<div class="kyc-doc-dropzone__existing-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="kyc-doc-dropzone__view"
|
||||
(click)="$event.preventDefault(); $event.stopPropagation(); viewExistingKycDoc()"
|
||||
>
|
||||
<mat-icon>visibility</mat-icon>
|
||||
View
|
||||
</button>
|
||||
<span class="kyc-doc-dropzone__sep">·</span>
|
||||
<span class="kyc-doc-dropzone__existing-hint">
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
Click here to replace
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="kyc-doc-dropzone__hint">
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
<span>Click to upload (JPG / PNG / PDF · max 5 MB)</span>
|
||||
</div>
|
||||
}
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (selectedKycDoc.sides === 2 && kycDocMergedPreview) {
|
||||
<!-- Combined preview + re-crop is an edit-mode tool — hide in read-only,
|
||||
and don't duplicate the thumbnail when nothing's been picked yet. -->
|
||||
@if (
|
||||
selectedKycDoc.sides === 2 && kycDocMergedPreview && !readOnly && (kycDocFiles.front || kycDocFiles.back)
|
||||
) {
|
||||
<div class="kyc-merged">
|
||||
<div class="kyc-merged__head">
|
||||
<span class="kyc-merged__title">
|
||||
|
||||
Reference in New Issue
Block a user