merge angular-17 into dev to upgrade from Angular v16 to v17

This commit is contained in:
gkbishnoi07
2025-06-05 15:51:43 +02:00
committed by Adam Saghy
parent 94e37d129c
commit 1d6b6fd743
65 changed files with 4565 additions and 4571 deletions
+5 -2
View File
@@ -4,9 +4,9 @@ name: build-run
on: on:
# Triggers the workflow on push or pull request events for specific branches # Triggers the workflow on push or pull request events for specific branches
push: push:
branches: [main, dev, angular-update] branches: [main, dev, angular-update-17-2]
pull_request: pull_request:
branches: [main, dev, angular-update] branches: [main, dev, angular-update-17-2]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
@@ -40,6 +40,9 @@ jobs:
- name: Run prettier - name: Run prettier
run: npx prettier . --check run: npx prettier . --check
- name: HTMLHint
run: npx htmlhint "src" --config .htmlhintrc
- name: Run build - name: Run build
run: npm run build:prod run: npm run build:prod
+2 -2
View File
@@ -2,9 +2,9 @@ name: Tests
on: on:
push: push:
branches: [main, dev, angular-update] branches: [main, dev, angular-update-17-2]
pull_request: pull_request:
branches: [main, dev, angular-update] branches: [main, dev, angular-update-17-2]
jobs: jobs:
testRigor: testRigor:
+4 -4
View File
@@ -93,14 +93,14 @@
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": { "options": {
"browserTarget": "mifosx-web-app:build" "buildTarget": "mifosx-web-app:build"
}, },
"configurations": { "configurations": {
"development": { "development": {
"browserTarget": "mifosx-web-app:build:development" "buildTarget": "mifosx-web-app:build:development"
}, },
"production": { "production": {
"browserTarget": "mifosx-web-app:build:production" "buildTarget": "mifosx-web-app:build:production"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
@@ -108,7 +108,7 @@
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "mifosx-web-app:build" "buildTarget": "mifosx-web-app:build"
} }
}, },
"test": { "test": {
+3982 -4330
View File
File diff suppressed because it is too large Load Diff
+33 -27
View File
@@ -29,22 +29,21 @@
"cypress:run": "cypress run" "cypress:run": "cypress run"
}, },
"dependencies": { "dependencies": {
"@angular-devkit/schematics": "16.2.16", "@angular-devkit/schematics": "17.3.17",
"@angular-material-components/datetime-picker": "^16.0.1", "@angular/animations": "17.3.12",
"@angular/animations": "16.2.12", "@angular/cdk": "^17.3.10",
"@angular/cdk": "^16.2.14", "@angular/common": "17.3.12",
"@angular/common": "16.2.12", "@angular/compiler": "17.3.12",
"@angular/compiler": "16.2.12", "@angular/core": "17.3.12",
"@angular/core": "16.2.12", "@angular/forms": "17.3.12",
"@angular/forms": "16.2.12", "@angular/localize": "17.3.12",
"@angular/localize": "16.2.12", "@angular/material": "^17.3.10",
"@angular/material": "^16.2.14", "@angular/platform-browser": "17.3.12",
"@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "17.3.12",
"@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "17.3.12",
"@angular/router": "16.2.12",
"@ckeditor/ckeditor5-angular": "6.0.1", "@ckeditor/ckeditor5-angular": "6.0.1",
"@ckeditor/ckeditor5-build-classic": "40.2.0", "@ckeditor/ckeditor5-build-classic": "40.2.0",
"@fortawesome/angular-fontawesome": "^0.13.0", "@fortawesome/angular-fontawesome": "0.14.1",
"@fortawesome/fontawesome-free": "^6.7.2", "@fortawesome/fontawesome-free": "^6.7.2",
"@fortawesome/fontawesome-svg-core": "6.2.1", "@fortawesome/fontawesome-svg-core": "6.2.1",
"@fortawesome/free-brands-svg-icons": "6.7.2", "@fortawesome/free-brands-svg-icons": "6.7.2",
@@ -55,6 +54,7 @@
"@tailwindcss/forms": "^0.5.4", "@tailwindcss/forms": "^0.5.4",
"chart.js": "3.0.0-alpha", "chart.js": "3.0.0-alpha",
"d3": "^7.9.0", "d3": "^7.9.0",
"exceljs": "^4.4.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"jspdf": "^3.0.1", "jspdf": "^3.0.1",
"jspdf-autotable": "^5.0.2", "jspdf-autotable": "^5.0.2",
@@ -65,25 +65,25 @@
"tslib": "^2.0.0", "tslib": "^2.0.0",
"vkbeautify": "^0.99.3", "vkbeautify": "^0.99.3",
"xlsx": "^0.18.5", "xlsx": "^0.18.5",
"zone.js": "0.13.3" "zone.js": "0.14.10"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^16.2.16", "@angular-devkit/build-angular": "^17.3.17",
"@angular-eslint/builder": "^19.3.0", "@angular-eslint/builder": "^19.7.0",
"@angular-eslint/eslint-plugin": "^19.3.0", "@angular-eslint/eslint-plugin": "^19.7.0",
"@angular-eslint/eslint-plugin-template": "^19.3.0", "@angular-eslint/eslint-plugin-template": "^19.7.0",
"@angular-eslint/schematics": "19.3.0", "@angular-eslint/schematics": "^19.7.0",
"@angular-eslint/template-parser": "^19.3.0", "@angular-eslint/template-parser": "^19.7.0",
"@angular/cli": "16.2.16", "@angular/cli": "17.3.17",
"@angular/compiler-cli": "16.2.12", "@angular/compiler-cli": "17.3.12",
"@angular/language-service": "16.2.12", "@angular/language-service": "17.3.12",
"@biesbjerg/ngx-translate-extract": "^7.0.4", "@vendure/ngx-translate-extract": "^9.4.0",
"@cypress/schematic": "^2.5.2", "@cypress/schematic": "^2.5.2",
"@types/d3-dispatch": "^3.0.1", "@types/d3-dispatch": "^3.0.1",
"@types/d3-drag": "^3.0.1", "@types/d3-drag": "^3.0.1",
"@types/d3-scale": "^3.2.2",
"@types/d3-shape": "^3.1.0", "@types/d3-shape": "^3.1.0",
"@types/d3-timer": "^3.0.0", "@types/d3-timer": "^3.0.0",
"@types/d3-scale": "^3.2.2",
"@types/jasmine": "3.3.13", "@types/jasmine": "3.3.13",
"@types/jasminewd2": "2.0.6", "@types/jasminewd2": "2.0.6",
"@types/lodash": "4.14.132", "@types/lodash": "4.14.132",
@@ -118,7 +118,7 @@
"stylelint-scss": "^6.8.1", "stylelint-scss": "^6.8.1",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"ts-node": "8.2.0", "ts-node": "8.2.0",
"typescript": "~4.9.5" "typescript": "^5.4.5"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -135,5 +135,11 @@
"*.{js,jsx,ts,tsx}": "eslint --cache", "*.{js,jsx,ts,tsx}": "eslint --cache",
"*.{css,scss}": "stylelint", "*.{css,scss}": "stylelint",
"*": "prettier --check --ignore-unknown" "*": "prettier --check --ignore-unknown"
},
"overrides": {
"exceljs": {
"archiver": "^7.0.1",
"unzipper": "^0.12.3"
}
} }
} }
@@ -263,7 +263,7 @@ export class CreateStandingInstructionsComponent implements OnInit {
/** Refine Object /** Refine Object
* Removes the object param with null or '' values * Removes the object param with null or '' values
*/ */
refineObject(dataObj: Object) { refineObject(dataObj: { [key: string]: any }) {
const propNames = Object.getOwnPropertyNames(dataObj); const propNames = Object.getOwnPropertyNames(dataObj);
for (let i = 0; i < propNames.length; i++) { for (let i = 0; i < propNames.length; i++) {
const propName = propNames[i]; const propName = propNames[i];
@@ -43,6 +43,9 @@ export class CenterActionsComponent {
) { ) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const name = this.route.snapshot.params['action']; const name = this.route.snapshot.params['action'];
this.actions[name] = true;
if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
} }
} }
@@ -24,6 +24,7 @@ export class ClientActionsComponent {
'Accept Transfer': boolean; 'Accept Transfer': boolean;
'Reject Transfer': boolean; 'Reject Transfer': boolean;
Reactivate: boolean; Reactivate: boolean;
Activate: boolean;
'Undo Rejection': boolean; 'Undo Rejection': boolean;
'Add Charge': boolean; 'Add Charge': boolean;
'Take Survey': boolean; 'Take Survey': boolean;
@@ -41,6 +42,7 @@ export class ClientActionsComponent {
'Accept Transfer': false, 'Accept Transfer': false,
'Reject Transfer': false, 'Reject Transfer': false,
Reactivate: false, Reactivate: false,
Activate: false,
'Undo Rejection': false, 'Undo Rejection': false,
'Add Charge': false, 'Add Charge': false,
'Take Survey': false, 'Take Survey': false,
@@ -57,7 +59,7 @@ export class ClientActionsComponent {
private router: Router private router: Router
) { ) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const name = this.route.snapshot.params['name']; const name = this.route.snapshot.params['name'] as keyof typeof this.actions;
this.actions[name] = true; this.actions[name] = true;
} }
} }
@@ -72,7 +72,7 @@ export class TakeSurveyComponent {
// TODO: document the function // TODO: document the function
groupBy(array: any, func: any) { groupBy(array: any, func: any) {
const groups = {}; const groups: { [key: string]: any[] } = {};
array.forEach((ele: any) => { array.forEach((ele: any) => {
const group = JSON.stringify(func(ele)); const group = JSON.stringify(func(ele));
groups[group] = groups[group] || []; groups[group] = groups[group] || [];
@@ -39,7 +39,7 @@
</mat-form-field> </mat-form-field>
<mat-checkbox formControlName="isDependent" labelPosition="before" class="flex-50-minus-25px"> <mat-checkbox formControlName="isDependent" labelPosition="before" class="flex-50-minus-25px">
>{{ 'labels.inputs.Is Dependent' | translate }}? {{ 'labels.inputs.Is Dependent' | translate }}?
</mat-checkbox> </mat-checkbox>
<mat-form-field class="flex-50-minus-25px"> <mat-form-field class="flex-50-minus-25px">
@@ -52,7 +52,10 @@ export class IndividualCollectionSheetComponent implements OnInit {
/** checks and stores the local storage values */ /** checks and stores the local storage values */
Success: boolean; Success: boolean;
/** Bulk Disbursement Transactions Data */ /** Bulk Disbursement Transactions Data */
bulkDisbursementTransactionsData = {}; bulkDisbursementTransactionsData: {
bulkRepaymentTransactions?: any[];
bulkSavingsDueTransactions?: any[];
} = {};
/** Bulk Repayment Transactions Data */ /** Bulk Repayment Transactions Data */
bulkRepaymentTransactions: any[] = []; bulkRepaymentTransactions: any[] = [];
/** Bulk Savings Due Data */ /** Bulk Savings Due Data */
@@ -261,7 +264,16 @@ export class IndividualCollectionSheetComponent implements OnInit {
if (response.data) { if (response.data) {
if (type === 'loans') { if (type === 'loans') {
const totalDue = this.getLoanTotalDueAmount(selectedData); const totalDue = this.getLoanTotalDueAmount(selectedData);
const loanTransaction = { const loanTransaction: {
loanId: any;
transactionAmount: number;
paymentTypeId?: string;
accountNumber?: any;
checkNumber?: number;
routingCode?: string;
receiptNumber?: number;
bankNumber?: number;
} = {
loanId: selectedData.loanId, loanId: selectedData.loanId,
transactionAmount: totalDue transactionAmount: totalDue
}; };
@@ -279,7 +291,17 @@ export class IndividualCollectionSheetComponent implements OnInit {
if (isNaN(dueAmount)) { if (isNaN(dueAmount)) {
dueAmount = 0; dueAmount = 0;
} }
const savingsTransaction = { const savingsTransaction: {
savingsId: any;
transactionAmount: any;
depositAccountType: number;
accountNumber?: any;
checkNumber?: number;
routingCode?: string;
receiptNumber?: number;
bankNumber?: number;
paymentTypeId?: string;
} = {
savingsId: selectedData.savingsId, savingsId: selectedData.savingsId,
transactionAmount: dueAmount, transactionAmount: dueAmount,
depositAccountType: depositAccountType:
@@ -10,7 +10,7 @@ import { environment } from '../../../environments/environment';
import { SettingsService } from 'app/settings/settings.service'; import { SettingsService } from 'app/settings/settings.service';
/** Http request (default) options headers. */ /** Http request (default) options headers. */
const httpOptions = { const httpOptions: { headers: { [key: string]: string } } = {
headers: { headers: {
'Fineract-Platform-TenantId': environment.fineractPlatformTenantId 'Fineract-Platform-TenantId': environment.fineractPlatformTenantId
} }
+2 -1
View File
@@ -107,7 +107,8 @@ export class HttpCacheService {
*/ */
setPersistence(persistence?: 'local' | 'session') { setPersistence(persistence?: 'local' | 'session') {
this.cleanCache(); this.cleanCache();
this.storage = persistence === 'local' || persistence === 'session' ? window[persistence + 'Storage'] : null; this.storage =
persistence === 'local' ? window.localStorage : persistence === 'session' ? window.sessionStorage : null;
this.loadCacheData(); this.loadCacheData();
} }
@@ -41,6 +41,8 @@ export class FixedDepositsAccountActionsComponent {
*/ */
constructor(private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
const name = this.route.snapshot.params['name']; const name = this.route.snapshot.params['name'];
this.actions[name] = true; if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
} }
} }
@@ -5,6 +5,7 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates'; import { Dates } from 'app/core/utils/dates';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Currency, PaymentType } from 'app/shared/models/general.model'; import { Currency, PaymentType } from 'app/shared/models/general.model';
import { TransactionCommand, TransactionTypeFlags } from '../../../transaction.model';
@Component({ @Component({
selector: 'mifosx-fixed-deposits-cash-transaction', selector: 'mifosx-fixed-deposits-cash-transaction',
@@ -23,9 +24,9 @@ export class FixedDepositsCashTransactionComponent implements OnInit {
/** Flag to enable payment details fields. */ /** Flag to enable payment details fields. */
addPaymentDetailsFlag: Boolean = false; addPaymentDetailsFlag: Boolean = false;
/** transaction type flag to render required UI */ /** transaction type flag to render required UI */
transactionType: { deposit: boolean; withdrawal: boolean } = { deposit: false, withdrawal: false }; transactionType: TransactionTypeFlags = { deposit: false, withdrawal: false };
/** transaction command for submit request */ /** transaction command for submit request */
transactionCommand: string; transactionCommand: TransactionCommand;
actionName: string; actionName: string;
/** saving account's Id */ /** saving account's Id */
accountId: string; accountId: string;
@@ -53,8 +54,14 @@ export class FixedDepositsCashTransactionComponent implements OnInit {
this.paymentTypeOptions = data.fixedDepositsAccountActionData.paymentTypeOptions; this.paymentTypeOptions = data.fixedDepositsAccountActionData.paymentTypeOptions;
}); });
this.actionName = this.route.snapshot.params['name']; this.actionName = this.route.snapshot.params['name'];
this.transactionCommand = this.actionName.toLowerCase(); const lowerName = this.actionName.toLowerCase();
this.transactionType[this.transactionCommand] = true; if (lowerName === 'deposit' || lowerName === 'withdrawal') {
this.transactionCommand = lowerName;
this.transactionType[this.transactionCommand] = true;
} else {
throw new Error(`Invalid transaction action: ${this.actionName}`);
}
this.accountId = this.route.parent.snapshot.params['fixedDepositAccountId']; this.accountId = this.route.parent.snapshot.params['fixedDepositAccountId'];
} }
@@ -8,6 +8,7 @@ import { RecurringDepositsService } from '../../recurring-deposits.service';
import { SettingsService } from 'app/settings/settings.service'; import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates'; import { Dates } from 'app/core/utils/dates';
import { Currency } from 'app/shared/models/general.model'; import { Currency } from 'app/shared/models/general.model';
import { TransactionCommand, TransactionTypeFlags } from '../../../transaction.model';
/** /**
* Deposits Recurring Deposits Account Component * Deposits Recurring Deposits Account Component
@@ -39,8 +40,8 @@ export class DepositRecurringDepositsAccountComponent implements OnInit {
action: string; action: string;
actionName: string; actionName: string;
transactionCommand: string; transactionCommand: TransactionCommand;
transactionType: { deposit: boolean; withdrawal: boolean } = { deposit: false, withdrawal: false }; transactionType: TransactionTypeFlags = { deposit: false, withdrawal: false };
/** /**
* Retrieves action details transactions template data from `resolve` * Retrieves action details transactions template data from `resolve`
@@ -66,13 +67,18 @@ export class DepositRecurringDepositsAccountComponent implements OnInit {
data.recurringDepositsAccountActionData.outstandingChargeAmount > 0 data.recurringDepositsAccountActionData.outstandingChargeAmount > 0
) { ) {
this.outstandingChargeAmount = data.recurringDepositsAccountActionData.outstandingChargeAmount; this.outstandingChargeAmount = data.recurringDepositsAccountActionData.outstandingChargeAmount;
this.transactionAmount = this.transactionAmount + this.outstandingChargeAmount; this.transactionAmount += this.outstandingChargeAmount;
} }
}); });
this.actionName = this.route.snapshot.params['name']; this.actionName = this.route.snapshot.params['name'];
this.action = this.actionName.toLowerCase(); this.action = this.actionName.toLowerCase();
this.transactionCommand = this.action.toLowerCase(); if (this.action === 'deposit' || this.action === 'withdrawal') {
this.transactionType[this.transactionCommand] = true; this.transactionCommand = this.action;
this.transactionType[this.transactionCommand] = true;
} else {
throw new Error(`Invalid transaction action: ${this.actionName}`);
}
this.accountId = this.route.parent.snapshot.params['recurringDepositAccountId']; this.accountId = this.route.parent.snapshot.params['recurringDepositAccountId'];
} }
@@ -47,6 +47,8 @@ export class RecurringDepositsAccountActionsComponent {
} }
}); });
const name = this.route.snapshot.params['name']; const name = this.route.snapshot.params['name'];
this.actions[name] = true; if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
} }
} }
@@ -69,8 +69,7 @@
{{ 'labels.inputs.Note' | translate }} {{ 'labels.inputs.Note' | translate }}
</div> </div>
<div class="flex-50"> <div class="flex-50" *ngIf="transactionData.note">
*ngIf="transactionData.note">
{{ transactionData.note }} {{ transactionData.note }}
</div> </div>
+5
View File
@@ -0,0 +1,5 @@
export type TransactionCommand = 'deposit' | 'withdrawal';
export type TransactionTypeFlags = {
[key in TransactionCommand]: boolean;
};
@@ -44,6 +44,8 @@ export class GroupActionsComponent {
) { ) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const action = this.route.snapshot.params['action']; const action = this.route.snapshot.params['action'];
this.actions[action] = true; if (action && action in this.actions) {
this.actions[action as keyof typeof this.actions] = true;
}
} }
} }
@@ -85,7 +85,7 @@ export class LoansAccountDatatableStepComponent implements OnInit {
get payload(): any { get payload(): any {
const dateFormat = this.settingsService.dateFormat; const dateFormat = this.settingsService.dateFormat;
const datatableDataValues = this.datatableForm.value; const datatableDataValues = this.datatableForm.value;
const data = { const data: { [key: string]: any } = {
locale: this.settingsService.language.code locale: this.settingsService.language.code
}; };
let existDate = false; let existDate = false;
@@ -15,6 +15,12 @@ import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { Currency } from 'app/shared/models/general.model'; import { Currency } from 'app/shared/models/general.model';
import { CodeName, OptionData } from 'app/shared/models/option-data.model'; import { CodeName, OptionData } from 'app/shared/models/option-data.model';
interface DisbursementData {
id?: number;
principal: number;
expectedDisbursementDate: string | Date;
}
/** /**
* Create Loans Account Terms Step * Create Loans Account Terms Step
*/ */
@@ -62,7 +68,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
/** Client Active Loan Data */ /** Client Active Loan Data */
clientActiveLoanData: any; clientActiveLoanData: any;
/** Multi Disbursement Data */ /** Multi Disbursement Data */
disbursementDataSource: {}[] = []; disbursementDataSource: DisbursementData[] = [];
/** Loan repayment strategies */ /** Loan repayment strategies */
transactionProcessingStrategyOptions: any = []; transactionProcessingStrategyOptions: any = [];
repaymentStrategyDisabled = false; repaymentStrategyDisabled = false;
@@ -24,7 +24,9 @@ export class EditRepaymentScheduleComponent implements OnInit {
/** Indicates If the Schedule has been validated */ /** Indicates If the Schedule has been validated */
wasValidated = false; wasValidated = false;
/** Stores the Repayment Schedule data */ /** Stores the Repayment Schedule data */
repaymentScheduleDetails: any[] | null = null; repaymentScheduleDetails: {
periods: { period?: number; dueDate: string; totalDueForPeriod?: number; changed?: boolean }[];
} | null = null;
/** Stores the Installments changed */ /** Stores the Installments changed */
repaymentScheduleChanges: any = {}; repaymentScheduleChanges: any = {};
@@ -56,7 +56,12 @@ export class RescheduleLoanTabComponent {
if (response.confirm) { if (response.confirm) {
const locale = this.settingsService.language.code; const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat; const dateFormat = this.settingsService.dateFormat;
const payload = { const payload: {
dateFormat: string;
locale: string;
approvedOnDate?: string;
rejectedOnDate?: string;
} = {
dateFormat, dateFormat,
locale locale
}; };
@@ -386,7 +386,7 @@ export class TransactionsTabComponent implements OnInit {
value: this.dateUtils.parseDate(transactionDate), value: this.dateUtils.parseDate(transactionDate),
type: 'datetime-local', type: 'datetime-local',
required: true, required: true,
minDate: transaction.date, minDate: this.dateUtils.parseDate(transaction.date),
order: 1 order: 1
}), }),
new InputBase({ new InputBase({
@@ -43,8 +43,7 @@
</mat-form-field> </mat-form-field>
<div class="flex-fill"> <div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75"> <span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
(click)="addPaymentDetails()">
<mat-slide-toggle> <mat-slide-toggle>
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'"> <div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span> <span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
@@ -25,9 +25,7 @@
[routerLink]="[routeMap[row.objectType], row.objectId]" [routerLink]="[routeMap[row.objectType], row.objectId]"
></tr> ></tr>
<tr *matNoDataRow> <tr *matNoDataRow>
<td [attr.colspan]="displayedColumns.length" style="text-align: center; padding: 16px; color: #999"> <td [attr.colspan]="displayedColumns.length">You don't have any notifications</td>
You don't have any notifications
</td>
</tr> </tr>
</table> </table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator> <mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
@@ -37,7 +37,7 @@ export class CreateHolidayComponent implements OnInit {
// Stores office data in a trie-like structure // Stores office data in a trie-like structure
officesTrie: any; officesTrie: any;
// Stores office data for access from DOM via Office ID // Stores office data for access from DOM via Office ID
officesDict = {}; officesDict: { [key: string]: any } = {};
// Angular Material Tree Configuration start ------------ // Angular Material Tree Configuration start ------------
@@ -100,7 +100,7 @@ export class CreateHolidayComponent implements OnInit {
}); });
} }
constructOfficeHierarchy() { constructOfficeHierarchy() {
const trie = {}; const trie: Record<string, any> = {};
// Iterates over all the offices // Iterates over all the offices
this.officesData.forEach((office: any) => { this.officesData.forEach((office: any) => {
this.officesDict[office.id] = office; this.officesDict[office.id] = office;
@@ -114,7 +114,7 @@ export class CreateHolidayComponent implements OnInit {
// Temporary variable to store current object // Temporary variable to store current object
let root = trie; let root: Record<string, any> = trie;
if (hierarchy.length === 0) { if (hierarchy.length === 0) {
root[office.id] = {}; root[office.id] = {};
@@ -161,7 +161,7 @@ export class BusinessRuleParametersComponent implements OnInit, OnChanges {
formattedResponse[newKey] = value; formattedResponse[newKey] = value;
break; break;
case 'select': case 'select':
formattedResponse[newKey] = value['id']; formattedResponse[newKey] = (value as { id: string | number })['id'];
break; break;
case 'date': case 'date':
const dateFormat = this.settingsService.dateFormat; const dateFormat = this.settingsService.dateFormat;
+1 -1
View File
@@ -48,6 +48,6 @@ export class StatusLookupPipe implements PipeTransform {
'smsCampaignStatus.closed': 'status-closed', 'smsCampaignStatus.closed': 'status-closed',
'purchasedSharesStatusType.applied': 'status-pending' 'purchasedSharesStatusType.applied': 'status-pending'
}; };
return cssClassNameLookup[status]; return cssClassNameLookup[status as keyof typeof cssClassNameLookup] ?? 'status-unknown';
} }
} }
@@ -91,7 +91,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
this.clientClassificationData = this.fixedDepositProductsTemplate.chartTemplate.clientClassificationOptions; this.clientClassificationData = this.fixedDepositProductsTemplate.chartTemplate.clientClassificationOptions;
this.incentiveTypeData = this.fixedDepositProductsTemplate.chartTemplate.incentiveTypeOptions; this.incentiveTypeData = this.fixedDepositProductsTemplate.chartTemplate.incentiveTypeOptions;
if (!(this.fixedDepositProductsTemplate === undefined)) { if (this.fixedDepositProductsTemplate) {
this.assignFormData(); this.assignFormData();
} }
} }
@@ -145,7 +145,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
formArray.push(chartSlabInfo); formArray.push(chartSlabInfo);
// Iterate for every slab in chartSlab // Iterate for every slab in chartSlab
const chartIncentiveControl = chartDetailControl.controls['chartSlabs']['controls'][j]; const chartIncentiveControl = (chartDetailControl.controls['chartSlabs'] as UntypedFormArray).controls[j];
// Iterate to input all the incentive for particular chart slab // Iterate to input all the incentive for particular chart slab
this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => { this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => {
@@ -158,8 +158,8 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
chartIncentiveDetail.attributeName, chartIncentiveDetail.attributeName,
Validators.required Validators.required
], ],
attribureValue: [ attributeValue: [
chartIncentiveDetail.attribureValue, chartIncentiveDetail.attributeValue,
Validators.required Validators.required
], ],
conditionType: [ conditionType: [
@@ -175,7 +175,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
Validators.required Validators.required
] ]
}); });
const newFormArray = chartIncentiveControl['controls']['incentives'] as UntypedFormArray; const newFormArray = (chartIncentiveControl as UntypedFormGroup).controls['incentives'] as UntypedFormArray;
newFormArray.push(incentiveInfo); newFormArray.push(incentiveInfo);
}); });
}); });
@@ -183,8 +183,8 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
} }
getChartsDetailsData() { getChartsDetailsData() {
this.chartDetailData.forEach((chartData: any) => { this.chartDetailData.forEach((chartData: ChartData) => {
const chart = { const chart: Chart = {
endDate: chartData.endDate ? new Date(chartData.endDate) : '', endDate: chartData.endDate ? new Date(chartData.endDate) : '',
fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '', fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '',
isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount, isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount,
@@ -193,7 +193,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
chartSlabs: this.getChartSlabsData(chartData) chartSlabs: this.getChartSlabsData(chartData)
}; };
if (chartData.id) { if (chartData.id) {
chart['id'] = chartData.id; chart.id = chartData.id;
} }
this.chartsDetail.push(chart); this.chartsDetail.push(chart);
}); });
@@ -213,7 +213,17 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
} }
chartSlabData.forEach((eachChartSlabData: any) => { chartSlabData.forEach((eachChartSlabData: any) => {
const chartSlab = { const chartSlab: {
id?: any;
periodType: any;
amountRangeFrom: any;
amountRangeTo: any;
annualInterestRate: any;
description: any;
fromPeriod: any;
toPeriod: any;
incentives: any[];
} = {
periodType: eachChartSlabData.periodType.id, periodType: eachChartSlabData.periodType.id,
amountRangeFrom: eachChartSlabData.amountRangeFrom, amountRangeFrom: eachChartSlabData.amountRangeFrom,
amountRangeTo: eachChartSlabData.amountRangeTo, amountRangeTo: eachChartSlabData.amountRangeTo,
@@ -221,7 +231,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
description: eachChartSlabData.description ? eachChartSlabData.description : '', description: eachChartSlabData.description ? eachChartSlabData.description : '',
fromPeriod: eachChartSlabData.fromPeriod, fromPeriod: eachChartSlabData.fromPeriod,
toPeriod: eachChartSlabData.toPeriod, toPeriod: eachChartSlabData.toPeriod,
incentives: this.getIncentivesData(chartSlabData) incentives: this.getIncentivesData(eachChartSlabData)
}; };
if (eachChartSlabData.id) { if (eachChartSlabData.id) {
chartSlab['id'] = eachChartSlabData.id; chartSlab['id'] = eachChartSlabData.id;
@@ -468,3 +478,28 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
return fixedDepositProductInterestRateChart; return fixedDepositProductInterestRateChart;
} }
} }
interface ChartData {
id?: number;
endDate?: string;
fromDate?: string;
isPrimaryGroupingByAmount: boolean;
name: string;
description: string;
chartSlabs: ChartSlab[];
}
interface ChartSlab {
periodType?: string;
fromPeriod?: number;
toPeriod?: number;
amountRangeFrom?: number;
amountRangeTo?: number;
annualInterestRate?: number;
description?: string;
}
interface Chart extends Omit<ChartData, 'endDate' | 'fromDate'> {
endDate: Date | string;
fromDate: Date | string;
}
@@ -378,7 +378,7 @@
<div class="flex-fill layout-row"> <div class="flex-fill layout-row">
<span class="flex-47">{{ 'labels.inputs.Repayment Strategy' | translate }}:</span> <span class="flex-47">{{ 'labels.inputs.Repayment Strategy' | translate }}:</span>
<span class="flex-53" class="repayment-strategy">{{ <span class="flex-53 repayment-strategy">{{
loanProduct.transactionProcessingStrategyName | translateKey: 'catalogs' loanProduct.transactionProcessingStrategyName | translateKey: 'catalogs'
}}</span> }}</span>
</div> </div>
@@ -563,7 +563,7 @@
<span class="flex-53">{{ loanProduct.canUseForTopup | yesNo }}</span> <span class="flex-53">{{ loanProduct.canUseForTopup | yesNo }}</span>
</div> </div>
<h3 class="mat-h3" class="flex-fill">{{ 'labels.heading.Interest Recalculation' | translate }}</h3> <h3 class="mat-h3 flex-fill">{{ 'labels.heading.Interest Recalculation' | translate }}</h3>
<mat-divider [inset]="true"></mat-divider> <mat-divider [inset]="true"></mat-divider>
@@ -212,7 +212,7 @@
<span class="flex-48 hide-lt-md"></span> <span class="flex-48 hide-lt-md"></span>
<div style="display: flex; justify-content: flex-start; width: 100%"> <div class="full-width-flex">
<div *ngIf="isAdvancedTransactionProcessingStrategy"> <div *ngIf="isAdvancedTransactionProcessingStrategy">
<h3 class="mat-h4 flex-98">{{ 'labels.inputs.Loan Charge-off behaviour' | translate }}</h3> <h3 class="mat-h4 flex-98">{{ 'labels.inputs.Loan Charge-off behaviour' | translate }}</h3>
-2
View File
@@ -21,14 +21,12 @@
<fa-icon <fa-icon
(click)="arrowBooleansToggle(0); $event.stopPropagation()" (click)="arrowBooleansToggle(0); $event.stopPropagation()"
*ngIf="!arrowBooleans[0]" *ngIf="!arrowBooleans[0]"
style="z-index: 1000"
icon="arrow-down" icon="arrow-down"
size="md" size="md"
></fa-icon> ></fa-icon>
<fa-icon <fa-icon
(click)="arrowBooleansToggle(0); $event.stopPropagation()" (click)="arrowBooleansToggle(0); $event.stopPropagation()"
*ngIf="arrowBooleans[0]" *ngIf="arrowBooleans[0]"
style="z-index: 1000"
icon="arrow-up" icon="arrow-up"
size="md" size="md"
></fa-icon> ></fa-icon>
@@ -145,7 +145,7 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
formArray.push(chartSlabInfo); formArray.push(chartSlabInfo);
// Iterate for every slab in chartSlab // Iterate for every slab in chartSlab
const chartIncentiveControl = chartDetailControl.controls['chartSlabs']['controls'][j]; const chartIncentiveControl = (chartDetailControl.controls['chartSlabs'] as UntypedFormArray).controls[j];
// Iterate to input all the incentive for particular chart slab // Iterate to input all the incentive for particular chart slab
this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => { this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => {
@@ -175,7 +175,7 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
Validators.required Validators.required
] ]
}); });
const newFormArray = chartIncentiveControl['controls']['incentives'] as UntypedFormArray; const newFormArray = (chartIncentiveControl as UntypedFormGroup).controls['incentives'] as UntypedFormArray;
newFormArray.push(incentiveInfo); newFormArray.push(incentiveInfo);
}); });
}); });
@@ -184,7 +184,14 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
getChartsDetailsData() { getChartsDetailsData() {
this.chartDetailData.forEach((chartData: any) => { this.chartDetailData.forEach((chartData: any) => {
const chart = { const chart: {
id?: any;
endDate: string | Date;
fromDate: string | Date;
isPrimaryGroupingByAmount: any;
name: any;
chartSlabs: any[];
} = {
endDate: chartData.endDate ? new Date(chartData.endDate) : '', endDate: chartData.endDate ? new Date(chartData.endDate) : '',
fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '', fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '',
isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount, isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount,
@@ -212,7 +219,17 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
} }
chartSlabData.forEach((eachChartSlabData: any) => { chartSlabData.forEach((eachChartSlabData: any) => {
const chartSlab = { const chartSlab: {
id?: any;
periodType: any;
amountRangeFrom: any;
amountRangeTo: any;
annualInterestRate: any;
description: any;
fromPeriod: any;
toPeriod: any;
incentives: any[];
} = {
periodType: eachChartSlabData.periodType.id, periodType: eachChartSlabData.periodType.id,
amountRangeFrom: eachChartSlabData.amountRangeFrom, amountRangeFrom: eachChartSlabData.amountRangeFrom,
amountRangeTo: eachChartSlabData.amountRangeTo, amountRangeTo: eachChartSlabData.amountRangeTo,
@@ -13,7 +13,7 @@ import { SelectOption } from '../common-models/select-option.model';
import { Dates } from 'app/core/utils/dates'; import { Dates } from 'app/core/utils/dates';
import { GlobalConfiguration } from 'app/system/configurations/global-configurations-tab/configuration.model'; import { GlobalConfiguration } from 'app/system/configurations/global-configurations-tab/configuration.model';
import * as XLSX from 'xlsx'; import * as ExcelJS from 'exceljs';
import { AlertService } from 'app/core/alert/alert.service'; import { AlertService } from 'app/core/alert/alert.service';
/** /**
@@ -251,7 +251,7 @@ export class RunReportComponent implements OnInit {
formattedResponse[newKey] = value; formattedResponse[newKey] = value;
break; break;
case 'select': case 'select':
formattedResponse[newKey] = value['id']; formattedResponse[newKey] = (value as { id: string | number })['id'];
break; break;
case 'date': case 'date':
if (this.isTableReport()) { if (this.isTableReport()) {
@@ -339,18 +339,46 @@ export class RunReportComponent implements OnInit {
}); });
} }
exportToXLS(reportName: string, csvData: any, displayedColumns: string[]): void { async exportToXLS(reportName: string, csvData: any, displayedColumns: string[]): Promise<void> {
const fileName = `${reportName}.xlsx`; const fileName = `${reportName}.xlsx`;
// Format data for ExcelJS
const data = csvData.map((object: any) => { const data = csvData.map((object: any) => {
const row = {}; const row: Record<string, any> = {};
for (let i = 0; i < displayedColumns.length; i++) { for (let i = 0; i < displayedColumns.length; i++) {
row[displayedColumns[i]] = object.row[i]; row[displayedColumns[i]] = object.row[i];
} }
return row; return row;
}); });
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, { header: displayedColumns });
const wb: XLSX.WorkBook = XLSX.utils.book_new(); // Create workbook and worksheet
XLSX.utils.book_append_sheet(wb, ws, 'report'); const workbook = new ExcelJS.Workbook();
XLSX.writeFile(wb, fileName); const worksheet = workbook.addWorksheet('report');
// Add header
worksheet.addRow(displayedColumns);
// Add data rows
data.forEach((rowObj: any) => {
worksheet.addRow(displayedColumns.map((col) => rowObj[col]));
});
// Write to buffer and trigger download
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
// Native download logic (no FileSaver)
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
} }
} }
@@ -14,7 +14,7 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { ProgressBarService } from 'app/core/progress-bar/progress-bar.service'; import { ProgressBarService } from 'app/core/progress-bar/progress-bar.service';
import * as XLSX from 'xlsx'; import * as ExcelJS from 'exceljs';
/** /**
* Table and SMS Component * Table and SMS Component
@@ -143,16 +143,33 @@ export class TableAndSmsComponent implements OnChanges {
exportToXLS(): void { exportToXLS(): void {
const fileName = `${this.dataObject.report.name}.xlsx`; const fileName = `${this.dataObject.report.name}.xlsx`;
const data = this.csvData.map((object: any) => { const data = this.csvData.map((object: any) => {
const row = {}; const row: { [key: string]: any } = {};
for (let i = 0; i < this.displayedColumns.length; i++) { for (let i = 0; i < this.displayedColumns.length; i++) {
row[this.displayedColumns[i]] = object.row[i]; row[this.displayedColumns[i]] = object.row[i];
} }
return row; return row;
}); });
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, { header: this.displayedColumns });
const wb: XLSX.WorkBook = XLSX.utils.book_new(); const workbook = new ExcelJS.Workbook();
XLSX.utils.book_append_sheet(wb, ws, 'Report'); const worksheet = workbook.addWorksheet('Report');
XLSX.writeFile(wb, fileName);
// Add header row
worksheet.addRow(this.displayedColumns);
// Add data rows
data.forEach((rowObj: any) => {
worksheet.addRow(this.displayedColumns.map((col) => rowObj[col]));
});
workbook.xlsx.writeBuffer().then((buffer: any) => {
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'filename.xlsx';
a.click();
URL.revokeObjectURL(url);
});
} }
/** /**
@@ -7,6 +7,15 @@ import { SettingsService } from 'app/settings/settings.service';
import { Currency } from 'app/shared/models/general.model'; import { Currency } from 'app/shared/models/general.model';
import { SystemService } from 'app/system/system.service'; import { SystemService } from 'app/system/system.service';
type TransactionCommandType = 'holdamount' | 'blockaccount' | 'blockdeposit' | 'blockwithdrawal';
interface TransactionType {
holdamount: boolean;
blockaccount: boolean;
blockdeposit: boolean;
blockwithdrawal: boolean;
}
@Component({ @Component({
selector: 'mifosx-manage-savings-account', selector: 'mifosx-manage-savings-account',
templateUrl: './manage-savings-account.component.html', templateUrl: './manage-savings-account.component.html',
@@ -22,16 +31,11 @@ export class ManageSavingsAccountComponent implements OnInit {
manageSavingsAccountForm: UntypedFormGroup; manageSavingsAccountForm: UntypedFormGroup;
/** Savings Account Id */ /** Savings Account Id */
savingAccountId: string; savingAccountId: string;
transactionCommand: string; transactionCommand: TransactionCommandType;
reasonOptions: any = []; reasonOptions: any = [];
transactionType: { transactionType: TransactionType = {
holdamount: boolean;
blockaccount: boolean;
blockdeposit: boolean;
blockwithdrawal: boolean;
} = {
holdamount: false, holdamount: false,
blockaccount: false, blockaccount: false,
blockdeposit: false, blockdeposit: false,
@@ -130,7 +134,7 @@ export class ManageSavingsAccountComponent implements OnInit {
submit() { submit() {
let command = ''; let command = '';
let payload = {}; let payload: { transactionAmount?: number; [key: string]: any } = {};
if (this.transactionType.holdamount) { if (this.transactionType.holdamount) {
const manageSavingsAccountFormData = this.manageSavingsAccountForm.value; const manageSavingsAccountFormData = this.manageSavingsAccountForm.value;
@@ -68,7 +68,9 @@ export class SavingAccountActionsComponent {
this.currency = data.savingsAccountActionData.currency; this.currency = data.savingsAccountActionData.currency;
} }
}); });
const name = this.route.snapshot.params['name']; const name = this.route.snapshot.params['name'] as string;
this.actions[name] = true; if (name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
} }
} }
@@ -66,7 +66,7 @@ export class SavingsAccountTransactionsComponent implements OnInit {
} }
}); });
this.transactionCommand = this.route.snapshot.params['name'].toLowerCase(); this.transactionCommand = this.route.snapshot.params['name'].toLowerCase();
this.transactionType[this.transactionCommand] = true; this.transactionType[this.transactionCommand as 'deposit' | 'withdrawal'] = true;
this.savingAccountId = this.route.snapshot.params['savingAccountId']; this.savingAccountId = this.route.snapshot.params['savingAccountId'];
} }
@@ -85,7 +85,7 @@ export class SavingsAccountViewComponent implements OnInit {
taskPermissionName: 'CREATE_ACCOUNTTRANSFER' taskPermissionName: 'CREATE_ACCOUNTTRANSFER'
}); });
} }
if (this.savingsAccountData.externalId && environment.interbankTransfers === 'true') { if (this.savingsAccountData.externalId && environment.interbankTransfers) {
this.buttonConfig.addOption({ this.buttonConfig.addOption({
name: 'Interbank Transfer', name: 'Interbank Transfer',
taskPermissionName: 'CREATE_ACCOUNTTRANSFER' taskPermissionName: 'CREATE_ACCOUNTTRANSFER'
@@ -38,8 +38,7 @@
</mat-form-field> </mat-form-field>
<div class="flex-fill"> <div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75"> <span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
(click)="addPaymentDetails()">
<mat-slide-toggle> <mat-slide-toggle>
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'"> <div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span> <span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
@@ -0,0 +1,15 @@
import { Component, Input } from '@angular/core';
/* eslint-disable @angular-eslint/component-selector */
/* eslint-disable @angular-eslint/prefer-standalone */
@Component({
selector: 'ngx-mat-datetime-picker',
template: `
<mat-datepicker-toggle [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
`,
standalone: false
})
export class DatetimePickerStubComponent {
@Input() enableMeridian: boolean = true;
}
@@ -50,14 +50,12 @@
<mat-label>{{ formfield.label }}</mat-label> <mat-label>{{ formfield.label }}</mat-label>
<input <input
matInput matInput
[ngxMatDatetimePicker]="datetimePicker" type="datetime-local"
[min]="formfield.minDate" [min]="formfield.minDate"
[max]="formfield.maxDate" [max]="formfield.maxDate"
[formControlName]="formfield.controlName" [formControlName]="formfield.controlName"
[required]="formfield.required" [required]="formfield.required"
/> />
<mat-datepicker-toggle matSuffix [for]="datetimePicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #datetimePicker [enableMeridian]="true"></ngx-mat-datetime-picker>
<mat-error *ngIf="form.controls[formfield.controlName].hasError('required')"> <mat-error *ngIf="form.controls[formfield.controlName].hasError('required')">
{{ formfield.label }} {{ 'labels.commons.is' | translate }} {{ formfield.label }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong> <strong>{{ 'labels.commons.required' | translate }}</strong>
@@ -1,13 +1,25 @@
import { FormfieldBase } from './formfield-base'; import { FormfieldBase } from './formfield-base';
interface DatepickerOptions {
minDate?: Date;
maxDate?: Date;
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
type?: string;
}
export class DatepickerBase extends FormfieldBase { export class DatepickerBase extends FormfieldBase {
controlType = 'datepicker'; controlType = 'datepicker';
minDate: Date; minDate: Date;
maxDate: Date; maxDate: Date;
constructor(options: {} = {}) { constructor(options: DatepickerOptions = {}) {
super(options); super(options);
this.minDate = options['minDate'] || new Date(2000, 0, 1); this.minDate = options.minDate || new Date(2000, 0, 1);
this.maxDate = options['maxDate'] || new Date(); this.maxDate = options.maxDate || new Date();
} }
} }
@@ -1,13 +1,29 @@
import { FormfieldBase } from './formfield-base'; import { FormfieldBase } from './formfield-base';
// Define the base options interface based on FormfieldBase requirements
interface FormfieldBaseOptions {
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
// Extend the base options for DateTimePicker
interface DateTimePickerOptions extends FormfieldBaseOptions {
minDate?: Date;
maxDate?: Date;
}
export class DateTimepickerBase extends FormfieldBase { export class DateTimepickerBase extends FormfieldBase {
controlType = 'datetimepicker'; controlType = 'datetimepicker';
minDate: Date; minDate: Date;
maxDate: Date; maxDate: Date;
constructor(options: {} = {}) { constructor(options: DateTimePickerOptions = {}) {
super(options); super(options);
this.minDate = options['minDate'] || new Date(2000, 0, 1); this.minDate = options.minDate || new Date(2000, 0, 1);
this.maxDate = options['maxDate'] || new Date(); this.maxDate = options.maxDate || new Date();
} }
} }
@@ -1,11 +1,25 @@
import { FormfieldBase } from './formfield-base'; import { FormfieldBase } from './formfield-base';
interface InputBaseOptions extends FormfieldBaseOptions {
type?: string;
[key: string]: any;
}
interface FormfieldBaseOptions {
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
export class InputBase extends FormfieldBase { export class InputBase extends FormfieldBase {
controlType = 'input'; controlType = 'input';
type: string; type: string;
constructor(options: {} = {}) { constructor(options: InputBaseOptions = {}) {
super(options); super(options);
this.type = options['type'] || 'text'; this.type = options.type || 'text';
} }
} }
@@ -1,15 +1,27 @@
import { FormfieldBase } from './formfield-base'; import { FormfieldBase } from './formfield-base';
interface SelectOption {
label: string;
value: string;
data: {}[];
}
interface SelectBaseOptions {
options?: SelectOption;
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
export class SelectBase extends FormfieldBase { export class SelectBase extends FormfieldBase {
controlType = 'select'; controlType = 'select';
options: { options: SelectOption;
label: string;
value: string;
data: {}[];
};
constructor(options: {} = {}) { constructor(options: SelectBaseOptions = {}) {
super(options); super(options);
this.options = options['options']; this.options = options.options || { label: '', value: '', data: [] };
} }
} }
+11 -6
View File
@@ -36,7 +36,7 @@ import { EntityDatatableTabComponent } from './tabs/entity-datatable-tab/entity-
import { DatatableSingleRowComponent } from './tabs/entity-datatable-tab/datatable-single-row/datatable-single-row.component'; import { DatatableSingleRowComponent } from './tabs/entity-datatable-tab/datatable-single-row/datatable-single-row.component';
import { DatatableMultiRowComponent } from './tabs/entity-datatable-tab/datatable-multi-row/datatable-multi-row.component'; import { DatatableMultiRowComponent } from './tabs/entity-datatable-tab/datatable-multi-row/datatable-multi-row.component';
import { SvgIconComponent } from './svg-icon/svg-icon.component'; import { SvgIconComponent } from './svg-icon/svg-icon.component';
import { NgxMatDatetimePickerModule, NgxMatNativeDateModule } from '@angular-material-components/datetime-picker'; // import { NgxMatDatetimePickerModule, NgxMatNativeDateModule } from '@angular-material-components/datetime-picker';
import { ViewJournalEntryComponent } from './accounting/view-journal-entry/view-journal-entry.component'; import { ViewJournalEntryComponent } from './accounting/view-journal-entry/view-journal-entry.component';
import { ViewJournalEntryTransactionComponent } from './accounting/view-journal-entry-transaction/view-journal-entry-transaction.component'; import { ViewJournalEntryTransactionComponent } from './accounting/view-journal-entry-transaction/view-journal-entry-transaction.component';
import { AccountNumberComponent } from './account-number/account-number.component'; import { AccountNumberComponent } from './account-number/account-number.component';
@@ -51,6 +51,7 @@ import { LongTextComponent } from './long-text/long-text.component';
import { DropdownComponent } from './dropdown/dropdown.component'; import { DropdownComponent } from './dropdown/dropdown.component';
import { InputAmountComponent } from './input-amount/input-amount.component'; import { InputAmountComponent } from './input-amount/input-amount.component';
import { InputPasswordComponent } from './input-password/input-password.component'; import { InputPasswordComponent } from './input-password/input-password.component';
import { DatetimePickerStubComponent } from './datetime-picker-stub/datetime-picker-stub.component'; // import Datetime Picker Stub
/** /**
* Shared Module * Shared Module
@@ -65,9 +66,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
ReactiveFormsModule, ReactiveFormsModule,
TranslateModule, TranslateModule,
PipesModule, PipesModule,
DirectivesModule, DirectivesModule
NgxMatDatetimePickerModule, // NgxMatDatetimePickerModule,
NgxMatNativeDateModule // NgxMatNativeDateModule
], ],
declarations: [ declarations: [
FormfieldComponent, FormfieldComponent,
@@ -108,7 +109,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
LongTextComponent, LongTextComponent,
DropdownComponent, DropdownComponent,
InputAmountComponent, InputAmountComponent,
InputPasswordComponent InputPasswordComponent,
DatetimePickerStubComponent // temporarily added stub for datetime picker
], ],
exports: [ exports: [
FileUploadComponent, FileUploadComponent,
@@ -143,7 +146,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
ThemeToggleComponent, ThemeToggleComponent,
LongTextComponent, LongTextComponent,
DropdownComponent, DropdownComponent,
InputAmountComponent InputAmountComponent,
DatetimePickerStubComponent // Export stub for datetime picker
] ]
}) })
export class SharedModule {} export class SharedModule {}
@@ -44,6 +44,8 @@ export class SharesAccountActionsComponent {
*/ */
constructor(private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
const name = this.route.snapshot.params['name']; const name = this.route.snapshot.params['name'];
this.actions[name] = true; if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
} }
} }
@@ -8,31 +8,48 @@ import { PopoverService } from '../../configuration-wizard/popover/popover.servi
import { ConfigurationWizardService } from '../../configuration-wizard/configuration-wizard.service'; import { ConfigurationWizardService } from '../../configuration-wizard/configuration-wizard.service';
import { SystemService } from '../system.service'; import { SystemService } from '../system.service';
interface Permission {
code: string;
id: number;
selected: boolean;
grouping?: string;
}
interface PermissionGroup {
permissions: Permission[];
}
interface PermissionData {
[key: string]: PermissionGroup;
}
interface SubmitPermissionData {
permissions: {
[key: string]: boolean;
};
}
@Component({ @Component({
selector: 'mifosx-configure-maker-checker-tasks', selector: 'mifosx-configure-maker-checker-tasks',
templateUrl: './configure-maker-checker-tasks.component.html', templateUrl: './configure-maker-checker-tasks.component.html',
styleUrls: ['./configure-maker-checker-tasks.component.scss'] styleUrls: ['./configure-maker-checker-tasks.component.scss']
}) })
export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewInit { export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewInit {
permissionsData: any; permissionsData: Permission[] = [];
groupings: string[] = []; groupings: string[] = [];
currentGrouping = '';
tempPermissionUIData: PermissionData = {};
permissions: PermissionGroup = { permissions: [] };
formData = {}; formData = {};
isDisabled = true; isDisabled = true;
newEntry: any; newEntry: any;
selectedItem = ''; selectedItem = '';
previousGrouping = ''; previousGrouping = '';
checkboxesChanged: Boolean = false; checkboxesChanged: Boolean = false;
currentGrouping: string;
formGroup: UntypedFormGroup; formGroup: UntypedFormGroup;
backupform: UntypedFormGroup; backupform: UntypedFormGroup;
permissions: {
permissions: { code: string; id: number }[];
};
tempPermissionUIData: {
permissions: { code: string }[];
}[];
/* Reference of edit button */ /* Reference of edit button */
@ViewChild('buttonEdit') buttonEdit: ElementRef<any>; @ViewChild('buttonEdit') buttonEdit: ElementRef<any>;
/* Template for popover on edit button */ /* Template for popover on edit button */
@@ -95,29 +112,33 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
}); });
} }
setMakerCheckerTask() { setMakerCheckerTask(): void {
this.tempPermissionUIData = [ this.tempPermissionUIData = {};
{
permissions: [] for (const permission of this.permissionsData) {
} if (permission.grouping !== this.currentGrouping) {
]; this.currentGrouping = permission.grouping || '';
for (const i in this.permissionsData) { this.groupings.push(this.currentGrouping);
if (this.permissionsData[i]) { this.tempPermissionUIData[this.currentGrouping] = { permissions: [] };
if (this.permissionsData[i].grouping !== this.currentGrouping) {
this.currentGrouping = this.permissionsData[i].grouping;
this.groupings.push(this.currentGrouping);
this.tempPermissionUIData[this.currentGrouping] = { permissions: [] };
}
const temp = { code: this.permissionsData[i].code, id: i, selected: this.permissionsData[i].selected };
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
} }
const temp: Permission = {
code: permission.code,
id: permission.id,
selected: permission.selected
};
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
} }
} }
showPermissions(grouping: string) { showPermissions(grouping: string): void {
this.permissions = this.tempPermissionUIData[grouping]; const group = this.tempPermissionUIData[grouping];
this.selectedItem = grouping; if (group) {
this.previousGrouping = grouping; this.permissions = group;
this.selectedItem = grouping;
this.previousGrouping = grouping;
}
} }
permissionName = function (name: any) { permissionName = function (name: any) {
@@ -175,17 +196,20 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
this.formGroup.controls.roster.disable(); this.formGroup.controls.roster.disable();
} }
submit() { submit(): void {
const value = this.formGroup.get('roster').value; const value = this.formGroup.get('roster')?.value;
const data = {}; const permissionData: SubmitPermissionData = {
const permissionData = {
permissions: {} permissions: {}
}; };
for (let i = 0; i < value.length; i++) {
data[value[i].code] = value[i].selected; if (Array.isArray(value)) {
value.forEach((item) => {
if (item.code && typeof item.selected === 'boolean') {
permissionData.permissions[item.code] = item.selected;
}
});
} }
permissionData.permissions = data; this.formGroup.get('roster')?.disable();
this.formGroup.controls.roster.disable();
this.checkboxesChanged = false; this.checkboxesChanged = false;
this.isDisabled = true; this.isDisabled = true;
this.systemService.updateMakerCheckerPermission(permissionData).subscribe((response: any) => {}); this.systemService.updateMakerCheckerPermission(permissionData).subscribe((response: any) => {});
@@ -108,7 +108,7 @@
<br /> <br />
<div class="layout-row-wrap responsive-column"> <div class="layout-row-wrap responsive-column">
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }}<span style="color: red">*</span></p> <p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }}<span class="red">*</span></p>
<button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()"> <button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()">
<fa-icon icon="plus" class="m-r-10"></fa-icon> <fa-icon icon="plus" class="m-r-10"></fa-icon>
@@ -108,7 +108,7 @@
<br /> <br />
<div class="layout-row-wrap responsive-column"> <div class="layout-row-wrap responsive-column">
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }} <span style="color: red">*</span></p> <p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }} <span class="red">*</span></p>
<button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()"> <button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()">
<fa-icon icon="plus" class="m-r-10"></fa-icon> <fa-icon icon="plus" class="m-r-10"></fa-icon>
@@ -9,7 +9,12 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
import { SystemService } from 'app/system/system.service'; import { SystemService } from 'app/system/system.service';
import { JobStep } from './workflow-diagram/workflow-diagram.component';
export interface JobStep {
stepName: string;
stepDescription: string;
order: number;
}
@Component({ @Component({
selector: 'mifosx-workflow-jobs', selector: 'mifosx-workflow-jobs',
@@ -21,7 +26,7 @@ export class WorkflowJobsComponent implements OnInit {
jobNameOptions: any = []; jobNameOptions: any = [];
jobStepsData: any = []; jobStepsData: any = [];
jobAvailableStepsData: any = []; jobAvailableStepsData: JobStep[] = [];
jobStepsDataBase: any = []; jobStepsDataBase: any = [];
jobStepName: String = null; jobStepName: String = null;
@@ -98,7 +98,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-fill" ="48"> <mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label>
<input matInput maxlength="255" required formControlName="text" /> <input matInput maxlength="255" required formControlName="text" />
<mat-error *ngIf="question.controls.text.hasError('required')"> <mat-error *ngIf="question.controls.text.hasError('required')">
@@ -74,7 +74,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-fill" ="48"> <mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label>
<input matInput maxlength="255" required formControlName="text" /> <input matInput maxlength="255" required formControlName="text" />
<mat-error *ngIf="question.get('text').hasError('required')"> <mat-error *ngIf="question.get('text').hasError('required')">
@@ -1,6 +1,6 @@
/** Angular Imports */ /** Angular Imports */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators, FormArray } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import * as _ from 'lodash'; import * as _ from 'lodash';
@@ -45,12 +45,14 @@ export class ViewRoleComponent implements OnInit {
backupform: UntypedFormGroup; backupform: UntypedFormGroup;
/** Temporarily stores Permission data */ /** Temporarily stores Permission data */
tempPermissionUIData: { tempPermissionUIData: {
permissions: { code: string }[]; [key: string]: {
}[]; permissions: { code: string; id: number; selected?: boolean }[];
};
} = {};
/** Stores permissions */ /** Stores permissions */
permissions: { permissions: {
permissions: { code: string; id: number }[]; permissions: { code: string; id: number }[];
}; } = { permissions: [] };
/** /**
* Retrieves the roledetails data from `resolve`. * Retrieves the roledetails data from `resolve`.
@@ -121,11 +123,7 @@ export class ViewRoleComponent implements OnInit {
* Groups the permissions based on rules * Groups the permissions based on rules
*/ */
groupRules() { groupRules() {
this.tempPermissionUIData = [ this.tempPermissionUIData = {};
{
permissions: []
}
];
for (const i in this.rolePermissionService.permissionUsageData) { for (const i in this.rolePermissionService.permissionUsageData) {
if (this.rolePermissionService.permissionUsageData[i]) { if (this.rolePermissionService.permissionUsageData[i]) {
if (this.rolePermissionService.permissionUsageData[i].grouping !== this.currentGrouping) { if (this.rolePermissionService.permissionUsageData[i].grouping !== this.currentGrouping) {
@@ -135,7 +133,7 @@ export class ViewRoleComponent implements OnInit {
} }
const temp = { const temp = {
code: this.rolePermissionService.permissionUsageData[i].code, code: this.rolePermissionService.permissionUsageData[i].code,
id: i, id: +i,
selected: this.rolePermissionService.permissionUsageData[i].selected selected: this.rolePermissionService.permissionUsageData[i].selected
}; };
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp); this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
@@ -177,7 +175,7 @@ export class ViewRoleComponent implements OnInit {
name = name || ''; name = name || '';
// replace '_' with ' ' // replace '_' with ' '
name = name.replace(/_/g, ' '); name = name.replace(/_/g, ' ');
// for reorts replace read with view // for reports replace read with view
if (this.previousGrouping === 'report') { if (this.previousGrouping === 'report') {
name = name.replace(/READ/g, 'View'); name = name.replace(/READ/g, 'View');
} }
@@ -185,7 +183,7 @@ export class ViewRoleComponent implements OnInit {
} }
/** /**
* Backups the valued * Backups the values
*/ */
backupCheckValues() { backupCheckValues() {
this.backupform = _.cloneDeep(this.formGroup) as UntypedFormGroup; this.backupform = _.cloneDeep(this.formGroup) as UntypedFormGroup;
@@ -220,7 +218,7 @@ export class ViewRoleComponent implements OnInit {
*/ */
submit() { submit() {
const value = this.formGroup.get('roster').value; const value = this.formGroup.get('roster').value;
const data = {}; const data: { [key: string]: boolean } = {};
const permissionData = { const permissionData = {
permissions: {} permissions: {}
}; };
@@ -238,8 +236,9 @@ export class ViewRoleComponent implements OnInit {
* Selects all the permission of a particular role * Selects all the permission of a particular role
*/ */
selectAll() { selectAll() {
const roster = this.formGroup.get('roster') as FormArray;
for (let i = 0; i < this.permissions.permissions.length; i++) { for (let i = 0; i < this.permissions.permissions.length; i++) {
this.formGroup.controls.roster['controls'][this.permissions.permissions[i].id].patchValue({ roster.at(this.permissions.permissions[i].id).patchValue({
selected: true selected: true
}); });
} }
@@ -249,8 +248,9 @@ export class ViewRoleComponent implements OnInit {
* Deselects all the permissions of a particular role * Deselects all the permissions of a particular role
*/ */
deselectAll() { deselectAll() {
const roster = this.formGroup.get('roster') as FormArray;
for (let i = 0; i < this.permissions.permissions.length; i++) { for (let i = 0; i < this.permissions.permissions.length; i++) {
this.formGroup.controls.roster['controls'][this.permissions.permissions[i].id].patchValue({ roster.at(this.permissions.permissions[i].id).patchValue({
selected: false selected: false
}); });
} }
@@ -15,6 +15,12 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates'; import { Dates } from 'app/core/utils/dates';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
interface OfficeNode {
id: number;
name: string;
loans: any[];
}
@Component({ @Component({
selector: 'mifosx-loan-approval', selector: 'mifosx-loan-approval',
templateUrl: './loan-approval.component.html', templateUrl: './loan-approval.component.html',
@@ -32,7 +38,7 @@ export class LoanApprovalComponent {
/** Row Selection Data */ /** Row Selection Data */
selection: SelectionModel<any>; selection: SelectionModel<any>;
/** Map data */ /** Map data */
idToNodeMap = {}; idToNodeMap: { [key: number]: OfficeNode } = {};
/** Grouped Office Data */ /** Grouped Office Data */
officesArray: any[]; officesArray: any[];
/** List of Requests */ /** List of Requests */
@@ -79,15 +85,15 @@ export class LoanApprovalComponent {
}); });
this.loans.forEach((loanEle: any) => { this.loans.forEach((loanEle: any) => {
if (loanEle.status.pendingApproval) { if (loanEle.status.pendingApproval) {
let tempOffice = {}; let tempOffice: OfficeNode | undefined;
if (loanEle.clientOfficeId) { if (loanEle.clientOfficeId) {
tempOffice = this.idToNodeMap[loanEle.clientOfficeId]; tempOffice = this.idToNodeMap[loanEle.clientOfficeId];
tempOffice['loans'].push(loanEle); } else if (loanEle.group?.officeId) {
} else { tempOffice = this.idToNodeMap[loanEle.group.officeId];
if (loanEle.group) { }
tempOffice = this.idToNodeMap[loanEle.group.officeId];
tempOffice['loans'].push(loanEle); if (tempOffice) {
} tempOffice.loans.push(loanEle);
} }
} }
}); });
@@ -15,6 +15,13 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates'; import { Dates } from 'app/core/utils/dates';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
interface RescheduleFormData {
dateFormat: string;
locale: string;
approvedOnDate?: string;
rejectedOnDate?: string;
}
@Component({ @Component({
selector: 'mifosx-reschedule-loan', selector: 'mifosx-reschedule-loan',
templateUrl: './reschedule-loan.component.html', templateUrl: './reschedule-loan.component.html',
@@ -107,14 +114,14 @@ export class RescheduleLoanComponent {
const dateFormat = this.settingsService.dateFormat; const dateFormat = this.settingsService.dateFormat;
const transactionDate = this.dateUtils.formatDate(this.settingsService.businessDate, dateFormat); const transactionDate = this.dateUtils.formatDate(this.settingsService.businessDate, dateFormat);
const locale = this.settingsService.language.code; const locale = this.settingsService.language.code;
const formData = { const formData: RescheduleFormData = {
dateFormat, dateFormat,
locale locale
}; };
if (command === 'approve') { if (command === 'approve') {
formData['approvedOnDate'] = transactionDate; formData.approvedOnDate = transactionDate;
} else { } else {
formData['rejectedOnDate'] = transactionDate; formData.rejectedOnDate = transactionDate;
} }
const listSelectedAccounts = this.selection.selected; const listSelectedAccounts = this.selection.selected;
this.batchRequests = []; this.batchRequests = [];
+25 -25
View File
@@ -6,32 +6,32 @@
// `.env.ts` is generated by the `npm run env` command // `.env.ts` is generated by the `npm run env` command
import env from './.env'; import env from './.env';
// The `window['env']` object is loaded in the `index.html` file // The `window.env` object is loaded in the `index.html` file
const loadedEnv = window['env'] || {}; const loadedEnv = window.env || {};
export const environment = { export const environment = {
production: false, production: false,
version: env.mifos_x.version, version: env.mifos_x.version,
hash: env.mifos_x.hash, hash: env.mifos_x.hash,
// For connecting to server running elsewhere update the tenant identifier // For connecting to server running elsewhere update the tenant identifier
fineractPlatformTenantId: loadedEnv['fineractPlatformTenantId'] || 'default', fineractPlatformTenantId: loadedEnv.fineractPlatformTenantId || 'default',
fineractPlatformTenantIds: loadedEnv['fineractPlatformTenantIds'] || 'default', fineractPlatformTenantIds: loadedEnv.fineractPlatformTenantIds || 'default',
// For connecting to others servers running elsewhere update the base API URL // For connecting to others servers running elsewhere update the base API URL
baseApiUrls: baseApiUrls:
loadedEnv['fineractApiUrls'] || loadedEnv.fineractApiUrls ||
'https://sandbox.mifos.community,https://demo.mifos.community,https://localhost:8443,' + window.location.origin, 'https://sandbox.mifos.community,https://demo.mifos.community,https://localhost:8443,' + window.location.origin,
// For connecting to server running elsewhere set the base API URL // For connecting to server running elsewhere set the base API URL
baseApiUrl: baseApiUrl:
loadedEnv['fineractApiUrl'] || loadedEnv.fineractApiUrl ||
(loadedEnv['fineractApiUrls']?.length > 0 ? loadedEnv['fineractApiUrls'].split(',')[0] : window.location.origin), (loadedEnv.fineractApiUrls?.length > 0 ? loadedEnv.fineractApiUrls.split(',')[0] : window.location.origin),
allowServerSwitch: env.allow_switching_backend_instance, allowServerSwitch: env.allow_switching_backend_instance,
apiProvider: loadedEnv['apiProvider'] || '/fineract-provider/api', apiProvider: loadedEnv.apiProvider || '/fineract-provider/api',
apiVersion: loadedEnv['apiVersion'] || '/v1', apiVersion: loadedEnv.apiVersion || '/v1',
serverUrl: '', serverUrl: '',
oauth: { oauth: {
enabled: loadedEnv['oauthServerEnabled'] || false, // For connecting to Mifos X using OAuth2 Authentication change the value to true enabled: loadedEnv.oauthServerEnabled || false, // For connecting to Mifos X using OAuth2 Authentication change the value to true
serverUrl: loadedEnv['oauthServerUrl'] || '', serverUrl: loadedEnv.oauthServerUrl || '',
appId: loadedEnv['oauthAppId'] || '' appId: loadedEnv.oauthAppId || ''
}, },
warningDialog: { warningDialog: {
title: 'Warning', title: 'Warning',
@@ -39,31 +39,31 @@ export const environment = {
'This system is for authorized use only. Unauthorized access will result in possible legal action. By accessing this system, you acknowledge that you are authorized to do so and that all data stored and processed here is confidential.', 'This system is for authorized use only. Unauthorized access will result in possible legal action. By accessing this system, you acknowledge that you are authorized to do so and that all data stored and processed here is confidential.',
buttonText: 'Close' buttonText: 'Close'
}, },
defaultLanguage: loadedEnv['defaultLanguage'] || 'en-US', defaultLanguage: loadedEnv.defaultLanguage || 'en-US',
supportedLanguages: supportedLanguages:
loadedEnv['supportedLanguages'] || 'cs-CS,de-DE,en-US,es-MX,fr-FR,it-IT,ko-KO,lt-LT,lv-LV,ne-NE,pt-PT,sw-SW', loadedEnv.supportedLanguages || 'cs-CS,de-DE,en-US,es-MX,fr-FR,it-IT,ko-KO,lt-LT,lv-LV,ne-NE,pt-PT,sw-SW',
preloadClients: loadedEnv['preloadClients'] || true, preloadClients: loadedEnv['preloadClients'] || true,
defaultCharDelimiter: loadedEnv['defaultCharDelimiter'] || ',', defaultCharDelimiter: loadedEnv.defaultCharDelimiter || ',',
displayBackEndInfo: loadedEnv['displayBackEndInfo'] || 'true', displayBackEndInfo: loadedEnv.displayBackEndInfo || 'true',
displayTenantSelector: loadedEnv['displayTenantSelector'] || 'true', displayTenantSelector: loadedEnv.displayTenantSelector || 'true',
// Time in seconds, default 60 seconds // Time in seconds, default 60 seconds
waitTimeForNotifications: loadedEnv['waitTimeForNotifications'] || 60, waitTimeForNotifications: loadedEnv.waitTimeForNotifications || 60,
// Time in seconds, default 30 seconds // Time in seconds, default 30 seconds
waitTimeForCOBCatchUp: loadedEnv['waitTimeForCOBCatchUp'] || 30, waitTimeForCOBCatchUp: loadedEnv.waitTimeForCOBCatchUp || 30,
session: { session: {
timeout: { timeout: {
idleTimeout: loadedEnv['sessionIdleTimeout'] || 300000 // 5 minutes idleTimeout: loadedEnv.sessionIdleTimeout || 300000 // 5 minutes
} }
}, },
vNextApiUrl: window['env']['vNextApiUrl'] || 'https://apis.flexcore.mx', vNextApiUrl: window.env?.vNextApiUrl || 'https://apis.flexcore.mx',
vNextApiProvider: window['env']['vNextApiProvider'] || '/vnext1', vNextApiProvider: window.env?.vNextApiProvider || '/vnext1',
vNextApiVersion: window['env']['vNextApiVersion'] || '/v1.0', vNextApiVersion: window.env?.vNextApiVersion || '/v1.0',
interbankTransfers: window['env']['interbankTransfers'] || false, interbankTransfers: window.env?.interbankTransfers || false,
minPasswordLength: loadedEnv['minPasswordLength'] || 12 minPasswordLength: loadedEnv.minPasswordLength || 12
}; };
// Server URL // Server URL
+20
View File
@@ -580,6 +580,10 @@
gap: 10px; gap: 10px;
} }
.menu-right-section fa-icon {
z-index: 1000;
}
.menu-right-section { .menu-right-section {
margin-left: auto; margin-left: auto;
display: flex; display: flex;
@@ -591,3 +595,19 @@
display: contents; display: contents;
flex: 1; flex: 1;
} }
mifosx-notifications-page td {
text-align: center;
padding: 16px;
color: #999;
}
.red {
color: red;
}
.full-width-flex {
display: flex;
justify-content: flex-start;
width: 100%;
}
+2 -1
View File
@@ -28,7 +28,8 @@ import '@angular/localize/init';
/*************************************************************************************************** /***************************************************************************************************
* Zone JS is required by default for Angular itself. * Zone JS is required by default for Angular itself.
*/ */
import 'zone.js/dist/zone'; // Included with Angular CLI. import 'zone.js';
// Included with Angular CLI.
/*************************************************************************************************** /***************************************************************************************************
* APPLICATION IMPORTS * APPLICATION IMPORTS
+29
View File
@@ -0,0 +1,29 @@
interface Window {
env?: {
[key: string]: any;
fineractPlatformTenantId?: string;
fineractPlatformTenantIds?: string;
fineractApiUrls?: string;
fineractApiUrl?: string;
allow_switching_backend_instance?: boolean;
apiProvider?: string;
apiVersion?: string;
oauthServerEnabled?: boolean;
oauthServerUrl?: string;
oauthAppId?: string;
defaultLanguage?: string;
supportedLanguages?: string;
preloadClients?: boolean;
defaultCharDelimiter?: string;
displayBackEndInfo?: string;
displayTenantSelector?: string;
waitTimeForNotifications?: number;
waitTimeForCOBCatchUp?: number;
sessionIdleTimeout?: number;
vNextApiUrl?: string;
vNextApiProvider?: string;
vNextApiVersion?: string;
interbankTransfers?: boolean;
minPasswordLength?: number;
};
}
+7
View File
@@ -11,6 +11,13 @@ interface NodeModule {
id: string; id: string;
} }
// Extend the global Window interface to include `env`
interface Window {
env: {
[key: string]: any;
};
}
declare module 'chart.js'; declare module 'chart.js';
declare module '@ckeditor/ckeditor5-build-classic' { declare module '@ckeditor/ckeditor5-build-classic' {
-1
View File
@@ -12,7 +12,6 @@
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"noImplicitAny": true, "noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"target": "ES2022", "target": "ES2022",
"typeRoots": [ "typeRoots": [
"node_modules/@types", "node_modules/@types",