diff --git a/webapp/src/components/SettingsPage.tsx b/webapp/src/components/SettingsPage.tsx index 79735be..6f6e777 100644 --- a/webapp/src/components/SettingsPage.tsx +++ b/webapp/src/components/SettingsPage.tsx @@ -4,6 +4,7 @@ import { copyTextToClipboard } from '@/lib/clipboard'; import qrcode from 'qrcode-generator'; import type { Profile } from '@/lib/types'; import { t } from '@/lib/i18n'; +import ConfirmDialog from '@/components/ConfirmDialog'; interface SettingsPageProps { profile: Profile; @@ -52,6 +53,9 @@ export default function SettingsPage(props: SettingsPageProps) { const [recoveryMasterPassword, setRecoveryMasterPassword] = useState(''); const [recoveryCode, setRecoveryCode] = useState(''); const [passkeyName, setPasskeyName] = useState(''); + const [renamePasskey, setRenamePasskey] = useState<{ id: string; name: string } | null>(null); + const [renamePasskeyName, setRenamePasskeyName] = useState(''); + const [deletePasskey, setDeletePasskey] = useState<{ id: string; name: string } | null>(null); useEffect(() => { if (!props.totpEnabled) { @@ -90,6 +94,28 @@ export default function SettingsPage(props: SettingsPageProps) { props.onNotify?.('success', t('txt_recovery_code_loaded')); } + function formatDateTime(value: string | null | undefined): string { + if (!value) return t('txt_dash'); + const parsed = new Date(value); + if (Number.isNaN(parsed.getTime())) return value; + return parsed.toLocaleString(); + } + + async function confirmRenamePasskey(): Promise { + if (!renamePasskey) return; + const nextName = renamePasskeyName.trim(); + if (!nextName) return; + await props.onRenamePasskey(renamePasskey.id, nextName); + setRenamePasskey(null); + setRenamePasskeyName(''); + } + + async function confirmDeletePasskey(): Promise { + if (!deletePasskey) return; + await props.onDeletePasskey(deletePasskey.id); + setDeletePasskey(null); + } + return (
@@ -159,19 +185,77 @@ export default function SettingsPage(props: SettingsPageProps) {

最多 5 个,支持重命名和删除。

-
+
{props.passkeys.map((item) => ( -
-
- void props.onRenamePasskey(item.id, (e.currentTarget as HTMLInputElement).value)} /> - -
+
+ {item.name} + + 创建于 {formatDateTime(item.creationDate)} + + +
))} {!props.passkeys.length &&
暂无 Passkey
}
+ void confirmRenamePasskey()} + onCancel={() => { + setRenamePasskey(null); + setRenamePasskeyName(''); + }} + > + + + + void confirmDeletePasskey()} + onCancel={() => setDeletePasskey(null)} + /> +