From 2d43b8d7c4914e2f11e1781c7efe6c4f42cd5073 Mon Sep 17 00:00:00 2001 From: httpjamesm Date: Sun, 24 Dec 2023 16:44:08 -0500 Subject: [PATCH] feat: delete passkey --- apps/accounts/src/pages/_app.tsx | 16 +++- .../src/pages/passkeys/DeletePasskeyModal.tsx | 70 +++++++++++++++++ .../pages/passkeys/ManagePasskeyDrawer.tsx | 76 +++++++++++-------- .../src/pages/passkeys/PasskeysList.tsx | 2 +- apps/accounts/src/services/passkeysService.ts | 17 +++++ 5 files changed, 146 insertions(+), 35 deletions(-) create mode 100644 apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx diff --git a/apps/accounts/src/pages/_app.tsx b/apps/accounts/src/pages/_app.tsx index 6237771dc..593bb153b 100644 --- a/apps/accounts/src/pages/_app.tsx +++ b/apps/accounts/src/pages/_app.tsx @@ -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) { - + + + ); diff --git a/apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx b/apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx new file mode 100644 index 000000000..318c02aaf --- /dev/null +++ b/apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx @@ -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 ( + + + + Are you sure you want to delete this passkey? This action is + irreversible. + + + Delete Passkey + + + + + ); +}; + +export default DeletePasskeyModal; diff --git a/apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx b/apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx index 65d7bfafa..1e011ab0b 100644 --- a/apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx +++ b/apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx @@ -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 ( - { - setShowPasskeyDrawer(false); - }}> - - { - setShowPasskeyDrawer(false); - }} - title="Manage Passkey" - onRootClose={() => { - setShowPasskeyDrawer(false); - }} - /> - - {}} - startIcon={} - label={'Rename Passkey'} + <> + { + setShowPasskeyDrawer(false); + }}> + + { + setShowPasskeyDrawer(false); + }} + title="Manage Passkey" + onRootClose={() => { + setShowPasskeyDrawer(false); + }} /> - - {}} - startIcon={} - label={'Delete Passkey'} - /> - - - + + {}} + startIcon={} + label={'Rename Passkey'} + /> + + { + setShowDeletePasskeyModal(true); + }} + startIcon={} + label={'Delete Passkey'} + /> + + + + { + setShowDeletePasskeyModal(false); + }} + /> + ); }; diff --git a/apps/accounts/src/pages/passkeys/PasskeysList.tsx b/apps/accounts/src/pages/passkeys/PasskeysList.tsx index 6eb952528..0d92e140a 100644 --- a/apps/accounts/src/pages/passkeys/PasskeysList.tsx +++ b/apps/accounts/src/pages/passkeys/PasskeysList.tsx @@ -9,7 +9,7 @@ const PasskeyComponent = () => { const init = async () => { const data = await getPasskeys(); - setPasskeys(data.passkeys); + setPasskeys(data.passkeys || []); }; useEffect(() => { diff --git a/apps/accounts/src/services/passkeysService.ts b/apps/accounts/src/services/passkeysService.ts index f5cb3bd06..9c087d3b1 100644 --- a/apps/accounts/src/services/passkeysService.ts +++ b/apps/accounts/src/services/passkeysService.ts @@ -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();