Files
cbsnexora/src/app/clients/clients-view/kyc-tab/kyc-tab.component.html
T
keshav 569f17ef46
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
kyc exception at client creation time and some tds work
2026-08-05 17:23:56 +05:30

817 lines
35 KiB
HTML

<!--
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/.
-->
<div class="kyc-tab-container">
<!-- Loading State -->
@if (loading) {
<div class="kyc-loading">
<mat-progress-spinner mode="indeterminate" diameter="48"></mat-progress-spinner>
<p>{{ 'labels.inputs.KYC Verification' | translate }}...</p>
</div>
}
@if (!loading) {
<!-- Header -->
<div class="kyc-tab-header">
<div class="kyc-tab-title">
<h3>{{ 'labels.inputs.KYC Verification' | translate }}</h3>
<span class="kyc-badge">KYC</span>
@if (kycData?.kycStatusCode) {
<span class="kyc-overall-status" [class]="'status-' + getStatusClass(kycData.kycStatusCode)">
{{ getStatusLabel(kycData.kycStatusCode) }}
</span>
}
</div>
<div class="kyc-header-actions">
@if (!isEditMode && kycData) {
<button mat-stroked-button class="kyc-print-btn" type="button" (click)="printSelfDeclaration()">
<fa-icon icon="file-pdf" class="m-r-6"></fa-icon> Self Declaration
</button>
}
<button mat-raised-button color="primary" (click)="toggleEditMode()" type="button">
<fa-icon [icon]="isEditMode ? 'times' : 'edit'" class="m-r-10"></fa-icon>
{{ isEditMode ? ('labels.buttons.Cancel' | translate) : ('labels.buttons.Edit' | translate) }}
</button>
</div>
</div>
<!-- KYC Summary (read-only when not in edit mode) -->
@if (!isEditMode && kycData) {
@if (kycData.isException && !kycData.exceptionResolved) {
<div class="kyc-exception-banner" style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 8px; padding: 16px; margin-bottom: 20px; display: flex; align-items: flex-start; gap: 12px;">
<mat-icon style="color: #d97706; margin-top: 2px;">warning</mat-icon>
<div>
<strong style="color: #92400e; font-size: 14px;">KYC Exception Active</strong>
<p style="color: #b45309; font-size: 13px; margin: 4px 0 0 0;">
Account is open under a temporary KYC Exception. Reason: <strong>{{ kycData.exceptionReason || 'Other' }}</strong>.
Please contact the customer and complete verification as soon as possible.
</p>
</div>
</div>
}
<!-- Verification Table -->
<div class="kv-table">
<div class="kv-table__header">
<span class="kv-table__col kv-table__col--doc">Document</span>
<span class="kv-table__col kv-table__col--num">Number</span>
<span class="kv-table__col kv-table__col--status">Status</span>
<span class="kv-table__col kv-table__col--date">Verified On</span>
<span class="kv-table__col kv-table__col--action">Action</span>
</div>
<!-- PAN Row -->
<div class="kv-table__row">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">credit_card</mat-icon> PAN
</span>
<span class="kv-table__col kv-table__col--num kv-mono">{{ kycData.panNumber || '—' }}</span>
<span class="kv-table__col kv-table__col--status">
@if (kycData.panVerified) {
<span class="kv-status kv-status--ok"><mat-icon>check_circle</mat-icon> Verified</span>
} @else {
<span class="kv-status kv-status--pending"><mat-icon>radio_button_unchecked</mat-icon> Pending</span>
}
</span>
<span class="kv-table__col kv-table__col--date">{{
kycData.panVerifiedOn ? formatDate(kycData.panVerifiedOn) : '—'
}}</span>
<span class="kv-table__col kv-table__col--action">
<button
mat-stroked-button
class="kv-action-btn"
type="button"
[disabled]="verifying.pan || !kycData.panNumber"
(click)="verifyPAN()"
>
@if (verifying.pan) {
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
} @else {
Re-Verify
}
</button>
</span>
</div>
<!-- Aadhaar Row -->
<div class="kv-table__row">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">fingerprint</mat-icon> Aadhaar
</span>
<span class="kv-table__col kv-table__col--num kv-mono">{{ kycData.aadhaarNumberMasked || '—' }}</span>
<span class="kv-table__col kv-table__col--status">
@if (kycData.aadhaarVerified) {
<span class="kv-status kv-status--ok"><mat-icon>check_circle</mat-icon> Verified</span>
} @else {
<span class="kv-status kv-status--pending"><mat-icon>radio_button_unchecked</mat-icon> Pending</span>
}
</span>
<span class="kv-table__col kv-table__col--date">{{
kycData.aadhaarVerifiedOn ? formatDate(kycData.aadhaarVerifiedOn) : '—'
}}</span>
<span class="kv-table__col kv-table__col--action">
@if (!showAadhaarReVerify && !aadhaarOtpSent) {
<button
mat-stroked-button
class="kv-action-btn"
type="button"
[disabled]="verifying.aadhaar || !kycData.aadhaarNumberMasked"
(click)="startAadhaarReVerify()"
>
Re-Verify
</button>
}
</span>
</div>
<!-- GSTIN Row (Non-Individual only) -->
@if (isNonIndividual) {
<div class="kv-table__row">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">business</mat-icon> GSTIN
</span>
<span class="kv-table__col kv-table__col--num kv-mono">{{ kycData.gstinNumber || '—' }}</span>
<span class="kv-table__col kv-table__col--status">
@if (kycData.gstinVerified) {
<span class="kv-status kv-status--ok"><mat-icon>check_circle</mat-icon> Verified</span>
} @else {
<span class="kv-status kv-status--pending"><mat-icon>radio_button_unchecked</mat-icon> Pending</span>
}
</span>
<span class="kv-table__col kv-table__col--date">{{
kycData.gstinVerifiedOn ? formatDate(kycData.gstinVerifiedOn) : '—'
}}</span>
<span class="kv-table__col kv-table__col--action">
<button
mat-stroked-button
class="kv-action-btn"
type="button"
[disabled]="verifying.gstin || !kycData.gstinNumber"
(click)="verifyGSTIN()"
>
@if (verifying.gstin) {
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
} @else {
Re-Verify
}
</button>
</span>
</div>
}
<!-- Enterprise PAN Row (Non-Individual) -->
@if (isNonIndividual && kycData?.enterprisePan) {
<div class="kv-table__row">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">credit_card</mat-icon> Enterprise PAN
</span>
<span class="kv-table__col kv-table__col--num kv-mono">{{ kycData.enterprisePan }}</span>
<span class="kv-table__col kv-table__col--status">
@if (kycData.enterprisePanVerified) {
<span class="kv-status kv-status--ok"><mat-icon>check_circle</mat-icon> Verified</span>
} @else {
<span class="kv-status kv-status--pending"><mat-icon>radio_button_unchecked</mat-icon> Pending</span>
}
</span>
<span class="kv-table__col kv-table__col--date">{{
kycData.enterprisePanVerifiedOn ? formatDate(kycData.enterprisePanVerifiedOn) : '—'
}}</span>
<span class="kv-table__col kv-table__col--action"></span>
</div>
}
<!-- CIN Row (Non-Individual / Company) -->
@if (isNonIndividual && kycData?.cinNumber) {
<div class="kv-table__row">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">verified_user</mat-icon> CIN
</span>
<span class="kv-table__col kv-table__col--num kv-mono">{{ kycData.cinNumber }}</span>
<span class="kv-table__col kv-table__col--status">
@if (kycData.cinVerified) {
<span class="kv-status kv-status--ok"><mat-icon>check_circle</mat-icon> Verified</span>
} @else {
<span class="kv-status kv-status--pending"><mat-icon>radio_button_unchecked</mat-icon> Pending</span>
}
</span>
<span class="kv-table__col kv-table__col--date">—</span>
<span class="kv-table__col kv-table__col--action"></span>
</div>
}
<!-- Incorporation Date Row (Non-Individual) -->
@if (isNonIndividual && kycData?.incorporationDate) {
<div class="kv-table__row kv-table__row--link">
<span class="kv-table__col kv-table__col--doc">
<mat-icon class="kv-doc-icon">event</mat-icon> Incorporation Date
</span>
<span class="kv-table__col kv-table__col--num">{{ formatDate(kycData.incorporationDate) }}</span>
<span class="kv-table__col kv-table__col--status">—</span>
<span class="kv-table__col kv-table__col--date">—</span>
<span class="kv-table__col kv-table__col--action"></span>
</div>
}
</div>
<!-- ─── PAN ↔ Aadhaar Link — premium status card (replaces the legacy
table row). Dark gradient base with state-driven accent so the
linking state is the first thing a reviewer sees. -->
<div
class="pal-card"
[class.pal-card--ok]="kycData?.panAadhaarSeedingStatus === 'Y'"
[class.pal-card--fail]="kycData?.panAadhaarSeedingStatus === 'N'"
[class.pal-card--info]="kycData?.panAadhaarSeedingStatus === 'E'"
[class.pal-card--pending]="
kycData?.panAadhaarSeedingStatus !== 'Y' &&
kycData?.panAadhaarSeedingStatus !== 'N' &&
kycData?.panAadhaarSeedingStatus !== 'E'
"
>
<div class="pal-card__left">
<div class="pal-card__icon">
<mat-icon>credit_card</mat-icon>
</div>
<div class="pal-card__txt">
<div class="pal-card__small">Verification Status</div>
<div class="pal-card__title">PAN &harr; Aadhaar</div>
<div class="pal-card__status">
@if (kycData?.panAadhaarSeedingStatus === 'Y') {
<mat-icon>check_circle</mat-icon> Linked (Seeded)
} @else if (kycData?.panAadhaarSeedingStatus === 'N') {
<mat-icon>cancel</mat-icon> Not Linked
} @else if (kycData?.panAadhaarSeedingStatus === 'E') {
<mat-icon>info</mat-icon> Exempt
} @else {
<mat-icon>radio_button_unchecked</mat-icon> Pending
}
</div>
</div>
</div>
<div class="pal-card__badge">
@if (kycData?.panAadhaarSeedingStatus === 'Y') {
<mat-icon>check</mat-icon>
} @else if (kycData?.panAadhaarSeedingStatus === 'N') {
<mat-icon>close</mat-icon>
} @else if (kycData?.panAadhaarSeedingStatus === 'E') {
<mat-icon>info</mat-icon>
} @else {
<mat-icon>schedule</mat-icon>
}
</div>
<div class="pal-card__hint">As per Income Tax Portal &mdash; Section 139AA</div>
</div>
<!-- Aadhaar OTP inline (shown below table when re-verifying) -->
@if (showAadhaarReVerify && !aadhaarOtpSent) {
<div class="kv-otp-bar">
<mat-form-field appearance="outline" class="kv-otp-input">
<mat-label>Enter 12-digit Aadhaar</mat-label>
<input
matInput
[(ngModel)]="aadhaarFullNumber"
[ngModelOptions]="{ standalone: true }"
maxlength="12"
type="password"
/>
</mat-form-field>
<button
mat-raised-button
color="primary"
type="button"
class="kv-otp-btn"
[disabled]="!aadhaarFullNumber || aadhaarFullNumber.length !== 12 || verifying.aadhaar"
(click)="sendAadhaarOtp()"
>
@if (verifying.aadhaar) {
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
} @else {
Send OTP
}
</button>
</div>
}
@if (aadhaarOtpSent) {
<div class="kv-otp-bar">
<span class="kv-otp-label"><mat-icon>sms</mat-icon> OTP sent</span>
<mat-form-field appearance="outline" class="kv-otp-input">
<mat-label>Enter OTP</mat-label>
<input
matInput
[(ngModel)]="aadhaarOtp"
[ngModelOptions]="{ standalone: true }"
maxlength="6"
autocomplete="one-time-code"
/>
</mat-form-field>
<button
mat-raised-button
color="primary"
type="button"
class="kv-otp-btn"
[disabled]="!aadhaarOtp || aadhaarOtp.length < 4 || aadhaarOtpVerifying"
(click)="verifyAadhaarOtp()"
>
@if (aadhaarOtpVerifying) {
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
} @else {
Verify
}
</button>
<button
mat-stroked-button
type="button"
class="kv-otp-btn"
[disabled]="verifying.aadhaar"
(click)="sendAadhaarOtp()"
>
Resend
</button>
</div>
}
@if (verificationError.aadhaar) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon> {{ verificationError.aadhaar }}
</div>
}
@if (verificationError.pan) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon> {{ verificationError.pan }}
</div>
}
<!-- KYC Meta Grid -->
<div class="kv-meta-grid">
<div class="kv-meta-item">
<span class="kv-meta-label">KYC Type</span>
<span class="kv-meta-value">{{
kycData.kycType === 1 ? 'Individual' : kycData.kycType === 2 ? 'Non-Individual' : '—'
}}</span>
</div>
<div class="kv-meta-item">
<span class="kv-meta-label">Risk Category</span>
<span class="kv-meta-value">{{
kycData.riskCategory === 1
? 'Low'
: kycData.riskCategory === 2
? 'Medium'
: kycData.riskCategory === 3
? 'High'
: '—'
}}</span>
</div>
<div class="kv-meta-item">
<span class="kv-meta-label">Initiated On</span>
<span class="kv-meta-value">{{ formatDate(kycData.initiatedOn) }}</span>
</div>
<div class="kv-meta-item">
<span class="kv-meta-label">Last Verified</span>
<span class="kv-meta-value">{{ formatDate(kycData.verifiedOn) }}</span>
</div>
<div class="kv-meta-item">
<span class="kv-meta-label">Expiry Date</span>
<span class="kv-meta-value">{{ formatDate(kycData.expiryDate) }}</span>
</div>
@if (kycData.remarks) {
<div class="kv-meta-item kv-meta-item--full">
<span class="kv-meta-label">Remarks</span>
<span class="kv-meta-value">{{ kycData.remarks }}</span>
</div>
}
</div>
<!-- Re-KYC: Upload Signed Declaration & Complete -->
<div class="rekyc-section">
<div class="rekyc-header">
<div class="rekyc-icon-wrap">
<fa-icon icon="sync-alt" class="rekyc-icon"></fa-icon>
</div>
<div class="rekyc-header-text">
<h4 class="rekyc-title">Re-KYC Completion</h4>
<p class="rekyc-desc">Print self-declaration, get it signed, upload &amp; complete re-KYC.</p>
</div>
</div>
<!-- Step 1 -->
<div class="rekyc-timeline">
<div class="rekyc-tl-item">
<div class="rekyc-tl-dot">
<span class="rekyc-tl-num">1</span>
<div class="rekyc-tl-line"></div>
</div>
<div class="rekyc-tl-content">
<div class="rekyc-tl-label">Download Self Declaration Form</div>
<div class="rekyc-tl-sub">System-generated PDF with PAN, Aadhaar &amp; KYC details</div>
<button mat-flat-button class="rekyc-btn-print" type="button" (click)="printSelfDeclaration()">
<fa-icon icon="file-pdf"></fa-icon> Download PDF
</button>
</div>
</div>
<!-- Step 2 -->
<div class="rekyc-tl-item">
<div class="rekyc-tl-dot">
<span class="rekyc-tl-num">2</span>
<div class="rekyc-tl-line"></div>
</div>
<div class="rekyc-tl-content">
<div class="rekyc-tl-label">Upload Signed Declaration</div>
<div class="rekyc-tl-sub">Get the form signed by the client and upload the scanned copy</div>
<label class="rekyc-upload-zone" [class.has-file]="selectedDeclarationFile">
<input type="file" accept=".pdf,.jpg,.jpeg,.png" (change)="onDeclarationFileSelected($event)" hidden />
@if (!selectedDeclarationFile) {
<mat-icon class="upload-zone-icon">cloud_upload</mat-icon>
<span class="upload-zone-text">Click to upload signed form</span>
<span class="upload-zone-hint">PDF, JPG or PNG</span>
} @else {
<fa-icon icon="check-circle" class="upload-zone-check"></fa-icon>
<span class="upload-zone-filename">{{ selectedDeclarationFile.name }}</span>
<span class="upload-zone-hint">Click to change file</span>
}
</label>
</div>
</div>
<!-- Step 3 -->
<div class="rekyc-tl-item rekyc-tl-item--last">
<div class="rekyc-tl-dot">
<span class="rekyc-tl-num">3</span>
</div>
<div class="rekyc-tl-content">
<div class="rekyc-tl-label">Complete Re-KYC</div>
<div class="rekyc-tl-sub">Updates Last Verified date and sets new Expiry Date as per RBI norms</div>
<button
mat-flat-button
color="primary"
class="rekyc-btn-complete"
type="button"
[disabled]="!selectedDeclarationFile || reKycCompleting || !kycId"
(click)="completeReKyc()"
>
@if (reKycCompleting) {
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
Completing...
} @else {
<fa-icon icon="check-circle"></fa-icon> Complete Re-KYC
}
</button>
</div>
</div>
</div>
@if (reKycSuccess) {
<div class="rekyc-result rekyc-result--success">
<fa-icon icon="check-circle" class="rekyc-result-icon"></fa-icon>
<div>
<strong>Re-KYC completed successfully</strong>
<p>Last Verified and Expiry Date have been updated.</p>
</div>
</div>
}
@if (reKycError) {
<div class="rekyc-result rekyc-result--error">
<mat-icon class="rekyc-result-icon">error_outline</mat-icon>
<div>
<strong>Re-KYC failed</strong>
<p>{{ reKycError }}</p>
</div>
</div>
}
</div>
}
<!-- No KYC Data State -->
@if (!isEditMode && !kycData) {
<div class="kyc-empty">
<mat-icon class="kyc-empty-icon">verified_user</mat-icon>
<p>{{ 'labels.inputs.KYC Verification' | translate }} not initiated yet.</p>
<button mat-raised-button color="primary" (click)="toggleEditMode()" type="button">
{{ 'labels.inputs.KYC verification initiated' | translate }}
</button>
</div>
}
<!-- Edit Form -->
@if (isEditMode) {
<mat-card class="kyc-edit-card">
<mat-card-content>
<form [formGroup]="kycForm" (ngSubmit)="saveKyc()">
<div class="kyc-edit-grid">
<!-- PAN -->
<div class="kyc-edit-field">
<div class="kyc-field-label-row">
<span class="kyc-field-title">{{ 'labels.inputs.PAN Number' | translate }}</span>
<span class="kyc-tag">KYC</span>
</div>
<div class="kyc-input-row">
<mat-form-field appearance="outline" class="kyc-input">
<mat-label>{{ 'labels.inputs.PAN Number' | translate }}</mat-label>
<input
matInput
formControlName="panNumber"
maxlength="10"
style="text-transform: uppercase"
(input)="
kycForm
.get('panNumber')
?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })
"
/>
@if (kycForm.get('panNumber')?.hasError('pattern') && kycForm.get('panNumber')?.touched) {
<mat-error>{{ 'labels.inputs.Enter 10-character PAN' | translate }}</mat-error>
}
@if (verificationStatus.pan === 'VERIFIED') {
<mat-icon matSuffix class="status-icon verified">check_circle</mat-icon>
}
@if (verificationStatus.pan === 'FAILED') {
<mat-icon matSuffix class="status-icon failed">cancel</mat-icon>
}
</mat-form-field>
<button
mat-raised-button
color="accent"
type="button"
class="verify-btn"
[disabled]="
!kycId || !kycForm.get('panNumber')?.value || kycForm.get('panNumber')?.invalid || verifying.pan
"
(click)="verifyPAN()"
[matTooltip]="!kycId ? 'Save KYC details first' : ''"
>
@if (verifying.pan) {
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
} @else {
{{ 'labels.inputs.Verify' | translate }}
}
</button>
</div>
@if (verificationError.pan) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon>
<span>{{ verificationError.pan }}</span>
</div>
}
@if (verificationStatus.pan === 'VERIFIED' && verificationDetails.pan?.name) {
<span class="verification-detail-text">{{ verificationDetails.pan.name }}</span>
}
</div>
<!-- Aadhaar -->
<div class="kyc-edit-field">
<div class="kyc-field-label-row">
<span class="kyc-field-title">{{ 'labels.inputs.Aadhaar Number' | translate }}</span>
<span class="kyc-tag">KYC</span>
</div>
<div class="kyc-input-row">
<mat-form-field appearance="outline" class="kyc-input">
<mat-label>{{ 'labels.inputs.Aadhaar Number' | translate }}</mat-label>
<input
matInput
formControlName="aadhaarNumber"
maxlength="12"
inputmode="numeric"
autocomplete="off"
placeholder="Enter 12-digit Aadhaar"
[readonly]="aadhaarOtpSent"
/>
@if (kycData?.aadhaarNumberMasked) {
<mat-hint>On file: {{ kycData.aadhaarNumberMasked }}</mat-hint>
}
@if (kycForm.get('aadhaarNumber')?.hasError('pattern') && kycForm.get('aadhaarNumber')?.touched) {
<mat-error>{{ 'labels.inputs.Enter 12-digit Aadhaar' | translate }}</mat-error>
}
@if (verificationStatus.aadhaar === 'VERIFIED') {
<mat-icon matSuffix class="status-icon verified">check_circle</mat-icon>
}
@if (verificationStatus.aadhaar === 'FAILED') {
<mat-icon matSuffix class="status-icon failed">cancel</mat-icon>
}
</mat-form-field>
@if (!aadhaarOtpSent) {
<button
mat-raised-button
color="accent"
type="button"
class="verify-btn"
[disabled]="
!kycId ||
!kycForm.get('aadhaarNumber')?.value ||
kycForm.get('aadhaarNumber')?.invalid ||
verifying.aadhaar
"
(click)="sendAadhaarOtp()"
[matTooltip]="!kycId ? 'Save KYC details first' : ''"
>
@if (verifying.aadhaar) {
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
} @else {
Send OTP
}
</button>
}
</div>
<!-- OTP Section in Edit Mode -->
@if (aadhaarOtpSent) {
<div class="otp-section">
<p class="otp-info">
<mat-icon class="otp-info-icon">sms</mat-icon>
OTP sent to Aadhaar-linked mobile
</p>
<div class="otp-inline">
<mat-form-field appearance="outline" class="otp-field">
<mat-label>Enter OTP</mat-label>
<input
matInput
[(ngModel)]="aadhaarOtp"
[ngModelOptions]="{ standalone: true }"
maxlength="6"
autocomplete="one-time-code"
/>
</mat-form-field>
<button
mat-raised-button
color="accent"
class="otp-verify-btn"
type="button"
[disabled]="!aadhaarOtp || aadhaarOtp.length < 4 || aadhaarOtpVerifying"
(click)="verifyAadhaarOtp()"
>
@if (aadhaarOtpVerifying) {
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
} @else {
Verify OTP
}
</button>
<button
mat-stroked-button
type="button"
class="otp-resend-btn"
[disabled]="verifying.aadhaar"
(click)="sendAadhaarOtp()"
>
Resend
</button>
</div>
</div>
}
@if (verificationError.aadhaar) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon>
<span>{{ verificationError.aadhaar }}</span>
</div>
}
</div>
<!-- GSTIN (Non-Individual only) -->
@if (isNonIndividual) {
<div class="kyc-edit-field">
<div class="kyc-field-label-row">
<span class="kyc-field-title">{{ 'labels.inputs.GSTIN Number' | translate }}</span>
<span class="kyc-tag">KYC</span>
</div>
<div class="kyc-input-row">
<mat-form-field appearance="outline" class="kyc-input">
<mat-label>{{ 'labels.inputs.GSTIN Number' | translate }}</mat-label>
<input
matInput
formControlName="gstinNumber"
maxlength="15"
style="text-transform: uppercase"
(input)="
kycForm
.get('gstinNumber')
?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })
"
/>
@if (kycForm.get('gstinNumber')?.hasError('pattern') && kycForm.get('gstinNumber')?.touched) {
<mat-error>{{ 'labels.inputs.Enter 15-character GSTIN' | translate }}</mat-error>
}
@if (verificationStatus.gstin === 'VERIFIED') {
<mat-icon matSuffix class="status-icon verified">check_circle</mat-icon>
}
@if (verificationStatus.gstin === 'FAILED') {
<mat-icon matSuffix class="status-icon failed">cancel</mat-icon>
}
</mat-form-field>
<button
mat-raised-button
color="accent"
type="button"
class="verify-btn"
[disabled]="
!kycId ||
!kycForm.get('gstinNumber')?.value ||
kycForm.get('gstinNumber')?.invalid ||
verifying.gstin
"
(click)="verifyGSTIN()"
[matTooltip]="!kycId ? 'Save KYC details first' : ''"
>
@if (verifying.gstin) {
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
} @else {
{{ 'labels.inputs.Verify' | translate }}
}
</button>
</div>
@if (verificationError.gstin) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon>
<span>{{ verificationError.gstin }}</span>
</div>
}
@if (verificationStatus.gstin === 'VERIFIED' && verificationDetails.gstin?.businessName) {
<span class="verification-detail-text">{{ verificationDetails.gstin.businessName }}</span>
}
</div>
}
<!-- KYC Type -->
@if (!kycId) {
<mat-form-field appearance="outline">
<mat-label>{{ 'labels.inputs.KYC Type' | translate }}</mat-label>
<mat-select formControlName="kycType">
<mat-option [value]="1">Individual</mat-option>
<mat-option [value]="2">Non-Individual</mat-option>
</mat-select>
</mat-form-field>
}
<!-- Risk Category -->
<mat-form-field appearance="outline">
<mat-label>{{ 'labels.inputs.Risk Category' | translate }}</mat-label>
<mat-select formControlName="riskCategory">
<mat-option [value]="1">Low</mat-option>
<mat-option [value]="2">Medium</mat-option>
<mat-option [value]="3">High</mat-option>
</mat-select>
</mat-form-field>
<!-- KYC Exception Flag -->
<div class="full-span exception-controls-row" style="display: flex; align-items: center; gap: 20px; margin-bottom: 12px; flex-wrap: wrap;">
<mat-checkbox formControlName="isException" style="margin-top: 8px;">Mark as KYC Exception</mat-checkbox>
@if (kycForm.get('isException')?.value) {
<mat-form-field appearance="outline" style="flex: 1; min-width: 250px;">
<mat-label>Exception Reasons</mat-label>
<mat-select formControlName="exceptionReason" multiple>
@if (!isNonIndividual) {
<mat-option value="PAN Card Verification Failed">PAN Card Verification Failed</mat-option>
<mat-option value="Aadhaar Verification Failed">Aadhaar Verification Failed</mat-option>
} @else {
<mat-option value="Enterprise PAN Verification Failed">Enterprise PAN Verification Failed</mat-option>
<mat-option value="GSTIN Verification Failed">GSTIN Verification Failed</mat-option>
<mat-option value="CIN Verification Failed">CIN Verification Failed</mat-option>
}
</mat-select>
</mat-form-field>
}
</div>
<!-- Remarks -->
<mat-form-field appearance="outline" class="full-span">
<mat-label>{{ 'labels.inputs.Remarks' | translate }}</mat-label>
<textarea matInput formControlName="remarks" rows="3"></textarea>
</mat-form-field>
</div>
@if (errorMessage) {
<div class="kyc-error-msg">
<mat-icon class="kyc-error-icon">error_outline</mat-icon>
<span>{{ errorMessage }}</span>
</div>
}
@if (!kycId) {
<div class="kyc-info-hint">
<mat-icon class="kyc-info-hint-icon">info</mat-icon>
<span>Save KYC details first to enable verification buttons.</span>
</div>
}
<div class="kyc-form-actions">
<button mat-raised-button type="submit" color="primary" [disabled]="kycForm.invalid || saving">
@if (saving) {
<mat-progress-spinner diameter="18" mode="indeterminate"></mat-progress-spinner>
} @else {
{{ 'labels.buttons.Submit' | translate }}
}
</button>
<button mat-stroked-button type="button" (click)="toggleEditMode()">
{{ 'labels.buttons.Cancel' | translate }}
</button>
</div>
</form>
</mat-card-content>
</mat-card>
}
}
</div>