diff --git a/drama-queen/src/bootstrap.tsx b/drama-queen/src/bootstrap.tsx index bcfa47e6..3c14c52d 100644 --- a/drama-queen/src/bootstrap.tsx +++ b/drama-queen/src/bootstrap.tsx @@ -6,7 +6,7 @@ import { createCoreProvider } from "core"; import { RouterProvider } from "react-router-dom"; const { CoreProvider } = createCoreProvider({ - "apiUrl": import.meta.env.VITE_API_URL, + "apiUrl": import.meta.env.VITE_QUEEN_API_URL, "publicUrl": import.meta.env.BASE_URL, "oidcParams": { "issuerUri": import.meta.env.VITE_OIDC_ISSUER, diff --git a/drama-queen/src/core/usecases/synchronizeData/selectors.ts b/drama-queen/src/core/usecases/synchronizeData/selectors.ts index 52df1f40..78163064 100644 --- a/drama-queen/src/core/usecases/synchronizeData/selectors.ts +++ b/drama-queen/src/core/usecases/synchronizeData/selectors.ts @@ -4,39 +4,34 @@ import { createSelector } from "@reduxjs/toolkit"; const state = (rootState: RootState) => rootState[name]; -const runningState = createSelector(state, (state) => { - if (state.stateDescription === "not running") { - return undefined; - } - return state; -}); +const runningStates = ["downloading", "uploading"]; -const isRunning = createSelector(runningState, (state) => state !== undefined); +const isRunning = createSelector(state, ({ stateDescription }) => + runningStates.includes(stateDescription) +); -const surveyUnitProgress = createSelector(runningState, (state) => { - if (state === undefined) { - return undefined; - } - return state.surveyUnitProgress; -}); +const surveyUnitProgress = createSelector(state, (state) => + state.stateDescription === "downloading" + ? state.surveyUnitProgress + : undefined +); +const nomenclatureProgress = createSelector(state, (state) => + state.stateDescription === "downloading" + ? state.nomenclatureProgress + : undefined +); +const surveyProgress = createSelector(state, (state) => + state.stateDescription === "downloading" ? state.surveyProgress : undefined +); -const nomenclatureProgress = createSelector(runningState, (state) => { - if (state === undefined) { - return undefined; - } - return state.nomenclatureProgress; -}); - -const surveyProgress = createSelector(runningState, (state) => { - if (state === undefined) { - return undefined; - } - return state.surveyProgress; -}); +const uploadProgress = createSelector(state, (state) => + state.stateDescription === "uploading" ? state.uploadProgress : undefined +); export const selectors = { isRunning, surveyUnitProgress, nomenclatureProgress, surveyProgress, + uploadProgress, }; diff --git a/drama-queen/src/core/usecases/synchronizeData/state.ts b/drama-queen/src/core/usecases/synchronizeData/state.ts index a4e27cfc..a403a1e7 100644 --- a/drama-queen/src/core/usecases/synchronizeData/state.ts +++ b/drama-queen/src/core/usecases/synchronizeData/state.ts @@ -1,14 +1,20 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit"; import { id } from "tsafe"; -export type State = State.NotRunning | State.Running; +export type State = State.NotRunning | State.Uploading | State.Downloading; export namespace State { export type NotRunning = { stateDescription: "not running"; }; - export type Running = { - stateDescription: "running"; + + export type Uploading = { + stateDescription: "uploading"; + uploadProgress: number; + }; + + export type Downloading = { + stateDescription: "downloading"; surveyUnitProgress: number; nomenclatureProgress: number; surveyProgress: number; @@ -25,7 +31,21 @@ export const { reducer, actions } = createSlice({ }) ), reducers: { - progressUpdated: ( + progressUploading: ( + _state, + { + payload, + }: PayloadAction<{ + uploadProgress: number; + }> + ) => { + const { uploadProgress } = payload; + return { + stateDescription: "uploading", + uploadProgress, + }; + }, + progressDownloading: ( _state, { payload, @@ -39,7 +59,7 @@ export const { reducer, actions } = createSlice({ payload; return { - stateDescription: "running", + stateDescription: "downloading", nomenclatureProgress, surveyProgress, surveyUnitProgress, diff --git a/drama-queen/src/core/usecases/synchronizeData/thunks.ts b/drama-queen/src/core/usecases/synchronizeData/thunks.ts index 8fa2c352..d91b05e7 100644 --- a/drama-queen/src/core/usecases/synchronizeData/thunks.ts +++ b/drama-queen/src/core/usecases/synchronizeData/thunks.ts @@ -1,8 +1,9 @@ import { Thunks } from "core/setup"; import { actions, name, type State } from "./state"; +import type { Campaign } from "core/ports/QueenApi/Campaing"; export const thunks = { - start: + startDownloading: () => async (...args) => { const [dispatch, getState] = args; @@ -10,13 +11,13 @@ export const thunks = { { const state = getState()[name]; - if (state.stateDescription === "running") { + if (state.stateDescription === "downloading") { return; } } dispatch( - actions.progressUpdated({ + actions.progressDownloading({ nomenclatureProgress: 0, surveyProgress: 0, surveyUnitProgress: 0, @@ -27,7 +28,7 @@ export const thunks = { await new Promise((resolve) => setTimeout(resolve, 1000)); dispatch( - actions.progressUpdated({ + actions.progressDownloading({ nomenclatureProgress: progress, surveyProgress: progress, surveyUnitProgress: progress, diff --git a/drama-queen/src/ui/pages/LoadingData.tsx b/drama-queen/src/ui/pages/LoadingData.tsx deleted file mode 100644 index a6d93497..00000000 --- a/drama-queen/src/ui/pages/LoadingData.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useEffect } from "react"; -import CircularProgress from "@mui/material/CircularProgress" -import LinearProgress from '@mui/material/LinearProgress'; -import { useCoreState, useCoreFunctions, useCoreEvts } from "core"; -import { useEvt } from "evt/hooks" - -export function LoadingData() { - const synchronizeDataState = useCoreState(state => state.synchronizeData); - - const { synchronizeData } = useCoreFunctions(); - - useEffect( - () => { - synchronizeData.start(); - }, - [] - ); - - const { evtSynchronizeData } = useCoreEvts(); - - useEvt( - ctx => { - evtSynchronizeData.$attach( - data => data.action === "redirect" ? [data] : null, - ctx, - () => { - alert("redirect to " + window.location.href) - } - ); - }, - [] - ); - - if (synchronizeDataState.stateDescription !== "running") { - return null; - } - - const { nomenclatureProgress, surveyProgress, surveyUnitProgress } = synchronizeDataState; - - return ( -
- - -
- -
- -
-
- - ) -} \ No newline at end of file diff --git a/drama-queen/src/ui/pages/synchronize-old/SynchronizePage.tsx b/drama-queen/src/ui/pages/synchronize-old/SynchronizePage.tsx new file mode 100644 index 00000000..5ef93c5e --- /dev/null +++ b/drama-queen/src/ui/pages/synchronize-old/SynchronizePage.tsx @@ -0,0 +1,103 @@ +import LinearProgress from '@mui/material/LinearProgress'; +import Typography from '@mui/material/Typography'; +import Stack from '@mui/material/Stack'; +import { useTranslate } from "hooks/useTranslate"; +import preloader from 'ui/assets/preloader.svg'; +import { tss } from "tss-react/mui"; +import { Fragment, useEffect, useState } from "react"; +import { type PullData, usePullData } from 'hooks/usePullData'; +import type { SurveyUnitWithId } from "core/ports/QueenApi/SurveyUnit"; +import { SyncError } from "hooks/queries/SyncError"; +import { storeSyncProgress } from "./storeSyncProgress"; +import { db } from 'core/indexedDb'; + +type SyncState = "Idle" | "Push" | "Pull" | "End"; + + +export const SynchronizePage = () => { + const { classes } = useStyles(); + const [state, setState] = useState("Pull") + + useEffect(() => { + storeSyncProgress() + }, []); + + const handlePullEnd = (data: PullData, errors: SyncError[]) => { + storeSyncProgress( + data, + errors + ) + db.surveyUnit.bulkAdd(data.surveyUnits); + setState("End") + } + + return + {state !== 'End' && } + {state === "Pull" && } + {state === "End" &&

Finished pulling data

} +
; +} + +const IndexProgress = () => { + return <>Index +} + +type DownloadProgressProps = { + onEnd: (data: PullData, errors: SyncError[]) => void +} + +const PullProgress = ({ onEnd }: DownloadProgressProps) => { + const { __ } = useTranslate(); + const { classes } = useStyles(); + const { progress, data, errors, status } = usePullData({ + onEnd: onEnd + }); + const progressBars = [{ + progress: progress.surveyUnits, + label: __('sync.surveyUnits') + }, + { + progress: progress.nomenclatures, + label: __('sync.nomenclatures') + }, + { + progress: progress.questionnaires, + label: __('sync.questionnaires') + }] + .filter(bar => bar.progress !== null) + + return <> + + {__('sync.progress')} + {__('sync.download')} + + + {progressBars.map(bar => + + + {bar.label} + + + )} + + +} + +const useStyles = tss + .create(() => ({ + lightText: { + opacity: .75, + }, + spinner: { + width: 200, + height: 200 + }, + progressBar: { + maxWidth: 700, + width: '80vw', + height: 10, + borderRadius: 10 + } + })); diff --git a/drama-queen/src/ui/pages/synchronize/index.ts b/drama-queen/src/ui/pages/synchronize-old/index.ts similarity index 100% rename from drama-queen/src/ui/pages/synchronize/index.ts rename to drama-queen/src/ui/pages/synchronize-old/index.ts diff --git a/drama-queen/src/ui/pages/synchronize/storeSyncProgress.ts b/drama-queen/src/ui/pages/synchronize-old/storeSyncProgress.ts similarity index 100% rename from drama-queen/src/ui/pages/synchronize/storeSyncProgress.ts rename to drama-queen/src/ui/pages/synchronize-old/storeSyncProgress.ts diff --git a/drama-queen/src/ui/pages/synchronize/SynchronizePage.tsx b/drama-queen/src/ui/pages/synchronize/SynchronizePage.tsx index 8a241b19..5d79f9a3 100644 --- a/drama-queen/src/ui/pages/synchronize/SynchronizePage.tsx +++ b/drama-queen/src/ui/pages/synchronize/SynchronizePage.tsx @@ -1,118 +1,92 @@ +import { useEffect, Fragment } from "react"; import LinearProgress from '@mui/material/LinearProgress'; import Typography from '@mui/material/Typography'; import Stack from '@mui/material/Stack'; -import { useTranslate } from "hooks/useTranslate"; -import preloader from 'ui/assets/preloader.svg'; +import { useCoreState, useCoreFunctions, useCoreEvts, selectors } from "core"; +import { useEvt } from "evt/hooks" import { tss } from "tss-react/mui"; -import { Fragment, useEffect, useState } from "react"; -import { type PullData, usePullData } from 'hooks/usePullData'; -import type { SurveyUnitWithId } from "core/ports/QueenApi/SurveyUnit"; -import { SyncError } from "hooks/queries/SyncError"; -import { storeSyncProgress } from "./storeSyncProgress"; -import { db } from 'core/indexedDb'; - -type SyncState = "Idle" | "Push" | "Pull" | "End"; - +import { useTranslate } from "hooks/useTranslate"; -export const SynchronizePage = () => { +export function SynchronizePage() { + const { __ } = useTranslate(); const { classes } = useStyles(); - const [state, setState] = useState("Pull") - useEffect(() => { - storeSyncProgress() - }, []); + /* refactor this when redux-clean-archi updated */ + const { isRunning: showProgress } = useCoreState(selectors.synchronizeData.isRunning); + const { uploadProgress } = useCoreState(selectors.synchronizeData.uploadProgress) + const { nomenclatureProgress } = useCoreState(selectors.synchronizeData.nomenclatureProgress); + const { surveyProgress } = useCoreState(selectors.synchronizeData.surveyProgress); + const { surveyUnitProgress } = useCoreState(selectors.synchronizeData.surveyUnitProgress) - const handlePullEnd = (data: PullData, errors: SyncError[]) => { - storeSyncProgress( - data, - errors - ) - db.surveyUnit.bulkAdd(data.surveyUnits); - setState("End") - } + const { synchronizeData } = useCoreFunctions(); - return - {state !== 'End' && } - {state === "Pull" && } - {state === "End" &&

Finished pulling data

} -
; -} + useEffect( + () => { + synchronizeData.startDownloading(); + }, [] + ); -const IndexProgress = () => { + const { evtSynchronizeData } = useCoreEvts(); - const testData = { - "id": "23", - "questionnaireId": "VQS2021X00", - "personalization": {}, - "data": { - "EXTERNAL": {}, - "COLLECTED": { - "NOM": { - "EDITED": null, - "FORCED": null, - "INPUTED": null, - "PREVIOUS": null, - "COLLECTED": null - }, - }, - "CALCULATED": {} + useEvt( + ctx => { + evtSynchronizeData.$attach( + data => data.action === "redirect" ? [data] : null, + ctx, + () => { + alert("redirect to " + window.location.href) + } + ); }, - "comment": {}, - "stateData": { - "state": "INIT", - "date": 1685457465071, - "currentPage": "19" - } - } satisfies SurveyUnitWithId + [] + ); + if (!showProgress) { + return null; + } - return <>Index -} -type DownloadProgressProps = { - onEnd: (data: PullData, errors: SyncError[]) => void -} + if (uploadProgress) { + return <>Uploading {uploadProgress} + } -const PullProgress = ({ onEnd }: DownloadProgressProps) => { - const { __ } = useTranslate(); - const { classes } = useStyles(); - const { progress, data, errors, status } = usePullData({ - onEnd: onEnd - }); const progressBars = [{ - progress: progress.surveyUnits, + progress: surveyProgress, label: __('sync.surveyUnits') }, { - progress: progress.nomenclatures, + progress: nomenclatureProgress, label: __('sync.nomenclatures') }, { - progress: progress.questionnaires, + progress: surveyUnitProgress, label: __('sync.questionnaires') }] .filter(bar => bar.progress !== null) + return ( + <> + + {__('sync.progress')} + {__('sync.download')} + + + {progressBars.map(bar => + + + {bar.label} + + + )} + + - return <> - - {__('sync.progress')} - {__('sync.download')} - - - {progressBars.map(bar => - - - {bar.label} - - - )} - - + ) } + const useStyles = tss .create(() => ({ lightText: { diff --git a/drama-queen/src/ui/routing/routes.tsx b/drama-queen/src/ui/routing/routes.tsx index 571fceb5..4d3dbf3e 100644 --- a/drama-queen/src/ui/routing/routes.tsx +++ b/drama-queen/src/ui/routing/routes.tsx @@ -2,10 +2,10 @@ import { DisplayEnvValues } from "ui/pages/env"; import { SurveyUnitMapping, VisualisationMapping } from "ui/pages/queenMapping"; import { READ_ONLY } from "ui/constants"; import type { RouteObject } from "react-router-dom"; -import { SynchronizePage } from "ui/pages/synchronize/SynchronizePage"; +import { SynchronizePage as SynchronizeOld } from "ui/pages/synchronize-old/SynchronizePage"; import { SurveyMapping } from "ui/pages/queenMapping/SuryveyMapping"; import { RequiresAuthentication } from "ui/auth"; -import { LoadingData } from "ui/pages/LoadingData"; +import { SynchronizePage } from "ui/pages/synchronize/SynchronizePage"; //ReadOnly path is a bad pattern must be change (affects pearl,moog,queen) export const routes: RouteObject[] = [ @@ -27,10 +27,10 @@ export const routes: RouteObject[] = [ }, { path: "/synchronize-old", - element: + element: }, { path: "/synchronize", - element: + element: } ] \ No newline at end of file