diff --git a/queen-v2/src/components/lightOrchestrator/LoopPanel/component.js b/queen-v2/src/components/lightOrchestrator/LoopPanel/component.js
index 50a5a559..fb91674a 100644
--- a/queen-v2/src/components/lightOrchestrator/LoopPanel/component.js
+++ b/queen-v2/src/components/lightOrchestrator/LoopPanel/component.js
@@ -1,14 +1,12 @@
-import { memo, useEffect, useState } from 'react';
+import { memo } from 'react';
import { useStyles } from './component.style';
import { Panel } from './panel';
-const LoopPanelNotMemo = ({ loopVariables = [], getData, pager, goToPage }) => {
+const LoopPanelNotMemo = ({ loopVariables = [], allData, pager, goToPage }) => {
const noLoopVariables = loopVariables.length === 0 || loopVariables[0] === undefined;
const classes = useStyles();
- const [datas, setDatas] = useState(null);
-
const {
page: currentPage,
subPage: currentSubPage,
@@ -16,17 +14,12 @@ const LoopPanelNotMemo = ({ loopVariables = [], getData, pager, goToPage }) => {
lastReachedPage,
} = pager;
- useEffect(() => {
- if (!noLoopVariables) setDatas(getData());
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [noLoopVariables, loopVariables]);
-
if (noLoopVariables) return null;
// use page to select loopVariables depth
const depth = 0;
const targetVariable = loopVariables[depth];
- const targetData = datas?.COLLECTED[targetVariable];
+ const targetData = allData?.COLLECTED[targetVariable];
const COLLECTED = targetData?.COLLECTED;
if (COLLECTED && (COLLECTED.length === 0 || COLLECTED[0] === null)) return null;
diff --git a/queen-v2/src/components/lightOrchestrator/lightOrchestrator.js b/queen-v2/src/components/lightOrchestrator/lightOrchestrator.js
index c8c71b7d..3f6a469f 100644
--- a/queen-v2/src/components/lightOrchestrator/lightOrchestrator.js
+++ b/queen-v2/src/components/lightOrchestrator/lightOrchestrator.js
@@ -1,11 +1,12 @@
import { useLunatic } from '@inseefr/lunatic';
-import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { memo, useEffect, useMemo, useRef, useState } from 'react';
import ButtonContinue from './buttons/continue/index';
import D from 'i18n';
import { componentHasResponse } from 'utils/components/deduceState';
import { QUEEN_URL } from 'utils/constants';
+import { useConstCallback } from 'utils/hook/useConstCallback';
import { LoopPanel } from './LoopPanel';
import { ComponentDisplayer } from './componentDisplayer';
import Header from './header';
@@ -36,6 +37,7 @@ function LightOrchestrator({
missing = true,
shortcut = true,
autoSuggesterLoading,
+ allData,
filterDescription,
onChange = onLogChange,
onDataChange = noDataChange,
@@ -47,7 +49,7 @@ function LightOrchestrator({
const classes = useStyles();
const lunaticStateRef = useRef();
- const lightCustomHandleChange = useCallback(valueChange => {
+ const lightCustomHandleChange = useConstCallback(valueChange => {
if (lunaticStateRef === undefined) return;
const { getComponents, goNextPage } = lunaticStateRef.current;
const currentComponent = getComponents()?.[0];
@@ -60,13 +62,13 @@ function LightOrchestrator({
) {
goNextPage();
}
- }, []);
+ });
- const missingStrategy = useCallback(() => {
+ const missingStrategy = useConstCallback(() => {
if (lunaticStateRef === undefined) return;
const { goNextPage } = lunaticStateRef.current;
goNextPage();
- }, []);
+ });
// TODO restore when lunatic handle object in missingButtons properties
// const dontKnowButton = ;
@@ -89,6 +91,7 @@ function LightOrchestrator({
missingShortcut,
dontKnowButton,
refusedButton,
+ trackChanges: true,
workersBasePath: `${QUEEN_URL}/workers`,
});
@@ -106,7 +109,8 @@ function LightOrchestrator({
// getErrors,
// getModalErrors,
// getCurrentErrors,
- getData,
+ // getData,
+ // getChangedData,
loopVariables = [],
Provider,
pageTag,
@@ -118,30 +122,30 @@ function LightOrchestrator({
useEffect(() => {
const savingTask = async () => {
if (lunaticStateRef.current === undefined) return;
- const { getData: freshGetData, pageTag, pager } = lunaticStateRef.current;
+ const { getChangedData: freshGetChangedData, pageTag, pager } = lunaticStateRef.current;
if (previousPageTag.current === undefined) {
previousPageTag.current = pageTag;
return;
}
if (pageTag !== previousPageTag.current) {
previousPageTag.current = pageTag;
- const allData = freshGetData();
- onDataChange(allData.COLLECTED);
- save(undefined, allData, pager.lastReachedPage);
+ const partialData = freshGetChangedData(true);
+ onDataChange(partialData);
+ save(undefined, partialData, pager.lastReachedPage);
}
};
savingTask();
}, [save, pager, onDataChange]);
- const memoQuit = useCallback(() => {
- const { getData: freshGetData, pager: freshPager } = lunaticStateRef.current;
- quit(freshPager, freshGetData);
- }, [quit]);
+ const memoQuit = useConstCallback(() => {
+ const { getChangedData: freshGetChangedData, pager: freshPager } = lunaticStateRef.current;
+ quit(freshPager, freshGetChangedData);
+ });
- const memoDefinitiveQuit = useCallback(() => {
- const { getData: freshGetData, pager: freshPager } = lunaticStateRef.current;
- definitiveQuit(freshPager, freshGetData);
- }, [definitiveQuit]);
+ const memoDefinitiveQuit = useConstCallback(() => {
+ const { getChangedData: freshGetChangedData, pager: freshPager } = lunaticStateRef.current;
+ definitiveQuit(freshPager, freshGetChangedData);
+ });
const [components, setComponents] = useState([]);
@@ -156,23 +160,20 @@ function LightOrchestrator({
// const modalErrors = getModalErrors();
// const currentErrors = typeof getCurrentErrors === 'function' ? getCurrentErrors() : [];
- const trueGoToPage = useCallback(
- targetPage => {
- if (typeof targetPage === 'string') {
- goToPage({ page: targetPage });
- } else {
- const { page, iteration, subPage } = targetPage;
- goToPage({ page: page, iteration: iteration, subPage: subPage });
- }
- },
- [goToPage]
- );
+ const trueGoToPage = useConstCallback(targetPage => {
+ if (typeof targetPage === 'string') {
+ goToPage({ page: targetPage });
+ } else {
+ const { page, iteration, subPage } = targetPage;
+ goToPage({ page: page, iteration: iteration, subPage: subPage });
+ }
+ });
- const goToLastReachedPage = useCallback(() => {
+ const goToLastReachedPage = useConstCallback(() => {
if (lunaticStateRef.current === undefined) return;
const { pager } = lunaticStateRef.current;
trueGoToPage(pager.lastReachedPage);
- }, [trueGoToPage]);
+ });
const firstComponent = useMemo(() => [...components]?.[0], [components]);
const hasResponse = componentHasResponse(firstComponent);
@@ -228,7 +229,7 @@ function LightOrchestrator({
diff --git a/queen-v2/src/components/orchestratorManager/orchestratorManager.js b/queen-v2/src/components/orchestratorManager/orchestratorManager.js
index 541218c5..5fbaf99a 100644
--- a/queen-v2/src/components/orchestratorManager/orchestratorManager.js
+++ b/queen-v2/src/components/orchestratorManager/orchestratorManager.js
@@ -1,4 +1,4 @@
-import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
+import { useContext, useEffect, useMemo, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { ORCHESTRATOR_COLLECT, ORCHESTRATOR_READONLY, READ_ONLY } from 'utils/constants';
import { EventsManager, INIT_ORCHESTRATOR_EVENT, INIT_SESSION_EVENT } from 'utils/events';
@@ -11,12 +11,14 @@ import Error from 'components/shared/Error';
import NotFound from 'components/shared/not-found';
import Preloader from 'components/shared/preloader';
import { sendCloseEvent } from 'utils/communication';
+import { useConstCallback } from 'utils/hook/useConstCallback';
import surveyUnitIdbService from 'utils/indexedbb/services/surveyUnit-idb-service';
-import { checkQuestionnaire } from 'utils/questionnaire';
+import { checkQuestionnaire, getFullData, removeNullCollectedData } from 'utils/questionnaire';
export const OrchestratorManager = () => {
const { standalone, apiUrl } = useContext(AppContext);
const { readonly: readonlyParam, idQ, idSU } = useParams();
+ const [surveyUnitData, setSurveyUnitData] = useState(null);
const history = useHistory();
const readonly = readonlyParam === READ_ONLY;
@@ -34,7 +36,6 @@ export const OrchestratorManager = () => {
const { surveyUnit, questionnaire, loadingMessage, errorMessage } = useAPIRemoteData(idSU, idQ);
const stateData = surveyUnit?.stateData;
- const initialData = surveyUnit?.data;
const { oidcUser } = useAuth();
const isAuthenticated = !!oidcUser?.profile;
@@ -46,7 +47,6 @@ export const OrchestratorManager = () => {
const { putUeData /* postParadata */ } = useAPI();
const [getState, changeState, onDataChange] = useQuestionnaireState(
surveyUnit?.id,
- initialData,
stateData?.state
);
@@ -66,6 +66,7 @@ export const OrchestratorManager = () => {
const { valid, error: questionnaireError } = checkQuestionnaire(questionnaire);
if (valid) {
setSource(questionnaire);
+ setSurveyUnitData(surveyUnit.data);
setInit(true);
LOGGER.log(INIT_ORCHESTRATOR_EVENT);
} else {
@@ -81,84 +82,76 @@ export const OrchestratorManager = () => {
/** take a survey-unit as parameter, then save it in IDB, then save paradatas in IDB
* If in standalone mode : make API calls to persist data in DB
*/
- const saveData = useCallback(
- async unit => {
- if (!readonly) {
- const putSurveyUnit = async unit => {
- const { id, ...other } = unit;
- await putUeData(id, other);
- };
-
- await surveyUnitIdbService.addOrUpdateSU(unit);
-
- /**
- * Disable temporaly paradata
- *
- * const paradatas = LOGGER.getEventsToSend();
- */
- // TODO : make a true update of paradatas : currently adding additional completed arrays => SHOULD save one and only one array
- // await paradataIdbService.update(paradatas);
- if (standalone) {
- // TODO managing errors
- await putSurveyUnit(unit);
- // await postParadata(paradatas);
- }
+ const saveData = useConstCallback(async unit => {
+ if (!readonly) {
+ const putSurveyUnit = async unit => {
+ const { id, ...other } = unit;
+ await putUeData(id, other);
+ };
+
+ await surveyUnitIdbService.addOrUpdateSU(unit);
+
+ /**
+ * Disable temporaly paradata
+ *
+ * const paradatas = LOGGER.getEventsToSend();
+ */
+ // TODO : make a true update of paradatas : currently adding additional completed arrays => SHOULD save one and only one array
+ // await paradataIdbService.update(paradatas);
+ if (standalone) {
+ // TODO managing errors
+ await putSurveyUnit(unit);
+ // await postParadata(paradatas);
}
- },
- [putUeData, readonly, standalone]
- );
-
- const saveQueen = useCallback(
- async (newState, newData, lastReachedPage) => {
- const currentState = getState();
- saveData({
- comment: {},
- ...surveyUnit,
- stateData: {
- state: newState ?? currentState,
- date: new Date().getTime(),
- currentPage: lastReachedPage,
- },
- data: newData ?? surveyUnit.data,
- });
- },
- [getState, saveData, surveyUnit]
- );
-
- const closeOrchestrator = useCallback(() => {
+ }
+ });
+
+ const savePartialQueen = useConstCallback(async (newState, newPartialData, lastReachedPage) => {
+ const currentState = getState();
+
+ const newData = getFullData(surveyUnitData, removeNullCollectedData(newPartialData));
+ setSurveyUnitData(newData);
+ saveData({
+ comment: {},
+ ...surveyUnit,
+ stateData: {
+ state: newState ?? currentState,
+ date: new Date().getTime(),
+ currentPage: lastReachedPage,
+ },
+ data: newData ?? surveyUnitData,
+ });
+ });
+
+ const closeOrchestrator = useConstCallback(() => {
if (standalone) {
history.push('/');
} else {
sendCloseEvent(surveyUnit.id);
}
- }, [history, standalone, surveyUnit?.id]);
-
- const quit = useCallback(
- async (pager, getData) => {
- const { page, maxPage, lastReachedPage } = pager;
- const isLastPage = page === maxPage;
- const newData = getData();
- if (isLastPage) {
- // TODO : make algo to calculate COMPLETED event
- changeState(COMPLETED);
- changeState(VALIDATED);
- await saveQueen(VALIDATED, newData, lastReachedPage);
- } else await saveQueen(undefined, newData, lastReachedPage);
- closeOrchestrator();
- },
- [changeState, closeOrchestrator, saveQueen]
- );
-
- const definitiveQuit = useCallback(
- async (pager, getData) => {
- const { lastReachedPage } = pager;
- const newData = getData();
+ });
+
+ const quit = useConstCallback(async (pager, getChangedData) => {
+ const { page, maxPage, lastReachedPage } = pager;
+ const isLastPage = page === maxPage;
+ const newData = getChangedData(true);
+ if (isLastPage) {
+ // TODO : make algo to calculate COMPLETED event
+ changeState(COMPLETED);
changeState(VALIDATED);
- await saveQueen(VALIDATED, newData, lastReachedPage);
- closeOrchestrator();
- },
- [changeState, closeOrchestrator, saveQueen]
- );
+ await savePartialQueen(VALIDATED, newData, lastReachedPage);
+ } else await savePartialQueen(undefined, newData, lastReachedPage);
+ closeOrchestrator();
+ });
+
+ const definitiveQuit = useConstCallback(async (pager, getChangedData) => {
+ const { lastReachedPage } = pager;
+ const newData = getChangedData(true);
+ changeState(VALIDATED);
+ await savePartialQueen(VALIDATED, newData, lastReachedPage);
+ closeOrchestrator();
+ });
+
return (
<>
{![READ_ONLY, undefined].includes(readonlyParam) && }
@@ -169,6 +162,7 @@ export const OrchestratorManager = () => {
surveyUnit={surveyUnit}
source={source}
getReferentiel={getReferentiel}
+ allData={surveyUnitData}
autoSuggesterLoading={true}
standalone={standalone}
readonly={readonly}
@@ -177,7 +171,7 @@ export const OrchestratorManager = () => {
missing={true}
shortcut={true}
filterDescription={false}
- save={saveQueen}
+ save={savePartialQueen}
onDataChange={onDataChange}
close={closeOrchestrator}
quit={quit}
diff --git a/queen-v2/src/components/visualizer/visualizer.js b/queen-v2/src/components/visualizer/visualizer.js
index cb31f1b9..a440e18d 100644
--- a/queen-v2/src/components/visualizer/visualizer.js
+++ b/queen-v2/src/components/visualizer/visualizer.js
@@ -1,6 +1,11 @@
-import { useCallback, useContext, useEffect, useState } from 'react';
+import { useContext, useEffect, useState } from 'react';
import { useGetReferentiel, useRemoteData, useVisuQuery } from 'utils/hook';
-import { checkQuestionnaire, downloadDataAsJson } from 'utils/questionnaire';
+import {
+ checkQuestionnaire,
+ downloadDataAsJson,
+ getFullData,
+ removeNullCollectedData,
+} from 'utils/questionnaire';
import { AppContext } from 'components/app';
import LightOrchestrator from 'components/lightOrchestrator';
@@ -8,11 +13,13 @@ import Error from 'components/shared/Error';
import Preloader from 'components/shared/preloader';
import { useHistory } from 'react-router';
import { useQuestionnaireState } from 'utils/hook/questionnaire';
+import { useConstCallback } from 'utils/hook/useConstCallback';
import surveyUnitIdbService from 'utils/indexedbb/services/surveyUnit-idb-service';
import QuestionnaireForm from './questionnaireForm';
const Visualizer = () => {
const { apiUrl, standalone } = useContext(AppContext);
+ const [surveyUnitData, setSurveyUnitData] = useState(null);
const [surveyUnit, setSurveyUnit] = useState(undefined);
const [error, setError] = useState(null);
@@ -30,7 +37,6 @@ const Visualizer = () => {
const [getState, , onDataChange] = useQuestionnaireState(
surveyUnit?.id,
- suData?.data,
suData?.stateData?.state
);
@@ -55,6 +61,7 @@ const Visualizer = () => {
const { valid, error: questionnaireError } = checkQuestionnaire(questionnaire);
if (valid) {
setSource(questionnaire);
+ setSurveyUnitData(suData?.data || {});
} else {
setError(questionnaireError);
}
@@ -65,49 +72,39 @@ const Visualizer = () => {
if (errorMessage) setError(errorMessage);
}, [errorMessage]);
- // const save = useCallback(async (unit, newData) => {
- // console.log(unit, newData);
- // await surveyUnitIdbService.addOrUpdateSU({
- // ...unit,
- // data: newData,
- // });
- // }, []);
-
- const save = useCallback(
- async (newState, newData, lastReachedPage) => {
- const currentState = getState();
- const unit = {
- ...surveyUnit,
- stateData: {
- state: newState ?? currentState,
- date: new Date().getTime(),
- currentPage: lastReachedPage,
- },
- data: newData ?? surveyUnit?.data,
- };
- await surveyUnitIdbService.addOrUpdateSU(unit);
- },
- [getState, surveyUnit]
- );
- const closeAndDownloadData = useCallback(
- async (pager, getData) => {
- const { lastReachedPage } = pager;
- const newData = getData();
- const unit = {
- ...surveyUnit,
- stateData: {
- state: getState(),
- date: new Date().getTime(),
- currentPage: lastReachedPage,
- },
- data: newData ?? surveyUnit?.data,
- };
-
- downloadDataAsJson(unit, 'data');
- history.push('/');
- },
- [getState, history, surveyUnit]
- );
+ const savePartial = useConstCallback(async (newState, newPartialData, lastReachedPage) => {
+ const currentState = getState();
+
+ const newData = getFullData(surveyUnitData, removeNullCollectedData(newPartialData));
+ setSurveyUnitData(newData);
+ const unit = {
+ ...surveyUnit,
+ stateData: {
+ state: newState ?? currentState,
+ date: new Date().getTime(),
+ currentPage: lastReachedPage,
+ },
+ data: newData ?? surveyUnit.data,
+ };
+ await surveyUnitIdbService.addOrUpdateSU(unit);
+ });
+
+ const closeAndDownloadData = useConstCallback(async (pager, getChangedData) => {
+ const { lastReachedPage } = pager;
+ const newData = getFullData(surveyUnitData, removeNullCollectedData(getChangedData(true)));
+ const unit = {
+ ...surveyUnit,
+ stateData: {
+ state: getState(),
+ date: new Date().getTime(),
+ currentPage: lastReachedPage,
+ },
+ data: newData ?? surveyUnit?.data,
+ };
+
+ downloadDataAsJson(unit, 'data');
+ history.push('/');
+ });
return (
<>
@@ -119,11 +116,12 @@ const Visualizer = () => {
source={source}
autoSuggesterLoading={true}
getReferentiel={getReferentielForVizu}
+ allData={surveyUnitData}
standalone={standalone}
readonly={readonly}
pagination={true}
missing={true}
- save={save}
+ save={savePartial}
onDataChange={onDataChange}
filterDescription={false}
quit={closeAndDownloadData}
diff --git a/queen-v2/src/utils/hook/questionnaire.js b/queen-v2/src/utils/hook/questionnaire.js
index 980b20b9..266eeb24 100644
--- a/queen-v2/src/utils/hook/questionnaire.js
+++ b/queen-v2/src/utils/hook/questionnaire.js
@@ -1,52 +1,37 @@
-import { sendCompletedEvent, sendStartedEvent, sendValidatedEvent } from 'utils/communication';
import { useCallback, useRef } from 'react';
+import { sendCompletedEvent, sendStartedEvent, sendValidatedEvent } from 'utils/communication';
+import { useConstCallback } from './useConstCallback';
export const NOT_STARTED = null;
export const INIT = 'INIT';
export const COMPLETED = 'COMPLETED';
export const VALIDATED = 'VALIDATED';
-export const useQuestionnaireState = (idSurveyUnit, initialData, initialState = NOT_STARTED) => {
- console.log('useQuestionnaireState', { idSurveyUnit, initialData, initialState });
+export const useQuestionnaireState = (idSurveyUnit, initialState = NOT_STARTED) => {
const stateRef = useRef(initialState);
const getState = useCallback(() => stateRef.current, []);
- const initialDataRef = useRef(initialData);
-
// Send an event when questionnaire's state has changed (started, completed, validated)
- const changeState = useCallback(
- newState => {
- console.log('change state to ', newState);
- if (newState === INIT) sendStartedEvent(idSurveyUnit);
- if (newState === COMPLETED) sendCompletedEvent(idSurveyUnit);
- if (newState === VALIDATED) sendValidatedEvent(idSurveyUnit);
- stateRef.current = newState;
- },
- [idSurveyUnit]
- );
- const onDataChange = useCallback(
- newData => {
- // initialisation des data de référence
- if (initialDataRef.current === undefined) {
- console.log('persisting initial data');
- initialDataRef.current = JSON.stringify(newData);
- }
+ const changeState = useConstCallback(newState => {
+ if (newState === INIT) sendStartedEvent(idSurveyUnit);
+ if (newState === COMPLETED) sendCompletedEvent(idSurveyUnit);
+ if (newState === VALIDATED) sendValidatedEvent(idSurveyUnit);
+ stateRef.current = newState;
+ });
+ const onDataChange = useConstCallback((newData = {}) => {
+ const { COLLECTED = {} } = newData;
+ const hasDataChanged = Object.keys(COLLECTED).length > 0;
- if (stateRef.current === NOT_STARTED) {
- changeState(INIT);
- } else if (
- stateRef.current === VALIDATED &&
- initialDataRef.current !== JSON.stringify(newData)
- ) {
- // state VALIDATED et données entrantes !== données initiales
- changeState(INIT);
- } else {
- // here we do nothing
- console.log({ newData, state: stateRef.current });
- }
- },
- [changeState]
- );
+ if (stateRef.current === NOT_STARTED) {
+ changeState(INIT);
+ } else if (stateRef.current === VALIDATED && hasDataChanged) {
+ // state VALIDATED et données entrantes !== données initiales
+ changeState(INIT);
+ } else {
+ // here we do nothing
+ console.log({ newData, state: stateRef.current });
+ }
+ });
// Analyse collected variables to update state (only to STARTED state)