Merge branch 'dev' into angular20
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
<div class="layout-column gap-2px">
|
||||
<h1 mat-dialog-title align="center">{{ 'labels.heading.Capture Client Image' | translate }}</h1>
|
||||
|
||||
<video #video width="540" height="480" autoplay></video>
|
||||
<video #video class="capture-video" autoplay></video>
|
||||
|
||||
<!-- Using a class will break renderer changes -->
|
||||
<canvas #canvas [ngStyle]="{ display: 'none' }"></canvas>
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
@use '../../../../../assets/styles/colours' as colors;
|
||||
|
||||
.capture-video {
|
||||
width: 100%;
|
||||
max-width: 640px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
border-radius: 4px;
|
||||
background-color: colors.$black;
|
||||
}
|
||||
|
||||
+21
-3
@@ -54,8 +54,13 @@ export class CaptureImageDialogComponent implements AfterViewInit, OnDestroy {
|
||||
*/
|
||||
startCamera() {
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
const videoConstraints: MediaTrackConstraints = {
|
||||
width: { ideal: 640 },
|
||||
height: { ideal: 480 },
|
||||
facingMode: 'user'
|
||||
};
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.getUserMedia({ video: videoConstraints })
|
||||
.then((stream: MediaStream) => {
|
||||
this.renderer.setProperty(this.video.nativeElement, 'srcObject', stream);
|
||||
this.video.nativeElement.play();
|
||||
@@ -95,13 +100,26 @@ export class CaptureImageDialogComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Captures the image by drawing video state on canvas, then converts canvas state to data URL.
|
||||
* Uses actual video dimensions to prevent aspect ratio distortion.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL for details.
|
||||
*/
|
||||
capture() {
|
||||
this.isCaptured = true;
|
||||
this.video.nativeElement.pause();
|
||||
this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, 150, 150);
|
||||
this.clientImageDataURL = this.canvas.nativeElement.toDataURL();
|
||||
|
||||
// Get actual video stream dimensions to preserve aspect ratio
|
||||
const videoWidth = this.video.nativeElement.videoWidth;
|
||||
const videoHeight = this.video.nativeElement.videoHeight;
|
||||
|
||||
// Set canvas dimensions to match video stream
|
||||
this.canvas.nativeElement.width = videoWidth;
|
||||
this.canvas.nativeElement.height = videoHeight;
|
||||
|
||||
// Draw the video frame at full resolution without distortion
|
||||
this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, videoWidth, videoHeight);
|
||||
|
||||
// Convert to data URL with JPEG format for smaller file size
|
||||
this.clientImageDataURL = this.canvas.nativeElement.toDataURL('image/jpeg', 0.9);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-1
@@ -255,6 +255,12 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
|
||||
this.loansAccountTermsForm.addControl('enableDownPayment', new UntypedFormControl(enableDownPayment));
|
||||
}
|
||||
|
||||
if (this.isFullTermTrancheEditable()) {
|
||||
const allowFullTermForTranche =
|
||||
this.loansAccountTermsData.allowFullTermForTranche ?? this.loanProduct?.allowFullTermForTranche ?? false;
|
||||
this.loansAccountTermsForm.patchValue({ allowFullTermForTranche });
|
||||
}
|
||||
|
||||
const allowAttributeOverrides = this.loansAccountTermsData.product.allowAttributeOverrides;
|
||||
if (!allowAttributeOverrides.repaymentEvery) {
|
||||
this.loansAccountTermsForm.controls.repaymentEvery.disable();
|
||||
@@ -517,7 +523,8 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
|
||||
multiDisburseLoan: [false],
|
||||
interestRateFrequencyType: [''],
|
||||
balloonRepaymentAmount: [''],
|
||||
interestRecognitionOnDisbursementDate: [false]
|
||||
interestRecognitionOnDisbursementDate: [false],
|
||||
allowFullTermForTranche: [false]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -699,4 +706,12 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
|
||||
collateral: this.collateralDataSource
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if full term tranche option should be editable at loan level.
|
||||
* Only available if the loan product has it enabled and is PROGRESSIVE schedule type.
|
||||
*/
|
||||
isFullTermTrancheEditable(): boolean {
|
||||
return this.isProgressive && this.loanProduct?.allowFullTermForTranche === true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
<span class="flex-60">{{ loanDetails.maxOutstandingLoanBalance | formatNumber }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-fill" *ngIf="loanDetails.allowFullTermForTranche">
|
||||
<span class="flex-40">{{ 'labels.inputs.Allow full term for each tranche' | translate }}:</span>
|
||||
<span class="flex-60">{{ loanDetails.allowFullTermForTranche | yesNo }}</span>
|
||||
</div>
|
||||
|
||||
<h3>{{ 'labels.heading.Loan Tranche Details' | translate }}</h3>
|
||||
|
||||
<div class="layout-row margin-t layout-xs-column layout-align-end gap-2percent">
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
||||
import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
|
||||
import { YesnoPipe } from '../../../pipes/yesno.pipe';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
@@ -49,7 +50,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
MatRowDef,
|
||||
MatRow,
|
||||
DateFormatPipe,
|
||||
FormatNumberPipe
|
||||
FormatNumberPipe,
|
||||
YesnoPipe
|
||||
]
|
||||
})
|
||||
export class LoanTrancheDetailsComponent implements OnInit {
|
||||
|
||||
+7
-1
@@ -146,6 +146,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
multiDisburseLoan: this.loanProductsTemplate.multiDisburseLoan,
|
||||
maxTrancheCount: this.loanProductsTemplate.maxTrancheCount,
|
||||
outstandingLoanBalance: this.loanProductsTemplate.outstandingLoanBalance,
|
||||
allowFullTermForTranche: this.loanProductsTemplate.allowFullTermForTranche,
|
||||
enableDownPayment: this.loanProductsTemplate.enableDownPayment,
|
||||
enableInstallmentLevelDelinquency: this.loanProductsTemplate.enableInstallmentLevelDelinquency,
|
||||
loanScheduleType: this.loanProductsTemplate.loanScheduleType.code,
|
||||
@@ -314,6 +315,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
isInterestRecalculationEnabled: [false],
|
||||
holdGuaranteeFunds: [false],
|
||||
multiDisburseLoan: [false],
|
||||
allowFullTermForTranche: [false],
|
||||
allowAttributeConfiguration: [true],
|
||||
allowPartialPeriodInterestCalculation: [false],
|
||||
allowAttributeOverrides: this.formBuilder.group({
|
||||
@@ -553,7 +555,10 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
} else {
|
||||
this.loanProductSettingsForm.removeControl('maxTrancheCount');
|
||||
this.loanProductSettingsForm.removeControl('outstandingLoanBalance');
|
||||
this.loanProductSettingsForm.patchValue({ disallowExpectedDisbursements: false });
|
||||
this.loanProductSettingsForm.patchValue({
|
||||
disallowExpectedDisbursements: false,
|
||||
allowFullTermForTranche: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -647,6 +652,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
this.advancedTransactionProcessingStrategyDisabled = false;
|
||||
this.isAdvancedTransactionProcessingStrategy = false;
|
||||
this.loanProductSettingsForm.removeControl('chargeOffBehaviour');
|
||||
this.loanProductSettingsForm.patchValue({ allowFullTermForTranche: false });
|
||||
} else {
|
||||
// Only Advanced Payment Allocation Strategy
|
||||
this.transactionProcessingStrategyDataBase.some((cn: CodeName) => {
|
||||
|
||||
@@ -97,6 +97,7 @@ export interface LoanProduct {
|
||||
creditAllocationAllocationTypes: OptionData[];
|
||||
multiDisburseLoan: boolean;
|
||||
maxTrancheCount: number;
|
||||
allowFullTermForTranche: boolean;
|
||||
disallowExpectedDisbursements: boolean;
|
||||
allowApprovedDisbursedAmountsOverApplied: boolean;
|
||||
overAppliedNumber: number;
|
||||
|
||||
@@ -1599,6 +1599,7 @@
|
||||
"Enable Dormancy Tracking": "Enable Dormancy Tracking",
|
||||
"Enable Down Payment": "Enable Down Payment",
|
||||
"Enable Multiple Disbursals": "Enable Multiple Disbursals",
|
||||
"Allow full term for each tranche": "Allow full term for each tranche",
|
||||
"Enabled": "Enabled",
|
||||
"End Date": "End Date",
|
||||
"End Point": "End Point",
|
||||
@@ -3566,6 +3567,7 @@
|
||||
"Keyboard Shortcuts": "Keyboard Shortcuts",
|
||||
"Leave this checkbox checked if the loan has Down Payment": "Leave this checkbox checked if the loan has Down Payment, A Down Payment is a sum a buyer pays upfront when purchasing a good. It represents a percentage of the total purchase price, and the balance is usually financed",
|
||||
"Leave this checkbox unchecked": "Leave this checkbox unchecked if the loan is a single disburse loan. Check this checkbox if the loan is a multi disburse loan. See additional fields for additional information required for this type of loan.",
|
||||
"Allow full term length for each tranche disbursement": "When enabled, each tranche disbursement will follow the full loan term schedule instead of fitting within the remaining term. Only available for PROGRESSIVE loan schedule type.",
|
||||
"Loan Account": "Loan Account",
|
||||
"Loan Product can be used to apply for Topup Loans": "If selected, the Loan Product can be used to apply for Top Up Loans.",
|
||||
"Loan products may be assigned": "Loan products may be assigned to a fund set up by your financial institution. If available, the fund field can be used for tracking and reporting on groups of loans.",
|
||||
|
||||
Reference in New Issue
Block a user