Conv
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { staticAppTitle } from "@/base/app";
|
||||
import { CustomHead } from "@/base/components/Head";
|
||||
import { LoadingOverlay } from "@/base/components/LoadingOverlay";
|
||||
import { LoadingOverlay } from "@/base/components/loaders";
|
||||
import { AttributedMiniDialog } from "@/base/components/MiniDialog";
|
||||
import { useAttributedMiniDialog } from "@/base/components/utils/dialog";
|
||||
import { useSetupI18n, useSetupLogs } from "@/base/components/utils/hooks-app";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { accountLogout } from "@/accounts/services/logout";
|
||||
import { clientPackageName, staticAppTitle } from "@/base/app";
|
||||
import { CustomHead } from "@/base/components/Head";
|
||||
import { LoadingOverlay } from "@/base/components/LoadingOverlay";
|
||||
import { LoadingOverlay } from "@/base/components/loaders";
|
||||
import { AttributedMiniDialog } from "@/base/components/MiniDialog";
|
||||
import { AppNavbar } from "@/base/components/Navbar";
|
||||
import { useAttributedMiniDialog } from "@/base/components/utils/dialog";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clientPackageName, isDesktop, staticAppTitle } from "@/base/app";
|
||||
import { CustomHead } from "@/base/components/Head";
|
||||
import { LoadingOverlay } from "@/base/components/LoadingOverlay";
|
||||
import { LoadingOverlay } from "@/base/components/loaders";
|
||||
import { AttributedMiniDialog } from "@/base/components/MiniDialog";
|
||||
import { AppNavbar } from "@/base/components/Navbar";
|
||||
import {
|
||||
|
||||
@@ -4,18 +4,20 @@ import {
|
||||
passkeySessionExpiredErrorMessage,
|
||||
saveCredentialsAndNavigateTo,
|
||||
} from "@/accounts/services/passkey";
|
||||
import { FormPaper, FormPaperFooter } from "@/base/components/FormPaper";
|
||||
import type { MiniDialogAttributes } from "@/base/components/MiniDialog";
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { genericErrorDialogAttributes } from "@/base/components/utils/dialog";
|
||||
import log from "@/base/log";
|
||||
import { customAPIHost } from "@/base/origins";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
import LinkButton from "@ente/shared/components/LinkButton";
|
||||
import { CircularProgress, Stack, Typography, styled } from "@mui/material";
|
||||
import { t } from "i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
AccountsPageContents,
|
||||
AccountsPageFooter,
|
||||
} from "./layouts/centered-paper";
|
||||
|
||||
export const PasswordHeader: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
@@ -44,7 +46,7 @@ const Header_ = styled("div")`
|
||||
gap: 8px;
|
||||
`;
|
||||
|
||||
export const LoginFlowFormFooter: React.FC<React.PropsWithChildren> = ({
|
||||
export const AccountsPageFooterWithHost: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [host, setHost] = useState<string | undefined>();
|
||||
@@ -52,16 +54,14 @@ export const LoginFlowFormFooter: React.FC<React.PropsWithChildren> = ({
|
||||
useEffect(() => void customAPIHost().then(setHost), []);
|
||||
|
||||
return (
|
||||
<FormPaperFooter>
|
||||
<Stack sx={{ gap: "16px", width: "100%", textAlign: "start" }}>
|
||||
{children}
|
||||
{host && (
|
||||
<Typography variant="small" sx={{ color: "text.faint" }}>
|
||||
{host}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
</FormPaperFooter>
|
||||
<Stack sx={{ gap: 2 }}>
|
||||
<AccountsPageFooter>{children}</AccountsPageFooter>
|
||||
{host && (
|
||||
<Typography variant="small" sx={{ color: "text.faint" }}>
|
||||
{host}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -119,59 +119,50 @@ export const VerifyingPasskey: React.FC<VerifyingPasskeyProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<FormPaper style={{ minWidth: "320px" }}>
|
||||
<PasskeyHeader>{email ?? ""}</PasskeyHeader>
|
||||
<AccountsPageContents>
|
||||
<PasskeyHeader>{email ?? ""}</PasskeyHeader>
|
||||
|
||||
<VerifyingPasskeyMiddle>
|
||||
<VerifyingPasskeyStatus>
|
||||
{verificationStatus == "checking" ? (
|
||||
<Typography>
|
||||
<CircularProgress color="accent" size="1.5em" />
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography sx={{ color: "text.muted" }}>
|
||||
{verificationStatus == "waiting"
|
||||
? t("waiting_for_verification")
|
||||
: t("verification_still_pending")}
|
||||
</Typography>
|
||||
)}
|
||||
</VerifyingPasskeyStatus>
|
||||
<VerifyingPasskeyMiddle>
|
||||
<VerifyingPasskeyStatus>
|
||||
{verificationStatus == "checking" ? (
|
||||
<Typography>
|
||||
<CircularProgress color="accent" size="1.5em" />
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography sx={{ color: "text.muted" }}>
|
||||
{verificationStatus == "waiting"
|
||||
? t("waiting_for_verification")
|
||||
: t("verification_still_pending")}
|
||||
</Typography>
|
||||
)}
|
||||
</VerifyingPasskeyStatus>
|
||||
|
||||
<ButtonStack>
|
||||
<FocusVisibleButton
|
||||
onClick={handleRetry}
|
||||
fullWidth
|
||||
color="secondary"
|
||||
>
|
||||
{t("try_again")}
|
||||
</FocusVisibleButton>
|
||||
|
||||
<FocusVisibleButton
|
||||
onClick={handleCheckStatus}
|
||||
fullWidth
|
||||
color="accent"
|
||||
>
|
||||
{t("check_status")}
|
||||
</FocusVisibleButton>
|
||||
</ButtonStack>
|
||||
</VerifyingPasskeyMiddle>
|
||||
|
||||
<LoginFlowFormFooter>
|
||||
<Stack
|
||||
direction="row"
|
||||
sx={{ justifyContent: "space-between" }}
|
||||
<ButtonStack>
|
||||
<FocusVisibleButton
|
||||
onClick={handleRetry}
|
||||
fullWidth
|
||||
color="secondary"
|
||||
>
|
||||
<LinkButton onClick={handleRecover}>
|
||||
{t("recover_account")}
|
||||
</LinkButton>
|
||||
<LinkButton onClick={logout}>
|
||||
{t("change_email")}
|
||||
</LinkButton>
|
||||
</Stack>
|
||||
</LoginFlowFormFooter>
|
||||
</FormPaper>
|
||||
</VerticallyCentered>
|
||||
{t("try_again")}
|
||||
</FocusVisibleButton>
|
||||
|
||||
<FocusVisibleButton
|
||||
onClick={handleCheckStatus}
|
||||
fullWidth
|
||||
color="accent"
|
||||
>
|
||||
{t("check_status")}
|
||||
</FocusVisibleButton>
|
||||
</ButtonStack>
|
||||
</VerifyingPasskeyMiddle>
|
||||
|
||||
<AccountsPageFooterWithHost>
|
||||
<LinkButton onClick={handleRecover}>
|
||||
{t("recover_account")}
|
||||
</LinkButton>
|
||||
<LinkButton onClick={logout}>{t("change_email")}</LinkButton>
|
||||
</AccountsPageFooterWithHost>
|
||||
</AccountsPageContents>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
import { AccountsPageContents } from "@/accounts/components/layouts/centered-paper";
|
||||
import {
|
||||
AccountsPageFooterWithHost,
|
||||
PasswordHeader,
|
||||
VerifyingPasskey,
|
||||
} from "@/accounts/components/LoginComponents";
|
||||
import { SecondFactorChoice } from "@/accounts/components/SecondFactorChoice";
|
||||
import { sessionExpiredDialogAttributes } from "@/accounts/components/utils/dialog";
|
||||
import { FormPaper } from "@/base/components/FormPaper";
|
||||
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
|
||||
import { useSecondFactorChoiceIfNeeded } from "@/accounts/components/utils/second-factor-choice";
|
||||
import { PAGES } from "@/accounts/constants/pages";
|
||||
import {
|
||||
openPasskeyVerificationURL,
|
||||
passkeyVerificationRedirectURL,
|
||||
} from "@/accounts/services/passkey";
|
||||
import {
|
||||
appHomeRoute,
|
||||
stashRedirect,
|
||||
unstashRedirect,
|
||||
} from "@/accounts/services/redirect";
|
||||
import { checkSessionValidity } from "@/accounts/services/session";
|
||||
import {
|
||||
configureSRP,
|
||||
generateSRPSetupAttributes,
|
||||
loginViaSRP,
|
||||
} from "@/accounts/services/srp";
|
||||
import type { SRPAttributes } from "@/accounts/services/srp-remote";
|
||||
import { getSRPAttributes } from "@/accounts/services/srp-remote";
|
||||
import type { PageProps } from "@/accounts/types/page";
|
||||
import { LoadingIndicator } from "@/base/components/loaders";
|
||||
import { sharedCryptoWorker } from "@/base/crypto";
|
||||
import type { B64EncryptionResult } from "@/base/crypto/libsodium";
|
||||
import { clearLocalStorage } from "@/base/local-storage";
|
||||
import log from "@/base/log";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
import LinkButton from "@ente/shared/components/LinkButton";
|
||||
import VerifyMasterPasswordForm, {
|
||||
type VerifyMasterPasswordFormProps,
|
||||
@@ -35,39 +60,12 @@ import {
|
||||
setKey,
|
||||
} from "@ente/shared/storage/sessionStorage";
|
||||
import type { KeyAttributes, User } from "@ente/shared/user/types";
|
||||
import { Stack } from "@mui/material";
|
||||
import { t } from "i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
LoginFlowFormFooter,
|
||||
PasswordHeader,
|
||||
VerifyingPasskey,
|
||||
} from "../components/LoginComponents";
|
||||
import { SecondFactorChoice } from "../components/SecondFactorChoice";
|
||||
import { useSecondFactorChoiceIfNeeded } from "../components/utils/second-factor-choice";
|
||||
import { PAGES } from "../constants/pages";
|
||||
import {
|
||||
openPasskeyVerificationURL,
|
||||
passkeyVerificationRedirectURL,
|
||||
} from "../services/passkey";
|
||||
import {
|
||||
appHomeRoute,
|
||||
stashRedirect,
|
||||
unstashRedirect,
|
||||
} from "../services/redirect";
|
||||
import { checkSessionValidity } from "../services/session";
|
||||
import {
|
||||
configureSRP,
|
||||
generateSRPSetupAttributes,
|
||||
loginViaSRP,
|
||||
} from "../services/srp";
|
||||
import type { SRPAttributes } from "../services/srp-remote";
|
||||
import { getSRPAttributes } from "../services/srp-remote";
|
||||
import type { PageProps } from "../types/page";
|
||||
|
||||
const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
const { logout, showNavBar, showMiniDialog } = appContext;
|
||||
const { logout, showMiniDialog } = appContext;
|
||||
|
||||
const [srpAttributes, setSrpAttributes] = useState<SRPAttributes>();
|
||||
const [keyAttributes, setKeyAttributes] = useState<KeyAttributes>();
|
||||
@@ -201,7 +199,6 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
}
|
||||
};
|
||||
void main();
|
||||
showNavBar(true);
|
||||
}, []);
|
||||
// TODO: ^ validateSession is a dependency, but add that only after we've
|
||||
// wrapped items from the callback (like logout) in useCallback too.
|
||||
@@ -336,11 +333,7 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
};
|
||||
|
||||
if (!keyAttributes && !srpAttributes) {
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<ActivityIndicator />
|
||||
</VerticallyCentered>
|
||||
);
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
if (passkeyVerificationData) {
|
||||
@@ -354,11 +347,7 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
// See: [Note: Passkey verification in the desktop app]
|
||||
|
||||
if (!globalThis.electron) {
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<ActivityIndicator />
|
||||
</VerticallyCentered>
|
||||
);
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -376,35 +365,26 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
// TODO: Handle the case when user is not present, or exclude that
|
||||
// possibility using types.
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<FormPaper style={{ minWidth: "320px" }}>
|
||||
<PasswordHeader>{user?.email ?? ""}</PasswordHeader>
|
||||
<AccountsPageContents>
|
||||
<PasswordHeader>{user?.email ?? ""}</PasswordHeader>
|
||||
|
||||
<VerifyMasterPasswordForm
|
||||
buttonText={t("sign_in")}
|
||||
callback={useMasterPassword}
|
||||
user={user}
|
||||
keyAttributes={keyAttributes}
|
||||
getKeyAttributes={getKeyAttributes}
|
||||
srpAttributes={srpAttributes}
|
||||
/>
|
||||
<VerifyMasterPasswordForm
|
||||
buttonText={t("sign_in")}
|
||||
callback={useMasterPassword}
|
||||
user={user}
|
||||
keyAttributes={keyAttributes}
|
||||
getKeyAttributes={getKeyAttributes}
|
||||
srpAttributes={srpAttributes}
|
||||
/>
|
||||
|
||||
<LoginFlowFormFooter>
|
||||
<Stack
|
||||
direction="row"
|
||||
sx={{ justifyContent: "space-between" }}
|
||||
>
|
||||
<LinkButton onClick={() => router.push(PAGES.RECOVER)}>
|
||||
{t("forgot_password")}
|
||||
</LinkButton>
|
||||
<LinkButton onClick={logout}>
|
||||
{t("change_email")}
|
||||
</LinkButton>
|
||||
</Stack>
|
||||
</LoginFlowFormFooter>
|
||||
</FormPaper>
|
||||
<AccountsPageFooterWithHost>
|
||||
<LinkButton onClick={() => router.push(PAGES.RECOVER)}>
|
||||
{t("forgot_password")}
|
||||
</LinkButton>
|
||||
<LinkButton onClick={logout}>{t("change_email")}</LinkButton>
|
||||
</AccountsPageFooterWithHost>
|
||||
<SecondFactorChoice {...secondFactorChoiceProps} />
|
||||
</VerticallyCentered>
|
||||
</AccountsPageContents>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ import type {
|
||||
import { getSRPAttributes } from "@/accounts/services/srp-remote";
|
||||
import { putAttributes, sendOTT, verifyEmail } from "@/accounts/services/user";
|
||||
import type { PageProps } from "@/accounts/types/page";
|
||||
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
|
||||
import { LoadingIndicator } from "@/base/components/loaders";
|
||||
import log from "@/base/log";
|
||||
import { VerticallyCentered } from "@ente/shared/components/Container";
|
||||
import LinkButton from "@ente/shared/components/LinkButton";
|
||||
import SingleInputForm, {
|
||||
type SingleInputFormProps,
|
||||
@@ -184,11 +183,7 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
};
|
||||
|
||||
if (!email) {
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<ActivityIndicator />
|
||||
</VerticallyCentered>
|
||||
);
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
if (passkeyVerificationData) {
|
||||
@@ -202,11 +197,7 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
||||
// See: [Note: Passkey verification in the desktop app]
|
||||
|
||||
if (!globalThis.electron) {
|
||||
return (
|
||||
<VerticallyCentered>
|
||||
<ActivityIndicator />
|
||||
</VerticallyCentered>
|
||||
);
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { Overlay } from "@/base/components/containers";
|
||||
import { Overlay, Stack100vhCenter } from "@/base/components/containers";
|
||||
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* A centered activity indicator shown in a container that fills up the entire
|
||||
* width and height of the viewport.
|
||||
*
|
||||
* This is meant as a root component of a page, e.g., during initial load.
|
||||
*/
|
||||
export const LoadingIndicator: React.FC = () => (
|
||||
<Stack100vhCenter>
|
||||
<ActivityIndicator />
|
||||
</Stack100vhCenter>
|
||||
);
|
||||
|
||||
/**
|
||||
* An opaque overlay that covers the entire viewport and shows an activity
|
||||
* indicator in its center.
|
||||
Reference in New Issue
Block a user