add auth page
This commit is contained in:
parent
720b1d77d1
commit
2454cca617
20 changed files with 54 additions and 196 deletions
|
@ -106,7 +106,7 @@ export default function App(props: EnteAppProps) {
|
|||
setupI18n().finally(() => setIsI18nReady(true));
|
||||
// set client package name in headers
|
||||
HTTPService.setHeaders({
|
||||
'X-Client-Package': CLIENT_PACKAGE_NAMES.get(APPS.PHOTOS),
|
||||
'X-Client-Package': CLIENT_PACKAGE_NAMES.get(APPS.AUTH),
|
||||
});
|
||||
// setup logging
|
||||
clearLogsIfLocalStorageLimitExceeded();
|
||||
|
@ -195,8 +195,8 @@ export default function App(props: EnteAppProps) {
|
|||
<Head>
|
||||
<title>
|
||||
{isI18nReady
|
||||
? t('TITLE', { context: APPS.PHOTOS })
|
||||
: APP_TITLES.get(APPS.PHOTOS)}
|
||||
? t('TITLE', { context: APPS.AUTH })
|
||||
: APP_TITLES.get(APPS.AUTH)}
|
||||
</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
|
@ -204,7 +204,7 @@ export default function App(props: EnteAppProps) {
|
|||
/>
|
||||
</Head>
|
||||
|
||||
<ThemeProvider theme={getTheme(themeColor, APPS.PHOTOS)}>
|
||||
<ThemeProvider theme={getTheme(themeColor, APPS.AUTH)}>
|
||||
<CssBaseline enableColorScheme />
|
||||
{showNavbar && <AppNavbar isMobile={isMobile} />}
|
||||
<MessageContainer>
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function ChangeEmail() {
|
|||
<ChangeEmailPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function ChangePassword() {
|
|||
<ChangePasswordPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Credential() {
|
|||
<CredentialPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Generate() {
|
|||
<GeneratePage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Login() {
|
|||
<LoginPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Recover() {
|
|||
<RecoverPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Sigup() {
|
|||
<SignupPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function TwoFactorRecover() {
|
|||
<TwoFactorRecoverPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function TwoFactorSetup() {
|
|||
<TwoFactorSetupPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function TwoFactorVerify() {
|
|||
<TwoFactorVerifyPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function Verify() {
|
|||
<VerifyPage
|
||||
appContext={appContext}
|
||||
router={router}
|
||||
appName={APPS.PHOTOS}
|
||||
appName={APPS.AUTH}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { HttpStatusCode } from 'axios';
|
||||
import HTTPService from 'services/HTTPService';
|
||||
import HTTPService from '@ente/shared/network/HTTPService';
|
||||
import { AuthEntity, AuthKey } from 'types/authenticator/api';
|
||||
import { Code } from 'types/authenticator/code';
|
||||
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
|
||||
import { getEndpoint } from 'utils/common/apiUtil';
|
||||
import { getActualKey, getToken } from 'utils/common/key';
|
||||
import { ApiError, CustomError } from 'utils/error';
|
||||
import ComlinkCryptoWorker from '@ente/shared/crypto';
|
||||
import { getEndpoint } from '@ente/shared/network/api';
|
||||
import { getActualKey } from '@ente/shared/user';
|
||||
import { getToken } from '@ente/shared/storage/localStorage/helpers';
|
||||
import { ApiError, CustomError } from '@ente/shared/error';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
|
||||
const ENDPOINT = getEndpoint();
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
import { Formik, FormikHelpers } from 'formik';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import SubmitButton from '@ente/shared/components/SubmitButton';
|
||||
import router from 'next/router';
|
||||
import { changeEmail, sendOTTForEmailChange } from 'services/userService';
|
||||
import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
|
||||
import { PHOTOS_PAGES as PAGES } from '@ente/shared/constants/pages';
|
||||
import { Alert, Box, TextField } from '@mui/material';
|
||||
import { VerticallyCentered } from './Container';
|
||||
import LinkButton from './pages/gallery/LinkButton';
|
||||
import FormPaperFooter from '@ente/shared/components/Form/FormPaper/Footer';
|
||||
import { sleep } from 'utils/common';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { t } from 'i18next';
|
||||
|
||||
interface formValues {
|
||||
email: string;
|
||||
ott?: string;
|
||||
}
|
||||
|
||||
function ChangeEmailForm() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [ottInputVisible, setShowOttInputVisibility] = useState(false);
|
||||
const ottInputRef = useRef(null);
|
||||
const [email, setEmail] = useState(null);
|
||||
const [showMessage, setShowMessage] = useState(false);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const requestOTT = async (
|
||||
{ email }: formValues,
|
||||
{ setFieldError }: FormikHelpers<formValues>
|
||||
) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await sendOTTForEmailChange(email);
|
||||
setEmail(email);
|
||||
setShowOttInputVisibility(true);
|
||||
setShowMessage(true);
|
||||
setTimeout(() => {
|
||||
ottInputRef.current?.focus();
|
||||
}, 250);
|
||||
} catch (e) {
|
||||
setFieldError('email', t('EMAIl_ALREADY_OWNED'));
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const requestEmailChange = async (
|
||||
{ email, ott }: formValues,
|
||||
{ setFieldError }: FormikHelpers<formValues>
|
||||
) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await changeEmail(email, ott);
|
||||
setData(LS_KEYS.USER, { ...getData(LS_KEYS.USER), email });
|
||||
setLoading(false);
|
||||
setSuccess(true);
|
||||
await sleep(1000);
|
||||
router.push(PAGES.GALLERY);
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
setFieldError('ott', t('INCORRECT_CODE'));
|
||||
}
|
||||
};
|
||||
|
||||
const goToGallery = () => router.push(PAGES.GALLERY);
|
||||
|
||||
return (
|
||||
<Formik<formValues>
|
||||
initialValues={{ email: '' }}
|
||||
validationSchema={Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email(t('EMAIL_ERROR'))
|
||||
.required(t('REQUIRED')),
|
||||
ott: ottInputVisible && Yup.string().required(t('REQUIRED')),
|
||||
})}
|
||||
validateOnChange={false}
|
||||
validateOnBlur={false}
|
||||
onSubmit={!ottInputVisible ? requestOTT : requestEmailChange}>
|
||||
{({ values, errors, handleChange, handleSubmit }) => (
|
||||
<>
|
||||
{showMessage && (
|
||||
<Alert
|
||||
color="success"
|
||||
onClose={() => setShowMessage(false)}>
|
||||
<Trans
|
||||
i18nKey="EMAIL_SENT"
|
||||
components={{
|
||||
a: (
|
||||
<Box
|
||||
color="text.muted"
|
||||
component={'span'}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
values={{ email }}
|
||||
/>
|
||||
</Alert>
|
||||
)}
|
||||
<form noValidate onSubmit={handleSubmit}>
|
||||
<VerticallyCentered>
|
||||
<TextField
|
||||
fullWidth
|
||||
InputProps={{
|
||||
readOnly: ottInputVisible,
|
||||
}}
|
||||
type="email"
|
||||
label={t('ENTER_EMAIL')}
|
||||
value={values.email}
|
||||
onChange={handleChange('email')}
|
||||
error={Boolean(errors.email)}
|
||||
helperText={errors.email}
|
||||
autoFocus
|
||||
disabled={loading}
|
||||
/>
|
||||
{ottInputVisible && (
|
||||
<TextField
|
||||
fullWidth
|
||||
type="text"
|
||||
label={t('ENTER_OTT')}
|
||||
value={values.ott}
|
||||
onChange={handleChange('ott')}
|
||||
error={Boolean(errors.ott)}
|
||||
helperText={errors.ott}
|
||||
disabled={loading}
|
||||
/>
|
||||
)}
|
||||
<SubmitButton
|
||||
success={success}
|
||||
sx={{ mt: 2 }}
|
||||
loading={loading}
|
||||
buttonText={
|
||||
!ottInputVisible
|
||||
? t('SEND_OTT')
|
||||
: t('VERIFY')
|
||||
}
|
||||
/>
|
||||
</VerticallyCentered>
|
||||
</form>
|
||||
|
||||
<FormPaperFooter
|
||||
style={{
|
||||
justifyContent: ottInputVisible && 'space-between',
|
||||
}}>
|
||||
{ottInputVisible && (
|
||||
<LinkButton
|
||||
onClick={() =>
|
||||
setShowOttInputVisibility(false)
|
||||
}>
|
||||
{t('CHANGE_EMAIL')}?
|
||||
</LinkButton>
|
||||
)}
|
||||
<LinkButton onClick={goToGallery}>
|
||||
{t('GO_BACK')}
|
||||
</LinkButton>
|
||||
</FormPaperFooter>
|
||||
</>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChangeEmailForm;
|
|
@ -13,13 +13,14 @@ import FormPaperFooter from '@ente/shared/components/Form/FormPaper/Footer';
|
|||
import { sleep } from '@ente/shared/utils';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { t } from 'i18next';
|
||||
import { APPS } from '@ente/shared/apps/constants';
|
||||
|
||||
interface formValues {
|
||||
email: string;
|
||||
ott?: string;
|
||||
}
|
||||
|
||||
function ChangeEmailForm() {
|
||||
function ChangeEmailForm({ appName }: { appName: string }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [ottInputVisible, setShowOttInputVisibility] = useState(false);
|
||||
const ottInputRef = useRef(null);
|
||||
|
@ -57,14 +58,20 @@ function ChangeEmailForm() {
|
|||
setLoading(false);
|
||||
setSuccess(true);
|
||||
await sleep(1000);
|
||||
router.push(PAGES.GALLERY);
|
||||
goToApp();
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
setFieldError('ott', t('INCORRECT_CODE'));
|
||||
}
|
||||
};
|
||||
|
||||
const goToGallery = () => router.push(PAGES.GALLERY);
|
||||
const goToApp = () => {
|
||||
if (appName === APPS.AUTH) {
|
||||
router.push(PAGES.AUTH);
|
||||
} else {
|
||||
router.push(PAGES.GALLERY);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik<formValues>
|
||||
|
@ -151,7 +158,7 @@ function ChangeEmailForm() {
|
|||
{t('CHANGE_EMAIL')}?
|
||||
</LinkButton>
|
||||
)}
|
||||
<LinkButton onClick={goToGallery}>
|
||||
<LinkButton onClick={goToApp}>
|
||||
{t('GO_BACK')}
|
||||
</LinkButton>
|
||||
</FormPaperFooter>
|
||||
|
|
|
@ -9,7 +9,7 @@ import FormPaper from '@ente/shared/components/Form/FormPaper';
|
|||
import FormPaperTitle from '@ente/shared/components/Form/FormPaper/Title';
|
||||
import { PageProps } from '@ente/shared/apps/types';
|
||||
|
||||
function ChangeEmailPage({ router }: PageProps) {
|
||||
function ChangeEmailPage({ router, appName }: PageProps) {
|
||||
useEffect(() => {
|
||||
const user = getData(LS_KEYS.USER);
|
||||
if (!user?.token) {
|
||||
|
@ -21,7 +21,7 @@ function ChangeEmailPage({ router }: PageProps) {
|
|||
<VerticallyCentered>
|
||||
<FormPaper>
|
||||
<FormPaperTitle>{t('CHANGE_EMAIL')}</FormPaperTitle>
|
||||
<ChangeEmailForm />
|
||||
<ChangeEmailForm appName={appName} />
|
||||
</FormPaper>
|
||||
</VerticallyCentered>
|
||||
);
|
||||
|
|
|
@ -90,7 +90,11 @@ export default function Credentials({
|
|||
}
|
||||
}
|
||||
if (key) {
|
||||
router.push(PAGES.GALLERY);
|
||||
if (appName === APPS.AUTH) {
|
||||
router.push(PAGES.AUTH);
|
||||
} else {
|
||||
router.push(PAGES.GALLERY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const kekEncryptedAttributes: B64EncryptionResult = getKey(
|
||||
|
|
|
@ -22,6 +22,7 @@ import { sendOtt } from '@ente/accounts/api/user';
|
|||
import InMemoryStore, { MS_KEYS } from '@ente/shared/storage/InMemoryStore';
|
||||
import { PageProps } from '@ente/shared/apps/types';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
import { APPS } from '@ente/shared/apps/constants';
|
||||
const bip39 = require('bip39');
|
||||
// mobile client library only supports english.
|
||||
bip39.setDefaultWordlist('english');
|
||||
|
@ -47,7 +48,11 @@ export default function Recover({ appContext, router, appName }: PageProps) {
|
|||
if (!keyAttributes) {
|
||||
router.push(PAGES.GENERATE);
|
||||
} else if (key) {
|
||||
router.push(PAGES.GALLERY);
|
||||
if (appName === APPS.AUTH) {
|
||||
router.push(PAGES.AUTH);
|
||||
} else {
|
||||
router.push(PAGES.GALLERY);
|
||||
}
|
||||
} else {
|
||||
setKeyAttributes(keyAttributes);
|
||||
}
|
||||
|
|
|
@ -16,13 +16,14 @@ import { TwoFactorSetup } from '@ente/accounts/components/two-factor/setup';
|
|||
import LinkButton from '@ente/shared/components/LinkButton';
|
||||
import { PageProps } from '@ente/shared/apps/types';
|
||||
import { logError } from '@ente/shared/sentry';
|
||||
import { APPS } from '@ente/shared/apps/constants';
|
||||
|
||||
export enum SetupMode {
|
||||
QR_CODE,
|
||||
MANUAL_CODE,
|
||||
}
|
||||
|
||||
export default function SetupTwoFactor({ router }: PageProps) {
|
||||
export default function SetupTwoFactor({ router, appName }: PageProps) {
|
||||
const [twoFactorSecret, setTwoFactorSecret] =
|
||||
useState<TwoFactorSecret>(null);
|
||||
|
||||
|
@ -55,7 +56,11 @@ export default function SetupTwoFactor({ router }: PageProps) {
|
|||
...getData(LS_KEYS.USER),
|
||||
isTwoFactorEnabled: true,
|
||||
});
|
||||
router.push(PAGES.GALLERY);
|
||||
if (appName === APPS.AUTH) {
|
||||
router.push(PAGES.AUTH);
|
||||
} else {
|
||||
router.push(PAGES.GALLERY);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { MenuItem, ButtonProps, Typography, Box } from '@mui/material';
|
||||
import { FluidContainer } from 'components/Container';
|
||||
import { OverflowMenuContext } from 'contexts/overflowMenu';
|
||||
import { FluidContainer } from '@ente/shared/components/Container';
|
||||
import { OverflowMenuContext } from './context';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
interface Iprops {
|
||||
|
|
Loading…
Add table
Reference in a new issue