diff --git a/src/app/products/loan-products/import-loan-product-dialog/import-loan-product-dialog.component.html b/src/app/products/loan-products/import-loan-product-dialog/import-loan-product-dialog.component.html
new file mode 100644
index 000000000..3b19c59f6
--- /dev/null
+++ b/src/app/products/loan-products/import-loan-product-dialog/import-loan-product-dialog.component.html
@@ -0,0 +1,24 @@
+
>(MatDialogRef);
+ private formBuilder = inject(UntypedFormBuilder);
+ data = inject(MAT_DIALOG_DATA);
+
+ /** Import Loan Product form. */
+ importLoanProductForm: UntypedFormGroup;
+
+ ngOnInit() {
+ this.createImportLoanProductForm();
+ }
+
+ /**
+ * Creates the import loan product form.
+ */
+ createImportLoanProductForm() {
+ this.importLoanProductForm = this.formBuilder.group({
+ file: [
+ '',
+ Validators.required
+ ]
+ });
+ }
+
+ /**
+ * Sets file form control value.
+ * @param {any} $event file change event.
+ */
+ onFileSelect($event: any) {
+ if ($event.target.files.length > 0) {
+ const file = $event.target.files[0];
+ this.importLoanProductForm.get('file').setValue(file);
+ }
+ }
+}
diff --git a/src/app/products/loan-products/loan-products.component.html b/src/app/products/loan-products/loan-products.component.html
index 6c629c01b..2c691b361 100644
--- a/src/app/products/loan-products/loan-products.component.html
+++ b/src/app/products/loan-products/loan-products.component.html
@@ -5,6 +5,12 @@
{{ 'labels.buttons.Create Loan Product' | translate }}
+
+
+
diff --git a/src/app/products/loan-products/loan-products.component.ts b/src/app/products/loan-products/loan-products.component.ts
index b098cc098..c0f4ee595 100644
--- a/src/app/products/loan-products/loan-products.component.ts
+++ b/src/app/products/loan-products/loan-products.component.ts
@@ -2,6 +2,7 @@
import { Component, OnInit, TemplateRef, ElementRef, ViewChild, AfterViewInit, inject } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, MatSortHeader } from '@angular/material/sort';
+import { MatDialog } from '@angular/material/dialog';
import {
MatTableDataSource,
MatTable,
@@ -17,9 +18,17 @@ import {
} from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
+/** rxjs Imports */
+import { switchMap, catchError, finalize } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+
/* Custom Services */
import { PopoverService } from '../../configuration-wizard/popover/popover.service';
import { ConfigurationWizardService } from '../../configuration-wizard/configuration-wizard.service';
+import { ProductsService } from '../products.service';
+import { SettingsService } from 'app/settings/settings.service';
+import { ErrorHandlerService } from 'app/core/error-handler/error-handler.service';
+import { ImportLoanProductDialogComponent } from './import-loan-product-dialog/import-loan-product-dialog.component';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { MatTooltip } from '@angular/material/tooltip';
import { StatusLookupPipe } from '../../pipes/status-lookup.pipe';
@@ -56,6 +65,10 @@ export class LoanProductsComponent implements OnInit, AfterViewInit {
private router = inject(Router);
private configurationWizardService = inject(ConfigurationWizardService);
private popoverService = inject(PopoverService);
+ private dialog = inject(MatDialog);
+ private productsService = inject(ProductsService);
+ private settingsService = inject(SettingsService);
+ private errorHandler = inject(ErrorHandlerService);
loanProductsData: any;
displayedColumns: string[] = [
@@ -157,4 +170,75 @@ export class LoanProductsComponent implements OnInit, AfterViewInit {
this.configurationWizardService.showLoanProducts = true;
this.router.navigate(['/products']);
}
+
+ /**
+ * Opens the import loan product dialog.
+ */
+ openImportDialog(): void {
+ const importDialogRef = this.dialog.open(ImportLoanProductDialogComponent, {
+ width: '50rem'
+ });
+
+ importDialogRef.afterClosed().subscribe((response: any) => {
+ if (response && response.file) {
+ this.importLoanProduct(response.file);
+ }
+ });
+ }
+
+ /**
+ * Imports a loan product from a JSON file.
+ * @param {File} file The JSON file containing loan product definition.
+ */
+ importLoanProduct(file: File): void {
+ const reader = new FileReader();
+
+ reader.onload = (e: any) => {
+ try {
+ const loanProductData = JSON.parse(e.target.result);
+
+ // Remove fields that shouldn't be included in creation
+ delete loanProductData.id;
+ delete loanProductData.status;
+
+ // Add required fields for API with null safety checks
+ const locale = this.settingsService.language?.code || 'en';
+ const dateFormat = this.settingsService.dateFormat || 'dd MMMM yyyy';
+
+ const payload = {
+ ...loanProductData,
+ locale,
+ dateFormat,
+ // Add default required fields if not present
+ currencyCode: loanProductData.currencyCode || 'USD',
+ digitsAfterDecimal: loanProductData.digitsAfterDecimal ?? 2,
+ charges: loanProductData.charges || []
+ };
+
+ // Call API to create loan product with proper error handling
+ this.productsService
+ .createLoanProduct(payload)
+ .pipe(
+ switchMap(() => this.productsService.getLoanProducts()),
+ catchError((error) => this.errorHandler.handleError(error, 'Loan Product Import'))
+ )
+ .subscribe({
+ next: (data: any) => {
+ this.loanProductsData = data;
+ this.dataSource.data = this.loanProductsData;
+ this.errorHandler.showSuccess('Loan product imported successfully!');
+ },
+ error: () => {
+ // Error already handled by ErrorHandlerService
+ }
+ });
+ } catch (error) {
+ this.errorHandler.showInfo(
+ 'The selected file is not a valid JSON file. Please check the file format and try again.'
+ );
+ }
+ };
+
+ reader.readAsText(file);
+ }
}