feat: delete passkey
This commit is contained in:
parent
38728df71a
commit
2d43b8d7c4
|
@ -1,20 +1,28 @@
|
|||
import React from 'react';
|
||||
import React, { createContext } from 'react';
|
||||
import { ThemeProvider } from '@mui/material/styles';
|
||||
import { getTheme } from '@ente/shared/themes';
|
||||
import { useLocalState } from '@ente/shared/hooks/useLocalState';
|
||||
import { LS_KEYS } from '@ente/shared/storage/localStorage';
|
||||
import { THEME_COLOR } from '@ente/shared/themes/constants';
|
||||
import { APPS } from '@ente/shared/apps/constants';
|
||||
import { CssBaseline } from '@mui/material';
|
||||
import { CssBaseline, useMediaQuery } from '@mui/material';
|
||||
import { EnteAppProps } from '@ente/shared/apps/types';
|
||||
import createEmotionCache from '@ente/shared/themes/createEmotionCache';
|
||||
import { CacheProvider } from '@emotion/react';
|
||||
import 'styles/global.css';
|
||||
|
||||
export const AppContext = createContext(
|
||||
{} as {
|
||||
isMobile: boolean;
|
||||
}
|
||||
);
|
||||
|
||||
// Client-side cache, shared for the whole session of the user in the browser.
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
export default function App(props: EnteAppProps) {
|
||||
const isMobile = useMediaQuery('(max-width:428px)');
|
||||
|
||||
const {
|
||||
Component,
|
||||
emotionCache = clientSideEmotionCache,
|
||||
|
@ -27,7 +35,9 @@ export default function App(props: EnteAppProps) {
|
|||
<CacheProvider value={emotionCache}>
|
||||
<ThemeProvider theme={getTheme(themeColor, APPS.PHOTOS)}>
|
||||
<CssBaseline enableColorScheme />
|
||||
<Component {...pageProps} />
|
||||
<AppContext.Provider value={{ isMobile }}>
|
||||
<Component {...pageProps} />
|
||||
</AppContext.Provider>
|
||||
</ThemeProvider>
|
||||
</CacheProvider>
|
||||
);
|
||||
|
|
70
apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx
Normal file
70
apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx
Normal file
|
@ -0,0 +1,70 @@
|
|||
import DialogBoxV2 from '@ente/shared/components/DialogBoxV2';
|
||||
import EnteButton from '@ente/shared/components/EnteButton';
|
||||
import { Button, Stack, Typography } from '@mui/material';
|
||||
import { AppContext } from 'pages/_app';
|
||||
import { useContext, useState } from 'react';
|
||||
import { deletePasskey } from 'services/passkeysService';
|
||||
import { PasskeysContext } from '.';
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const DeletePasskeyModal = (props: IProps) => {
|
||||
const { isMobile } = useContext(AppContext);
|
||||
const { selectedPasskey } = useContext(PasskeysContext);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const doDelete = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await deletePasskey(selectedPasskey.id);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogBoxV2
|
||||
fullWidth
|
||||
open={props.open}
|
||||
onClose={props.onClose}
|
||||
fullScreen={isMobile}
|
||||
attributes={{
|
||||
title: 'Delete Passkey',
|
||||
secondary: {
|
||||
action: props.onClose,
|
||||
text: 'Cancel',
|
||||
},
|
||||
}}>
|
||||
<Stack spacing={'8px'}>
|
||||
<Typography>
|
||||
Are you sure you want to delete this passkey? This action is
|
||||
irreversible.
|
||||
</Typography>
|
||||
<EnteButton
|
||||
type="submit"
|
||||
size="large"
|
||||
color="critical"
|
||||
loading={loading}
|
||||
onClick={doDelete}>
|
||||
Delete Passkey
|
||||
</EnteButton>
|
||||
<Button
|
||||
size="large"
|
||||
color={'secondary'}
|
||||
onClick={props.onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Stack>
|
||||
</DialogBoxV2>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeletePasskeyModal;
|
|
@ -4,10 +4,11 @@ import { Stack } from '@mui/material';
|
|||
import Titlebar from '@ente/shared/components/Titlebar';
|
||||
import { MenuItemGroup } from '@ente/shared/components/Menu/MenuItemGroup';
|
||||
import { EnteMenuItem } from '@ente/shared/components/Menu/EnteMenuItem';
|
||||
import { useContext } from 'react';
|
||||
import { useContext, useState } from 'react';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import MenuItemDivider from '@ente/shared/components/Menu/MenuItemDivider';
|
||||
import DeletePasskeyModal from './DeletePasskeyModal';
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
|
@ -15,38 +16,51 @@ interface IProps {
|
|||
|
||||
const ManagePasskeyDrawer = (props: IProps) => {
|
||||
const { setShowPasskeyDrawer } = useContext(PasskeysContext);
|
||||
|
||||
const [showDeletePasskeyModal, setShowDeletePasskeyModal] = useState(false);
|
||||
|
||||
return (
|
||||
<EnteDrawer
|
||||
anchor="right"
|
||||
open={props.open}
|
||||
onClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}>
|
||||
<Stack spacing={'4px'} py={'12px'}>
|
||||
<Titlebar
|
||||
onClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}
|
||||
title="Manage Passkey"
|
||||
onRootClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}
|
||||
/>
|
||||
<MenuItemGroup>
|
||||
<EnteMenuItem
|
||||
onClick={() => {}}
|
||||
startIcon={<EditIcon />}
|
||||
label={'Rename Passkey'}
|
||||
<>
|
||||
<EnteDrawer
|
||||
anchor="right"
|
||||
open={props.open}
|
||||
onClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}>
|
||||
<Stack spacing={'4px'} py={'12px'}>
|
||||
<Titlebar
|
||||
onClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}
|
||||
title="Manage Passkey"
|
||||
onRootClose={() => {
|
||||
setShowPasskeyDrawer(false);
|
||||
}}
|
||||
/>
|
||||
<MenuItemDivider />
|
||||
<EnteMenuItem
|
||||
onClick={() => {}}
|
||||
startIcon={<DeleteIcon />}
|
||||
label={'Delete Passkey'}
|
||||
/>
|
||||
</MenuItemGroup>
|
||||
</Stack>
|
||||
</EnteDrawer>
|
||||
<MenuItemGroup>
|
||||
<EnteMenuItem
|
||||
onClick={() => {}}
|
||||
startIcon={<EditIcon />}
|
||||
label={'Rename Passkey'}
|
||||
/>
|
||||
<MenuItemDivider />
|
||||
<EnteMenuItem
|
||||
onClick={() => {
|
||||
setShowDeletePasskeyModal(true);
|
||||
}}
|
||||
startIcon={<DeleteIcon />}
|
||||
label={'Delete Passkey'}
|
||||
/>
|
||||
</MenuItemGroup>
|
||||
</Stack>
|
||||
</EnteDrawer>
|
||||
<DeletePasskeyModal
|
||||
open={showDeletePasskeyModal}
|
||||
onClose={() => {
|
||||
setShowDeletePasskeyModal(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const PasskeyComponent = () => {
|
|||
|
||||
const init = async () => {
|
||||
const data = await getPasskeys();
|
||||
setPasskeys(data.passkeys);
|
||||
setPasskeys(data.passkeys || []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -21,6 +21,23 @@ export const getPasskeys = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const deletePasskey = async (id: string) => {
|
||||
try {
|
||||
const token = getToken();
|
||||
if (!token) return;
|
||||
const response = await HTTPService.delete(
|
||||
`${ENDPOINT}/passkeys/${id}`,
|
||||
{},
|
||||
{},
|
||||
{ 'X-Auth-Token': token }
|
||||
);
|
||||
return await response.data;
|
||||
} catch (e) {
|
||||
logError(e, 'delete passkey failed');
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPasskeyRegistrationOptions = async () => {
|
||||
try {
|
||||
const token = getToken();
|
||||
|
|
Loading…
Reference in a new issue