diff --git a/package.json b/package.json index d0344861d4dea23b585dd0e8a084f4d2c3b9ae46..0809a2eb723c2640fb15a33649b6fa5643adc407 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "homepage": "https://forge.grandlyon.com/web-et-numerique/llle_project/ecolyo#readme", "devDependencies": { "@babel/preset-typescript": "^7.7.4", + "@types/classnames": "^2.2.10", "@types/d3": "^5.7.2", "@types/lodash": "^4.14.149", "@types/luxon": "^1.21.0", @@ -104,6 +105,7 @@ "react-lottie": "^1.2.3", "react-router-dom": "5.2.0", "react-swipeable-views": "0.13.4", + "recoil": "^0.0.13", "sass-loader": "^8.0.0" }, "husky": { diff --git a/src/atoms/challenge.state.ts b/src/atoms/challenge.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a396a8b22102fc8c277aa60e21cba9245c152cf --- /dev/null +++ b/src/atoms/challenge.state.ts @@ -0,0 +1,7 @@ +import { atom } from 'recoil' +import { UserChallenge } from 'models' + +export const currentChallengeState = atom<UserChallenge | null>({ + key: 'currentChallengeState', + default: null, +}) diff --git a/src/atoms/fluidState.state.ts b/src/atoms/fluidState.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..abcd30e621bc6d2ff07e627f9f556a045d03b0df --- /dev/null +++ b/src/atoms/fluidState.state.ts @@ -0,0 +1,29 @@ +import { atom } from 'recoil' +import { FluidType } from 'enum/fluid.enum' +import { FluidStatus } from 'models' + +export const fluidTypeState = atom<FluidType[]>({ + key: 'fluidState', + default: [], +}) + +export const fluidSatusState = atom<FluidStatus[]>({ + key: 'fluidState', + default: [ + { + fluidType: 0, + status: null, + lastDataDate: null, + }, + { + fluidType: 1, + status: null, + lastDataDate: null, + }, + { + fluidType: 2, + status: null, + lastDataDate: null, + }, + ], +}) diff --git a/src/atoms/initialization.state.ts b/src/atoms/initialization.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..79f243454c3265f80fec3c9e75db42fd72650152 --- /dev/null +++ b/src/atoms/initialization.state.ts @@ -0,0 +1,18 @@ +import { atom, selectorFamily } from 'recoil' +import InitializationService from 'services/initialization.service' + +export const initializationSelector = selectorFamily({ + key: 'InitSelector', + get: client => async () => { + if (client) { + const initializationService = new InitializationService(client) + return await initializationService.initialization() + } + return false + }, +}) + +export const initializationState = atom<boolean>({ + key: 'initializationState', + default: initializationSelector(null), +}) diff --git a/src/atoms/notification.state.ts b/src/atoms/notification.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..1065bca143e112e2f32cdec8dffba43f26712d85 --- /dev/null +++ b/src/atoms/notification.state.ts @@ -0,0 +1,6 @@ +import { atom } from 'recoil' + +export const challengeNotificationState = atom<boolean>({ + key: 'challengeNotificationState', + default: false, +}) diff --git a/src/atoms/screenTypeState.state.ts b/src/atoms/screenTypeState.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dd09e49e2669a24c454373c52a22ad98ca0e6fe --- /dev/null +++ b/src/atoms/screenTypeState.state.ts @@ -0,0 +1,7 @@ +import { ScreenType } from 'enum/screen.enum' +import { atom } from 'recoil' + +export const screenTypeState = atom<ScreenType>({ + key: 'screenTypeState', + default: ScreenType.DESKTOP, +}) diff --git a/src/atoms/userProfile.state.ts b/src/atoms/userProfile.state.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ee27c403e94d72ce2467d53869f773e23a3ea4c --- /dev/null +++ b/src/atoms/userProfile.state.ts @@ -0,0 +1,21 @@ +import { UserProfile } from 'models' +import { atom, selector } from 'recoil' + +export const userProfileState = atom<UserProfile>({ + key: 'userProfileState', + default: { + id: '', + level: 0, + challengeTypeHash: '', + ecogestureHash: '', + haveSeenWelcomeModal: false, + notificationEcogesture: [], + report: false, + }, +}) + +export const proxyUserProfileSelector = selector<any>({ + key: 'ProxyUserProfileSelector', + get: ({ get }) => get(userProfileState), + set: ({ set }, newValue) => set(userProfileState, newValue), +}) diff --git a/src/components/App.jsx b/src/components/App.jsx index 39fda658ad41d39c84e008a0a0fd48bc2b87a440..61bcd4be56df8def8282ff176027a28ab951ee06 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -1,9 +1,45 @@ import React from 'react' import { hot } from 'react-hot-loader' -import ViewContainer from 'components/ContainerComponents/ViewContainer/ViewContainer' +import { RecoilRoot } from 'recoil' +import { HashRouter } from 'react-router-dom' +import { createBrowserHistory } from 'history' +import { Layout, Main, Content } from 'cozy-ui/transpiled/react/Layout' +import { Sprite as IconSprite } from 'cozy-ui/transpiled/react/Icon' + +import Routes from 'components/Routes/Routes' +import Navbar from 'components/ContentComponents/Navbar/Navbar' +import ScrollToTop from 'components/ContainerComponents/ScrollToTop/ScrollToTop' +import FeedbackContainer from 'components/ContainerComponents/FeedbackContainer/FeedbackContainer' +import SplashRoot from './ContentComponents/Splash/SplashRoot' +import SplashScreen from 'components/ContentComponents/Splash/SplashScreen' +import SplashScreenError from 'components/ContentComponents/Splash/SplashScreenError' + +export const history = createBrowserHistory() export const App = () => { - return <ViewContainer /> + return ( + <HashRouter {...history}> + <Layout> + <RecoilRoot> + <SplashRoot + splashComponent={SplashScreen} + splashErrorComponent={SplashScreenError} + > + <Navbar /> + <Main> + <FeedbackContainer /> + <Content className="app-content"> + <ScrollToTop> + <Routes /> + </ScrollToTop> + </Content> + </Main> + <IconSprite /> + </SplashRoot> + </RecoilRoot> + </Layout> + </HashRouter> + ) } /* diff --git a/src/components/ContainerComponents/Content/Content.tsx b/src/components/ContainerComponents/Content/Content.tsx index 717da9b382fccb6c7ba2c62c19897176515a9ea0..3a9b90d3334602195941afffc8e88cf001b8880e 100644 --- a/src/components/ContainerComponents/Content/Content.tsx +++ b/src/components/ContainerComponents/Content/Content.tsx @@ -1,7 +1,13 @@ -import React, { useContext } from 'react' -import { AppContext } from 'components/Contexts/AppContextProvider' +import React, { useCallback, useEffect } from 'react' +import { useClient } from 'cozy-client' +import { useRecoilState } from 'recoil' + import { ScreenType } from 'enum/screen.enum' -import SplashContainer from '../SplashContainer/SplashContainer' +import { UserProfile } from 'models' +import { userProfileState } from 'atoms/userProfile.state' +import { screenTypeState } from 'atoms/screenTypeState.state' +import UserProfileService from 'services/userProfile.service' + import WelcomeModalContainer from '../WelcomeModalContainer/WelcomeModalContainer' interface ContentProps { @@ -15,36 +21,63 @@ const Content: React.FC<ContentProps> = ({ height = 0, background = 'inherit', }: ContentProps) => { - const { - isContextLoaded, - screenType, - userProfile, - setWelcomeModalViewed, - } = useContext(AppContext) + const client = useClient() const cozyBarHeight = 48 const cozyNavHeight = 56 + + const [screenType, setScreenType] = useRecoilState<ScreenType>( + screenTypeState + ) + const [userProfile, setUserProfile] = useRecoilState<UserProfile>( + userProfileState + ) + + const setWelcomeModalViewed = useCallback(() => { + const userProfileService = new UserProfileService(client) + userProfileService + .updateUserProfile({ haveSeenWelcomeModal: true }) + .then(updatedUserProfile => { + updatedUserProfile && setUserProfile(updatedUserProfile) + }) + }, [setUserProfile]) + + useEffect(() => { + function handleResize() { + if (innerWidth <= 768) { + setScreenType(ScreenType.MOBILE) + } else if (innerWidth <= 1024) { + setScreenType(ScreenType.TABLET) + } else { + setScreenType(ScreenType.DESKTOP) + } + } + handleResize() + window.addEventListener('resize', handleResize) + return () => { + window.removeEventListener('resize', handleResize) + } + }, []) + return ( <> - {!isContextLoaded ? ( - <SplashContainer /> - ) : userProfile && !userProfile.haveSeenWelcomeModal ? ( - <WelcomeModalContainer handleClose={setWelcomeModalViewed} /> - ) : ( - <div - className="content-view" - style={{ - marginTop: height, - paddingBottom: 0, - minHeight: - screenType !== ScreenType.DESKTOP - ? `calc(100vh - ${height}px - ${cozyBarHeight}px - ${cozyNavHeight}px)` - : `unset`, - background: background, - }} - > - {children} - </div> - )} + <WelcomeModalContainer + open={!userProfile.haveSeenWelcomeModal} + handleClose={setWelcomeModalViewed} + /> + <div + className="content-view" + style={{ + marginTop: height, + paddingBottom: 0, + minHeight: + screenType !== ScreenType.DESKTOP + ? `calc(100vh - ${height}px - ${cozyBarHeight}px - ${cozyNavHeight}px)` + : `unset`, + background: background, + }} + > + {children} + </div> </> ) } diff --git a/src/components/ContainerComponents/SplashContainer/SplashContainer.tsx b/src/components/ContainerComponents/SplashContainer/SplashContainer.tsx deleted file mode 100644 index 99afbaecc324ff03d0a1ee0aada6a858c0f93caf..0000000000000000000000000000000000000000 --- a/src/components/ContainerComponents/SplashContainer/SplashContainer.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useContext } from 'react' -import Lottie from 'react-lottie' -import { translate } from 'cozy-ui/react/I18n' -import { AppContext } from 'components/Contexts/AppContextProvider' -import StyledButton from 'components/CommonKit/Button/StyledButton' - -import * as loadingData from 'assets/anims/splash.json' - -const loadingOptions = { - loop: true, - autoplay: true, - animationData: loadingData, - rendererSettings: { - preserveAspectRatio: 'xMidYMid slice', - }, -} - -interface SplashContainerProps { - t: Function -} - -const SplashContainer: React.FC<SplashContainerProps> = ({ - t, -}: SplashContainerProps) => { - const appContext = useContext(AppContext) - - return ( - <div className="splash-root"> - <div className="splash-content"> - <Lottie - options={loadingOptions} - height={300} - width={300} - isStopped={appContext.isError} - /> - </div> - <div className="splash-footer"> - {appContext.isError && ( - <> - <div className="splash-footer-error-text text-16-normal"> - {t('LOADING.ERROR_LOADING')} - </div> - <StyledButton - className="splash-footer-button" - onClick={() => window.location.reload()} - > - {t('LOADING.RELOAD')} - </StyledButton> - </> - )} - </div> - </div> - ) -} - -export default translate()(SplashContainer) diff --git a/src/components/ContainerComponents/WelcomeModalContainer/WelcomeModalContainer.tsx b/src/components/ContainerComponents/WelcomeModalContainer/WelcomeModalContainer.tsx index 247efaefa0b1e89e5af9279f960ba1cea67104b7..7764d0850a6528f5ac998a68e6eb5999ab0494b3 100644 --- a/src/components/ContainerComponents/WelcomeModalContainer/WelcomeModalContainer.tsx +++ b/src/components/ContainerComponents/WelcomeModalContainer/WelcomeModalContainer.tsx @@ -6,12 +6,14 @@ import { translate } from 'cozy-ui/react/I18n' import userInstanceSettings from 'components/Hooks/userInstanceSettings' interface WelcomeModalContainerProps { + open: boolean handleClose: () => void t: Function client: Client } const WelcomeModalContainer: React.FC<WelcomeModalContainerProps> = ({ + open, handleClose, t, client, @@ -20,7 +22,7 @@ const WelcomeModalContainer: React.FC<WelcomeModalContainerProps> = ({ return ( <React.Fragment> - <Modal open={true} handleCloseClick={handleClose} yellowBorder={true}> + <Modal open={open} handleCloseClick={handleClose} yellowBorder={true}> <div className="wm-header text-24-bold"> {t('COMMON.WELCOME_MODAL_TITLE')} </div> diff --git a/src/components/ContentComponents/Splash/SplashRoot.tsx b/src/components/ContentComponents/Splash/SplashRoot.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1a523f6bd7e5f258a0d3c48407cfbc60cc2c3d87 --- /dev/null +++ b/src/components/ContentComponents/Splash/SplashRoot.tsx @@ -0,0 +1,126 @@ +import React, { useState, useEffect, ComponentType, ReactNode } from 'react' +import { useClient } from 'cozy-client' +import { useSetRecoilState } from 'recoil' +import classNames from 'classnames' +import { fluidSatusState, fluidTypeState } from 'atoms/fluidState.state' +import { userProfileState } from 'atoms/userProfile.state' +import { currentChallengeState } from 'atoms/challenge.state' +import { challengeNotificationState } from 'atoms/notification.state' +import InitializationService from 'services/initialization.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 setUserProfile = useSetRecoilState(userProfileState) + const setFluidTypeState = useSetRecoilState(fluidTypeState) + const setFluidSatusState = useSetRecoilState(fluidSatusState) + const setCurrentChallengeState = useSetRecoilState(currentChallengeState) + const setChallengeNotificationState = useSetRecoilState( + challengeNotificationState + ) + + useEffect(() => { + let timeoutSplash: NodeJS.Timeout + if (splashStart) { + timeoutSplash = setTimeout(() => { + setState(prev => ({ ...prev, splashEnd: true })) + }, fadeTimer) + } + return () => timeoutSplash && clearTimeout(timeoutSplash) + }, [splashStart, fadeTimer]) + + useEffect(() => { + let subscribed = true + const initializationService = new InitializationService(client) + async function loadData() { + try { + await initializationService.initIndex() + let profile = await initializationService.initUserProfile() + if (subscribed && profile) { + const resultChallengeType = await initializationService.initChallengeType( + profile.challengeTypeHash + ) + if ( + subscribed && + resultChallengeType.result && + resultChallengeType.userProfile + ) { + profile = resultChallengeType.userProfile + } + const resultEcogesture = await initializationService.initEcogesture( + profile.ecogestureHash + ) + if ( + subscribed && + resultEcogesture.result && + resultEcogesture.userProfile + ) { + profile = resultEcogesture.userProfile + } + setUserProfile(profile) + await initializationService.initUserChallenge() + const fluidTypes = await initializationService.initFluidTypes() + setFluidTypeState(fluidTypes) + const fluidStatus = await initializationService.initFluidStatus() + setFluidSatusState(fluidStatus) + const currentChallenge = await initializationService.initCurrentChallenge() + if (currentChallenge) { + setCurrentChallengeState(currentChallenge) + const isChallengeOver = await initializationService.isCurrentChallengeOver( + currentChallenge, + fluidTypes + ) + setChallengeNotificationState(isChallengeOver) + } + setState(prev => ({ + ...prev, + splashStart: true, + })) + } + } catch (err) { + setError(err) + } + } + loadData() + return () => { + subscribed = false + } + }, []) + + return ( + <> + {!splashEnd && ( + <div + style={{ transitionDuration: `${fadeTimer / 1000}s` }} + className={classNames('splash-root', { + ['splash-fade']: splashStart, + })} + > + {!error ? <SplashComponent /> : <SplashErrorComponent />} + </div> + )} + {splashStart && children} + </> + ) +} +export default SplashRoot diff --git a/src/components/ContentComponents/Splash/SplashScreen.tsx b/src/components/ContentComponents/Splash/SplashScreen.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e7d587555f91bf82bf286bc4388e433b9179bc0c --- /dev/null +++ b/src/components/ContentComponents/Splash/SplashScreen.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import Lottie from 'react-lottie' + +import * as loadingData from 'assets/anims/splash.json' + +const loadingOptions = { + loop: true, + autoplay: true, + animationData: loadingData, + rendererSettings: { + preserveAspectRatio: 'xMidYMid slice', + }, +} + +const SplashScreen: React.FC = () => { + return ( + <> + <div className="splash-content"> + <Lottie options={loadingOptions} height={300} width={300} /> + </div> + <div className="splash-footer"></div> + </> + ) +} + +export default SplashScreen diff --git a/src/components/ContentComponents/Splash/SplashScreenError.tsx b/src/components/ContentComponents/Splash/SplashScreenError.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e3b1e2b3d8433ad64058514bff0825495f937cb3 --- /dev/null +++ b/src/components/ContentComponents/Splash/SplashScreenError.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import Lottie from 'react-lottie' +import { translate } from 'cozy-ui/react/I18n' +import StyledButton from 'components/CommonKit/Button/StyledButton' + +import * as loadingData from 'assets/anims/splash.json' + +const loadingOptions = { + loop: false, + autoplay: false, + animationData: loadingData, + rendererSettings: { + preserveAspectRatio: 'xMidYMid slice', + }, +} + +interface SplashScreenErrorProps { + t: Function +} + +const SplashScreenError: React.FC<SplashScreenErrorProps> = ({ + t, +}: SplashScreenErrorProps) => { + return ( + <> + <div className="splash-content"> + <Lottie options={loadingOptions} height={300} width={300} /> + </div> + <div className="splash-footer"> + <div className="splash-footer-error-text text-16-normal"> + {t('LOADING.ERROR_LOADING')} + </div> + <StyledButton + className="splash-footer-button" + onClick={() => window.location.reload()} + > + {t('LOADING.RELOAD')} + </StyledButton> + </div> + </> + ) +} + +export default translate()(SplashScreenError) diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0b5d64fea1a51c4304365d99f4cdc0f7ff512741 --- /dev/null +++ b/src/components/Routes/Routes.tsx @@ -0,0 +1,94 @@ +import React from 'react' +import { Route, Switch, Redirect } from 'react-router-dom' +import { FluidType } from 'enum/fluid.enum' + +import HomeViewContainer from 'components/ContainerComponents/ViewContainer/HomeViewContainer' +import ChallengesViewContainer from 'components/ContainerComponents/ViewContainer/ChallengesViewContainer' +import SingleFluidViewContainer from 'components/ContainerComponents/ViewContainer/SingleFluidViewContainer' +import ParametersViewContainer from 'components/ContainerComponents/ViewContainer/ParametersViewContainer' +import FAQViewContainer from 'components/ContainerComponents/ViewContainer/FAQViewContainer' +import FinishedChallengeDetailsViewContainer from 'components/ContainerComponents/ViewContainer/FinishedChallengeDetailsViewContainer' +import OngoingChallengeDetailsViewContainer from 'components/ContainerComponents/ViewContainer/OngoingChallengeDetailsViewContainer' +import LockedChallengeDetailsViewContainer from 'components/ContainerComponents/ViewContainer/LockedChallengeDetailsViewContainer' +import AvailableChallengeDetailsViewContainer from 'components/ContainerComponents/ViewContainer//AvailableChallengeDetailsViewContainer' +import LegalNoticeViewContainer from 'components/ContainerComponents/ViewContainer/LegalNoticeViewContainer' +import EcogesturesContainer from 'components/ContainerComponents/EcogestureContainer/EcogesturesContainer' +import ProfileViewContainer from 'components/ContainerComponents/ViewContainer/ProfileViewContainer' + +const Routes = () => { + return ( + <Switch> + <Route + path="/consumption" + render={({ match: { url } }) => ( + <> + <Route + path={`${url}/electricité`} + component={() => ( + <SingleFluidViewContainer + fluidTypes={[FluidType.ELECTRICITY]} + /> + )} + /> + <Route + path={`${url}/eau`} + component={() => ( + <SingleFluidViewContainer fluidTypes={[FluidType.WATER]} /> + )} + /> + <Route + path={`${url}/gaz`} + component={() => ( + <SingleFluidViewContainer fluidTypes={[FluidType.GAS]} /> + )} + /> + <Route path={`${url}/`} component={HomeViewContainer} exact /> + </> + )} + /> + <Route + path="/challenges" + render={({ match: { url } }) => ( + <> + <Route + path={`${url}/locked`} + component={LockedChallengeDetailsViewContainer} + /> + <Route + path={`${url}/available`} + component={AvailableChallengeDetailsViewContainer} + /> + <Route + path={`${url}/ongoing`} + component={OngoingChallengeDetailsViewContainer} + /> + <Route + path={`${url}/finished`} + component={FinishedChallengeDetailsViewContainer} + /> + <Route path={`${url}/`} component={ChallengesViewContainer} exact /> + </> + )} + /> + <Route + path="/parameters" + render={({ match: { url } }) => ( + <> + <Route path={`${url}/FAQ`} component={FAQViewContainer} /> + <Route + path={`${url}/legalnotice`} + component={LegalNoticeViewContainer} + /> + <Route path={`${url}/`} component={ParametersViewContainer} exact /> + </> + )} + /> + <Route path="/ecogestures" component={EcogesturesContainer} /> + <Route path="/profile" component={ProfileViewContainer} /> + <Redirect from="/" to="/consumption" /> + <Redirect from="*" to="/consumption" /> + </Switch> + ) +} + +export default Routes diff --git a/src/services/challenge.service.ts b/src/services/challenge.service.ts index fd9e6bd9c0160893aa423768d882f1ef03a480cf..f1745a8656502d4b1831dea61b97b4864276d38f 100644 --- a/src/services/challenge.service.ts +++ b/src/services/challenge.service.ts @@ -389,14 +389,10 @@ export default class ChallengeService { public async deleteAllChallengeTypeEntities(): Promise<boolean> { const challengeType = await this.getAllChallengeTypeEntities() if (!challengeType) return true - try { - for (let index = 0; index < challengeType.length; index++) { - await this._client.destroy(challengeType[index]) - } - return true - } catch (error) { - return false + for (let index = 0; index < challengeType.length; index++) { + await this._client.destroy(challengeType[index]) } + return true } public async getAvailableChallenges( diff --git a/src/services/initialization.service.ts b/src/services/initialization.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..00a61b3cadbfe697fd95d78e52410f921f1a1235 --- /dev/null +++ b/src/services/initialization.service.ts @@ -0,0 +1,17 @@ +import { Client } from 'cozy-client' + +export default class InitializationService { + private readonly _client: Client + + constructor(_client: Client) { + this._client = _client + } + + public async initialization(): Promise<boolean> { + // Check and create index + // Load UserProfil + // Check Ecogesture + // Check ChallengeType + return true + } +} diff --git a/src/styles/components/_splash.scss b/src/styles/components/_splash.scss index aaa2ac7cd9011d2ef07cba7b46e627633311f34c..a8a5edb2709751254bc1c7773b9b033919e6ee45 100644 --- a/src/styles/components/_splash.scss +++ b/src/styles/components/_splash.scss @@ -3,16 +3,24 @@ .splash-root { position: fixed; - z-index: 1000; + z-index: 1500; left: 0; top: 0; height: 100vh; width: 100vw; + opacity: 1; overflow: hidden; background-color: rgba(27, 28, 34, 1); display: flex; flex-direction: column; - .splash-header { + transition-property: opacity; + transition-timing-function: ease-in-out; + &.splash-fade { + opacity: 0; + } +} + +.splash-header { height: 6rem; display: flex; align-items: center; @@ -42,5 +50,4 @@ .splash-footer-button { max-width: 50vw; } - } -} + } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a703eb6ee10aa8a49115a1c69fa1f56683a2495a..531a28bd1176363e7c145f4ae552cb7299818b29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1362,6 +1362,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/classnames@^2.2.10": + version "2.2.10" + resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999" + integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ== + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -11895,6 +11900,11 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +recoil@^0.0.13: + version "0.0.13" + resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.0.13.tgz#23e6d63135c07d8defbd91aaa35dca94ec5c15a6" + integrity sha512-2OToaQ8GR//KsdKdaEhMi04QKStLGRpk3qjC58iBpZpUtsByZ4dUy2UJtRcYuhnVlltGZ8HNwcEQRdFOS864SQ== + "recompose@0.28.0 - 0.30.0": version "0.30.0" resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0"