import React, { useState, useEffect } from 'react' import { withClient, Client } from 'cozy-client' import { FluidType } from 'enum/fluid.enum' import { ScreenType } from 'enum/screen.enum' import InitDataManager from 'services/initDataManagerService' import UserProfileDataManager from 'services/userProfileDataManagerService' import { UserChallenge, UserProfile } from 'services/dataChallengeContracts' interface AppContextProps { isIndexesLoading: boolean isIndexesLoadingSuccess: boolean | null isDataLoading: boolean isDataLoadingSuccess: boolean | null isFluidTypesLoading: boolean isFluidTypesLoadingSuccess: boolean | null fluidTypes: FluidType[] refreshFluidTypes: Function isCurrentChallengeUpdateLoading: boolean isCurrentChallengeUpdateLoadingSuccess: boolean | null currentChallenge: UserChallenge | null challengeNotification: boolean refreshCurrentChallenge: Function isContextLoaded: boolean isError: boolean screenType: ScreenType userProfile: UserProfile | null setWelcomeModalViewed: Function } export const AppContext = React.createContext<AppContextProps>({ isIndexesLoading: false, isIndexesLoadingSuccess: null, isDataLoading: false, isDataLoadingSuccess: null, isFluidTypesLoading: false, isFluidTypesLoadingSuccess: null, fluidTypes: [], refreshFluidTypes: () => null, isCurrentChallengeUpdateLoading: false, isCurrentChallengeUpdateLoadingSuccess: null, currentChallenge: null, challengeNotification: false, refreshCurrentChallenge: () => Promise, isContextLoaded: false, isError: false, screenType: ScreenType.MOBILE, userProfile: null, setWelcomeModalViewed: () => null, }) interface AppContextProviderProps { children: React.ReactNode client: Client } const AppContextProvider: React.FC<AppContextProviderProps> = ({ children, client, }: AppContextProviderProps) => { const [isIndexesLoading, setIndexesLoading] = useState<boolean>(false) const [isIndexesLoadingSuccess, setIndexesLoadingSuccess] = useState< boolean | null >(null) const [isDataLoading, setDataLoading] = useState<boolean>(false) const [isDataLoadingSuccess, setDataLoadingSuccess] = useState< boolean | null >(null) const [isFluidTypesLoading, setFluidTypesLoading] = useState<boolean>(false) const [isFluidTypesLoadingSuccess, setFluidTypesLoadingSuccess] = useState< boolean | null >(null) const [fluidTypes, setFluidTypes] = useState<FluidType[]>([]) const [ isCurrentChallengeUpdateLoading, setCurrentChallengeUpdateLoading, ] = useState<boolean>(false) const [ isCurrentChallengeUpdateLoadingSuccess, setCurrentChallengeUpdateLoadingSuccess, ] = useState<boolean | null>(null) const [ currentChallenge, setCurrentChallenge, ] = useState<UserChallenge | null>(null) const [challengeNotification, setChallengeNotification] = useState<boolean>( false ) const [isContextLoaded, setContextLoaded] = useState<boolean>(false) const [isError, setError] = useState<boolean>(false) const [screenType, setScreenType] = useState<ScreenType>(ScreenType.MOBILE) const [isUserProfileLoadingSuccess, setUserProfileLoadingSuccess] = useState< boolean | null >(null) const [userProfile, setUserProfile] = useState<UserProfile | null>(null) const defineScreenType = () => { if (screen.width <= 768) { setScreenType(ScreenType.MOBILE) } else if (screen.width <= 1024) { setScreenType(ScreenType.TABLET) } else { setScreenType(ScreenType.DESKTOP) } } const refreshFluidTypes = async () => { const im = new InitDataManager(client) const resultFluidTypes = await im.checkFluidTypes() if (resultFluidTypes) { setFluidTypes(resultFluidTypes) const resultAchievement = await im.checkAchievement('CHA00000001') if (resultAchievement) { const resultNotificationChallenge = await im.isCurrentChallengeOver( resultAchievement, resultFluidTypes ) if (resultNotificationChallenge) { setChallengeNotification(resultNotificationChallenge) } } } } const setWelcomeModalViewed = async () => { const upm = new UserProfileDataManager(client) const updatedUserProfile = await upm.updateUserProfile({ haveSeenWelcomeModal: true, }) if (updatedUserProfile) { setUserProfile(updatedUserProfile) } } const refreshCurrentChallenge = async (): Promise<boolean> => { const im = new InitDataManager(client) try { const resultUpdateChallenge = await im.checkCurrentChallenge(fluidTypes) setCurrentChallenge(resultUpdateChallenge) if (resultUpdateChallenge) { const resultNotificationChallenge = await im.isCurrentChallengeOver( resultUpdateChallenge, fluidTypes ) if (resultNotificationChallenge) { setChallengeNotification(resultNotificationChallenge) } } else { setChallengeNotification(false) } return true } catch { setCurrentChallenge(null) setChallengeNotification(false) return false } } useEffect(() => { let subscribed = true function handleResize() { defineScreenType() } handleResize() window.addEventListener('resize', handleResize) const im = new InitDataManager(client) const updm = new UserProfileDataManager(client) async function loadData() { // Create missing indexes setIndexesLoading(true) const resultIndexConsoData = await im.initIndex() if (subscribed && !resultIndexConsoData) { setIndexesLoadingSuccess(false) setError(true) } if (subscribed && resultIndexConsoData) { console.log( '%c Context: Indexes created', 'background: #222; color: white' ) setIndexesLoadingSuccess(true) } setIndexesLoading(false) // Load challenges, ecogestures and user profile data setDataLoading(true) const resultInitData = await im.initData() if (subscribed && !resultInitData) { setDataLoadingSuccess(false) setError(true) } if (subscribed && resultInitData) { setDataLoadingSuccess(true) } setDataLoading(false) // Load configured fluidTypes setFluidTypesLoading(true) const resultFluidTypes = await im.checkFluidTypes() if (subscribed && resultFluidTypes) { console.log( '%c Context: Konnectors loaded ', 'background: #222; color: white' ) setFluidTypes(resultFluidTypes) setFluidTypesLoadingSuccess(true) } setFluidTypesLoading(false) // Update current challenge if exists setCurrentChallengeUpdateLoading(true) try { const resultUpdateChallenge = await im.checkCurrentChallenge( resultFluidTypes ? resultFluidTypes : [] ) if (subscribed && resultUpdateChallenge) { const resultNotificationChallenge = await im.isCurrentChallengeOver( resultUpdateChallenge, resultFluidTypes ? resultFluidTypes : [] ) if (subscribed && resultNotificationChallenge) { setChallengeNotification(resultNotificationChallenge) } } if (subscribed) { console.log( '%c Context: Current Challenge checked', 'background: #222; color: white' ) setCurrentChallenge(resultUpdateChallenge) setCurrentChallengeUpdateLoadingSuccess(true) } } catch { setCurrentChallengeUpdateLoadingSuccess(false) setError(true) } finally { setCurrentChallengeUpdateLoading(false) } //Retrieve the UserProfile const loadedUserProfile = await updm.getUserProfile() if (!loadedUserProfile) { setError(true) } if (subscribed && loadedUserProfile) { console.log( '%c Context: UserProfile Loaded', 'background: #222; color: white' ) setUserProfile(loadedUserProfile) setUserProfileLoadingSuccess(true) } } loadData() return () => { subscribed = false window.removeEventListener('resize', handleResize) } }, []) useEffect(() => { if ( isIndexesLoadingSuccess && isDataLoadingSuccess && isFluidTypesLoadingSuccess && isCurrentChallengeUpdateLoadingSuccess && isUserProfileLoadingSuccess && !isError ) { setTimeout(function() { setContextLoaded(true) }, 1000) } }, [ isIndexesLoadingSuccess, isDataLoadingSuccess, isFluidTypesLoadingSuccess, isCurrentChallengeUpdateLoadingSuccess, isUserProfileLoadingSuccess, isError, ]) return ( <AppContext.Provider value={{ isIndexesLoading, isIndexesLoadingSuccess, isDataLoading, isDataLoadingSuccess, isFluidTypesLoading, isFluidTypesLoadingSuccess, fluidTypes, refreshFluidTypes, isCurrentChallengeUpdateLoading, isCurrentChallengeUpdateLoadingSuccess, currentChallenge, challengeNotification, refreshCurrentChallenge, isContextLoaded, isError, screenType, userProfile, setWelcomeModalViewed, }} > {children} </AppContext.Provider> ) } export default withClient(AppContextProvider)