Merge branch 'dev' into WEB-642/add-originators-tab-on-loan-details-view

This commit is contained in:
Jose Alberto Hernandez 2026-01-31 21:45:03 -05:00 committed by GitHub
commit 447e0718de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
100 changed files with 1100 additions and 674 deletions

View File

@ -25,3 +25,5 @@ services:
- MIFOS_SESSION_IDLE_TIMEOUT=300000
- MIFOS_PRELOAD_CLIENTS=true
- MIFOS_DEFAULT_CHAR_DELIMITER=,
# Production mode - set to true for minimal hero with only branding
- MIFOS_PRODUCTION_MODE=false

View File

@ -41,3 +41,7 @@ MIFOS_HTTP_CACHE_ENABLED=true
# Hide client data information (set to true to mask client names)
MIFOS_COMPLIANCE_HIDE_CLIENT_DATA=false
# Production mode - when true, shows minimal hero with only branding at bottom
# Set to true for financial institutions that want a clean, professional look
MIFOS_PRODUCTION_MODE=false

455
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@
"jspdf": "^3.0.1",
"jspdf-autotable": "^5.0.2",
"lightgallery": "^2.9.0",
"lodash": "4.17.21",
"lodash": "4.17.23",
"moment": "^2.29.4",
"ngx-mat-select-search": "^8.0.2",
"rxjs": "^7.8.2",

View File

@ -84,17 +84,17 @@ export class AccountingComponent implements AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showChartofAccounts === true) {
if (this.configurationWizardService.showChartofAccounts) {
setTimeout(() => {
this.showPopover(this.templateChartofAccounts, this.chartofAccounts.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showAccountsLinked === true) {
if (this.configurationWizardService.showAccountsLinked) {
setTimeout(() => {
this.showPopover(this.templateAccountsLinked, this.accountsLinked.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showMigrateOpeningBalances === true) {
if (this.configurationWizardService.showMigrateOpeningBalances) {
setTimeout(() => {
this.showPopover(
this.templateMigrateOpeningBalances,
@ -104,12 +104,12 @@ export class AccountingComponent implements AfterViewInit {
);
});
}
if (this.configurationWizardService.showClosingEntries === true) {
if (this.configurationWizardService.showClosingEntries) {
setTimeout(() => {
this.showPopover(this.templateClosingEntries, this.closingEntries.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showCreateJournalEntries === true) {
if (this.configurationWizardService.showCreateJournalEntries) {
setTimeout(() => {
this.showPopover(this.templateCreateJournalEntries, this.createJournalEntries.nativeElement, 'bottom', true);
});

View File

@ -181,13 +181,13 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
}
};
this.tableDataSource.sort = this.sort;
if (this.configurationWizardService.showChartofAccountsPage === true) {
if (this.configurationWizardService.showChartofAccountsPage) {
setTimeout(() => {
this.showPopover(this.templateButtonTreeView, this.buttonTreeView.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showChartofAccountsList === true) {
if (this.configurationWizardService.showChartofAccountsList) {
setTimeout(() => {
this.showPopover(this.templateAccountsTable, this.accountsTable.nativeElement, 'top', true);
});

View File

@ -173,7 +173,7 @@ export class CreateGlAccountComponent implements OnInit, AfterViewInit {
return;
}
this.accountingService.createGlAccount(this.glAccountForm.value).subscribe((response: any) => {
if (this.configurationWizardService.showChartofAccounts === true) {
if (this.configurationWizardService.showChartofAccounts) {
this.configurationWizardService.showChartofAccounts = false;
this.openDialog();
} else {
@ -208,7 +208,7 @@ export class CreateGlAccountComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showChartofAccountsForm === true) {
if (this.configurationWizardService.showChartofAccountsForm) {
setTimeout(() => {
this.showPopover(this.templateAccountFormRef, this.accountFormRef.nativeElement, 'bottom', true);
});

View File

@ -184,13 +184,13 @@ export class ClosingEntriesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showClosingEntriesPage === true) {
if (this.configurationWizardService.showClosingEntriesPage) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateClosure, this.buttonCreateClosure.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showClosingEntriesList === true) {
if (this.configurationWizardService.showClosingEntriesList) {
setTimeout(() => {
this.showPopover(this.templateClosuresTable, this.closuresTable.nativeElement, 'top', true);
});

View File

@ -251,7 +251,7 @@ export class CreateJournalEntryComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showCreateJournalEntries === true) {
if (this.configurationWizardService.showCreateJournalEntries) {
setTimeout(() => {
this.showPopover(this.templateCreateJournalFormRef, this.createJournalFormRef.nativeElement, 'top', true);
});

View File

@ -149,13 +149,13 @@ export class FinancialActivityMappingsComponent implements OnInit, AfterViewInit
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showAccountsLinkedPage === true) {
if (this.configurationWizardService.showAccountsLinkedPage) {
setTimeout(() => {
this.showPopover(this.templateButtonDefineMapping, this.buttonDefineMapping.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showAccountsLinkedList === true) {
if (this.configurationWizardService.showAccountsLinkedList) {
setTimeout(() => {
this.showPopover(this.templateActivitiesTable, this.activitiesTable.nativeElement, 'top', true);
});

View File

@ -240,7 +240,7 @@ export class MigrateOpeningBalancesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showMigrateOpeningBalances === true) {
if (this.configurationWizardService.showMigrateOpeningBalances) {
setTimeout(() => {
this.showPopover(this.templateSearchFormRef, this.searchFormRef.nativeElement, 'bottom', true);
});

View File

@ -181,7 +181,7 @@
</div>
}
@if (createClientForm.value.legalFormId === 1) {
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Gender' | translate }}</mat-label>
<mat-select formControlName="genderId">
@ -205,7 +205,7 @@
</mat-select>
</mat-form-field>
@if (createClientForm.value.legalFormId === 1) {
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
<mat-checkbox class="flex-48 margin-v" labelPosition="before" formControlName="isStaff">
{{ 'labels.inputs.Is staff' | translate }}?
</mat-checkbox>

View File

@ -7,7 +7,7 @@
*/
/** Angular Imports */
import { Component, OnInit, Input, Output, EventEmitter, inject } from '@angular/core';
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, inject } from '@angular/core';
import {
UntypedFormBuilder,
UntypedFormGroup,
@ -15,8 +15,11 @@ import {
UntypedFormControl,
ReactiveFormsModule
} from '@angular/forms';
import { Subject } from 'rxjs';
import { filter, switchMap, takeUntil } from 'rxjs/operators';
import { ClientsService } from 'app/clients/clients.service';
import { Dates } from 'app/core/utils/dates';
import { LegalFormId } from 'app/clients/models/legal-form.enum';
/** Custom Services */
import { SettingsService } from 'app/settings/settings.service';
@ -44,14 +47,20 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
MatStepperNext
]
})
export class ClientGeneralStepComponent implements OnInit {
export class ClientGeneralStepComponent implements OnInit, OnDestroy {
private formBuilder = inject(UntypedFormBuilder);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
private clientService = inject(ClientsService);
/** Subject to trigger unsubscription on destroy */
private destroy$ = new Subject<void>();
@Output() legalFormChangeEvent = new EventEmitter<{ legalForm: number }>();
/** Expose enum to template */
readonly LegalFormId = LegalFormId;
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
@ -151,76 +160,95 @@ export class ClientGeneralStepComponent implements OnInit {
* Adds controls conditionally.
*/
buildDependencies() {
this.createClientForm.get('legalFormId').valueChanges.subscribe((legalFormId: number) => {
this.legalFormChangeEvent.emit({ legalForm: legalFormId });
if (legalFormId === 1) {
this.createClientForm.removeControl('fullname');
this.createClientForm.removeControl('clientNonPersonDetails');
this.createClientForm.addControl(
'firstname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
this.createClientForm.addControl('middlename', new UntypedFormControl('', Validators.pattern('(^[A-z]).*')));
this.createClientForm.addControl(
'lastname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
} else {
this.createClientForm.removeControl('firstname');
this.createClientForm.removeControl('middlename');
this.createClientForm.removeControl('lastname');
this.createClientForm.addControl(
'fullname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
this.createClientForm.addControl(
'clientNonPersonDetails',
this.formBuilder.group({
constitutionId: [
'',
Validators.required
],
incorpValidityTillDate: [''],
incorpNumber: [''],
mainBusinessLineId: [''],
remarks: ['']
})
);
}
});
this.createClientForm.get('legalFormId').patchValue(1);
this.createClientForm.get('active').valueChanges.subscribe((active: boolean) => {
if (active) {
this.createClientForm.addControl('activationDate', new UntypedFormControl('', Validators.required));
} else {
this.createClientForm.removeControl('activationDate');
}
});
this.createClientForm.get('addSavings').valueChanges.subscribe((active: boolean) => {
if (active) {
this.createClientForm.addControl('savingsProductId', new UntypedFormControl('', Validators.required));
} else {
this.createClientForm.removeControl('savingsProductId');
}
});
this.createClientForm.get('officeId').valueChanges.subscribe((officeId: number) => {
this.clientService.getClientWithOfficeTemplate(officeId).subscribe((clientTemplate: any) => {
this.createClientForm
.get('legalFormId')
.valueChanges.pipe(takeUntil(this.destroy$))
.subscribe((legalFormId: number) => {
this.legalFormChangeEvent.emit({ legalForm: legalFormId });
if (legalFormId === LegalFormId.PERSON) {
this.createClientForm.removeControl('fullname');
this.createClientForm.removeControl('clientNonPersonDetails');
this.createClientForm.addControl(
'firstname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
this.createClientForm.addControl('middlename', new UntypedFormControl('', Validators.pattern('(^[A-z]).*')));
this.createClientForm.addControl(
'lastname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
} else {
this.createClientForm.removeControl('firstname');
this.createClientForm.removeControl('middlename');
this.createClientForm.removeControl('lastname');
this.createClientForm.addControl(
'fullname',
new UntypedFormControl('', [
Validators.required,
Validators.pattern('(^[A-z]).*')
])
);
this.createClientForm.addControl(
'clientNonPersonDetails',
this.formBuilder.group({
constitutionId: [
'',
Validators.required
],
incorpValidityTillDate: [''],
incorpNumber: [''],
mainBusinessLineId: [''],
remarks: ['']
})
);
}
});
this.createClientForm.get('legalFormId').patchValue(LegalFormId.PERSON);
this.createClientForm
.get('active')
.valueChanges.pipe(takeUntil(this.destroy$))
.subscribe((active: boolean) => {
if (active) {
this.createClientForm.addControl('activationDate', new UntypedFormControl('', Validators.required));
} else {
this.createClientForm.removeControl('activationDate');
}
});
this.createClientForm
.get('addSavings')
.valueChanges.pipe(takeUntil(this.destroy$))
.subscribe((active: boolean) => {
if (active) {
this.createClientForm.addControl('savingsProductId', new UntypedFormControl('', Validators.required));
} else {
this.createClientForm.removeControl('savingsProductId');
}
});
this.createClientForm
.get('officeId')
.valueChanges.pipe(
filter((officeId: number) => !!officeId),
switchMap((officeId: number) => this.clientService.getClientWithOfficeTemplate(officeId)),
takeUntil(this.destroy$)
)
.subscribe((clientTemplate: any) => {
this.staffOptions = clientTemplate.staffOptions;
});
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
getDateLabel(legalFormId: number, values: string[]): string {
return legalFormId === 1 ? values[0] : values[1];
return legalFormId === LegalFormId.PERSON ? values[0] : values[1];
}
/**

View File

@ -13,10 +13,10 @@
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.name' | translate }}</span>
@if (client.legalFormId === 2) {
@if (client.legalFormId === LegalFormId.ENTITY) {
<span class="flex-60">{{ client.fullname }}</span>
}
@if (client.legalFormId === 1) {
@if (client.legalFormId === LegalFormId.PERSON) {
<span class="flex-60"
>{{ client.firstname }}
{{ client.middlename ? client.middlename + ' ' + client.lastname : client.lastname }}</span
@ -43,7 +43,9 @@
@if (client.dateOfBirth) {
<div class="flex-fill">
<span class="flex-40">{{ client.legalFormId === 1 ? 'Date of Birth' : 'Incorporation Date' }}</span>
<span class="flex-40">{{
client.legalFormId === LegalFormId.PERSON ? 'Date of Birth' : 'Incorporation Date'
}}</span>
<span class="flex-60">{{ client.dateOfBirth | dateFormat }}</span>
</div>
}
@ -115,7 +117,7 @@
</div>
}
@if (client.legalFormId === 1) {
@if (client.legalFormId === LegalFormId.PERSON) {
@if (client.genderId) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Gender' | translate }}</span>
@ -128,7 +130,7 @@
</div>
}
@if (client.legalFormId === 2) {
@if (client.legalFormId === LegalFormId.ENTITY) {
@if (client.clientNonPersonDetails.incorpValidityTillDate) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Incorporation Validity Till Date' | translate }}</span>

View File

@ -23,6 +23,7 @@ import { FindPipe } from '../../../pipes/find.pipe';
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
import { YesnoPipe } from '../../../pipes/yesno.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { LegalFormId } from 'app/clients/models/legal-form.enum';
/**
* Client Preview Step Component
@ -58,6 +59,9 @@ export class ClientPreviewStepComponent {
/** Form submission event */
@Output() submitEvent = new EventEmitter();
/** Expose enum to template */
readonly LegalFormId = LegalFormId;
constructor() {}
/**

View File

@ -146,7 +146,7 @@ export class AddClientChargeComponent implements OnInit {
clientCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
clientCharge.monthDayFormat = monthDayFormat;
if (clientCharge.feeOnMonthDay) {

View File

@ -14,6 +14,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
/** Custom Imports */
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
import { LegalFormId } from 'app/clients/models/legal-form.enum';
/** Interfaces */
interface ClientViewData {
@ -71,16 +72,16 @@ export class PersonalDataTabComponent {
}
/**
* Check if client is a person (legalFormId = 1) or entity (legalFormId = 2)
* Check if client is a person (individual)
*/
isPerson(): boolean {
return this.clientViewData?.legalForm?.id === 1;
return this.clientViewData?.legalForm?.id === LegalFormId.PERSON;
}
/**
* Check if client is a legal entity
* Check if client is a legal entity (organization)
*/
isLegalEntity(): boolean {
return this.clientViewData?.legalForm?.id === 2;
return this.clientViewData?.legalForm?.id === LegalFormId.ENTITY;
}
}

View File

@ -159,7 +159,7 @@
<mat-datepicker #dateOfBirthDatePicker></mat-datepicker>
</mat-form-field>
@if (legalFormId === 1) {
@if (legalFormId === LegalFormId.PERSON) {
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Gender' | translate }}</mat-label>
<mat-select formControlName="genderId">
@ -186,7 +186,7 @@
</mat-select>
</mat-form-field>
@if (legalFormId === 1) {
@if (legalFormId === LegalFormId.PERSON) {
<mat-checkbox class="flex-48 margin-v" labelPosition="before" formControlName="isStaff">
{{ 'labels.inputs.Is staff' | translate }}?
</mat-checkbox>

View File

@ -9,6 +9,7 @@
/** Angular Imports */
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { LegalFormId } from 'app/clients/models/legal-form.enum';
import {
UntypedFormBuilder,
UntypedFormGroup,
@ -74,7 +75,10 @@ export class EditClientComponent implements OnInit {
constitutionOptions: any;
/** Gender Options */
genderOptions: any;
legalFormId = 1;
legalFormId = LegalFormId.PERSON;
/** Expose enum to template */
readonly LegalFormId = LegalFormId;
/**
* Fetches client template data from `resolve`
@ -96,7 +100,7 @@ export class EditClientComponent implements OnInit {
this.createEditClientForm();
this.setOptions();
this.buildDependencies();
this.legalFormId = 1;
this.legalFormId = LegalFormId.PERSON;
this.editClientForm.patchValue({
officeId: this.clientDataAndTemplate.officeId,
staffId: this.clientDataAndTemplate.staffId,
@ -172,7 +176,7 @@ export class EditClientComponent implements OnInit {
*/
buildDependencies() {
this.editClientForm.get('legalFormId').valueChanges.subscribe((legalFormId: any) => {
if (legalFormId === 1) {
if (legalFormId === LegalFormId.PERSON) {
this.editClientForm.removeControl('fullname');
this.editClientForm.removeControl('clientNonPersonDetails');
this.editClientForm.addControl(
@ -217,7 +221,7 @@ export class EditClientComponent implements OnInit {
}
getDateLabel(legalFormId: number, values: string[]): string {
return legalFormId === 1 ? values[0] : values[1];
return legalFormId === LegalFormId.PERSON ? values[0] : values[1];
}
/**

View File

@ -0,0 +1,18 @@
/**
* 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/.
*/
/**
* Legal Form IDs for client types.
* These represent the different legal forms a client can have.
*/
export enum LegalFormId {
/** Individual/Personal client */
PERSON = 1,
/** Non-person/Entity client (Organization, Corporation, etc.) */
ENTITY = 2
}

View File

@ -19,6 +19,7 @@ import { CentersService } from 'app/centers/centers.service';
import { GroupsService } from 'app/groups/groups.service';
import { Dates } from 'app/core/utils/dates';
import { CollectionSheetData, JLGGroupData, MeetingFallCenter } from '../models/collection-sheet-data.model';
import { Logger } from 'app/core/logger/logger.service';
@Component({
selector: 'mifosx-collection-sheet',
@ -30,6 +31,7 @@ import { CollectionSheetData, JLGGroupData, MeetingFallCenter } from '../models/
]
})
export class CollectionSheetComponent implements OnInit {
private readonly log = new Logger('CollectionSheetComponent');
private formBuilder = inject(UntypedFormBuilder);
private centerService = inject(CentersService);
private collectionsService = inject(CollectionsService);
@ -140,7 +142,7 @@ export class CollectionSheetComponent implements OnInit {
this.collectionsService
.generateCollectionSheetData(this.meetingFallCenters[0].id, payload)
.subscribe((jlgGroupData: JLGGroupData) => {
console.log(jlgGroupData);
this.log.debug('JLG Group Data:', jlgGroupData);
});
}
});

View File

@ -21,186 +21,186 @@ export class ConfigurationWizardService {
*/
/*To show toolbar*/
showToolbar = false;
showToolbar: boolean = false;
/*To show popover on admin section in toolbar*/
showToolbarAdmin = false;
showToolbarAdmin: boolean = false;
/*To show side navbar*/
showSideNav = false;
showSideNav: boolean = false;
/*To show popover on chart of accounts section in sidenav bar*/
showSideNavChartofAccounts = false;
showSideNavChartofAccounts: boolean = false;
/*To show breadcrumbs*/
showBreadcrumbs = false;
showBreadcrumbs: boolean = false;
/*To show home*/
showHome = false;
showHome: boolean = false;
/*To show search activity in home*/
showHomeSearchActivity = false;
showHomeSearchActivity: boolean = false;
/**
* Organization Setup
*/
/*To show popover on manage offices on oganization page*/
showCreateOffice = false;
showCreateOffice: boolean = false;
/*To show popover on button in offices page*/
showOfficeList = false;
showOfficeList: boolean = false;
/*To show popover on offices table*/
showOfficeTable = false;
showOfficeTable: boolean = false;
/*To show popover on create office form*/
showOfficeForm = false;
showOfficeForm: boolean = false;
/*To show popover on add edit currency on organization page*/
showAddEditCurrency = false;
showAddEditCurrency: boolean = false;
/*To show popover on button in currency page*/
showCurrencyPage = false;
showCurrencyPage: boolean = false;
/*To show popover on currency table*/
showCurrencyList = false;
showCurrencyList: boolean = false;
/*To show popover on currency form*/
showCurrencyForm = false;
showCurrencyForm: boolean = false;
/*To show popover on manage holiday on organization page*/
showCreateHoliday = false;
showCreateHoliday: boolean = false;
/*To show popover on button in holiday page*/
showHolidayPage = false;
showHolidayPage: boolean = false;
/*To show popover on filter in holiday table*/
showHolidayFilter = false;
showHolidayFilter: boolean = false;
/*To show popover on manage employees on organization page*/
showCreateEmployee = false;
showCreateEmployee: boolean = false;
/*To show popover on button in employee page*/
showEmployeeList = false;
showEmployeeList: boolean = false;
/*To show popover on employees table*/
showEmployeeTable = false;
showEmployeeTable: boolean = false;
/*To show popover on create employee form*/
showEmployeeForm = false;
showEmployeeForm: boolean = false;
/*To show popover on define working days*/
showDefineWorkingDays = false;
showDefineWorkingDays: boolean = false;
/**
* System Setup
*/
/*To show popover on manage datatables on system page*/
showDatatables = false;
showDatatables: boolean = false;
/*To show popover on button in datatables page*/
showDatatablesPage = false;
showDatatablesPage: boolean = false;
/*To show popover on datatables table*/
showDatatablesList = false;
showDatatablesList: boolean = false;
/*To show popover on create datable form*/
showDatatablesForm = false;
showDatatablesForm: boolean = false;
/*To show popover manage codes on system page*/
showSystemCodes = false;
showSystemCodes: boolean = false;
/*To show popover on button in codes page*/
showSystemCodesPage = false;
showSystemCodesPage: boolean = false;
/*To show popover on codes table*/
showSystemCodesList = false;
showSystemCodesList: boolean = false;
/*To show popover on create codes form*/
showSystemCodesForm = false;
showSystemCodesForm: boolean = false;
/*To show popover on manage roles and permision on system page*/
showRolesandPermission = false;
showRolesandPermission: boolean = false;
/*To show popover on button in rolaes and permission page*/
showRolesandPermissionPage = false;
showRolesandPermissionPage: boolean = false;
/*To show popover on roles and permission list*/
showRolesandPermissionList = false;
showRolesandPermissionList: boolean = false;
/*To show popover on button on user page*/
showUsers = false;
showUsers: boolean = false;
/*To show popover on users table*/
showUsersList = false;
showUsersList: boolean = false;
/*To show popover on create user form*/
showUsersForm = false;
showUsersForm: boolean = false;
/*To show popover on maker checker table in system page*/
showMakerCheckerTable = false;
showMakerCheckerTable: boolean = false;
/*To show popover on button in make checker tasks page*/
showMakerCheckerTablePage = false;
showMakerCheckerTablePage: boolean = false;
/*To show popover on maker checker tasks table*/
showMakerCheckerTableList = false;
showMakerCheckerTableList: boolean = false;
/*To show popover on global configuration in system page*/
showConfigurations = false;
showConfigurations: boolean = false;
/*To show popover on button in configuration page*/
showConfigurationsPage = false;
showConfigurationsPage: boolean = false;
/*To show popover on button in configuration list*/
showConfigurationsList = false;
showConfigurationsList: boolean = false;
/*To show popover on manage scheduler jobs on system page*/
showSchedulerJobs = false;
showSchedulerJobs: boolean = false;
/*To show popover on button in scheduler jobs page*/
showSchedulerJobsPage = false;
showSchedulerJobsPage: boolean = false;
/*To show popover on scheduler jobs table*/
showSchedulerJobsList = false;
showSchedulerJobsList: boolean = false;
/**
* Accounting Setup
*/
/*To show popover on chart of accounts on accounting page*/
showChartofAccounts = false;
showChartofAccounts: boolean = false;
/*To show popover on button in chart of accounts page*/
showChartofAccountsPage = false;
showChartofAccountsPage: boolean = false;
/*To show popover on button in chart of accounts page*/
showChartofAccountsList = false;
showChartofAccountsList: boolean = false;
/*To show popover on create chart of accounts form*/
showChartofAccountsForm = false;
showChartofAccountsForm: boolean = false;
/*To show popover on accounts linked on accounting page*/
showAccountsLinked = false;
showAccountsLinked: boolean = false;
/*To show popover on button in accounting page*/
showAccountsLinkedPage = false;
showAccountsLinkedPage: boolean = false;
/*To show popover on accounts linked table*/
showAccountsLinkedList = false;
showAccountsLinkedList: boolean = false;
/*To show popover on migrate openening balances*/
showMigrateOpeningBalances = false;
showMigrateOpeningBalances: boolean = false;
/*To show popover on closing entries on accounting page*/
showClosingEntries = false;
showClosingEntries: boolean = false;
/*To show popover on button in closing entries page*/
showClosingEntriesPage = false;
showClosingEntriesPage: boolean = false;
/*To show popover on closing entries table*/
showClosingEntriesList = false;
showClosingEntriesList: boolean = false;
/*To show popover on create journal entry*/
showCreateJournalEntries = false;
showCreateJournalEntries: boolean = false;
/**
* Products Setup
*/
/*To show popover on charges on products page*/
showCharges = false;
showCharges: boolean = false;
/*To show popover on button in charges page*/
showChargesPage = false;
showChargesPage: boolean = false;
/*To show popover on charges table*/
showChargesList = false;
showChargesList: boolean = false;
/*To show popover on loan products on products page*/
showLoanProducts = false;
showLoanProducts: boolean = false;
/*To show popover on button in load products page*/
showLoanProductsPage = false;
showLoanProductsPage: boolean = false;
/*To show popover on loan products table*/
showLoanProductsList = false;
showLoanProductsList: boolean = false;
/*To show popover on savings products on products page*/
showSavingsProducts = false;
showSavingsProducts: boolean = false;
/*To show popover on button in savings products page*/
showSavingsProductsPage = false;
showSavingsProductsPage: boolean = false;
/*To show popover on savings products table*/
showSavingsProductsList = false;
showSavingsProductsList: boolean = false;
/*To show popover on shares products on products page*/
showShareProducts = false;
showShareProducts: boolean = false;
/*To show popover on button in share products page*/
showShareProductsPage = false;
showShareProductsPage: boolean = false;
/*To show popover on share products table*/
showShareProductsList = false;
showShareProductsList: boolean = false;
/*To show popover on fixed deposit products on products page*/
showFixedDepositProducts = false;
showFixedDepositProducts: boolean = false;
/*To show popover on button in fixed deposit products page*/
showFixedDepositProductsPage = false;
showFixedDepositProductsPage: boolean = false;
/*To show popover on fixed deposit products table*/
showFixedDepositProductsList = false;
showFixedDepositProductsList: boolean = false;
/*To show popover on recrurring deposit products on products page*/
showRecurringDepositProducts = false;
showRecurringDepositProducts: boolean = false;
/*To show popover on button in recurring deposit products page*/
showRecurringDepositProductsPage = false;
showRecurringDepositProductsPage: boolean = false;
/*To show popover on recurring deposit products table*/
showRecurringDepositProductsList = false;
showRecurringDepositProductsList: boolean = false;
/**
* Manage Funds and manage reports Setup
*/
/*To show popover on manage funds*/
showManageFunds = false;
showManageFunds: boolean = false;
/*To show popover on manage reports*/
showManageReports = false;
showManageReports: boolean = false;
constructor() {}

View File

@ -183,7 +183,7 @@ export class PopoverService {
}
];
}
if (backdrop === true) {
if (backdrop) {
showbackdrop = true;
} else {
showbackdrop = false;

View File

@ -252,7 +252,7 @@ export class BreadcrumbComponent implements AfterViewInit, OnDestroy {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showBreadcrumbs === true) {
if (this.configurationWizardService.showBreadcrumbs) {
setTimeout(() => {
this.showPopover(this.templateBreadcrumb, this.breadcrumb.nativeElement, 'bottom', true);
});

View File

@ -226,12 +226,12 @@ export class SidenavComponent implements OnInit, AfterViewInit {
* To show popovers
*/
ngAfterViewInit() {
if (this.configurationWizardService.showSideNav === true) {
if (this.configurationWizardService.showSideNav) {
setTimeout(() => {
this.showPopover(this.templateLogo, this.logo.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSideNavChartofAccounts === true) {
if (this.configurationWizardService.showSideNavChartofAccounts) {
setTimeout(() => {
this.showPopover(this.templateChartOfAccounts, this.chartOfAccounts.nativeElement, 'top', true);
});

View File

@ -234,20 +234,17 @@ export class ToolbarComponent implements OnInit, AfterViewInit, AfterContentChec
* To show popovers
*/
ngAfterViewInit() {
if (this.configurationWizardService.showToolbar === true) {
if (this.configurationWizardService.showToolbar) {
setTimeout(() => {
this.showPopover(this.templateInstitution, this.institution.nativeElement);
});
}
if (
this.configurationWizardService.showSideNav === true ||
this.configurationWizardService.showSideNavChartofAccounts === true
) {
if (this.configurationWizardService.showSideNav || this.configurationWizardService.showSideNavChartofAccounts) {
this.toggleSidenavCollapse();
}
if (this.configurationWizardService.showToolbarAdmin === true) {
if (this.configurationWizardService.showToolbarAdmin) {
setTimeout(() => {
this.showPopover(this.templateAppMenu, this.appMenu.nativeElement);
});

View File

@ -18,7 +18,7 @@ export class Commons {
let sortOrder = 1;
if (property[0] === '-') {
sortOrder = -1;
property = property.substr(1);
property = property.substring(1);
}
return (a: any, b: any) => {
const result = a[property] < b[property] ? -1 : a[property] > b[property] ? 1 : 0;

View File

@ -29,7 +29,8 @@ export class Dates {
}
public formatDateAsString(value: Date, dateFormat: string): string {
return moment(value).format(dateFormat);
const momentFormat = dateFormat.replace(/y/g, 'Y').replace(/d/g, 'D').replace(/a/g, 'A');
return moment(value).format(momentFormat);
}
public parseDate(value: any): Date {
@ -45,7 +46,8 @@ export class Dates {
}
public convertToDate(value: any, format: string): Date {
return moment(value).toDate();
const momentFormat = format.replace(/y/g, 'Y').replace(/d/g, 'D').replace(/a/g, 'A');
return moment(value, momentFormat).toDate();
}
get language() {

View File

@ -16,10 +16,10 @@ import { environment } from '../../../environments/environment';
providedIn: 'root'
})
export class PasswordsUtility {
minPasswordLength: number = environment.minPasswordLength | 12;
minPasswordLength: number = environment.minPasswordLength || 12;
public static PASSWORD_REGEX =
'^(?!.*(.)\\1)(?!.*\\s)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^\\w\\s]).{' +
(environment.minPasswordLength | 12) +
(environment.minPasswordLength || 12) +
',50}$';
public getPasswordValidators(): ValidatorFn[] {

View File

@ -147,7 +147,7 @@ export class AddChargeFixedDepositsAccountComponent implements OnInit {
savingsCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
savingsCharge.monthDayFormat = monthDayFormat;
if (savingsCharge.feeOnMonthDay) {

View File

@ -146,7 +146,7 @@ export class AddChargeRecurringDepositsAccountComponent implements OnInit {
savingsCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
savingsCharge.monthDayFormat = monthDayFormat;
if (savingsCharge.feeOnMonthDay) {

View File

@ -117,10 +117,10 @@ export class TransactionsTabComponent implements OnInit {
*/
isDebit(transactionType: any) {
return (
transactionType.withdrawal === true ||
transactionType.feeDeduction === true ||
transactionType.overdraftInterest === true ||
transactionType.withholdTax === true
transactionType.withdrawal ||
transactionType.feeDeduction ||
transactionType.overdraftInterest ||
transactionType.withholdTax
);
}

View File

@ -141,12 +141,12 @@ export class HomeComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showHome === true) {
if (this.configurationWizardService.showHome) {
setTimeout(() => {
this.showPopover(this.templateButtonDashboard, this.buttonDashboard.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showHomeSearchActivity === true) {
if (this.configurationWizardService.showHomeSearchActivity) {
setTimeout(() => {
this.showPopover(this.templateSearchActivity, this.searchActivity.nativeElement, 'bottom', true);
});

View File

@ -720,6 +720,6 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
* Available when PROGRESSIVE schedule type and multi-disbursement is enabled.
*/
isFullTermTrancheEditable(): boolean {
return this.isProgressive && this.multiDisburseLoan === true;
return this.isProgressive && !!this.multiDisburseLoan;
}
}

View File

@ -87,7 +87,7 @@ export class PenaltyManagementService {
}
// Check if it's a penalty charge
const isPenalty =
charge.penalty === true ||
charge.penalty ||
charge.penalty === 'true' ||
(charge.chargeTimeType &&
(charge.chargeTimeType.value?.toLowerCase().includes('overdue') ||
@ -99,7 +99,7 @@ export class PenaltyManagementService {
}
// Check if already waived or paid
if (charge.waived === true || charge.waived === 'true' || charge.paid === true || charge.paid === 'true') {
if (charge.waived || charge.waived === 'true' || charge.paid || charge.paid === 'true') {
return false;
}

View File

@ -80,13 +80,6 @@
<mat-spinner [diameter]="20" class="button-spinner"></mat-spinner>
}
</mifosx-m3-button>
<!-- Forgot Password Link -->
<div class="login-actions">
<a href="#" class="forgot-password-link">
{{ 'labels.links.Forgot Password?' | translate }}
</a>
</div>
</form>
</div>
}

View File

@ -21,7 +21,7 @@
#login-form {
display: flex;
flex-direction: column;
gap: 0.25rem;
gap: 0.5rem;
animation: slide-in 0.4s ease-out;
flex: 1;
}
@ -71,7 +71,7 @@
}
.mat-mdc-form-field-icon-prefix {
padding-right: 0.75rem;
padding: 0 0.75rem 0 0.5rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
fa-icon {
@ -122,7 +122,8 @@
font-size: 1rem;
font-weight: 400;
color: var(--md-sys-color-on-surface, #1a1c1e);
padding: 0.875rem 0.75rem;
padding: 0.875rem 0;
margin-left: 0;
&::placeholder {
color: var(--md-sys-color-on-surface-variant, #44474e);
@ -134,11 +135,12 @@
.mat-mdc-floating-label {
font-size: 1rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
left: 0 !important;
}
// Prefix icon
.mat-mdc-form-field-icon-prefix {
padding-right: 0.75rem;
padding: 0 0.75rem 0 0.5rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
fa-icon {
@ -147,6 +149,11 @@
}
}
// Form field infix - align label with input
.mat-mdc-form-field-infix {
padding-left: 0;
}
// Suffix button (password toggle)
.mat-mdc-form-field-icon-suffix {
button {
@ -216,33 +223,6 @@
}
}
// ===== Login Actions =====
.login-actions {
display: flex;
justify-content: center;
margin-top: 0.5rem;
}
.forgot-password-link {
font-size: 0.875rem;
color: var(--md-sys-color-primary, #1074b9);
text-decoration: none;
font-weight: 500;
padding: 0.5rem 1rem;
border-radius: 20px;
transition: all 0.2s ease;
&:hover {
background: #1074b914;
text-decoration: underline;
}
&:focus {
outline: 2px solid var(--md-sys-color-primary, #1074b9);
outline-offset: 2px;
}
}
// ===== OIDC Login =====
.oidc-login-container {
width: 100%;
@ -370,14 +350,6 @@
}
}
.forgot-password-link {
color: var(--md-sys-color-primary, #5ba2ec);
&:hover {
background: #5ba2ec1f;
}
}
.oidc-description {
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
}
@ -444,7 +416,7 @@
}
.mat-mdc-form-field-icon-prefix {
padding-right: 0.5rem;
padding: 0 0.5rem 0 0.35rem;
}
}
}
@ -454,15 +426,6 @@
margin-top: 0.4rem;
}
.login-actions {
margin-top: 0.4rem;
}
.forgot-password-link {
font-size: 0.8125rem;
padding: 0.35rem 0.65rem;
}
.oidc-actions {
flex-direction: column;

View File

@ -8,41 +8,55 @@
<!-- Modern Material Design 3 Login Layout -->
<div class="login-wrapper">
<!-- Left Panel - Hero Section (Hidden on mobile) -->
<div class="hero-panel hide-lt-md">
<div class="hero-panel hide-lt-md" [class.production-mode]="productionMode">
<div class="hero-overlay"></div>
<div class="hero-content">
<div class="hero-text">
<h1 class="hero-title">{{ 'APP_NAME' | translate }}</h1>
<p class="hero-subtitle">
{{ 'labels.text.A' | translate }}
<span class="hero-highlight">{{ 'labels.text.global community' | translate }}</span>
{{ 'labels.text.elimination of poverty' | translate }}
</p>
<div class="hero-features">
<div class="feature-item">
<fa-icon icon="shield-alt" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Secure & Reliable' | translate }}</span>
<!-- Default Mode: Full content -->
@if (!productionMode) {
<div class="hero-text">
<h1 class="hero-title">{{ 'APP_NAME' | translate }}</h1>
<p class="hero-subtitle">
{{ 'labels.text.A' | translate }}
<span class="hero-highlight">{{ 'labels.text.global community' | translate }}</span>
{{ 'labels.text.elimination of poverty' | translate }}
</p>
<div class="hero-features">
<div class="feature-item">
<fa-icon icon="shield-alt" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Secure & Reliable' | translate }}</span>
</div>
<div class="feature-item">
<fa-icon icon="users" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Community Driven' | translate }}</span>
</div>
<div class="feature-item">
<fa-icon icon="globe" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Global Impact' | translate }}</span>
</div>
</div>
<div class="feature-item">
<fa-icon icon="users" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Community Driven' | translate }}</span>
</div>
<div class="feature-item">
<fa-icon icon="globe" class="feature-icon"></fa-icon>
<span class="feature-text">{{ 'labels.heading.Global Impact' | translate }}</span>
<div class="hero-links">
<a [href]="'mifosHome' | documentationLink" target="_blank" rel="noopener noreferrer" class="hero-link">
{{ 'labels.text.Mifos Initiative' | translate }}
<fa-icon icon="external-link-alt" size="sm"></fa-icon>
</a>
<a
[href]="'mifosVolunteer' | documentationLink"
target="_blank"
rel="noopener noreferrer"
class="hero-link"
>
{{ 'labels.text.Get involved' | translate }}
<fa-icon icon="external-link-alt" size="sm"></fa-icon>
</a>
</div>
</div>
<div class="hero-links">
<a [href]="'mifosHome' | documentationLink" target="_blank" rel="noopener noreferrer" class="hero-link">
{{ 'labels.text.Mifos Initiative' | translate }}
<fa-icon icon="external-link-alt" size="sm"></fa-icon>
</a>
<a [href]="'mifosVolunteer' | documentationLink" target="_blank" rel="noopener noreferrer" class="hero-link">
{{ 'labels.text.Get involved' | translate }}
<fa-icon icon="external-link-alt" size="sm"></fa-icon>
</a>
}
<!-- Production Mode: Minimal branding at bottom -->
@if (productionMode) {
<div class="hero-branding-bottom">
<h1 class="hero-title-minimal">{{ 'APP_NAME' | translate }}</h1>
</div>
</div>
}
</div>
</div>
@ -69,7 +83,6 @@
} @else {
<img src="assets/images/white-mifos.png" alt="{{ 'APP_NAME' | translate }} Logo" class="logo-image" />
}
<h2 class="welcome-text">{{ 'labels.heading.Welcome to Mifos' | translate }}</h2>
</div>
<!-- Form Section -->
@ -95,61 +108,64 @@
}
</div>
<!-- Version Info Table -->
<!-- Version Info Section -->
<div class="login-version-info" *ngIf="displayBackendInfo">
<table class="login-version-table">
<tr>
<td class="version-label">{{ 'labels.version.Tenant' | translate }}</td>
<td class="version-value">{{ versions?.tenant || 'Default' }}</td>
</tr>
<tr>
<td class="version-label">{{ 'labels.version.Mifos WebApp' | translate }}</td>
<td class="version-value">{{ versions?.mifos }}</td>
</tr>
<tr>
<td class="version-label">{{ 'labels.version.Apache Fineract' | translate }}</td>
<td class="version-value">{{ versions?.fineract?.version }}</td>
</tr>
<tr>
<td class="version-label">{{ 'labels.version.Server' | translate }}</td>
<td class="version-value">{{ server }}</td>
</tr>
</table>
<div class="version-info-container">
<div class="version-item">
<span class="version-label">{{ 'labels.version.Tenant' | translate }}</span>
<span class="version-value">{{ tenantDisplayName }}</span>
</div>
<div class="version-item">
<span class="version-label">{{ 'labels.version.Mifos WebApp' | translate }}</span>
<span class="version-value">{{ versions?.mifos }}</span>
</div>
<div class="version-item">
<span class="version-label">{{ 'labels.version.Apache Fineract' | translate }}</span>
<span class="version-value">{{ versions?.fineract?.version }}</span>
</div>
<div class="version-item">
<span class="version-label">{{ 'labels.version.Server' | translate }}</span>
<span class="version-value">{{ server }}</span>
</div>
</div>
</div>
<!-- Resources Links -->
<div class="resources-section">
<div class="resources-divider">
<span class="divider-text">{{ 'labels.links.Resources' | translate }}</span>
<!-- Resources Links (hidden in production mode) -->
@if (!productionMode) {
<div class="resources-section">
<div class="resources-branding">
<span class="branding-text"
>{{ 'labels.text.Powered by' | translate }}
<a href="https://mifos.org" target="_blank" rel="noopener noreferrer">{{
'labels.text.Mifos Initiative' | translate
}}</a></span
>
</div>
<div class="resources-links">
<button mat-button [matMenuTriggerFor]="resourcesMenu" class="resource-button">
<fa-icon icon="book" size="sm"></fa-icon>
{{ 'labels.links.Resources' | translate }}
</button>
<button mat-button [matMenuTriggerFor]="communityMenu" class="resource-button">
<fa-icon icon="users" size="sm"></fa-icon>
{{ 'labels.links.Community' | translate }}
</button>
<button mat-button [matMenuTriggerFor]="contributeMenu" class="resource-button">
<fa-icon icon="heart" size="sm"></fa-icon>
{{ 'labels.links.Contribute' | translate }}
</button>
</div>
</div>
<div class="resources-links">
<button mat-button [matMenuTriggerFor]="resourcesMenu" class="resource-button">
<fa-icon icon="book" size="sm"></fa-icon>
{{ 'labels.links.Resources' | translate }}
</button>
<button mat-button [matMenuTriggerFor]="communityMenu" class="resource-button">
<fa-icon icon="users" size="sm"></fa-icon>
{{ 'labels.links.Community' | translate }}
</button>
<button mat-button [matMenuTriggerFor]="contributeMenu" class="resource-button">
<fa-icon icon="heart" size="sm"></fa-icon>
{{ 'labels.links.Contribute' | translate }}
</button>
</div>
</div>
}
</div>
<!-- Footer -->
<div class="login-footer">
<div class="layout-column copy-label">
<p class="footer-content align-center">
{{ 'APP_NAME' | translate }} {{ 'labels.text.by' | translate }} Mifos
</p>
</div>
<button
mat-icon-button
(click)="reloadSettings()"
class="reload-button"
title="Reload Settings"
matTooltip="Reload Settings"
attr.aria-label="Reload Settings"
>

View File

@ -5,45 +5,143 @@
* 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/.
*/
// Version Info Table
.login-version-table {
// ===== Version Info Section - Modern Card Style =====
.login-version-info {
margin-bottom: 1rem;
width: 100%;
margin: 0 5px;
border-collapse: collapse;
font-size: 0.75rem;
color: var(--md-sys-color-on-surface, #1a1c1e);
background: none;
display: flex;
justify-content: center;
align-items: center;
}
.login-version-table td {
padding: 0.4rem 0.7rem;
text-align: left;
vertical-align: middle;
.version-info-container {
width: 100%;
background: var(--md-sys-color-surface-container, #f3f3f6);
border-radius: 12px;
padding: 0.75rem 1rem;
border: 1px solid var(--md-sys-color-outline-variant, #c4c6d0);
}
.version-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem 0;
border-bottom: 1px solid var(--md-sys-color-outline-variant, #e0e0e0);
&:last-child {
border-bottom: none;
}
}
.version-label {
font-weight: 500;
font-size: 0.75rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
width: 50%;
flex-shrink: 0;
}
.version-value {
font-weight: 400;
font-size: 0.75rem;
color: var(--md-sys-color-on-surface, #1a1c1e);
width: 50%;
word-break: break-all;
text-align: right;
word-break: break-word;
max-width: 60%;
}
// Responsive
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
@media (max-width: 768px) {
.login-version-table {
font-size: 0.85rem;
max-width: 100%;
// ===== Resources Branding =====
.resources-branding {
text-align: center;
margin-bottom: 0.75rem;
.branding-text {
font-size: 0.8rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
font-weight: 400;
a {
color: var(--md-sys-color-primary, #1074b9);
text-decoration: none;
font-weight: 500;
&:hover {
text-decoration: underline;
}
}
}
}
// ===== Dark Mode Support =====
:host-context(.dark-theme),
:host-context([data-theme='dark']) {
.version-info-container {
background: var(--md-sys-color-surface-container-low, #2a2a2a);
border-color: var(--md-sys-color-outline-variant, #3d3d3d);
}
.login-version-table td {
padding: 0.3rem 0.4rem;
.version-item {
border-bottom-color: var(--md-sys-color-outline-variant, #3d3d3d);
}
.version-label {
color: var(--md-sys-color-on-surface-variant, #c4c6cf);
}
.version-value {
color: var(--md-sys-color-on-surface, #e2e2e5);
}
.resources-branding {
.branding-text {
color: var(--md-sys-color-on-surface-variant, #c4c6cf);
a {
color: var(--md-sys-color-primary, #a8c8ff);
}
}
}
.resource-button {
color: var(--md-sys-color-primary, #a8c8ff);
&:hover {
background: rgb(168 200 255 / 12%);
}
}
.login-card {
border: 1px solid var(--md-sys-color-outline-variant, #3d3d3d);
}
.login-header {
::ng-deep mifosx-theme-toggle button,
::ng-deep mifosx-server-selector,
::ng-deep mifosx-language-selector {
color: var(--md-sys-color-on-surface, #e2e2e5);
}
}
.logo-section {
border-bottom-color: var(--md-sys-color-outline-variant, #3d3d3d);
}
}
// Responsive for version info
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
@media (max-width: 768px) {
.version-info-container {
padding: 0.5rem 0.75rem;
}
.version-item {
padding: 0.35rem 0;
}
.version-label,
.version-value {
font-size: 0.7rem;
}
}
@ -58,6 +156,7 @@
height: 100%;
width: 100%;
background: var(--md-sys-color-background, #fafafa);
overflow-x: hidden;
}
// ===== Hero Panel (Left Side) =====
@ -68,7 +167,7 @@
background-size: cover;
overflow: hidden;
// Dark overlay for better text contrast
// Overlay removed for clean image view
.hero-overlay {
position: absolute;
/* stylelint-disable declaration-block-no-redundant-longhand-properties -- Safari compatibility */
@ -77,7 +176,7 @@
bottom: 0;
left: 0;
/* stylelint-enable declaration-block-no-redundant-longhand-properties */
background: linear-gradient(135deg, #1074b99e 0%, #004989a6 100%);
background: transparent;
z-index: 1;
}
@ -88,15 +187,21 @@
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
justify-content: center;
padding: 4rem;
}
.hero-text {
max-width: 600px;
max-width: 550px;
color: #fff;
animation: fade-in-up 0.8s ease-out;
flex: 0 1 auto;
// Minimal backdrop - more image visibility
background: rgb(0 0 0 / 35%);
border-radius: 20px;
padding: 2rem;
border: 1px solid rgb(255 255 255 / 15%);
box-shadow: 0 4px 24px rgb(0 0 0 / 20%);
}
// Footer in hero panel
@ -142,65 +247,66 @@
margin: 0 0 1.5rem;
line-height: 1.2;
letter-spacing: -0.02em;
background: linear-gradient(135deg, #fff 0%, #e3f2fd 100%);
/* stylelint-disable-next-line property-no-vendor-prefix -- Safari compatibility */
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: #fff;
text-shadow:
0 2px 4px rgb(0 0 0 / 30%),
0 4px 12px rgb(0 0 0 / 15%);
}
.hero-subtitle {
font-size: 1.25rem;
line-height: 1.6;
margin: 0 0 3rem;
opacity: 0.95;
margin: 0 0 2rem;
font-weight: 400;
color: rgb(255 255 255 / 95%);
text-shadow: 0 1px 3px rgb(0 0 0 / 40%);
}
.hero-highlight {
font-weight: 600;
color: #b4d575;
text-shadow: 0 1px 2px rgb(0 0 0 / 30%);
}
.hero-features {
display: flex;
flex-direction: column;
gap: 1.5rem;
margin-bottom: 3rem;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.feature-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: #ffffff1a;
border-radius: 12px;
/* stylelint-disable-next-line property-no-vendor-prefix -- Safari compatibility */
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
gap: 0.75rem;
padding: 0.5rem 0;
background: transparent;
border-radius: 8px;
transition: all 0.3s ease;
&:hover {
background: #ffffff26;
transform: translateX(8px);
transform: translateX(4px);
}
}
.feature-icon {
font-size: 1.5rem;
font-size: 1.25rem;
color: #b4d575;
filter: drop-shadow(0 1px 2px rgb(0 0 0 / 30%));
}
.feature-text {
font-size: 1rem;
font-size: 0.95rem;
font-weight: 500;
color: rgb(255 255 255 / 95%);
text-shadow: 0 1px 2px rgb(0 0 0 / 30%);
}
.hero-links {
display: flex;
gap: 2rem;
gap: 1rem;
flex-wrap: wrap;
margin-top: 0.5rem;
}
.hero-link {
@ -211,20 +317,54 @@
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
border: 2px solid #ffffff4d;
border: 1px solid rgb(255 255 255 / 30%);
border-radius: 24px;
background: rgb(255 255 255 / 10%);
/* stylelint-disable-next-line property-no-vendor-prefix -- Safari compatibility */
-webkit-backdrop-filter: blur(4px);
backdrop-filter: blur(4px);
transition: all 0.3s ease;
text-shadow: 0 1px 2px rgb(0 0 0 / 20%);
box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
&:hover {
background: #ffffff1a;
border-color: #fff;
background: rgb(255 255 255 / 20%);
border-color: rgb(255 255 255 / 50%);
transform: translateY(-2px);
box-shadow: 0 4px 16px rgb(0 0 0 / 15%);
}
fa-icon {
opacity: 0.7;
opacity: 0.85;
}
}
// ===== Production Mode Styles =====
&.production-mode {
.hero-content {
justify-content: flex-end;
padding-bottom: 3rem;
}
}
.hero-branding-bottom {
animation: fade-in-up 0.8s ease-out;
}
.hero-title-minimal {
font-size: 2.5rem;
font-weight: 700;
color: #fff;
text-shadow:
0 2px 8px rgb(0 0 0 / 40%),
0 4px 16px rgb(0 0 0 / 20%);
letter-spacing: -0.01em;
margin: 0;
padding: 1.5rem 2rem;
background: rgb(0 0 0 / 30%);
border-radius: 16px;
border: 1px solid rgb(255 255 255 / 15%);
}
}
// ===== Login Panel (Right Side) =====
@ -234,19 +374,21 @@
flex-direction: column;
background: var(--md-sys-color-surface, #fff);
position: relative;
min-height: 100vh;
min-height: -webkit-fill-available; // Safari fix: use available height
overflow-y: auto;
min-height: 100vh;
overflow: hidden auto;
}
.login-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 1rem 1.5rem;
padding: 0.75rem 1rem;
background: transparent;
flex-shrink: 0; // Safari fix: prevent header from growing
max-height: 76px; // Safari fix: constrain header height
flex-wrap: nowrap;
overflow: hidden;
.header-control {
opacity: 0.8;
@ -282,7 +424,8 @@
// Language Selector Outlined Styles
::ng-deep mifosx-language-selector {
width: 20%;
min-width: 80px;
max-width: 100px;
flex-shrink: 0; // Safari fix
#language-selector.outlined-variant {
@ -318,8 +461,9 @@
// Server Selector Outlined Styles
::ng-deep mifosx-server-selector {
width: 70%;
flex-shrink: 0; // Safari fix
flex: 1;
min-width: 0;
max-width: 250px;
#server-selector.outlined-variant {
width: 100%;
@ -360,7 +504,7 @@
flex-direction: column;
align-items: center;
justify-content: flex-start; // Safari fix: avoid center calculation issues
padding: 1rem;
padding: 0 1rem 1rem;
min-height: 0; // Safari fix: allows flex item to shrink below content size
animation: fade-in 0.6s ease-out;
}
@ -388,31 +532,23 @@
// ===== Logo Section =====
.logo-section {
text-align: center;
margin-bottom: 1rem;
margin-bottom: 0.75rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--md-sys-color-outline-variant, #e8eaed);
flex-shrink: 0;
animation: fade-in-down 0.6s ease-out 0.2s both;
animation: fade-in 0.5s ease-out 0.1s both;
}
.logo-image {
max-width: 180px;
height: auto;
margin-bottom: 1rem;
filter: drop-shadow(0 2px 8px #0000001a);
}
height: 130px;
width: auto;
margin: 8px 24px;
opacity: 0.95;
transition: opacity 0.3s ease;
.welcome-text {
font-size: 1.75rem;
font-weight: 600;
margin: 0 0 0.5rem;
color: var(--md-sys-color-on-surface, #1a1c1e);
letter-spacing: -0.01em;
}
.welcome-subtitle {
font-size: 0.95rem;
color: var(--md-sys-color-on-surface-variant, #44474e);
margin: 0;
font-weight: 400;
&:hover {
opacity: 1;
}
}
// ===== Form Section =====
@ -429,15 +565,6 @@
flex-shrink: 0;
}
// ===== Version Info Section =====
.login-version-info {
margin-bottom: 1rem;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
// ===== Resources Section =====
.resources-section {
margin-top: auto;
@ -446,34 +573,6 @@
animation: fade-in-up 0.6s ease-out 0.4s both;
}
.resources-divider {
position: relative;
text-align: center;
margin-bottom: 1.5rem;
&::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: var(--md-sys-color-outline-variant, #c4c6d0);
}
.divider-text {
position: relative;
display: inline-block;
padding: 0 1rem;
background: var(--md-sys-color-surface-container-low, #fff);
color: var(--md-sys-color-on-surface-variant, #44474e);
font-size: 0.85rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
}
}
.resources-links {
display: flex;
justify-content: center;
@ -504,19 +603,13 @@
.login-footer {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: center;
gap: 1rem;
padding: 1rem 1.5rem;
padding: 0.75rem 1.5rem;
position: relative;
margin-top: auto;
flex-direction: column;
flex-shrink: 0;
mifosx-footer {
flex: 1;
text-align: left;
}
.reload-button {
color: var(--mat-app-text-color, #c4c6d0);
opacity: 0.6;
@ -652,7 +745,7 @@
}
.login-card-container {
padding: 1rem;
padding: 0 1rem 1rem;
justify-content: center;
height: auto;
min-height: calc(100vh - 56px); // 56px for header
@ -700,16 +793,14 @@
}
.logo-section {
margin-bottom: 1rem;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
}
.logo-image {
max-width: 140px;
margin-bottom: 0.75rem;
}
.welcome-text {
font-size: 1.5rem;
height: 100px;
width: auto;
margin: 8px 20px;
}
// Hide resources section on medium and small screens
@ -755,7 +846,7 @@
}
.login-card-container {
padding: 0.5rem;
padding: 0 0.5rem 0.5rem;
justify-content: center;
}
@ -764,20 +855,14 @@
}
.logo-section {
margin-bottom: 0.75rem;
margin-bottom: 0.5rem;
padding-bottom: 0.25rem;
}
.logo-image {
max-width: 110px;
margin-bottom: 0.5rem;
}
.welcome-text {
font-size: 1.25rem;
}
.welcome-subtitle {
font-size: 0.875rem;
height: 80px;
width: auto;
margin: 4px 16px;
}
.form-section {

View File

@ -75,6 +75,8 @@ import { VersionService } from '../system/version.service';
export class LoginComponent implements OnInit, OnDestroy {
/** Show version info table if env allows */
displayBackendInfo = environment.displayBackEndInfo !== 'false';
/** Production mode - minimal hero with branding only */
productionMode = environment.productionMode === true;
private alertService = inject(AlertService);
private settingsService = inject(SettingsService);
@ -90,6 +92,12 @@ export class LoginComponent implements OnInit, OnDestroy {
/** Server info for display */
server: string = '';
/** Get tenant display name with first letter capitalized */
get tenantDisplayName(): string {
const tenant = this.versions?.tenant || this.settingsService.tenantIdentifier || 'default';
return tenant.charAt(0).toUpperCase() + tenant.slice(1).toLowerCase();
}
/** True if password requires a reset. */
resetPassword = false;
/** True if user requires two factor authentication. */

View File

@ -146,13 +146,13 @@ export class CurrenciesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showCurrencyPage === true) {
if (this.configurationWizardService.showCurrencyPage) {
setTimeout(() => {
this.showPopover(this.templateButtonAddEdit, this.buttonAddEdit.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showCurrencyList === true) {
if (this.configurationWizardService.showCurrencyList) {
setTimeout(() => {
this.showPopover(this.templateTableCurrencies, this.tableCurrencies.nativeElement, 'top', true);
});

View File

@ -166,7 +166,7 @@ export class ManageCurrenciesComponent implements OnInit, AfterViewInit, OnDestr
this.organizationservice.updateCurrencies(selectedCurrencyCodes).subscribe((response: any) => {
this.selectedCurrencies.push(newCurrency);
this.formRef.resetForm();
if (this.configurationWizardService.showCurrencyForm === true) {
if (this.configurationWizardService.showCurrencyForm) {
this.configurationWizardService.showCurrencyForm = false;
this.openDialog();
}
@ -205,7 +205,7 @@ export class ManageCurrenciesComponent implements OnInit, AfterViewInit, OnDestr
}
ngAfterViewInit() {
if (this.configurationWizardService.showCurrencyForm === true) {
if (this.configurationWizardService.showCurrencyForm) {
setTimeout(() => {
this.showPopover(this.templateCurrencyFormRef, this.currencyFormRef.nativeElement, 'bottom', true);
});

View File

@ -142,7 +142,7 @@ export class CreateEmployeeComponent implements OnInit, AfterViewInit {
locale
};
this.organizationService.createEmployee(data).subscribe((response: any) => {
if (this.configurationWizardService.showEmployeeForm === true) {
if (this.configurationWizardService.showEmployeeForm) {
this.configurationWizardService.showEmployeeForm = false;
this.openDialog();
} else {
@ -171,7 +171,7 @@ export class CreateEmployeeComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showEmployeeForm === true) {
if (this.configurationWizardService.showEmployeeForm) {
setTimeout(() => {
this.showPopover(this.templateCreateEmployeeForm, this.createEmployeeFormRef.nativeElement, 'right', true);
});

View File

@ -151,12 +151,12 @@ export class EmployeesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showEmployeeList === true) {
if (this.configurationWizardService.showEmployeeList) {
setTimeout(() => {
this.showPopover(this.templateButtonImportEmployees, this.buttonImportEmployees.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showEmployeeTable === true) {
if (this.configurationWizardService.showEmployeeTable) {
setTimeout(() => {
this.showPopover(this.templateTableEmployees, this.tableEmployees.nativeElement, 'top', true);
});

View File

@ -173,13 +173,13 @@ export class HolidaysComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showHolidayPage === true) {
if (this.configurationWizardService.showHolidayPage) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateHoliday, this.buttonCreateHoliday.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showHolidayFilter === true) {
if (this.configurationWizardService.showHolidayFilter) {
setTimeout(() => {
this.showPopover(this.templateFilterRef, this.filterRef.nativeElement, 'bottom', true);
});

View File

@ -157,7 +157,7 @@ export class ManageFundsComponent implements OnInit, AfterViewInit {
name: newFund.name
});
this.formRef.resetForm();
if (this.configurationWizardService.showManageFunds === true) {
if (this.configurationWizardService.showManageFunds) {
this.configurationWizardService.showManageFunds = false;
this.openDialog();
}
@ -215,7 +215,7 @@ export class ManageFundsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showManageFunds === true) {
if (this.configurationWizardService.showManageFunds) {
setTimeout(() => {
this.showPopover(this.templateFundFormRef, this.fundFormRef.nativeElement, 'bottom', true);
});

View File

@ -121,7 +121,7 @@ export class CreateOfficeComponent implements OnInit, AfterViewInit {
locale
};
this.organizationService.createOffice(data).subscribe((response) => {
if (this.configurationWizardService.showOfficeForm === true) {
if (this.configurationWizardService.showOfficeForm) {
this.configurationWizardService.showOfficeForm = false;
this.openDialog();
} else {
@ -176,7 +176,7 @@ export class CreateOfficeComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showOfficeForm === true) {
if (this.configurationWizardService.showOfficeForm) {
setTimeout(() => {
this.showPopover(this.templateCreateOfficeForm, this.createOfficeFormRef.nativeElement, 'right', true);
});

View File

@ -240,12 +240,12 @@ export class OfficesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showOfficeList === true) {
if (this.configurationWizardService.showOfficeList) {
setTimeout(() => {
this.showPopover(this.templateButtonTreeView, this.buttonTreeView.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showOfficeTable === true) {
if (this.configurationWizardService.showOfficeTable) {
setTimeout(() => {
this.showPopover(this.templateTableOffices, this.tableOffices.nativeElement, 'top', true);
});

View File

@ -90,32 +90,32 @@ export class OrganizationComponent implements AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showCreateOffice === true) {
if (this.configurationWizardService.showCreateOffice) {
setTimeout(() => {
this.showPopover(this.templateOffice, this.office.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showAddEditCurrency === true) {
if (this.configurationWizardService.showAddEditCurrency) {
setTimeout(() => {
this.showPopover(this.templateAddEditCurrency, this.addEditCurrency.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showCreateHoliday === true) {
if (this.configurationWizardService.showCreateHoliday) {
setTimeout(() => {
this.showPopover(this.templateHolidays, this.holidays.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showCreateEmployee === true) {
if (this.configurationWizardService.showCreateEmployee) {
setTimeout(() => {
this.showPopover(this.templateEmployee, this.employee.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showDefineWorkingDays === true) {
if (this.configurationWizardService.showDefineWorkingDays) {
setTimeout(() => {
this.showPopover(this.templateWorkingDays, this.workingDays.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showManageFunds === true) {
if (this.configurationWizardService.showManageFunds) {
setTimeout(() => {
this.showPopover(this.templateManageFunds, this.manageFunds.nativeElement, 'bottom', true);
});

View File

@ -75,7 +75,7 @@ export class PasswordPreferencesComponent implements OnInit {
*/
setPasswordPreferencesForm() {
for (const passwordPreference of this.passwordPreferencesData) {
if (passwordPreference.active === true) {
if (passwordPreference.active) {
this.passwordPreferencesForm.get('validationPolicyId').setValue(passwordPreference.id);
}
}

View File

@ -153,7 +153,7 @@ export class WorkingDaysComponent implements OnInit, AfterViewInit {
}
workingDays.recurrence = recurrence;
this.organizationService.updateWorkingDays(workingDays).subscribe((response) => {
if (this.configurationWizardService.showDefineWorkingDays === true) {
if (this.configurationWizardService.showDefineWorkingDays) {
this.configurationWizardService.showDefineWorkingDays = false;
this.openNextStepDialog();
} else {
@ -182,7 +182,7 @@ export class WorkingDaysComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showDefineWorkingDays === true) {
if (this.configurationWizardService.showDefineWorkingDays) {
setTimeout(() => {
this.showPopover(this.templateWorkingDaysFormRef, this.workingDaysFormRef.nativeElement, 'right', true);
});

View File

@ -89,7 +89,7 @@ export class AccountsFilterPipe implements PipeTransform {
if (type === 'guarantor') {
if (status === false) {
accounts = accounts.filter((account: any) => {
return account.status === true;
return account.status;
});
} else {
return accounts;

View File

@ -154,13 +154,13 @@ export class ChargesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showChargesPage === true) {
if (this.configurationWizardService.showChargesPage) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateCharge, this.buttonCreateCharge.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showChargesList === true) {
if (this.configurationWizardService.showChargesList) {
setTimeout(() => {
this.showPopover(this.templateChargesTable, this.chargesTable.nativeElement, 'top', true);
});

View File

@ -130,7 +130,7 @@ export class FixedDepositProductsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showFixedDepositProductsPage === true) {
if (this.configurationWizardService.showFixedDepositProductsPage) {
setTimeout(() => {
this.showPopover(
this.templateButtonCreateFixedProduct,
@ -141,7 +141,7 @@ export class FixedDepositProductsComponent implements OnInit, AfterViewInit {
});
}
if (this.configurationWizardService.showFixedDepositProductsList === true) {
if (this.configurationWizardService.showFixedDepositProductsList) {
setTimeout(() => {
this.showPopover(this.templateFixedProductsTable, this.fixedProductsTable.nativeElement, 'top', true);
});

View File

@ -339,7 +339,7 @@ export class EditLoanProductComponent implements OnInit {
submit() {
const loanProduct = this.loanProducts.buildPayload(this.loanProduct, this.itemsByDefault);
if (loanProduct['useDueForRepaymentsConfigurations'] === true) {
if (loanProduct['useDueForRepaymentsConfigurations']) {
loanProduct['dueDaysForRepaymentEvent'] = null;
loanProduct['overDueDaysForRepaymentEvent'] = null;
}

View File

@ -125,7 +125,7 @@ export class LoanProductsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showLoanProductsPage === true) {
if (this.configurationWizardService.showLoanProductsPage) {
setTimeout(() => {
this.showPopover(
this.templateButtonCreateLoanProduct,
@ -136,7 +136,7 @@ export class LoanProductsComponent implements OnInit, AfterViewInit {
});
}
if (this.configurationWizardService.showLoanProductsList === true) {
if (this.configurationWizardService.showLoanProductsList) {
setTimeout(() => {
this.showPopover(this.templateLoanProductsTable, this.loanProductsTable.nativeElement, 'top', true);
});

View File

@ -71,32 +71,32 @@ export class ProductsComponent implements AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showCharges === true) {
if (this.configurationWizardService.showCharges) {
setTimeout(() => {
this.showPopover(this.templateCharges, this.charges.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showLoanProducts === true) {
if (this.configurationWizardService.showLoanProducts) {
setTimeout(() => {
this.showPopover(this.templateLoanProducts, this.loanProducts.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSavingsProducts === true) {
if (this.configurationWizardService.showSavingsProducts) {
setTimeout(() => {
this.showPopover(this.templateSavingsProducts, this.savingsProducts.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showShareProducts === true) {
if (this.configurationWizardService.showShareProducts) {
setTimeout(() => {
this.showPopover(this.templateShareProducts, this.shareProducts.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showFixedDepositProducts === true) {
if (this.configurationWizardService.showFixedDepositProducts) {
setTimeout(() => {
this.showPopover(this.templateFixedDepositProducts, this.fixedDepositProducts.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showRecurringDepositProducts === true) {
if (this.configurationWizardService.showRecurringDepositProducts) {
setTimeout(() => {
this.showPopover(
this.templateRecurringDepositProducts,

View File

@ -137,7 +137,7 @@ export class RecurringDepositProductsComponent implements OnInit, AfterViewInit
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showRecurringDepositProductsPage === true) {
if (this.configurationWizardService.showRecurringDepositProductsPage) {
setTimeout(() => {
this.showPopover(
this.templateButtonCreateRecurringProduct,
@ -148,7 +148,7 @@ export class RecurringDepositProductsComponent implements OnInit, AfterViewInit
});
}
if (this.configurationWizardService.showRecurringDepositProductsList === true) {
if (this.configurationWizardService.showRecurringDepositProductsList) {
setTimeout(() => {
this.showPopover(this.templateRecurringProductsTable, this.recurringProductsTable.nativeElement, 'top', true);
});

View File

@ -104,13 +104,13 @@ export class SavingProductsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showSavingsProductsPage === true) {
if (this.configurationWizardService.showSavingsProductsPage) {
setTimeout(() => {
this.showPopover(this.templateButtonSavingProduct, this.buttonSavingProduct.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSavingsProductsList === true) {
if (this.configurationWizardService.showSavingsProductsList) {
setTimeout(() => {
this.showPopover(this.templateSavingProductTable, this.savingProductTable.nativeElement, 'top', true);
});

View File

@ -105,7 +105,7 @@ export class ShareProductsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showShareProductsPage === true) {
if (this.configurationWizardService.showShareProductsPage) {
setTimeout(() => {
this.showPopover(
this.templateButtonCreateShareProduct,
@ -116,7 +116,7 @@ export class ShareProductsComponent implements OnInit, AfterViewInit {
});
}
if (this.configurationWizardService.showShareProductsList === true) {
if (this.configurationWizardService.showShareProductsList) {
setTimeout(() => {
this.showPopover(this.templateShareProductsTable, this.shareProductsTable.nativeElement, 'top', true);
});

View File

@ -133,8 +133,10 @@ export class CreateSavingsAccountComponent {
charges: this.savingsAccount.charges.map((charge: any) => ({
chargeId: charge.id,
amount: charge.amount,
dueDate: charge.dueDate,
feeOnMonthDay: charge.feeOnMonthDay,
dueDate: charge.dueDate ? this.dateUtils.formatDate(charge.dueDate, dateFormat) : charge.dueDate,
feeOnMonthDay: charge.feeOnMonthDay
? this.dateUtils.formatDate(charge.feeOnMonthDay, monthDayFormat)
: charge.feeOnMonthDay,
feeInterval: charge.feeInterval
})),
submittedOnDate: this.dateUtils.formatDate(this.savingsAccount.submittedOnDate, dateFormat),

View File

@ -146,7 +146,7 @@ export class AddChargeSavingsAccountComponent implements OnInit {
savingsCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
savingsCharge.monthDayFormat = monthDayFormat;
if (savingsCharge.feeOnMonthDay) {

View File

@ -54,7 +54,7 @@ export class ChangePasswordDialogComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private passwordsUtility = inject(PasswordsUtility);
minPasswordLength: number = environment.minPasswordLength | 12;
minPasswordLength: number = environment.minPasswordLength || 12;
/** Change Password Form */
changePasswordForm: any;

View File

@ -21,7 +21,7 @@
<div class="sticky">
<form [formGroup]="form" (ngSubmit)="addNewServer()">
<div class="actions">
<mat-form-field class="ml align-start">
<mat-form-field class="add-server-field" appearance="outline">
<span matPrefix><mat-icon>language</mat-icon></span>
<mat-label>{{ 'labels.placeholders.Add new server' | translate }}</mat-label>
<input matInput type="text" autocomplete="off" formControlName="url" />
@ -31,7 +31,7 @@
</mat-error>
}
</mat-form-field>
<button type="submit" [disabled]="form.invalid" class="ml" mat-raised-button color="primary">
<button type="submit" [disabled]="form.invalid" mat-raised-button color="primary">
{{ 'labels.buttons.Add' | translate }}
</button>
</div>

View File

@ -142,12 +142,22 @@
// ===== Common Styles =====
.actions {
display: flex;
align-items: center;
justify-content: space-evenly;
}
align-items: flex-start;
justify-content: space-between;
gap: 0.75rem;
padding: 0.75rem 1rem;
.ml {
margin-left: 10px;
.mat-mdc-form-field {
flex: 1;
margin-bottom: 0;
}
button {
flex-shrink: 0;
height: 40px;
min-width: 60px;
margin-top: 4px;
}
}
.sticky {
@ -156,8 +166,10 @@
top: 0; // fix at the top
background-color: var(--md-sys-color-surface-container, white); // don't see mat-option when scrolling
box-shadow: 1px -2px 10px 0 rgb(0 0 0 / 10%); // shadow at the bottom
padding-bottom: 0.5rem;
margin-bottom: 0.5rem;
}
mat-form-field {
width: 96%;
width: 100%;
}

View File

@ -10,7 +10,7 @@
<mat-select [formControl]="tenantSelector" (selectionChange)="setTenantIdentifier()" class="tenantselector">
@for (tenant of tenants; track tenant) {
<mat-option [value]="tenant">
{{ tenant }}
{{ tenant | titlecase }}
</mat-option>
}
</mat-select>

View File

@ -142,12 +142,12 @@ export class CodesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showSystemCodesPage === true) {
if (this.configurationWizardService.showSystemCodesPage) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateCode, this.buttonCreateCode.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSystemCodesList === true) {
if (this.configurationWizardService.showSystemCodesList) {
setTimeout(() => {
this.showPopover(this.templateTableCodes, this.tableCodes.nativeElement, 'top', true);
});

View File

@ -67,7 +67,7 @@ export class CreateCodeComponent implements OnInit, AfterViewInit {
*/
submit() {
this.systemService.createCode(this.codeForm.value).subscribe((response: any) => {
if (this.configurationWizardService.showSystemCodesForm === true) {
if (this.configurationWizardService.showSystemCodesForm) {
this.configurationWizardService.showSystemCodesForm = false;
this.configurationWizardService.showRolesandPermission = true;
this.router.navigate(['/system']);
@ -103,7 +103,7 @@ export class CreateCodeComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showSystemCodesForm === true) {
if (this.configurationWizardService.showSystemCodesForm) {
setTimeout(() => {
this.showPopover(this.templateCodeFormRef, this.codeFormRef.nativeElement, 'right', true);
});

View File

@ -176,13 +176,13 @@ export class GlobalConfigurationsTabComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showConfigurationsPage === true) {
if (this.configurationWizardService.showConfigurationsPage) {
setTimeout(() => {
this.showPopover(this.templateFilter, this.filter.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showConfigurationsList === true) {
if (this.configurationWizardService.showConfigurationsList) {
setTimeout(() => {
this.showPopover(this.templateConfigurationsTable, this.configurationsTable.nativeElement, 'top', true);
});

View File

@ -258,12 +258,12 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showMakerCheckerTablePage === true) {
if (this.configurationWizardService.showMakerCheckerTablePage) {
setTimeout(() => {
this.showPopover(this.templateButtonEdit, this.buttonEdit.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showMakerCheckerTableList === true) {
if (this.configurationWizardService.showMakerCheckerTableList) {
setTimeout(() => {
this.showPopover(this.templateMcTable, this.mcTable.nativeElement, 'top', true);
});

View File

@ -95,7 +95,7 @@ export class AmazonS3Component implements OnInit {
const value = configuration.value;
if (configuration.name === 's3_access_key' || configuration.name === 's3_secret_key') {
return value
? value.replace(value.substr(1, value.length - 3), value.substr(1, value.length - 3).replace(/./g, '*'))
? value.replace(value.substring(1, value.length - 2), value.substring(1, value.length - 2).replace(/./g, '*'))
: '';
}
return value;

View File

@ -94,7 +94,10 @@ export class NotificationComponent implements OnInit {
getConfigurationValue(configuration: any): string {
const value = configuration.value;
if (configuration.name === 'server_key') {
return value.replace(value.substr(1, value.length - 3), value.substr(1, value.length - 3).replace(/./g, '*'));
return value.replace(
value.substring(1, value.length - 2),
value.substring(1, value.length - 2).replace(/./g, '*')
);
}
return value;
}

View File

@ -110,7 +110,7 @@ export class ColumnDialogComponent implements OnInit {
return 'Dropdown';
}
default: {
return columnDisplayType[0] + columnDisplayType.substr(1).toLowerCase();
return columnDisplayType[0] + columnDisplayType.substring(1).toLowerCase();
}
}
}

View File

@ -296,7 +296,7 @@ export class CreateDataTableComponent implements OnInit, AfterViewInit {
delete payload.entitySubType;
}
this.systemService.createDataTable(payload).subscribe((response: any) => {
if (this.configurationWizardService.showDatatablesForm === true) {
if (this.configurationWizardService.showDatatablesForm) {
this.configurationWizardService.showDatatablesForm = false;
this.openDialog();
} else {
@ -331,7 +331,7 @@ export class CreateDataTableComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showDatatablesForm === true) {
if (this.configurationWizardService.showDatatablesForm) {
setTimeout(() => {
this.showPopover(this.templateDataTableFormRef, this.dataTableFormRef.nativeElement, 'bottom', true);
});

View File

@ -449,7 +449,7 @@ export class EditDataTableComponent implements OnInit {
return 'Dropdown';
}
default: {
return columnDisplayType[0] + columnDisplayType.substr(1).toLowerCase();
return columnDisplayType[0] + columnDisplayType.substring(1).toLowerCase();
}
}
}

View File

@ -147,12 +147,12 @@ export class ManageDataTablesComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showDatatablesPage === true) {
if (this.configurationWizardService.showDatatablesPage) {
setTimeout(() => {
this.showPopover(this.templateCreateDatatableRef, this.createDatatableRef.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showDatatablesList === true) {
if (this.configurationWizardService.showDatatablesList) {
setTimeout(() => {
this.showPopover(this.templateDatatablesList, this.datatablesList.nativeElement, 'top', true);
});

View File

@ -265,12 +265,12 @@ export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showSchedulerJobsPage === true) {
if (this.configurationWizardService.showSchedulerJobsPage) {
setTimeout(() => {
this.showPopover(this.templateSchedulerStatus, this.schedulerStatus.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSchedulerJobsList === true) {
if (this.configurationWizardService.showSchedulerJobsList) {
setTimeout(() => {
this.showPopover(this.templateJobsTable, this.jobsTable.nativeElement, 'top', true);
});

View File

@ -135,7 +135,7 @@ export class ManageReportsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showManageReports === true) {
if (this.configurationWizardService.showManageReports) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateReport, this.buttonCreateReport.nativeElement, 'bottom', true);
});

View File

@ -159,12 +159,12 @@ export class RolesAndPermissionsComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showRolesandPermissionPage === true) {
if (this.configurationWizardService.showRolesandPermissionPage) {
setTimeout(() => {
this.showPopover(this.templateButtonAddRole, this.buttonAddRole.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showRolesandPermissionList === true) {
if (this.configurationWizardService.showRolesandPermissionList) {
setTimeout(() => {
this.showPopover(
this.templateTableRolesandPermissions,

View File

@ -92,37 +92,37 @@ export class SystemComponent implements AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showDatatables === true) {
if (this.configurationWizardService.showDatatables) {
setTimeout(() => {
this.showPopover(this.templateDatatables, this.datatables.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSystemCodes === true) {
if (this.configurationWizardService.showSystemCodes) {
setTimeout(() => {
this.showPopover(this.templateCodes, this.codes.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showRolesandPermission === true) {
if (this.configurationWizardService.showRolesandPermission) {
setTimeout(() => {
this.showPopover(this.templateRolesandPermission, this.rolesandpermission.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showMakerCheckerTable === true) {
if (this.configurationWizardService.showMakerCheckerTable) {
setTimeout(() => {
this.showPopover(this.templateMakerCheckerTable, this.makerCheckerTable.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showConfigurations === true) {
if (this.configurationWizardService.showConfigurations) {
setTimeout(() => {
this.showPopover(this.templateConfigurations, this.configurations.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showSchedulerJobs === true) {
if (this.configurationWizardService.showSchedulerJobs) {
setTimeout(() => {
this.showPopover(this.templateSchedulerJobs, this.schedulerJobs.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showManageReports === true) {
if (this.configurationWizardService.showManageReports) {
setTimeout(() => {
this.showPopover(this.templateManageReports, this.manageReports.nativeElement, 'bottom', true);
});

View File

@ -230,7 +230,7 @@ export class LoanApprovalComponent {
this.tasksService.getAllLoansToBeApproved().subscribe((response: any) => {
this.loans = response.pageItems;
this.loans = this.loans.filter((account: any) => {
return account.status.waitingForDisbursal === true;
return account.status.waitingForDisbursal;
});
this.dataSource = new MatTableDataSource(this.loans);
this.selection = new SelectionModel(true, []);

View File

@ -177,7 +177,7 @@ export class LoanDisbursalComponent {
this.tasksService.getAllLoansToBeDisbursed().subscribe((response: any) => {
this.loans = response.pageItems;
this.loans = this.loans.filter((account: any) => {
return account.status.waitingForDisbursal === true;
return account.status.waitingForDisbursal;
});
this.dataSource = new MatTableDataSource(this.loans);
this.selection = new SelectionModel(true, []);

View File

@ -187,7 +187,7 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
delete user.staffId;
}
this.usersService.createUser(user).subscribe((response: any) => {
if (this.configurationWizardService.showUsersForm === true) {
if (this.configurationWizardService.showUsersForm) {
this.configurationWizardService.showUsersForm = false;
this.openDialog();
} else {
@ -222,7 +222,7 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showUsersForm === true) {
if (this.configurationWizardService.showUsersForm) {
setTimeout(() => {
this.showPopover(this.templateUserFormRef, this.userFormRef.nativeElement, 'top', true);
});

View File

@ -150,13 +150,13 @@ export class UsersComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showUsers === true) {
if (this.configurationWizardService.showUsers) {
setTimeout(() => {
this.showPopover(this.templateButtonCreateUser, this.buttonCreateUser.nativeElement, 'bottom', true);
});
}
if (this.configurationWizardService.showUsersList === true) {
if (this.configurationWizardService.showUsersList) {
setTimeout(() => {
this.showPopover(this.templateUsersTable, this.usersTable.nativeElement, 'top', true);
});

View File

@ -265,7 +265,7 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
if (selectedRoleIds?.length > 0) {
this.usersService.assignRolesToUser(userId, selectedRoleIds).subscribe(
() => {
if (this.configurationWizardService.showUsersForm === true) {
if (this.configurationWizardService.showUsersForm) {
this.configurationWizardService.showUsersForm = false;
this.openDialog();
} else {
@ -310,7 +310,7 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
* To show popover.
*/
ngAfterViewInit() {
if (this.configurationWizardService.showUsersForm === true) {
if (this.configurationWizardService.showUsersForm) {
setTimeout(() => {
this.showPopover(this.templateUserFormRef, this.userFormRef.nativeElement, 'top', true);
});

View File

@ -3302,6 +3302,7 @@
"Manual journal entry transactions recorded in a journal": "Manual journal entry transactions recorded in a journal",
"Message Gateway": "Message Gateway",
"Mifos Initiative": "Mifos® Initiative",
"Powered by": "Powered by",
"Mifos X data-tables allow the user to add custom fields": "Mifos X data-tables allow the user to add custom fields in addition to the built-in fields to a client profile, loan/saving account, group, center or an office.",
"Migrate Opening Balances": "Migrate Opening Balances",
"Modify Loans Account": "Modify Loans Account",

View File

@ -3207,6 +3207,7 @@
"Manual journal entry transactions recorded in a journal": "Transacciones de asiento de diario manuales registradas en un diario",
"Message Gateway": "Puerta de enlace de mensajes",
"Mifos Initiative": "Iniciativa Mifos®",
"Powered by": "Impulsado por",
"Mifos X data-tables allow the user to add custom fields": "Las tablas de datos de Mifos X permiten al usuario agregar campos personalizados además de los campos integrados a un perfil de cliente, cuenta de Crédito/ahorro, grupo, centro u oficina.",
"Migrate Opening Balances": "Migrar saldos de apertura",
"Modify Loans Account": "Modificar cuenta de Créditos",

View File

@ -3210,6 +3210,7 @@
"Manual journal entry transactions recorded in a journal": "Transacciones de asiento de diario manuales registradas en un diario",
"Message Gateway": "Puerta de enlace de mensajes",
"Mifos Initiative": "Iniciativa Mifos®",
"Powered by": "Impulsado por",
"Mifos X data-tables allow the user to add custom fields": "Las tablas de datos de Mifos X permiten al usuario agregar campos personalizados además de los campos integrados a un perfil de cliente, cuenta de Crédito/ahorro, grupo, centro u oficina.",
"Migrate Opening Balances": "Migrar saldos de apertura",
"Modify Loans Account": "Modificar cuenta de Créditos",

View File

@ -3205,6 +3205,7 @@
"Manual journal entry transactions recorded in a journal": "Opérations d'écriture de journal manuelle enregistrées dans un journal",
"Message Gateway": "Passerelle de messages",
"Mifos Initiative": "Initiative Mifos®",
"Powered by": "Alimenté par",
"Mifos X data-tables allow the user to add custom fields": "Les tables de données Mifos X permettent à l'utilisateur d'ajouter des champs personnalisés en plus des champs intégrés à un profil client, un compte de prêt/épargne, un groupe, un centre ou un bureau.",
"Migrate Opening Balances": "Migrer les soldes d'ouverture",
"Modify Loans Account": "Modifier le compte de prêts",

View File

@ -3205,6 +3205,7 @@
"Manual journal entry transactions recorded in a journal": "Transazioni di registrazione a giornale manuali registrate in un giornale",
"Message Gateway": "Portale dei messaggi",
"Mifos Initiative": "Iniziativa Mifos®",
"Powered by": "Offerto da",
"Mifos X data-tables allow the user to add custom fields": "Le tabelle dati di Mifos X consentono all'utente di aggiungere campi personalizzati oltre ai campi integrati al profilo cliente, conto di prestito/risparmio, gruppo, centro o ufficio.",
"Migrate Opening Balances": "Migrare i saldi di apertura",
"Modify Loans Account": "Modifica conto prestiti",

View File

@ -3206,6 +3206,7 @@
"Manual journal entry transactions recorded in a journal": "분개장에 기록된 수동 분개 거래",
"Message Gateway": "메시지 게이트웨이",
"Mifos Initiative": "Mifos® 이니셔티브",
"Powered by": "제공:",
"Mifos X data-tables allow the user to add custom fields": "Mifos X 데이터 테이블을 사용하면 사용자는 클라이언트 프로필, 대출/저축 계좌, 그룹, 센터 또는 사무실에 기본 제공 필드 외에 사용자 정의 필드를 추가할 수 있습니다.",
"Migrate Opening Balances": "개방 잔액을 마이그레이션합니다",
"Modify Loans Account": "대출 계정 수정",

View File

@ -3206,6 +3206,7 @@
"Manual journal entry transactions recorded in a journal": "Neautomatinio žurnalo įrašymo operacijos, įrašytos į žurnalą",
"Message Gateway": "Pranešimų vartai",
"Mifos Initiative": "Mifos® iniciatyva",
"Powered by": "Varomas",
"Mifos X data-tables allow the user to add custom fields": "„Mifos X“ duomenų lentelės leidžia vartotojui pridėti pasirinktinius laukus be įtaisytųjų laukų prie kliento profilio, paskolos / taupymo sąskaitos, grupės, centro ar biuro.",
"Migrate Opening Balances": "Perkelkite atidarymo balansus",
"Modify Loans Account": "Modifikuoti paskolų sąskaitą",

View File

@ -3206,6 +3206,7 @@
"Manual journal entry transactions recorded in a journal": "Manuālā žurnāla ieraksta darījumi, kas ierakstīti žurnālā",
"Message Gateway": "Ziņojumu vārteja",
"Mifos Initiative": "Mifos® iniciatīva",
"Powered by": "Darbojas ar",
"Mifos X data-tables allow the user to add custom fields": "Mifos X datu tabulas ļauj lietotājam papildus iebūvētajiem laukiem pievienot pielāgotus laukus klienta profilam, aizdevuma/uzkrājuma kontam, grupai, centram vai birojam.",
"Migrate Opening Balances": "Migrēt atveres atlikumus",
"Modify Loans Account": "Modificēt aizdevuma kontu",

View File

@ -885,7 +885,6 @@
"GreaterThan": "भन्दा ठुलो",
"NotEqual": "बराबर छैन"
},
"heading": {
"Account Linked Financial": "विभिन्न वित्तीय गतिविधिहरु संग जोडिएको खाताहरु को सूची। थप जान्नको लागि क्लिक गर्नुहोस्:",
"Account Name": "खाताको नाम",
@ -3205,6 +3204,7 @@
"Manual journal entry transactions recorded in a journal": "जर्नलमा रेकर्ड गरिएको म्यानुअल जर्नल प्रविष्टि लेनदेन",
"Message Gateway": "सन्देश गेटवे",
"Mifos Initiative": "Mifos® पहल",
"Powered by": "द्वारा संचालित",
"Mifos X data-tables allow the user to add custom fields": "Mifos X डाटा-टेबलहरूले प्रयोगकर्तालाई ग्राहक प्रोफाइल, ऋण/बचत खाता, समूह, केन्द्र वा कार्यालयमा निर्मित क्षेत्रहरू बाहेक अनुकूलन क्षेत्रहरू थप्न अनुमति दिन्छ।",
"Migrate Opening Balances": "ओप्रवाहको ब्यालेन्स सारियो",
"Modify Loans Account": "ऋण खाता परिमार्जन गर्नुहोस्",

View File

@ -975,7 +975,6 @@
"Create fixed deposit product": "Criar produto de depósito fixo",
"Create loan product": "Criar produto de empréstimo",
"Create recurring deposit product": "Crie um produto de depósito recorrente",
"Create share product": "Criar produto compartilhado",
"Currency": "Moeda",
"Currency Configuration": "Configuração de moeda",
@ -3206,6 +3205,7 @@
"Manual journal entry transactions recorded in a journal": "Transações de lançamento manual registradas em um diário",
"Message Gateway": "Gateway de mensagens",
"Mifos Initiative": "Iniciativa Mifos®",
"Powered by": "Desenvolvido por",
"Mifos X data-tables allow the user to add custom fields": "As tabelas de dados Mifos X permitem ao usuário adicionar campos personalizados além dos campos integrados a um perfil de cliente, empréstimo/conta poupança, grupo, centro ou escritório.",
"Migrate Opening Balances": "Migrar saldos de abertura",
"Modify Loans Account": "Modificar conta de empréstimos",

View File

@ -3202,6 +3202,7 @@
"Manual journal entry transactions recorded in a journal": "Uingizaji wa shughuli za jarida kwa mikono iliyorekodiwa kwenye jarida",
"Message Gateway": "Lango la Ujumbe",
"Mifos Initiative": "Mpango wa Mifos®",
"Powered by": "Imeendeshwa na",
"Mifos X data-tables allow the user to add custom fields": "Jedwali la data la Mifos X huruhusu mtumiaji kuongeza sehemu maalum pamoja na sehemu zilizojengewa ndani kwa wasifu wa mteja, akaunti ya mkopo/kuokoa, kikundi, kituo au ofisi.",
"Migrate Opening Balances": "Kuhamia mizani ya ufunguzi",
"Modify Loans Account": "Rekebisha Akaunti ya Mikopo",

View File

@ -60,7 +60,9 @@ export const environment = {
displayBackEndInfo: loadedEnv['displayBackEndInfo'] || 'true',
displayTenantSelector: loadedEnv['displayTenantSelector'] || 'true',
tenantLogoUrl: loadedEnv['tenantLogoUrl'] || 'assets/images/mifos_lg-logo.jpg',
/** Production mode - when true, shows minimal hero with only branding at bottom */
productionMode: loadedEnv['productionMode'] === 'true' || loadedEnv['productionMode'] === true || false,
tenantLogoUrl: loadedEnv['tenantLogoUrl'] || 'assets/images/default_home.png',
documentationBaseUrl: loadedEnv['documentationBaseUrl'] || 'https://mifosforge.jira.com/wiki',
// Time in seconds, default 60 seconds
waitTimeForNotifications: loadedEnv['waitTimeForNotifications'] || 60,

View File

@ -64,7 +64,9 @@ export const environment = {
displayBackEndInfo: loadedEnv.displayBackEndInfo || 'true',
displayTenantSelector: loadedEnv.displayTenantSelector || 'true',
tenantLogoUrl: loadedEnv.tenantLogoUrl || 'assets/images/mifos_lg-logo.jpg',
/** Production mode - when true, shows minimal hero with only branding at bottom */
productionMode: loadedEnv.productionMode === 'true' || loadedEnv.productionMode === true || false,
tenantLogoUrl: loadedEnv.tenantLogoUrl || 'assets/images/default_home.png',
documentationBaseUrl: loadedEnv.documentationBaseUrl || 'https://mifosforge.jira.com/wiki',
// Time in seconds, default 60 seconds
waitTimeForNotifications: loadedEnv.waitTimeForNotifications || 60,

View File

@ -17,11 +17,15 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { Logger } from './app/core/logger/logger.service';
const log = new Logger('Bootstrap');
if (environment.production) {
enableProdMode();
Logger.enableProductionMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.log(err));
.catch((err) => log.error('Application bootstrap failed:', err));

2
src/typings.d.ts vendored
View File

@ -31,6 +31,8 @@ interface Window {
defaultCharDelimiter?: string;
displayBackEndInfo?: string;
displayTenantSelector?: string;
/** Production mode - when true, shows minimal hero with only branding at bottom */
productionMode?: string | boolean;
waitTimeForNotifications?: number;
waitTimeForCOBCatchUp?: number;
sessionIdleTimeout?: number;