ente/apps/photos/src/pages/index.tsx
2023-04-18 17:29:40 -04:00

259 lines
8.4 KiB
TypeScript

import React, { useContext, useEffect, useState } from 'react';
import Carousel from 'react-bootstrap/Carousel';
import { styled, Button, Typography, TypographyProps } from '@mui/material';
import { AppContext } from './_app';
import Login from 'components/Login';
import { useRouter } from 'next/router';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import EnteSpinner from 'components/EnteSpinner';
import SignUp from 'components/SignUp';
import { t } from 'i18next';
import localForage from 'utils/storage/localForage';
import { logError } from 'utils/sentry';
import { PAGES } from 'constants/pages';
import { EnteLogo } from 'components/EnteLogo';
import isElectron from 'is-electron';
import safeStorageService from 'services/electron/safeStorage';
import { saveKeyInSessionStore } from 'utils/crypto';
import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import { getAlbumsURL } from 'utils/common/apiUtil';
import { Trans } from 'react-i18next';
import { APPS, getAppName } from 'constants/apps';
const Container = styled('div')`
display: flex;
flex: 1;
align-items: center;
justify-content: center;
background-color: #000;
@media (max-width: 1024px) {
flex-direction: column;
}
`;
const SlideContainer = styled('div')`
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
@media (max-width: 1024px) {
flex-grow: 0;
}
`;
const DesktopBox = styled('div')`
flex: 1;
height: 100%;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
background-color: #242424;
@media (max-width: 1024px) {
display: none;
}
`;
const MobileBox = styled('div')`
display: none;
@media (max-width: 1024px) {
max-width: 375px;
width: 100%;
padding: 12px;
display: flex;
flex-direction: column;
gap: 8px;
}
`;
const SideBox = styled('div')`
display: flex;
flex-direction: column;
min-width: 320px;
`;
const TextContainer = (props: TypographyProps) => (
<Typography color={'text.muted'} mt={2} mb={3} {...props} />
);
const FeatureText = (props: TypographyProps) => (
<Typography variant="h3" mt={4} {...props} />
);
const Img = styled('img')`
height: 250px;
object-fit: contain;
@media (max-width: 400px) {
height: 180px;
}
`;
export default function LandingPage() {
const router = useRouter();
const appContext = useContext(AppContext);
const [loading, setLoading] = useState(true);
const [showLogin, setShowLogin] = useState(true);
useEffect(() => {
appContext.showNavBar(false);
const currentURL = new URL(window.location.href);
const albumsURL = new URL(getAlbumsURL());
currentURL.pathname = router.pathname;
if (
currentURL.host === albumsURL.host &&
currentURL.pathname !== PAGES.SHARED_ALBUMS
) {
handleAlbumsRedirect(currentURL);
} else {
handleNormalRedirect();
}
}, []);
const handleAlbumsRedirect = async (currentURL: URL) => {
const end = currentURL.hash.lastIndexOf('&');
const hash = currentURL.hash.slice(1, end !== -1 ? end : undefined);
await router.replace({
pathname: PAGES.SHARED_ALBUMS,
search: currentURL.search,
hash: hash,
});
await initLocalForage();
};
const handleNormalRedirect = async () => {
const appName = getAppName();
const user = getData(LS_KEYS.USER);
let key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
if (!key && isElectron()) {
key = await safeStorageService.getEncryptionKey();
if (key) {
await saveKeyInSessionStore(
SESSION_KEYS.ENCRYPTION_KEY,
key,
true
);
}
}
if (key) {
if (appName === APPS.AUTH) {
await router.push(PAGES.AUTH);
} else {
await router.push(PAGES.GALLERY);
}
} else if (user?.email) {
await router.push(PAGES.VERIFY);
} else {
if (appName === APPS.AUTH) {
await router.push(PAGES.LOGIN);
}
}
await initLocalForage();
setLoading(false);
};
const initLocalForage = async () => {
try {
await localForage.ready();
} catch (e) {
logError(e, 'usage in incognito mode tried');
appContext.setDialogMessage({
title: t('LOCAL_STORAGE_NOT_ACCESSIBLE'),
nonClosable: true,
content: t('LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE'),
});
} finally {
setLoading(false);
}
};
const signUp = () => setShowLogin(false);
const login = () => setShowLogin(true);
const redirectToSignupPage = () => router.push(PAGES.SIGNUP);
const redirectToLoginPage = () => router.push(PAGES.LOGIN);
return (
<Container>
{loading ? (
<EnteSpinner />
) : (
<>
<SlideContainer>
<EnteLogo height={24} sx={{ mb: 8 }} />
<Carousel controls={false}>
<Carousel.Item>
<Img
src="/images/onboarding-lock/1x.png"
srcSet="/images/onboarding-lock/2x.png 2x,
/images/onboarding-lock/3x.png 3x"
/>
<FeatureText>
<Trans i18nKey={'HERO_SLIDE_1_TITLE'} />
</FeatureText>
<TextContainer>
{t('HERO_SLIDE_1')}
</TextContainer>
</Carousel.Item>
<Carousel.Item>
<Img
src="/images/onboarding-safe/1x.png"
srcSet="/images/onboarding-safe/2x.png 2x,
/images/onboarding-safe/3x.png 3x"
/>
<FeatureText>
<Trans i18nKey={'HERO_SLIDE_2_TITLE'} />
</FeatureText>
<TextContainer>
{t('HERO_SLIDE_2')}
</TextContainer>
</Carousel.Item>
<Carousel.Item>
<Img
src="/images/onboarding-sync/1x.png"
srcSet="/images/onboarding-sync/2x.png 2x,
/images/onboarding-sync/3x.png 3x"
/>
<FeatureText>
<Trans i18nKey={'HERO_SLIDE_3_TITLE'} />
</FeatureText>
<TextContainer>
{t('HERO_SLIDE_3')}
</TextContainer>
</Carousel.Item>
</Carousel>
</SlideContainer>
<MobileBox>
<Button
color="accent"
size="large"
onClick={redirectToSignupPage}>
{t('NEW_USER')}
</Button>
<Button size="large" onClick={redirectToLoginPage}>
{t('EXISTING_USER')}
</Button>
</MobileBox>
<DesktopBox>
<SideBox>
{showLogin ? (
<Login signUp={signUp} />
) : (
<SignUp login={login} />
)}
</SideBox>
</DesktopBox>
</>
)}
</Container>
);
}