Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor!: app field settings #2320

Merged
merged 17 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions packages/data-models/appConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,6 @@ const DYNAMIC_PREFIXES = [
"raw",
] as const;

/**
* All localstorage fields will be prefixed with this
* TODO - this has not been consistently applied so refactoring required
* */
const FIELD_PREFIX = "rp-contact-field";

/**
* Fieldnames hardcoded into the app
* TODO - these have not been consistently applied so refactoring required
* */
const APP_FIELDS = {
APP_AUTH_USER: `${FIELD_PREFIX}._app_auth_user`,
APP_LANGUAGE: `${FIELD_PREFIX}._app_language`,
APP_SKIN: `${FIELD_PREFIX}._app_skin`,
APP_THEME: `${FIELD_PREFIX}._app_theme`,
APP_VERSION: `${FIELD_PREFIX}._app_version`,
CONTENT_VERSION: `${FIELD_PREFIX}._content_version`,
DEPLOYMENT_NAME: `${FIELD_PREFIX}._deployment_name`,
SERVER_SYNC_LATEST: `${FIELD_PREFIX}._server_sync_latest`,
};

const APP_LANGUAGES = {
/** Language used during first load. If translations do not exist will default to source strings (gb_en) */
default: "gb_en",
Expand Down Expand Up @@ -180,9 +159,6 @@ const FEEDBACK_MODULE_DEFAULTS = {
displayedTemplate: "feature_feedback_text_select",
},
],
/** Field to populate with selected text for use in templates */
selected_text_field: "_feedback_selected_text",
sidebar_open_field: "_feedback_sidebar_open",
};

const APP_UPDATES = {
Expand All @@ -194,10 +170,6 @@ const APP_UPDATES = {
* If no template is provided provided, installation of the downloaded flexible update will be completed on next app init
*/
completeUpdateTemplate: "app_update_complete",
/** Track whether an update is available for download */
app_update_available_field: "_app_update_available",
/** Track whether an update has been downloaded and is available for install */
app_update_downloaded_field: "_app_update_downloaded",
};

const ASSET_PACKS = {
Expand All @@ -216,7 +188,6 @@ const TASKS = {
};

const APP_CONFIG = {
APP_FIELDS,
APP_HEADER_DEFAULTS,
APP_INITIALISATION_DEFAULTS,
APP_AUTHENTICATION_DEFAULTS,
Expand All @@ -231,7 +202,6 @@ const APP_CONFIG = {
ASSET_PACKS,
DYNAMIC_PREFIXES,
FEEDBACK_MODULE_DEFAULTS,
FIELD_PREFIX,
NOTIFICATIONS_SYNC_FREQUENCY_MS,
NOTIFICATION_DEFAULTS,
SERVER_SYNC_FREQUENCY_MS,
Expand Down
27 changes: 27 additions & 0 deletions packages/data-models/fields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Protected fields can be set by field service and will be prefixed with an underscore
* They are used to store store computed or exported variables and are not user overridable
*/
enum PROTECTED_FIELDS {
APP_AUTH_USER = "app_auth_user",
APP_FIRST_LAUNCH = "app_first_launch",
APP_LANGUAGE = "app_language",
APP_SKIN = "app_skin",
APP_THEME = "app_theme",
/** Track whether an update is available for download */
APP_UPDATE_AVAILABLE = "app_update_available",
/** Track whether an update has been downloaded and is available for install */
APP_UPDATE_DOWNLOADED = "app_update_downloaded",
APP_USER_ID = "app_user_id",
APP_VERSION = "app_version",
CONTENT_VERSION = "content_version",
DEPLOYMENT_NAME = "deployment_name",
FEEDBACK_SELECTED_TEXT = "feedback_selected_text",
FEEDBACK_SIDEBAR_OPEN = "feedback_sidebar_open",
SERVER_SYNC_LATEST = "server_sync_latest",
}

/** Whenever retrieving a protected field make sure to include underscore prefix */
export const getProtectedFieldName = (key: IProtectedFieldName) => `_${PROTECTED_FIELDS[key]}`;

export type IProtectedFieldName = keyof typeof PROTECTED_FIELDS;
1 change: 1 addition & 0 deletions packages/data-models/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./appConfig";
export * from "./db.model";
export * from "./deployment.model";
export * from "./fields";
export * from "./flowTypes";
export * from "./functions";
export * from "./skin.model";
23 changes: 16 additions & 7 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { SyncServiceBase } from "./shared/services/syncService.base";
import { SeoService } from "./shared/services/seo/seo.service";
import { FeedbackService } from "./feature/feedback/feedback.service";
import { ShareService } from "./shared/services/share/share.service";
import { LocalStorageService } from "./shared/services/local-storage/local-storage.service";

@Component({
selector: "app-root",
Expand All @@ -51,7 +52,6 @@ export class AppComponent {
CONTENT_VERSION = environment.deploymentConfig.git.content_tag_latest;
DEPLOYMENT_NAME = environment.deploymentName;
appConfig: IAppConfig;
appFields: IAppConfig["APP_FIELDS"];
appAuthenticationDefaults: IAppConfig["APP_AUTHENTICATION_DEFAULTS"];
sideMenuDefaults: IAppConfig["APP_SIDEMENU_DEFAULTS"];
footerDefaults: IAppConfig["APP_FOOTER_DEFAULTS"];
Expand All @@ -72,6 +72,7 @@ export class AppComponent {
private menuController: MenuController,
private router: Router,
// App services
private localStorageService: LocalStorageService,
private skinService: SkinService,
private appConfigService: AppConfigService,
private dynamicDataService: DynamicDataService,
Expand Down Expand Up @@ -112,10 +113,7 @@ export class AppComponent {
this.platform.ready().then(async () => {
this.platforms = this.platform.platforms().join(" ");
this.subscribeToAppConfigChanges();
// ensure deployment field set correctly for use in any startup services or templates
localStorage.setItem(this.appFields.DEPLOYMENT_NAME, this.DEPLOYMENT_NAME);
localStorage.setItem(this.appFields.APP_VERSION, this.APP_VERSION);
localStorage.setItem(this.appFields.CONTENT_VERSION, this.CONTENT_VERSION);
await this.populateAppInitFields();
await this.initialiseCoreServices();
this.hackSetDeveloperOptions();
const isDeveloperMode = this.templateFieldService.getField("user_mode") === false;
Expand Down Expand Up @@ -147,6 +145,18 @@ export class AppComponent {
this.scheduleReinitialisation();
});
}
/** Populate contact fields that may be used by other services during initialisation */
private async populateAppInitFields() {
this.localStorageService.setProtected("DEPLOYMENT_NAME", this.DEPLOYMENT_NAME);
this.localStorageService.setProtected("APP_VERSION", this.APP_VERSION);
this.localStorageService.setProtected("CONTENT_VERSION", this.CONTENT_VERSION);
// HACK - ensure first_app_launch migrated from event service
if (!this.localStorageService.getProtected("APP_FIRST_LAUNCH")) {
await this.appEventService.ready();
const { first_app_launch } = this.appEventService.summary;
this.localStorageService.setProtected("APP_FIRST_LAUNCH", first_app_launch);
}
}

/**
* Authentication requires verified domain and app ids populated to firebase console
Expand Down Expand Up @@ -178,7 +188,6 @@ export class AppComponent {
this.sideMenuDefaults = this.appConfig.APP_SIDEMENU_DEFAULTS;
this.footerDefaults = this.appConfig.APP_FOOTER_DEFAULTS;
this.appAuthenticationDefaults = this.appConfig.APP_AUTHENTICATION_DEFAULTS;
this.appFields = this.appConfig.APP_FIELDS;
});
}

Expand Down Expand Up @@ -311,7 +320,7 @@ export class AppComponent {
if (location.hostname === "localhost" && !environment.production) {
const isUserMode = this.templateFieldService.getField("user_mode");
if (isUserMode !== false) {
this.templateFieldService.setField("user_mode", "false");
this.localStorageService.setString("user_mode", "false");
}
}
}
Expand Down
17 changes: 4 additions & 13 deletions src/app/feature/feedback/feedback.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { UserMetaService } from "src/app/shared/services/userMeta/userMeta.servi
import { TemplateService } from "src/app/shared/components/template/services/template.service";
import { generateTimestamp } from "src/app/shared/utils";
import { environment } from "src/environments/environment";
import { TemplateFieldService } from "src/app/shared/components/template/services/template-field.service";
import { DbService } from "src/app/shared/services/db/db.service";
import { DBSyncService } from "src/app/shared/services/db/db-sync.service";
import {
Expand All @@ -38,6 +37,7 @@ import {
TemplateActionRegistry,
} from "src/app/shared/components/template/services/instance/template-action.registry";
import { SyncServiceBase } from "src/app/shared/services/syncService.base";
import { LocalStorageService } from "src/app/shared/services/local-storage/local-storage.service";

@Injectable({
providedIn: "root",
Expand Down Expand Up @@ -71,7 +71,7 @@ export class FeedbackService extends SyncServiceBase {
constructor(
private contextMenuService: ContextMenuService,
private templateService: TemplateService,
private templateFieldService: TemplateFieldService,
private localStorageService: LocalStorageService,
private userMetaService: UserMetaService,
private toastController: ToastController,
private dbService: DbService,
Expand Down Expand Up @@ -183,19 +183,12 @@ export class FeedbackService extends SyncServiceBase {
}

public async sidebarOpen() {
await this.setSidebarField(true);
this.router.navigate([{ outlets: { sidebar: ["feedback"] } }]);
}
public async sidebarClose() {
await this.setSidebarField(false);
this.router.navigate([{ outlets: { sidebar: [] } }]);
}

private async setSidebarField(isOpen: boolean) {
const { sidebar_open_field } = this.feedbackModuleDefaults;
await this.templateFieldService.setField(sidebar_open_field, `${isOpen}`);
}

/**
* Create a standalone popup of the provided template and use to collect user feedback.
* Modal dismiss and feedback retrieval will be handled by the feedback actions handlers
Expand Down Expand Up @@ -332,17 +325,15 @@ export class FeedbackService extends SyncServiceBase {
feedbackButton: IFeedbackContextMenuButton,
contextData: IContextMenuActionData = {}
) {
// set selected text to field for access in templates
const { selected_text_field } = this.feedbackModuleDefaults;
if (contextData?.selectedText) {
await this.templateFieldService.setField(selected_text_field, contextData.selectedText);
this.localStorageService.setProtected("FEEDBACK_SELECTED_TEXT", contextData.selectedText);
}
// launch feedback template, disable feedback mode to prevent actions on feedback poup
const additional = { ...contextData, id: feedbackButton.id };
await this.runFeedbackTemplate(feedbackButton.displayedTemplate, additional, ev);

// clear previously set field
await this.templateFieldService.setField(selected_text_field, null);
this.localStorageService.setProtected("FEEDBACK_SELECTED_TEXT", null);
}

/**
Expand Down
6 changes: 2 additions & 4 deletions src/app/feature/theme/services/theme.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { SyncServiceBase } from "src/app/shared/services/syncService.base";
export class ThemeService extends SyncServiceBase {
currentTheme$ = new BehaviorSubject<string>(null);
availableThemes: IAppConfig["APP_THEMES"]["available"];
appFields: IAppConfig["APP_FIELDS"];
defaultThemeName: string;

constructor(
Expand Down Expand Up @@ -41,14 +40,14 @@ export class ThemeService extends SyncServiceBase {
document.body.dataset.theme = themeName;
this.currentTheme$.next(themeName);
// Use local storage so that the current theme persists across app launches
this.localStorageService.setString(this.appFields.APP_THEME, themeName);
this.localStorageService.setProtected("APP_THEME", themeName);
} else {
console.error(`No theme found with name "${themeName}"`);
}
}

public getCurrentTheme() {
return this.localStorageService.getString(this.appFields.APP_THEME);
return this.localStorageService.getProtected("APP_THEME");
}

/** Calculate all custom properties inherited for a particular element */
Expand Down Expand Up @@ -91,7 +90,6 @@ export class ThemeService extends SyncServiceBase {

subscribeToAppConfigChanges() {
this.appConfigService.appConfig$.subscribe((appConfig: IAppConfig) => {
this.appFields = appConfig.APP_FIELDS;
this.availableThemes = appConfig.APP_THEMES.available;
this.defaultThemeName = appConfig.APP_THEMES.defaultThemeName;
});
Expand Down
17 changes: 7 additions & 10 deletions src/app/feature/user/pages/user-debug/user-debug.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, Injector, OnInit } from "@angular/core";
import { TemplateActionService } from "src/app/shared/components/template/services/instance/template-action.service";
import { TemplateFieldService } from "src/app/shared/components/template/services/template-field.service";
import { DynamicDataService } from "src/app/shared/services/dynamic-data/dynamic-data.service";
import { LocalStorageService } from "src/app/shared/services/local-storage/local-storage.service";

interface IDynamicDataEntry {
id: string;
Expand All @@ -19,6 +20,7 @@ export class UserDebugPage implements OnInit {
constructor(
private fieldService: TemplateFieldService,
private dynamicDataService: DynamicDataService,
private localStorageService: LocalStorageService,
private injector: Injector
) {}
/** Id of current user */
Expand Down Expand Up @@ -87,16 +89,11 @@ export class UserDebugPage implements OnInit {

/** Retrieve localStorage entries prefixed by field service prefix */
private getUserContactFields() {
const contactFields: { key: string; value: string }[] = [];
const prefix = `${this.fieldService.prefix}.`;
for (const key in localStorage) {
if (key.startsWith(prefix)) {
contactFields.push({
key: key.replace(prefix, ""),
value: localStorage.getItem(key),
});
}
}
const localStorageHashmap = this.localStorageService.getAll();
const contactFields = Object.entries<string>(localStorageHashmap).map(([key, value]) => ({
key,
value,
}));
return contactFields.sort((a, b) => (a.key > b.key ? 1 : -1));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ import { AppConfigService } from "src/app/shared/services/app-config/app-config.
export class TemplateFieldService extends AsyncServiceBase {
globals: { [name: string]: FlowTypes.GlobalRow } = {};

/** App config prefix used */
public prefix: string;

constructor(
private localStorageService: LocalStorageService,
private dbService: DbService,
Expand All @@ -26,7 +23,6 @@ export class TemplateFieldService extends AsyncServiceBase {
super("TemplateField");
this.registerInitFunction(this.initialise);
this.registerTemplateActionHandlers();
this.prefix = appConfigService.APP_CONFIG.FIELD_PREFIX;
}

private async initialise() {
Expand All @@ -50,12 +46,12 @@ export class TemplateFieldService extends AsyncServiceBase {
}

/**
* Retrieve fields from localstorage. These are automatically prefixed with 'rp-contact-field'
* and will be returned as string or boolean
* Retrieve fields from localstorage and return as string or boolean
* TODO - ideally showWarnings should be linked to some sort of debug mode
*/
public getField(key: string, showWarnings = true) {
let val: any = this.localStorageService.getString(`${this.prefix}.${key}`);
if (!key) return undefined;
let val: any = this.localStorageService.getString(key);
// provide a fallback if the target variable does not exist in local storage
if (val === null && showWarnings) {
// console.warn("field value not found for key:", key);
Expand Down Expand Up @@ -86,7 +82,7 @@ export class TemplateFieldService extends AsyncServiceBase {
}
}
// write to local storage - this will cast to string
this.localStorageService.setString(`${this.prefix}.${key}`, value);
this.localStorageService.setString(key, value);

// write to db - note this can handle more data formats but only string/number will be available to queries
if (typeof value === "boolean") value = "value";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export class TemplateTranslateService extends AsyncServiceBase {
* Formatted as country-language code, e.g. za-en
**/
app_language$ = new BehaviorSubject<string>(null);
appFields: IAppConfig["APP_FIELDS"];
appLanguages: IAppConfig["APP_LANGUAGES"];
translation_strings = {};

Expand All @@ -39,7 +38,7 @@ export class TemplateTranslateService extends AsyncServiceBase {
this.appConfigService,
]);
this.subscribeToAppConfigChanges();
const currentLanguage = this.localStorageService.getString(this.appFields.APP_LANGUAGE);
const currentLanguage = this.localStorageService.getProtected("APP_LANGUAGE");
if (currentLanguage) {
await this.setLanguage(currentLanguage, false);
} else {
Expand All @@ -55,7 +54,7 @@ export class TemplateTranslateService extends AsyncServiceBase {
async setLanguage(code: string, updateDB = true) {
if (code) {
if (updateDB) {
this.localStorageService.setString(this.appFields.APP_LANGUAGE, code);
this.localStorageService.setProtected("APP_LANGUAGE", code);
}
const translationStrings = await this.appDataService.getTranslationStrings(code);
this.translation_strings = translationStrings || {};
Expand Down Expand Up @@ -139,7 +138,6 @@ export class TemplateTranslateService extends AsyncServiceBase {

subscribeToAppConfigChanges() {
this.appConfigService.appConfig$.subscribe((appConfig: IAppConfig) => {
this.appFields = appConfig.APP_FIELDS;
this.appLanguages = appConfig.APP_LANGUAGES;
});
}
Expand Down
Loading
Loading