From 88b5e53e9622cd95a0ef7350c8ae41279335fcf9 Mon Sep 17 00:00:00 2001 From: mkurczewski Date: Thu, 3 Oct 2024 17:35:23 +0200 Subject: [PATCH] Implemented progress bar for entities loader --- .../models/src/lib/entities-loader.ts | 1 + .../store/src/lib/entities/reducer.ts | 1 + .../store/src/lib/selectors/entities.ts | 28 +++++++++-- .../ui/src/lib/entities/entities-loader.tsx | 47 ++++++++++++++----- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/libs/generic-view/models/src/lib/entities-loader.ts b/libs/generic-view/models/src/lib/entities-loader.ts index d5f630c6d8..52c649a21b 100644 --- a/libs/generic-view/models/src/lib/entities-loader.ts +++ b/libs/generic-view/models/src/lib/entities-loader.ts @@ -9,6 +9,7 @@ const dataValidator = z.undefined() const configValidator = z.object({ entitiesTypes: z.array(z.string()), + text: z.string().optional(), }) export type EntitiesLoaderConfig = z.infer diff --git a/libs/generic-view/store/src/lib/entities/reducer.ts b/libs/generic-view/store/src/lib/entities/reducer.ts index 3a6beed822..1e3f45cc30 100644 --- a/libs/generic-view/store/src/lib/entities/reducer.ts +++ b/libs/generic-view/store/src/lib/entities/reducer.ts @@ -25,6 +25,7 @@ interface Entities { data?: EntityData[] metadata?: EntitiesMetadata loading?: boolean + progress?: number error?: boolean } diff --git a/libs/generic-view/store/src/lib/selectors/entities.ts b/libs/generic-view/store/src/lib/selectors/entities.ts index afb6c943f7..7c1f445094 100644 --- a/libs/generic-view/store/src/lib/selectors/entities.ts +++ b/libs/generic-view/store/src/lib/selectors/entities.ts @@ -57,17 +57,35 @@ export const selectEntitiesLoadingState = createSelector( (entities) => { return Object.entries(entities).reduce( ( - acc: Record, + acc: Record< + string, + | { state: "error" } + | { + state: "loading" | "loaded" | "idle" + progress: number + } + >, [entitiesType, entity] ) => { if (entity?.error) { - acc[entitiesType] = "error" + acc[entitiesType] = { + state: "error", + } } else if (entity?.metadata?.totalEntities === 0 || entity?.data) { - acc[entitiesType] = "loaded" + acc[entitiesType] = { + state: "loaded", + progress: 100, + } } else if (entity?.loading) { - acc[entitiesType] = "loading" + acc[entitiesType] = { + state: "loading", + progress: entity.progress || 0, + } } else { - acc[entitiesType] = "idle" + acc[entitiesType] = { + state: "idle", + progress: 0, + } } return acc }, diff --git a/libs/generic-view/ui/src/lib/entities/entities-loader.tsx b/libs/generic-view/ui/src/lib/entities/entities-loader.tsx index 7e18ed42c2..34794d8bd9 100644 --- a/libs/generic-view/ui/src/lib/entities/entities-loader.tsx +++ b/libs/generic-view/ui/src/lib/entities/entities-loader.tsx @@ -3,7 +3,7 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import React, { useEffect } from "react" +import React, { useEffect, useState } from "react" import { APIFC } from "generic-view/utils" import { EntitiesLoaderConfig } from "generic-view/models" import { @@ -13,8 +13,10 @@ import { } from "generic-view/store" import { useDispatch, useSelector } from "react-redux" import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store" -import { SpinnerLoader } from "../shared/spinner-loader" import styled from "styled-components" +import { H3 } from "../texts/headers" +import { ProgressBar } from "../interactive/progress-bar/progress-bar" +import { sum } from "lodash" export const EntitiesLoader: APIFC = ({ config, @@ -28,30 +30,49 @@ export const EntitiesLoader: APIFC = ({ selectEntitiesLoadingState(state, { deviceId }) ) const allLoaded = config.entitiesTypes.every( - (entitiesType) => entitiesLoadingStates[entitiesType] === "loaded" + (entitiesType) => entitiesLoadingStates[entitiesType].state === "loaded" ) + const [showProgress, setShowProgress] = useState(!allLoaded) + const [totalProgress, setTotalProgress] = useState(0) useEffect(() => { + const progress: Record = {} + for (const entitiesType of config.entitiesTypes) { - if (entitiesLoadingStates[entitiesType] === "idle") { + const entity = entitiesLoadingStates[entitiesType] + if (entity.state === "idle") { + progress[entitiesType] = 0 dispatch(getEntitiesDataAction({ entitiesType, deviceId })) + } else if (entity.state === "loading" || entity.state === "loaded") { + progress[entitiesType] = entity.progress } } + setTotalProgress( + sum(Object.values(progress)) / Object.keys(progress).length + ) }, [config.entitiesTypes, deviceId, dispatch, entitiesLoadingStates]) - if (allLoaded) { + useEffect(() => { + let timeout: NodeJS.Timeout + if (allLoaded) { + timeout = setTimeout(() => setShowProgress(false), 300) + } + return () => { + clearTimeout(timeout) + } + }, [allLoaded]) + + if (!showProgress) { return children } return ( - - - +
+ {config.text &&

{config.text}

} + +
) } -const Wrapper = styled.div` - & > * { - width: 5rem; - height: 5rem; - } +const Progress = styled(ProgressBar)` + max-width: 22.3rem; `