270 lines
9.3 KiB
TypeScript
270 lines
9.3 KiB
TypeScript
/**
|
|
* 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,
|
|
OnInit,
|
|
TemplateRef,
|
|
ElementRef,
|
|
ViewChild,
|
|
AfterViewInit,
|
|
OnDestroy,
|
|
OnChanges,
|
|
SimpleChanges,
|
|
inject
|
|
} from '@angular/core';
|
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
import { UntypedFormBuilder, UntypedFormControl, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
|
|
/** Custom Dialogs */
|
|
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
|
|
|
/** Custom Services */
|
|
import { OrganizationService } from '../../organization.service';
|
|
import { PopoverService } from '../../../configuration-wizard/popover/popover.service';
|
|
import { ConfigurationWizardService } from '../../../configuration-wizard/configuration-wizard.service';
|
|
|
|
/** Custom Dialog Component */
|
|
import { ContinueSetupDialogComponent } from '../../../configuration-wizard/continue-setup-dialog/continue-setup-dialog.component';
|
|
import { takeUntil } from 'rxjs/operators';
|
|
import { ReplaySubject, Subject } from 'rxjs';
|
|
import { Currency } from 'app/shared/models/general.model';
|
|
import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';
|
|
import { AsyncPipe } from '@angular/common';
|
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
|
import { MatGridList, MatGridTile } from '@angular/material/grid-list';
|
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|
import { AlertService } from 'app/core/alert/alert.service';
|
|
|
|
/**
|
|
* Manage Currencies component.
|
|
*/
|
|
@Component({
|
|
selector: 'mifosx-manage-currencies',
|
|
templateUrl: './manage-currencies.component.html',
|
|
styleUrls: ['./manage-currencies.component.scss'],
|
|
imports: [
|
|
...STANDALONE_SHARED_IMPORTS,
|
|
NgxMatSelectSearchModule,
|
|
FaIconComponent,
|
|
MatGridList,
|
|
MatGridTile,
|
|
AsyncPipe
|
|
]
|
|
})
|
|
export class ManageCurrenciesComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
|
|
private route = inject(ActivatedRoute);
|
|
private formBuilder = inject(UntypedFormBuilder);
|
|
private organizationservice = inject(OrganizationService);
|
|
dialog = inject(MatDialog);
|
|
private router = inject(Router);
|
|
private translateService = inject(TranslateService);
|
|
private configurationWizardService = inject(ConfigurationWizardService);
|
|
private popoverService = inject(PopoverService);
|
|
private alertService = inject(AlertService);
|
|
|
|
//** Defining PlaceHolders for the search bar */
|
|
placeHolderLabel = '';
|
|
noEntriesFoundLabel = '';
|
|
/** Selected Currencies data. */
|
|
selectedCurrencies: any[];
|
|
/** Currency options data */
|
|
currencyList: Currency[] = [];
|
|
/** Currency form */
|
|
currencyForm: any;
|
|
|
|
/** Currency form reference */
|
|
@ViewChild('formRef', { static: true }) formRef: any;
|
|
@ViewChild('currencyFormRef') currencyFormRef: ElementRef<any>;
|
|
@ViewChild('templateCurrencyFormRef') templateCurrencyFormRef: TemplateRef<any>;
|
|
|
|
/** Currency data. */
|
|
protected currencyData: ReplaySubject<Currency[]> = new ReplaySubject<Currency[]>(1);
|
|
|
|
/** control for the filter select */
|
|
protected filterFormCtrl: UntypedFormControl = new UntypedFormControl('');
|
|
|
|
/** Subject that emits when the component has been destroyed. */
|
|
protected _onDestroy = new Subject<void>();
|
|
|
|
/**
|
|
* Retrieves the currency data from `resolve`.
|
|
* @param {ActivatedRoute} route Activated Route
|
|
* @param {FormBuilder} formBuilder Form Builder
|
|
* @param {OrganizationService} organizationservice Organization Service
|
|
* @param {MatDialog} dialog Mat Dialog
|
|
*/
|
|
constructor() {
|
|
this.route.parent.data.subscribe((data: { currencies: any }) => {
|
|
this.selectedCurrencies = data.currencies.selectedCurrencyOptions;
|
|
this.currencyList = data.currencies.currencyOptions;
|
|
});
|
|
}
|
|
|
|
ngOnInit() {
|
|
this.placeHolderLabel = this.translateService.instant('labels.text.Search');
|
|
this.noEntriesFoundLabel = this.translateService.instant('labels.text.No data found');
|
|
this.filterFormCtrl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
|
this.searchItem();
|
|
});
|
|
this.createCurrencyForm();
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this._onDestroy.next();
|
|
this._onDestroy.complete();
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges): void {
|
|
if (this.currencyList) {
|
|
this.currencyData.next(this.currencyList.slice());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates the currency form.
|
|
*/
|
|
createCurrencyForm() {
|
|
this.currencyForm = this.formBuilder.group({
|
|
currency: [
|
|
'',
|
|
Validators.required
|
|
]
|
|
});
|
|
}
|
|
|
|
searchItem(): void {
|
|
if (this.currencyList) {
|
|
const search: string = this.filterFormCtrl.value.toLowerCase();
|
|
|
|
if (!search) {
|
|
this.currencyData.next(this.currencyList.slice());
|
|
} else {
|
|
this.currencyData.next(
|
|
this.currencyList.filter((option: Currency) => {
|
|
return option.name.toLowerCase().indexOf(search) >= 0 || option.code.toLowerCase().indexOf(search) >= 0;
|
|
})
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a new currency to the list.
|
|
*/
|
|
addCurrency() {
|
|
const newCurrency = this.currencyForm.value.currency;
|
|
const selectedCurrencyCodes: any[] = this.selectedCurrencies.map((currency) => currency.code);
|
|
if (!selectedCurrencyCodes.includes(newCurrency.code)) {
|
|
selectedCurrencyCodes.push(newCurrency.code);
|
|
this.organizationservice.updateCurrencies(selectedCurrencyCodes).subscribe((response: any) => {
|
|
this.formRef.resetForm();
|
|
if (response?.rollbackTransaction) {
|
|
// Parked for checker approval - the currency has not actually been added yet, so the
|
|
// local list must not be mutated as if it had.
|
|
this.alertService.alert({
|
|
type: 'Success',
|
|
message: 'Currency configuration update has been submitted for approval.'
|
|
});
|
|
return;
|
|
}
|
|
this.selectedCurrencies.push(newCurrency);
|
|
if (this.configurationWizardService.showCurrencyForm) {
|
|
this.configurationWizardService.showCurrencyForm = false;
|
|
this.openDialog();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes Currency
|
|
* @param {string} currencyCode Currency Code
|
|
* @param {number} index Index
|
|
*/
|
|
deleteCurrency(currencyCode: string, index: number) {
|
|
const selectedCurrencyCodes: any[] = this.selectedCurrencies.map((currency) => currency.code);
|
|
selectedCurrencyCodes.splice(index, 1);
|
|
const deleteCurrencyDialogRef = this.dialog.open(DeleteDialogComponent, {
|
|
data: { deleteContext: `currency: ${currencyCode}` }
|
|
});
|
|
deleteCurrencyDialogRef.afterClosed().subscribe((response: any) => {
|
|
if (response.delete) {
|
|
this.organizationservice.updateCurrencies(selectedCurrencyCodes).subscribe((updateResponse: any) => {
|
|
this.formRef.resetForm();
|
|
if (updateResponse?.rollbackTransaction) {
|
|
// Parked for checker approval - the currency has not actually been removed yet, so the
|
|
// local list must not be mutated as if it had.
|
|
this.alertService.alert({
|
|
type: 'Success',
|
|
message: 'Currency configuration update has been submitted for approval.'
|
|
});
|
|
return;
|
|
}
|
|
this.selectedCurrencies.splice(index, 1);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
showPopover(
|
|
template: TemplateRef<any>,
|
|
target: HTMLElement | ElementRef<any>,
|
|
position: string,
|
|
backdrop: boolean
|
|
): void {
|
|
setTimeout(() => this.popoverService.open(template, target, position, backdrop, {}), 200);
|
|
}
|
|
|
|
ngAfterViewInit() {
|
|
if (this.configurationWizardService.showCurrencyForm) {
|
|
setTimeout(() => {
|
|
this.showPopover(this.templateCurrencyFormRef, this.currencyFormRef.nativeElement, 'bottom', true);
|
|
});
|
|
}
|
|
}
|
|
|
|
nextStep() {
|
|
this.configurationWizardService.showCurrencyForm = false;
|
|
this.configurationWizardService.showCreateHoliday = true;
|
|
this.router.navigate(['/organization']);
|
|
}
|
|
|
|
previousStep() {
|
|
this.configurationWizardService.showCurrencyForm = false;
|
|
this.configurationWizardService.showCurrencyList = true;
|
|
this.router.navigate(['/organization/currencies']);
|
|
}
|
|
|
|
openDialog() {
|
|
const continueSetupDialogRef = this.dialog.open(ContinueSetupDialogComponent, {
|
|
data: {
|
|
stepName: 'currency'
|
|
}
|
|
});
|
|
continueSetupDialogRef.afterClosed().subscribe((response: { step: number }) => {
|
|
if (response.step === 1) {
|
|
this.configurationWizardService.showCurrencyForm = false;
|
|
this.router.navigate(['../'], { relativeTo: this.route });
|
|
} else if (response.step === 2) {
|
|
this.configurationWizardService.showCurrencyForm = true;
|
|
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
|
this.router.onSameUrlNavigation = 'reload';
|
|
this.router.navigate(['/organization/currencies/manage']);
|
|
} else if (response.step === 3) {
|
|
this.configurationWizardService.showCurrencyForm = false;
|
|
this.configurationWizardService.showCreateHoliday = true;
|
|
this.router.navigate(['/organization']);
|
|
}
|
|
});
|
|
}
|
|
}
|