Newer
Older
import React, {
useState,
useEffect,
ComponentType,
ReactNode,
Dispatch,
} from 'react'
import { useClient } from 'cozy-client'
import classNames from 'classnames'
import { useDispatch } from 'react-redux'
toggleAnalysisNotification,
toggleChallengeExplorationNotification,
toggleChallengeActionNotification,
toggleChallengeDuelNotification,
import {
ProfileActionTypes,
updateProfile,
} from 'store/profile/profile.actions'
} from 'store/challenge/challenge.actions'
import { ChartActionTypes, setSelectedDate } from 'store/chart/chart.actions'
import InitializationService from 'services/initialization.service'
import { UserChallengeState } from 'enum/userChallenge.enum'
import { UserDuelState } from 'enum/userDuel.enum'
import ChallengeService from 'services/challenge.service'
import useExploration from 'components/Hooks/useExploration'
import {
UserExplorationID,
UserExplorationState,
} from 'enum/userExploration.enum'
import { DateTime } from 'luxon'
import { UserActionState } from 'enum/userAction.enum'
import ActionService from 'services/action.service'
interface SplashRootProps {
fadeTimer?: number
splashComponent: ComponentType
splashErrorComponent: ComponentType
children: ReactNode
}
/**
* Added splash screen if data is not ready
* @param params {{ fadeTimer, splashComponent, children }}
*/
const SplashRoot = ({
fadeTimer = 1000,
splashComponent: SplashComponent,
splashErrorComponent: SplashErrorComponent,
children,
}: SplashRootProps) => {
const client = useClient()
const [{ splashEnd, splashStart }, setState] = useState({
splashEnd: false,
splashStart: false,
})
const [error, setError] = useState<Error | null>(null)
const dispatch: Dispatch<
| ChallengeActionTypes
| ChartActionTypes
| GlobalActionTypes
| ProfileActionTypes
> = useDispatch()
useEffect(() => {
let timeoutSplash: NodeJS.Timeout
if (splashStart) {
timeoutSplash = setTimeout(() => {
setState(prev => ({ ...prev, splashEnd: true }))
}, fadeTimer)
}
return () => timeoutSplash && clearTimeout(timeoutSplash)
}, [splashStart, fadeTimer])
const [, setValidExploration] = useExploration()
useEffect(() => {
let subscribed = true
async function loadData() {
const initializationService = new InitializationService(client)
// Init profile and update ecogestures, challenges, analysis
const profile = await initializationService.initProfile()
setValidExploration(UserExplorationID.EXPLORATION007)
const [
ecogestureHash,
duelHash,
quizHash,
challengeHash,
explorationHash,
analysisResult,
] = await Promise.all([
initializationService.initEcogesture(profile.ecogestureHash),
initializationService.initDuelEntity(profile.duelHash),
initializationService.initQuizEntity(profile.quizHash),
initializationService.initExplorationEntity(profile.challengeHash),
initializationService.initChallengeEntity(profile.explorationHash),
initializationService.initAnalysis(profile),
])
profile.ecogestureHash = ecogestureHash
profile.duelHash = duelHash
profile.quizHash = quizHash
profile.challengeHash = challengeHash
profile.explorationHash = explorationHash
profile.monthlyAnalysisDate = analysisResult.monthlyAnalysisDate
profile.haveSeenLastAnalysis = analysisResult.haveSeenLastAnalysis
dispatch(toggleAnalysisNotification(!profile.haveSeenLastAnalysis))
// Init Fluid status && lastDate for the chart
const fluidStatus = await initializationService.initFluidStatus()
if (subscribed) {
dispatch(setFluidStatus(fluidStatus))
const refDate: DateTime = DateTime.fromISO('0001-01-01')
let lastDataDate: DateTime | null = DateTime.fromISO('0001-01-01')
for (const fluid of fluidStatus) {
if (fluid.lastDataDate && fluid.lastDataDate > lastDataDate) {
lastDataDate = fluid.lastDataDate
}
}
if (lastDataDate > refDate) {
dispatch(setSelectedDate(lastDataDate))
}
const userChallengeList = await initializationService.initUserChallenges(
fluidStatus
)
dispatch(setUserChallengeList(userChallengeList))
const filteredCurrentOngoingChallenge = userChallengeList.filter(
challenge => challenge.state === UserChallengeState.ONGOING
)
// Set Notification if exploration state is notification
if (
filteredCurrentOngoingChallenge[0] &&
filteredCurrentOngoingChallenge[0].exploration.state ===
UserExplorationState.NOTIFICATION
) {
// Set Notification if action state is notification
if (
filteredCurrentOngoingChallenge[0] &&
filteredCurrentOngoingChallenge[0].action.state ===
UserActionState.ONGOING
) {
const actionService = new ActionService(client)
const updatedUserChallenge: UserChallenge | null = await actionService.isActionDone(
filteredCurrentOngoingChallenge[0]
)
if (updatedUserChallenge) {
dispatch(updateUserChallengeList(updatedUserChallenge))
const filteredCurrentDuelChallenge = userChallengeList.filter(
challenge => challenge.state === UserChallengeState.DUEL
filteredCurrentDuelChallenge[0] &&
filteredCurrentDuelChallenge[0].duel.state === UserDuelState.ONGOING
} = await initializationService.initDuelProgress(
filteredCurrentDuelChallenge[0]
if (subscribed) {
dispatch(setChallengeConsumption(updatedUserChallenge, dataloads))
// Check is duel is done and display notification
const challengeService = new ChallengeService(client)
const { isDone } = await challengeService.isChallengeDone(
updatedUserChallenge,
dataloads
)
// Update state
setState(prev => ({
...prev,
splashStart: true,
}))
} catch (err) {
setError(err)
}
}
loadData()
return () => {
subscribed = false
}
}, [client, dispatch, setValidExploration])
return (
<>
{!splashEnd && (
<div
style={{ transitionDuration: `${fadeTimer / 1000}s` }}
className={classNames('splash-root', {
['splash-fade']: splashStart,
})}
>
{!error ? <SplashComponent /> : <SplashErrorComponent />}
</div>
)}
{splashStart && children}
</>
)
}
export default SplashRoot