Skip to content

Commit

Permalink
Implemented progress bar for entities loader
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurczewski committed Oct 3, 2024
1 parent e1f15ac commit 88b5e53
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 18 deletions.
1 change: 1 addition & 0 deletions libs/generic-view/models/src/lib/entities-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof configValidator>
Expand Down
1 change: 1 addition & 0 deletions libs/generic-view/store/src/lib/entities/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface Entities {
data?: EntityData[]
metadata?: EntitiesMetadata
loading?: boolean
progress?: number
error?: boolean
}

Expand Down
28 changes: 23 additions & 5 deletions libs/generic-view/store/src/lib/selectors/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,35 @@ export const selectEntitiesLoadingState = createSelector(
(entities) => {
return Object.entries(entities).reduce(
(
acc: Record<string, "loading" | "loaded" | "idle" | "error">,
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
},
Expand Down
47 changes: 34 additions & 13 deletions libs/generic-view/ui/src/lib/entities/entities-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<undefined, EntitiesLoaderConfig> = ({
config,
Expand All @@ -28,30 +30,49 @@ export const EntitiesLoader: APIFC<undefined, EntitiesLoaderConfig> = ({
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<string, number> = {}

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 (
<Wrapper {...props}>
<SpinnerLoader dark />
</Wrapper>
<div {...props}>
{config.text && <H3>{config.text}</H3>}
<Progress config={{ maxValue: 100 }} data={{ value: totalProgress }} />
</div>
)
}

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

0 comments on commit 88b5e53

Please sign in to comment.