Only pages in pages

This commit is contained in:
Manav Rathi
2024-06-05 14:47:47 +05:30
parent ecaba3fb78
commit b987f80ee5
6 changed files with 260 additions and 292 deletions

View File

@@ -1,74 +0,0 @@
import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
import EnteButton from "@ente/shared/components/EnteButton";
import { Button, Stack, Typography, useMediaQuery } from "@mui/material";
import { t } from "i18next";
import { useContext, useState } from "react";
import { deletePasskey } from "services/passkeysService";
import { PasskeysContext } from ".";
interface IProps {
open: boolean;
onClose: () => void;
}
const DeletePasskeyModal = (props: IProps) => {
const { selectedPasskey, setShowPasskeyDrawer } =
useContext(PasskeysContext);
const [loading, setLoading] = useState(false);
const isMobile = useMediaQuery("(max-width: 428px)");
const doDelete = async () => {
if (!selectedPasskey) return;
setLoading(true);
try {
await deletePasskey(selectedPasskey.id);
} catch (error) {
console.error(error);
return;
} finally {
setLoading(false);
}
props.onClose();
setShowPasskeyDrawer(false);
};
return (
<DialogBoxV2
fullWidth
open={props.open}
onClose={props.onClose}
fullScreen={isMobile}
attributes={{
title: t("DELETE_PASSKEY"),
secondary: {
action: props.onClose,
text: t("CANCEL"),
},
}}
>
<Stack spacing={"8px"}>
<Typography>{t("DELETE_PASSKEY_CONFIRMATION")}</Typography>
<EnteButton
type="submit"
size="large"
color="critical"
loading={loading}
onClick={doDelete}
>
{t("DELETE")}
</EnteButton>
<Button
size="large"
color={"secondary"}
onClick={props.onClose}
>
{t("CANCEL")}
</Button>
</Stack>
</DialogBoxV2>
);
};
export default DeletePasskeyModal;

View File

@@ -1,101 +0,0 @@
import { EnteDrawer } from "@ente/shared/components/EnteDrawer";
import InfoItem from "@ente/shared/components/Info/InfoItem";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import MenuItemDivider from "@ente/shared/components/Menu/MenuItemDivider";
import { MenuItemGroup } from "@ente/shared/components/Menu/MenuItemGroup";
import Titlebar from "@ente/shared/components/Titlebar";
import { formatDateTimeFull } from "@ente/shared/time/format";
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import { Stack } from "@mui/material";
import { t } from "i18next";
import { useContext, useState } from "react";
import { PasskeysContext } from ".";
import DeletePasskeyModal from "./DeletePasskeyModal";
import RenamePasskeyModal from "./RenamePasskeyModal";
interface IProps {
open: boolean;
}
const ManagePasskeyDrawer = (props: IProps) => {
const { setShowPasskeyDrawer, refreshPasskeys, selectedPasskey } =
useContext(PasskeysContext);
const [showDeletePasskeyModal, setShowDeletePasskeyModal] = useState(false);
const [showRenamePasskeyModal, setShowRenamePasskeyModal] = useState(false);
return (
<>
<EnteDrawer
anchor="right"
open={props.open}
onClose={() => {
setShowPasskeyDrawer(false);
}}
>
{selectedPasskey && (
<>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={() => {
setShowPasskeyDrawer(false);
}}
title="Manage Passkey"
onRootClose={() => {
setShowPasskeyDrawer(false);
}}
/>
<InfoItem
icon={<CalendarTodayIcon />}
title={t("CREATED_AT")}
caption={
`${formatDateTimeFull(
selectedPasskey.createdAt / 1000,
)}` || ""
}
loading={!selectedPasskey}
hideEditOption
/>
<MenuItemGroup>
<EnteMenuItem
onClick={() => {
setShowRenamePasskeyModal(true);
}}
startIcon={<EditIcon />}
label={"Rename Passkey"}
/>
<MenuItemDivider />
<EnteMenuItem
onClick={() => {
setShowDeletePasskeyModal(true);
}}
startIcon={<DeleteIcon />}
label={"Delete Passkey"}
color="critical"
/>
</MenuItemGroup>
</Stack>
</>
)}
</EnteDrawer>
<DeletePasskeyModal
open={showDeletePasskeyModal}
onClose={() => {
setShowDeletePasskeyModal(false);
refreshPasskeys();
}}
/>
<RenamePasskeyModal
open={showRenamePasskeyModal}
onClose={() => {
setShowRenamePasskeyModal(false);
refreshPasskeys();
}}
/>
</>
);
};
export default ManagePasskeyDrawer;

View File

@@ -1,29 +0,0 @@
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import KeyIcon from "@mui/icons-material/Key";
import { useContext } from "react";
import type { Passkey } from "types/passkey";
import { PasskeysContext } from ".";
interface IProps {
passkey: Passkey;
}
const PasskeyListItem = (props: IProps) => {
const { setSelectedPasskey, setShowPasskeyDrawer } =
useContext(PasskeysContext);
return (
<EnteMenuItem
onClick={() => {
setSelectedPasskey(props.passkey);
setShowPasskeyDrawer(true);
}}
startIcon={<KeyIcon />}
endIcon={<ChevronRightIcon />}
label={props.passkey?.friendlyName}
/>
);
};
export default PasskeyListItem;

View File

@@ -1,26 +0,0 @@
import MenuItemDivider from "@ente/shared/components/Menu/MenuItemDivider";
import { MenuItemGroup } from "@ente/shared/components/Menu/MenuItemGroup";
import { Fragment } from "react";
import type { Passkey } from "types/passkey";
import PasskeyListItem from "./PasskeyListItem";
interface IProps {
passkeys: Passkey[];
}
const PasskeyComponent = (props: IProps) => {
return (
<>
<MenuItemGroup>
{props.passkeys?.map((passkey, i) => (
<Fragment key={passkey.id}>
<PasskeyListItem passkey={passkey} />
{i < props.passkeys.length - 1 && <MenuItemDivider />}
</Fragment>
))}
</MenuItemGroup>
</>
);
};
export default PasskeyComponent;

View File

@@ -1,58 +0,0 @@
import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
import SingleInputForm from "@ente/shared/components/SingleInputForm";
import { useMediaQuery } from "@mui/material";
import { t } from "i18next";
import { useContext } from "react";
import { renamePasskey } from "services/passkeysService";
import { PasskeysContext } from ".";
interface IProps {
open: boolean;
onClose: () => void;
}
const RenamePasskeyModal = (props: IProps) => {
const { selectedPasskey } = useContext(PasskeysContext);
const isMobile = useMediaQuery("(max-width: 428px)");
const onSubmit = async (inputValue: string) => {
if (!selectedPasskey) return;
try {
await renamePasskey(selectedPasskey.id, inputValue);
} catch (error) {
console.error(error);
return;
}
props.onClose();
};
return (
<DialogBoxV2
fullWidth
open={props.open}
onClose={props.onClose}
fullScreen={isMobile}
attributes={{
title: t("RENAME_PASSKEY"),
secondary: {
action: props.onClose,
text: t("CANCEL"),
},
}}
>
<SingleInputForm
initialValue={selectedPasskey?.friendlyName}
callback={onSubmit}
placeholder={t("ENTER_PASSKEY_NAME")}
buttonText={t("RENAME")}
fieldType="text"
secondaryButtonAction={props.onClose}
submitButtonProps={{ sx: { mt: 1, mb: 2 } }}
/>
</DialogBoxV2>
);
};
export default RenamePasskeyModal;

View File

@@ -1,25 +1,44 @@
import log from "@/next/log";
import { ensure } from "@/utils/ensure";
import { CenteredFlex } from "@ente/shared/components/Container";
import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
import EnteButton from "@ente/shared/components/EnteButton";
import { EnteDrawer } from "@ente/shared/components/EnteDrawer";
import FormPaper from "@ente/shared/components/Form/FormPaper";
import InfoItem from "@ente/shared/components/Info/InfoItem";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import MenuItemDivider from "@ente/shared/components/Menu/MenuItemDivider";
import { MenuItemGroup } from "@ente/shared/components/Menu/MenuItemGroup";
import SingleInputForm from "@ente/shared/components/SingleInputForm";
import Titlebar from "@ente/shared/components/Titlebar";
import { ACCOUNTS_PAGES } from "@ente/shared/constants/pages";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { Box, Typography } from "@mui/material";
import { formatDateTimeFull } from "@ente/shared/time/format";
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import KeyIcon from "@mui/icons-material/Key";
import { Box, Button, Stack, Typography, useMediaQuery } from "@mui/material";
import { t } from "i18next";
import _sodium from "libsodium-wrappers";
import { useRouter } from "next/router";
import { useAppContext } from "pages/_app";
import type { Dispatch, SetStateAction } from "react";
import { createContext, useEffect, useState } from "react";
import {
Fragment,
createContext,
useContext,
useEffect,
useState,
} from "react";
import { deletePasskey, renamePasskey } from "services/passkeysService";
import type { Passkey } from "types/passkey";
import {
finishPasskeyRegistration,
getPasskeyRegistrationOptions,
getPasskeys,
} from "../../services/passkeysService";
import ManagePasskeyDrawer from "./ManagePasskeyDrawer";
import PasskeysList from "./PasskeysList";
export const PasskeysContext = createContext(
{} as {
@@ -164,3 +183,240 @@ const Passkeys = () => {
};
export default Passkeys;
interface PasskeysListProps {
passkeys: Passkey[];
}
const PasskeysList: React.FC<PasskeysListProps> = ({ passkeys }) => {
return (
<>
<MenuItemGroup>
{passkeys.map((passkey, i) => (
<Fragment key={passkey.id}>
<PasskeyListItem passkey={passkey} />
{i < passkeys.length - 1 && <MenuItemDivider />}
</Fragment>
))}
</MenuItemGroup>
</>
);
};
interface PasskeyListItemProps {
passkey: Passkey;
}
const PasskeyListItem: React.FC<PasskeyListItemProps> = ({ passkey }) => {
const { setSelectedPasskey, setShowPasskeyDrawer } =
useContext(PasskeysContext);
return (
<EnteMenuItem
onClick={() => {
setSelectedPasskey(passkey);
setShowPasskeyDrawer(true);
}}
startIcon={<KeyIcon />}
endIcon={<ChevronRightIcon />}
label={passkey?.friendlyName}
/>
);
};
interface ManagePasskeyDrawerProps {
open: boolean;
}
const ManagePasskeyDrawer: React.FC<ManagePasskeyDrawerProps> = (props) => {
const { setShowPasskeyDrawer, refreshPasskeys, selectedPasskey } =
useContext(PasskeysContext);
const [showDeletePasskeyModal, setShowDeletePasskeyModal] = useState(false);
const [showRenamePasskeyModal, setShowRenamePasskeyModal] = useState(false);
return (
<>
<EnteDrawer
anchor="right"
open={props.open}
onClose={() => {
setShowPasskeyDrawer(false);
}}
>
{selectedPasskey && (
<>
<Stack spacing={"4px"} py={"12px"}>
<Titlebar
onClose={() => {
setShowPasskeyDrawer(false);
}}
title="Manage Passkey"
onRootClose={() => {
setShowPasskeyDrawer(false);
}}
/>
<InfoItem
icon={<CalendarTodayIcon />}
title={t("CREATED_AT")}
caption={
`${formatDateTimeFull(
selectedPasskey.createdAt / 1000,
)}` || ""
}
loading={!selectedPasskey}
hideEditOption
/>
<MenuItemGroup>
<EnteMenuItem
onClick={() => {
setShowRenamePasskeyModal(true);
}}
startIcon={<EditIcon />}
label={"Rename Passkey"}
/>
<MenuItemDivider />
<EnteMenuItem
onClick={() => {
setShowDeletePasskeyModal(true);
}}
startIcon={<DeleteIcon />}
label={"Delete Passkey"}
color="critical"
/>
</MenuItemGroup>
</Stack>
</>
)}
</EnteDrawer>
<DeletePasskeyModal
open={showDeletePasskeyModal}
onClose={() => {
setShowDeletePasskeyModal(false);
refreshPasskeys();
}}
/>
<RenamePasskeyModal
open={showRenamePasskeyModal}
onClose={() => {
setShowRenamePasskeyModal(false);
refreshPasskeys();
}}
/>
</>
);
};
interface DeletePasskeyModalProps {
open: boolean;
onClose: () => void;
}
const DeletePasskeyModal: React.FC<DeletePasskeyModalProps> = (props) => {
const { selectedPasskey, setShowPasskeyDrawer } =
useContext(PasskeysContext);
const [loading, setLoading] = useState(false);
const isMobile = useMediaQuery("(max-width: 428px)");
const doDelete = async () => {
if (!selectedPasskey) return;
setLoading(true);
try {
await deletePasskey(selectedPasskey.id);
} catch (error) {
console.error(error);
return;
} finally {
setLoading(false);
}
props.onClose();
setShowPasskeyDrawer(false);
};
return (
<DialogBoxV2
fullWidth
open={props.open}
onClose={props.onClose}
fullScreen={isMobile}
attributes={{
title: t("DELETE_PASSKEY"),
secondary: {
action: props.onClose,
text: t("CANCEL"),
},
}}
>
<Stack spacing={"8px"}>
<Typography>{t("DELETE_PASSKEY_CONFIRMATION")}</Typography>
<EnteButton
type="submit"
size="large"
color="critical"
loading={loading}
onClick={doDelete}
>
{t("DELETE")}
</EnteButton>
<Button
size="large"
color={"secondary"}
onClick={props.onClose}
>
{t("CANCEL")}
</Button>
</Stack>
</DialogBoxV2>
);
};
interface RenamePasskeyModalProps {
open: boolean;
onClose: () => void;
}
const RenamePasskeyModal: React.FC<RenamePasskeyModalProps> = (props) => {
const { selectedPasskey } = useContext(PasskeysContext);
const isMobile = useMediaQuery("(max-width: 428px)");
const onSubmit = async (inputValue: string) => {
if (!selectedPasskey) return;
try {
await renamePasskey(selectedPasskey.id, inputValue);
} catch (error) {
console.error(error);
return;
}
props.onClose();
};
return (
<DialogBoxV2
fullWidth
open={props.open}
onClose={props.onClose}
fullScreen={isMobile}
attributes={{
title: t("RENAME_PASSKEY"),
secondary: {
action: props.onClose,
text: t("CANCEL"),
},
}}
>
<SingleInputForm
initialValue={selectedPasskey?.friendlyName}
callback={onSubmit}
placeholder={t("ENTER_PASSKEY_NAME")}
buttonText={t("RENAME")}
fieldType="text"
secondaryButtonAction={props.onClose}
submitButtonProps={{ sx: { mt: 1, mb: 2 } }}
/>
</DialogBoxV2>
);
};