diff --git a/packages/core/src/auth/components/molecules/ProcessHistoryCard/ProcessHistoryCard.tsx b/packages/core/src/auth/components/molecules/ProcessHistoryCard/ProcessHistoryCard.tsx
index 2022a8fe5b..1676e71868 100644
--- a/packages/core/src/auth/components/molecules/ProcessHistoryCard/ProcessHistoryCard.tsx
+++ b/packages/core/src/auth/components/molecules/ProcessHistoryCard/ProcessHistoryCard.tsx
@@ -53,7 +53,7 @@ const ProccessHistoryCard = ({
const I18n = useTranslator();
const borderStyle = useMemo(() => {
- return getStyles(ProcessHistory.getStatusColor(status, Colors).background)
+ return getStyles(ProcessHistory.getStatusColor(status, Colors)?.background)
?.border;
}, [Colors, status]);
@@ -72,6 +72,7 @@ const ProccessHistoryCard = ({
iconName: 'calendar-event',
indicatorText: I18n.t('User_ProcessHistory_StartedOn'),
displayText: formatDateTime(startedDate, I18n.t('Base_DateFormat')),
+ hideIf: startedDate == null,
},
{
iconName: 'calendar-check',
diff --git a/packages/core/src/auth/screens/ProcessHistoryListScreen.js b/packages/core/src/auth/screens/ProcessHistoryListScreen.js
index 1ab69ddca4..aadb9a09b5 100644
--- a/packages/core/src/auth/screens/ProcessHistoryListScreen.js
+++ b/packages/core/src/auth/screens/ProcessHistoryListScreen.js
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import React, {useCallback, useEffect, useState} from 'react';
import {StyleSheet} from 'react-native';
import {
@@ -32,13 +33,14 @@ import {useTranslator} from '../../i18n';
import {ProcessHistory} from '../types';
import {isToday} from './process-history-list-screen-helper';
+// TODO: add refresh method to the list
const ProcessHistoryListScreen = () => {
const I18n = useTranslator();
const Colors = useThemeColor();
- const {allProcessList} = useLoaderListener();
+ const {processList} = useLoaderListener();
- const [filteredList, setFilteredList] = useState(allProcessList);
+ const [filteredList, setFilteredList] = useState(processList);
const [today, setToday] = useState(true);
const [selectedStatus, setSelectedStatus] = useState([]);
@@ -48,7 +50,11 @@ const ProcessHistoryListScreen = () => {
return [];
} else {
if (today) {
- return list?.filter(item => isToday(item?.startedDate));
+ return list?.filter(
+ item =>
+ isToday(item?.startedDate) ||
+ item?.status === ProcessStatus.PENDING,
+ );
} else {
return list;
}
@@ -65,8 +71,8 @@ const ProcessHistoryListScreen = () => {
);
useEffect(() => {
- setFilteredList(filterOnStatus(filterOnDate(allProcessList)));
- }, [filterOnDate, filterOnStatus, allProcessList]);
+ setFilteredList(filterOnStatus(filterOnDate(processList)));
+ }, [filterOnDate, filterOnStatus, processList]);
return (
diff --git a/packages/core/src/auth/storage/ProcessStorage.ts b/packages/core/src/auth/storage/ProcessStorage.ts
index fe8d97605f..98492ad413 100644
--- a/packages/core/src/auth/storage/ProcessStorage.ts
+++ b/packages/core/src/auth/storage/ProcessStorage.ts
@@ -18,24 +18,35 @@
import {Storage, storage} from '../../storage/Storage';
import {ProcessItem} from '../../components';
+import {deserialize, serialize} from './process-storage.helper';
const PROCESS_HISTORY_KEY = 'PROCESS_HISTORY';
class ProcessStorage {
private processList: ProcessItem[];
- private refreshCallBack: (sessionList: ProcessItem[]) => void;
+ private refreshCallBack: (processList: ProcessItem[]) => void;
constructor(private localStorage: Storage) {
this.processList = [];
}
+ private updateState() {
+ if (this.refreshCallBack == null) {
+ return;
+ }
+
+ this.refreshCallBack(this.processList);
+ }
+
register(callBack) {
this.refreshCallBack = callBack;
}
getProcessList(): ProcessItem[] {
if (this.processList == null || this.processList.length === 0) {
- this.processList = this.localStorage.getItem(PROCESS_HISTORY_KEY) || [];
+ this.processList = deserialize(
+ this.localStorage.getItem(PROCESS_HISTORY_KEY),
+ );
}
return this.processList;
}
@@ -45,7 +56,7 @@ class ProcessStorage {
return;
}
- if (this.processList.find(_item => _item.key === process.key)) {
+ if (this.processList.find(_item => _item.key === process.key) != null) {
this.processList = this.processList.map(_item => {
if (_item.key === process.key) {
return {..._item, ...process};
@@ -57,7 +68,7 @@ class ProcessStorage {
this.processList.push(process);
}
- this.localStorage.setItem(PROCESS_HISTORY_KEY, this.processList);
+ this.localStorage.setItem(PROCESS_HISTORY_KEY, serialize(this.processList));
this.updateState();
}
@@ -77,14 +88,6 @@ class ProcessStorage {
this.localStorage.setItem(PROCESS_HISTORY_KEY, processList);
this.updateState();
}
-
- private updateState() {
- if (this.refreshCallBack == null) {
- return;
- }
-
- this.refreshCallBack(this.processList);
- }
}
export const processStorage = new ProcessStorage(storage);
diff --git a/packages/core/src/auth/storage/process-storage.helper.ts b/packages/core/src/auth/storage/process-storage.helper.ts
new file mode 100644
index 0000000000..f8f106e10a
--- /dev/null
+++ b/packages/core/src/auth/storage/process-storage.helper.ts
@@ -0,0 +1,66 @@
+/*
+ * Axelor Business Solutions
+ *
+ * Copyright (C) 2024 Axelor ().
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import {ProcessItem} from '../../components';
+
+const serializeItem = (p: ProcessItem) => {
+ return JSON.stringify(p, (k, v) => {
+ if (typeof v === 'function') {
+ return v.toString();
+ }
+
+ return v;
+ });
+};
+
+const deserializeItem = (data: string) => {
+ return JSON.parse(data, (k, v) => {
+ if (typeof v === 'string') {
+ if (v.startsWith('function') || v.startsWith('() =>')) {
+ // eslint-disable-next-line no-eval
+ return eval(`(${v})`);
+ }
+ }
+ return v;
+ });
+};
+
+export const serialize = (list: ProcessItem[]): string => {
+ if (!Array.isArray(list) || list.length === 0) {
+ return '[]';
+ }
+
+ return JSON.stringify(list.map(p => serializeItem(p)));
+};
+
+export const deserialize = (data: string) => {
+ if (data == null || data.length === 0) {
+ return [];
+ }
+
+ try {
+ if (!Array.isArray(data)) {
+ return [];
+ }
+
+ return data.map(i => deserializeItem(i));
+ } catch (e) {
+ console.error('Deserialization error:', e);
+ return [];
+ }
+};
diff --git a/packages/core/src/auth/types/process-history.tsx b/packages/core/src/auth/types/process-history.tsx
index ca1d4ed43c..b59525023f 100644
--- a/packages/core/src/auth/types/process-history.tsx
+++ b/packages/core/src/auth/types/process-history.tsx
@@ -25,6 +25,8 @@ class ProcessHistory {
Colors: ThemeColors,
): Color => {
switch (status) {
+ case ProcessStatus.PENDING:
+ return Colors.plannedColor;
case ProcessStatus.RUNNING:
return Colors.progressColor;
case ProcessStatus.COMPLETED:
diff --git a/packages/core/src/components/templates/Loader/ProcessProvider.ts b/packages/core/src/components/templates/Loader/ProcessProvider.ts
index 7eb9429dd6..713d805222 100644
--- a/packages/core/src/components/templates/Loader/ProcessProvider.ts
+++ b/packages/core/src/components/templates/Loader/ProcessProvider.ts
@@ -28,6 +28,7 @@ import {
Event,
} from './types';
+//TODO: resolve toast press
class ProcessProvider {
private _events: Map;
private _processMap: Map;
@@ -40,7 +41,8 @@ class ProcessProvider {
this._processMap = new Map(this._processList.map(p => [p.key, p]));
this._numberRunningProcess = 0;
- processStorage.register(this.setProcessList);
+ this.onCompleted = this.onCompleted.bind(this);
+ this.onFailed = this.onFailed.bind(this);
}
get numberRunningProcess() {
@@ -51,14 +53,6 @@ class ProcessProvider {
return this._processList.filter(p => p.completed && !p.resolved).length;
}
- get allProcessList() {
- return this._processList;
- }
-
- setProcessList(processList: ProcessItem[]) {
- this._processList = processList;
- }
-
on(key: string, e: EventType, c: callBack) {
const event = this._events.has(key) ? this._events.get(key) : ({} as Event);
@@ -87,7 +81,7 @@ class ProcessProvider {
failedDate: null,
notifyMe: false,
response: null,
- status: null,
+ status: ProcessStatus.PENDING,
completed: false,
resolved: false,
};
@@ -118,8 +112,8 @@ class ProcessProvider {
throw new Error(`Process with key ${p.key} not found.`);
}
- this.onStart(p);
- this.executeProcess(p, I18n);
+ const _p = this.onStart(p);
+ this.executeProcess(_p, I18n);
}
private onFinish(
@@ -136,15 +130,15 @@ class ProcessProvider {
completed: true,
completedDate:
status === ProcessStatus.COMPLETED && new Date().toISOString(),
- failedDate: status === ProcessStatus.FAILED && new Date().toISOString(),
+ failedDate:
+ status === ProcessStatus.FAILED ? new Date().toISOString() : null,
};
- this._processMap.set(p.key, _p);
- processStorage.saveProcess(_p);
-
this.decrementNumberOfRunningProcess();
- this.resolveProcess(p.key);
+ this.resolveProcess(_p);
+ this._processMap.set(p.key, _p);
+ processStorage.saveProcess(_p);
this.emit(
p.key,
status === ProcessStatus.COMPLETED
@@ -157,8 +151,10 @@ class ProcessProvider {
private onCompleted(p: ProcessItem, I18n: TranslatorProps) {
const {notifyMe, response, disabled, onSuccess} = p;
+
if (!notifyMe) {
- this.onFinishCallBack(p.key, onSuccess, response);
+ onSuccess(response);
+ this.resolveProcess(p);
} else {
showToastMessage({
type: 'success',
@@ -169,16 +165,17 @@ class ProcessProvider {
typeof response === 'string'
? response
: I18n.t('Base_Loader_ProccessSuccessMessage'),
- onPress: () =>
- !disabled && this.onFinishCallBack(p.key, onSuccess, response),
+ onPress: () => !disabled && onSuccess(response),
});
}
}
private onFailed(p: ProcessItem, I18n: TranslatorProps) {
const {notifyMe, response, disabled, onError} = p;
+
if (!notifyMe) {
- this.onFinishCallBack(p.key, onError, response);
+ onError(response);
+ this.resolveProcess(p);
} else {
showToastMessage({
type: 'error',
@@ -189,8 +186,7 @@ class ProcessProvider {
typeof response === 'string'
? response
: I18n.t('Base_Loader_ProccessErrorMessage'),
- onPress: () =>
- !disabled && this.onFinishCallBack(p.key, onError, response),
+ onPress: () => !disabled && onError(response),
});
}
}
@@ -203,27 +199,21 @@ class ProcessProvider {
this._numberRunningProcess = Math.max(0, this._numberRunningProcess - 1);
}
- private resolveProcess(key: string) {
- if (!this._processMap.has(key)) {
- throw new Error(`Process with key ${key} not found.`);
+ private resolveProcess(p: ProcessItem) {
+ if (!this._processMap.has(p?.key)) {
+ throw new Error(`Process with key ${p?.key} not found.`);
}
- const p = this._processMap.get(key);
if (!p.completed) {
- throw new Error(`Could not resolve uncompleted process ${key}`);
+ throw new Error(`Could not resolve uncompleted process ${p.key}`);
}
const _p = {...p, resolved: true};
- this._processMap.set(key, _p);
+ this._processMap.set(p.key, _p);
processStorage.saveProcess(_p);
}
- private onFinishCallBack(key: string, cb: callBack, response: any) {
- this.resolveProcess(key);
- cb(response);
- }
-
- private onStart(p: ProcessItem) {
+ private onStart(p: ProcessItem): ProcessItem {
const _p = {
...p,
loading: true,
@@ -238,6 +228,8 @@ class ProcessProvider {
this.on(p.key, EventType.COMPLETED, this.onCompleted);
this.on(p.key, EventType.FAILED, this.onFailed);
this.emit(p.key, EventType.STARTED);
+
+ return _p;
}
private async executeProcess(p: ProcessItem, I18n: TranslatorProps) {
diff --git a/packages/core/src/components/templates/Loader/types.ts b/packages/core/src/components/templates/Loader/types.ts
index d6392005a8..ac0ed91f85 100644
--- a/packages/core/src/components/templates/Loader/types.ts
+++ b/packages/core/src/components/templates/Loader/types.ts
@@ -29,6 +29,7 @@ export type Event = {
};
export enum ProcessStatus {
+ PENDING = 'PENDING',
RUNNING = 'RUNNING',
COMPLETED = 'COMPLETED',
FAILED = 'FAILED',
diff --git a/packages/core/src/components/templates/Loader/use-loader-listener.ts b/packages/core/src/components/templates/Loader/use-loader-listener.ts
index c99be044c1..c9bd4757dc 100644
--- a/packages/core/src/components/templates/Loader/use-loader-listener.ts
+++ b/packages/core/src/components/templates/Loader/use-loader-listener.ts
@@ -17,13 +17,14 @@
*/
import {useEffect, useMemo, useState} from 'react';
+import {processStorage} from '../../../auth/storage/ProcessStorage';
import {processProvider} from './ProcessProvider';
import {ProcessItem} from './types';
const useLoaderListener = () => {
const [numberProcesses, setNumberProcesses] = useState(0);
const [numberUnresolvedProcess, setUnresolvedProcess] = useState(0);
- const [allProcessList, setAllProcessList] = useState([]);
+ const [processList, setProcessList] = useState([]);
useEffect(() => {
setNumberProcesses(processProvider.numberRunningProcess);
@@ -36,13 +37,17 @@ const useLoaderListener = () => {
}, [processProvider.numberUnresolvedProcess]);
useEffect(() => {
- setAllProcessList(processProvider.allProcessList);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [processProvider.allProcessList]);
+ setProcessList(processStorage.getProcessList());
+ processStorage.register(setProcessList);
+ }, [setProcessList]);
return useMemo(
- () => ({numberProcesses, numberUnresolvedProcess, allProcessList}),
- [numberProcesses, numberUnresolvedProcess, allProcessList],
+ () => ({
+ numberProcesses,
+ numberUnresolvedProcess,
+ processList,
+ }),
+ [numberProcesses, numberUnresolvedProcess, processList],
);
};