diff --git a/src/app/core/utils/json.ts b/src/app/core/utils/json.ts new file mode 100644 index 000000000..d506ca2bc --- /dev/null +++ b/src/app/core/utils/json.ts @@ -0,0 +1,28 @@ +export function safeParse(raw: string | null | undefined, defaultValue: T): T { + if (!raw) return defaultValue; + try { + return JSON.parse(raw) as T; + } catch { + return defaultValue; + } +} + +export function safeParseObject(raw: string | null | undefined, defaultValue: T): T { + if (!raw) return defaultValue; + try { + const parsed = JSON.parse(raw); + return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as T) : defaultValue; + } catch { + return defaultValue; + } +} + +export function safeParseArray(raw: string | null | undefined, defaultValue: T[] = []): T[] { + if (!raw) return defaultValue; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? (parsed as T[]) : defaultValue; + } catch { + return defaultValue; + } +} diff --git a/src/app/settings/settings.service.ts b/src/app/settings/settings.service.ts index 228c574cf..e9bd505fc 100644 --- a/src/app/settings/settings.service.ts +++ b/src/app/settings/settings.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { AlertService } from 'app/core/alert/alert.service'; import { Dates } from 'app/core/utils/dates'; +import { safeParse, safeParseArray, safeParseObject } from 'app/core/utils/json'; /** Environment Imports */ import { environment } from '../../environments/environment'; @@ -108,8 +109,9 @@ export class SettingsService { /** * Returns date format setting. */ - get dateFormat() { - return JSON.parse(localStorage.getItem('mifosXDateFormat')); + get dateFormat(): string { + const parsed = safeParse(localStorage.getItem('mifosXDateFormat'), null); + return typeof parsed === 'string' && parsed.length > 0 ? parsed : 'dd MMMM yyyy'; } /** @@ -119,7 +121,10 @@ export class SettingsService { if (!localStorage.getItem('mifosXLanguage')) { this.setDefaultLanguage(); } - return JSON.parse(localStorage.getItem('mifosXLanguage')); + return safeParseObject<{ name: string; code: string } | undefined>( + localStorage.getItem('mifosXLanguage'), + undefined + ); } get languageCode() { @@ -147,7 +152,7 @@ export class SettingsService { * Returns list of default server */ get servers() { - return JSON.parse(localStorage.getItem('mifosXServers')); + return safeParseArray(localStorage.getItem('mifosXServers'), []); } /** @@ -160,7 +165,7 @@ export class SettingsService { if (environment.baseApiUrl && environment.baseApiUrl !== '') { return environment.baseApiUrl; } else { - return this.servers()[0]; + return this.servers[0]; } } @@ -217,7 +222,7 @@ export class SettingsService { * Returns list of Tenant Identifiers */ get tenantIdentifiers(): any { - return JSON.parse(localStorage.getItem('mifosXTenantIdentifiers')); + return safeParseArray(localStorage.getItem('mifosXTenantIdentifiers'), []); } /** @@ -260,6 +265,6 @@ export class SettingsService { } get themeDarkEnabled(): boolean { - return JSON.parse(localStorage.getItem('mifosXThemeDarkEnabled')); + return safeParse(localStorage.getItem('mifosXThemeDarkEnabled'), false); } } diff --git a/src/app/shared/theme-picker/theme-storage.service.ts b/src/app/shared/theme-picker/theme-storage.service.ts index 8fc4d9adf..876ab149a 100644 --- a/src/app/shared/theme-picker/theme-storage.service.ts +++ b/src/app/shared/theme-picker/theme-storage.service.ts @@ -1,4 +1,5 @@ import { Injectable, EventEmitter } from '@angular/core'; +import { safeParseObject } from 'app/core/utils/json'; import { Theme } from './theme.model'; import { ThemeManagerService } from './theme-manager.service'; @@ -19,7 +20,7 @@ export class ThemeStorageService { } getTheme(): Theme { - return JSON.parse(localStorage.getItem(this.themeStorageKey)); + return safeParseObject(localStorage.getItem(this.themeStorageKey), null); } clearTheme() { diff --git a/src/app/system/configurations/business-date-tab/business-date-tab.component.ts b/src/app/system/configurations/business-date-tab/business-date-tab.component.ts index 0fbbd7d98..715127552 100644 --- a/src/app/system/configurations/business-date-tab/business-date-tab.component.ts +++ b/src/app/system/configurations/business-date-tab/business-date-tab.component.ts @@ -46,7 +46,7 @@ export class BusinessDateTabComponent implements OnInit { businessDateData: any; dateIndex = 0; - userDateFormat: ''; + userDateFormat: string = ''; isBusinessDateEnabled = false; isEditInProgress = false; diff --git a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts index 627789eb4..bd1683387 100644 --- a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts +++ b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts @@ -15,6 +15,7 @@ import { MatDivider } from '@angular/material/divider'; import { NgIf, NgFor, KeyValuePipe } from '@angular/common'; import { DateFormatPipe } from '../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { safeParseObject } from 'app/core/utils/json'; @Component({ selector: 'mifosx-view-checker-inbox', @@ -52,7 +53,7 @@ export class ViewCheckerInboxComponent { ) { this.route.data.subscribe((data: { checkerInboxDetail: any }) => { this.checkerInboxDetail = data.checkerInboxDetail; - this.jsondata = JSON.parse(this.checkerInboxDetail.commandAsJson); + this.jsondata = safeParseObject(this.checkerInboxDetail.commandAsJson, {}); this.displayJSONData = !_.isEmpty(this.jsondata); }); } diff --git a/src/app/web-app.component.ts b/src/app/web-app.component.ts index d70c97daf..74d8149d0 100644 --- a/src/app/web-app.component.ts +++ b/src/app/web-app.component.ts @@ -31,6 +31,7 @@ import { Dates } from './core/utils/dates'; import { animate, style, transition, trigger } from '@angular/animations'; import { I18nService } from './core/i18n/i18n.service'; import { ThemingService } from './shared/theme-toggle/theming.service'; +import { safeParseArray } from 'app/core/utils/json'; import { AuthService } from './zitadel/auth.service'; @@ -195,7 +196,7 @@ export class WebAppComponent implements OnInit, OnDestroy { // Stores top 100 user activites as local storage object. let activities: string[] = []; if (localStorage.getItem('mifosXLocation')) { - const activitiesArray: string[] = JSON.parse(localStorage.getItem('mifosXLocation')); + const activitiesArray = safeParseArray(localStorage.getItem('mifosXLocation'), []); const length = activitiesArray.length; activities = length > 100 ? activitiesArray.slice(length - 100) : activitiesArray; }