/** * 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/. */ /** Angular Imports */ import { Component, inject } from '@angular/core'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { SelectionModel } from '@angular/cdk/collections'; import * as _ from 'lodash'; import { MatTableDataSource, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow } from '@angular/material/table'; import { MatDialog } from '@angular/material/dialog'; /** Dialog Imports */ import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; /** Custom Services */ import { TasksService } from '../../tasks.service'; import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; import { TranslateService } from '@ngx-translate/core'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MatCheckbox } from '@angular/material/checkbox'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; interface RescheduleFormData { dateFormat: string; locale: string; approvedOnDate?: string; rejectedOnDate?: string; } @Component({ selector: 'mifosx-reschedule-loan', templateUrl: './reschedule-loan.component.html', styleUrls: ['./reschedule-loan.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, FaIconComponent, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCheckbox, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, DateFormatPipe ] }) export class RescheduleLoanComponent { private route = inject(ActivatedRoute); private dialog = inject(MatDialog); private dateUtils = inject(Dates); private router = inject(Router); private settingsService = inject(SettingsService); private translateService = inject(TranslateService); private tasksService = inject(TasksService); /** Loans Data */ loans: any; /** Datasource */ dataSource: MatTableDataSource; /** Rows Selection Data */ selection: SelectionModel; /** Batch Requests */ batchRequests: any[]; /** Displayed Columns */ displayedColumns: string[] = [ 'select', 'client', 'rescheduleRequestNo', 'loanAccountNo', 'rescheduleForm', 'rescheduleReason' ]; /** * Retrieves the reschedule loan data from `resolve`. * @param {ActivatedRoute} route Activated Route. * @param {Dialog} dialog MatDialog. * @param {Dates} dateUtils Date Utils. * @param {router} router Router. * @param {SettingsService} settingsService Settings Service. * @param {TasksService} tasksService Tasks Service. */ constructor() { this.route.data.subscribe((data: { rescheduleLoansData: any }) => { this.loans = data.rescheduleLoansData; this.dataSource = new MatTableDataSource(this.loans); this.selection = new SelectionModel(true, []); }); } /** Whether the number of selected elements matches the total number of rows. */ isAllSelected() { const numSelected = this.selection.selected.length; const numRows = this.dataSource.data.length; return numSelected === numRows; } /** Selects all rows if they are not all selected; otherwise clear selection. */ masterToggle() { this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach((row: any) => this.selection.select(row)); } /** The label for the checkbox on the passed row */ checkboxLabel(row?: any): string { if (!row) { return `${this.isAllSelected() ? 'select' : 'deselect'} all`; } return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`; } bulkLoanReschedule(action: string) { const rescheduleLoanDialogRef = this.dialog.open(ConfirmationDialogComponent, { data: { heading: this.translateService.instant('labels.heading.Reschedule Loan'), dialogContext: this.translateService.instant('labels.dialogContext.Are you sure you want to') + action + this.translateService.instant('labels.dialogContext.the Reschedule Loan') } }); rescheduleLoanDialogRef.afterClosed().subscribe((response: { confirm: any }) => { if (response.confirm) { this.bulkLoanRescheduleRequest(action.toLowerCase()); } }); } bulkLoanRescheduleRequest(command: string) { const dateFormat = this.settingsService.dateFormat; const transactionDate = this.dateUtils.formatDate(this.settingsService.businessDate, dateFormat); const locale = this.settingsService.language.code; const formData: RescheduleFormData = { dateFormat, locale }; if (command === 'approve') { formData.approvedOnDate = transactionDate; } else { formData.rejectedOnDate = transactionDate; } const listSelectedAccounts = this.selection.selected; this.batchRequests = []; let reqId = 1; listSelectedAccounts.forEach((element: any) => { const url = 'rescheduleloans/' + element.id + '?command=' + command; const bodyData = JSON.stringify(formData); const batchData = { requestId: reqId++, relativeUrl: url, method: 'POST', body: bodyData }; this.batchRequests.push(batchData); }); this.tasksService.submitBatchData(this.batchRequests).subscribe((response: any) => { this.reload(); }); } applyFilter(filterValue: string = '') { this.dataSource.filter = filterValue.trim().toLowerCase(); } /** * Refetches data fot the component * TODO: Replace by a custom reload component instead of hard-coded back-routing. */ reload() { const url: string = this.router.url; this.router .navigateByUrl(`/checker-inbox-and-tasks`, { skipLocationChange: true }) .then(() => this.router.navigate([url])); } }