Skip to content
Snippets Groups Projects
SplashRoot.tsx 7.65 KiB
Newer Older
  • Learn to ignore specific revisions
  • import React, {
      useState,
      useEffect,
      ComponentType,
      ReactNode,
      Dispatch,
    } from 'react'
    
    import { useClient } from 'cozy-client'
    import classNames from 'classnames'
    
    import { useDispatch } from 'react-redux'
    
    Hugo's avatar
    Hugo committed
      toggleAnalysisNotification,
      toggleChallengeExplorationNotification,
      toggleChallengeActionNotification,
      toggleChallengeDuelNotification,
    
      setFluidStatus,
    
      GlobalActionTypes,
    
    } from 'store/global/global.actions'
    
    import {
      ProfileActionTypes,
      updateProfile,
    } from 'store/profile/profile.actions'
    
      setUserChallengeList,
    
      setChallengeConsumption,
    
      updateUserChallengeList,
    
      ChallengeActionTypes,
    
    } from 'store/challenge/challenge.actions'
    
    import { ChartActionTypes, setSelectedDate } from 'store/chart/chart.actions'
    
    import InitializationService from 'services/initialization.service'
    
    import './splashRoot.scss'
    
    import { UserChallengeState } from 'enum/userChallenge.enum'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    import { UserDuelState } from 'enum/userDuel.enum'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    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'
    
    import { UserChallenge } from 'models'
    
    
    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 index
    
            await initializationService.initIndex()
    
            // Init profile and update ecogestures, challenges, analysis
    
            const profile = await initializationService.initProfile()
    
            if (subscribed && profile) {
    
              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(updateProfile(profile))
    
    Hugo's avatar
    Hugo committed
              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))
              }
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
            const userChallengeList = await initializationService.initUserChallenges(
              fluidStatus
            )
    
            if (subscribed) {
    
              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
              ) {
    
    Hugo's avatar
    Hugo committed
                dispatch(toggleChallengeExplorationNotification(true))
    
              // 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))
    
    Hugo's avatar
    Hugo committed
                  dispatch(toggleChallengeActionNotification(true))
    
    Yoan VALLET's avatar
    Yoan VALLET committed
              const filteredCurrentDuelChallenge = userChallengeList.filter(
                challenge => challenge.state === UserChallengeState.DUEL
    
    Yoan VALLET's avatar
    Yoan VALLET committed
                filteredCurrentDuelChallenge[0] &&
                filteredCurrentDuelChallenge[0].duel.state === UserDuelState.ONGOING
    
                  updatedUserChallenge,
    
    Yoan VALLET's avatar
    Yoan VALLET committed
                } = 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
                  )
    
    Hugo's avatar
    Hugo committed
                  dispatch(toggleChallengeDuelNotification(isDone))
    
            // 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