diff --git a/apps/dashboard/src/components/dashboard-account-settings/email-and-auth/passkey-section.tsx b/apps/dashboard/src/components/dashboard-account-settings/email-and-auth/passkey-section.tsx new file mode 100644 index 000000000..0f84301b2 --- /dev/null +++ b/apps/dashboard/src/components/dashboard-account-settings/email-and-auth/passkey-section.tsx @@ -0,0 +1,117 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { useState } from "react"; +import { useStackApp, useUser } from "@stackframe/stack"; +import { Section } from "../section"; + +export function PasskeySection(props?: { + mockMode?: boolean, +}) { + const isInMockMode = !!props?.mockMode; + const user = useUser({ or: isInMockMode ? 'return-null' : "redirect" }); + const stackApp = useStackApp(); + + // In mock mode, show a placeholder message + if (isInMockMode && !user) { + return ( +
+ Passkey management is not available in demo mode. +
+ ); + } + + if (!user) { + return null; + } + + const project = stackApp.useProject(); + if (!project.config.passkeyEnabled) { + return null; + } + + return ; +} + +function PasskeySectionInner({ user }: { user: any }) { + const contactChannels = user.useContactChannels(); + + // passkey is enabled if there is a passkey + const hasPasskey = user.passkeyAuthEnabled; + + const isLastAuth = user.passkeyAuthEnabled && !user.hasPassword && user.oauthProviders.length === 0 && !user.otpAuthEnabled; + const [showConfirmationModal, setShowConfirmationModal] = useState(false); + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const hasValidEmail = contactChannels.filter((x: any) => (x.type as string) === 'email' && x.isVerified && x.usedForAuth).length > 0; + + const handleDeletePasskey = async () => { + await user.update({ passkeyAuthEnabled: false }); + setShowConfirmationModal(false); + }; + + const handleAddNewPasskey = async () => { + await user.registerPasskey(); + }; + + return ( +
+
+ {!hasValidEmail && ( + + To enable Passkey sign-in, please add a verified sign-in email. + + )} + {hasValidEmail && hasPasskey && isLastAuth && ( + + Passkey sign-in is enabled and cannot be disabled as it is currently the only sign-in method. + + )} + {!hasPasskey && hasValidEmail && ( + + )} + {hasValidEmail && hasPasskey && !isLastAuth && !showConfirmationModal && ( + + )} + {hasValidEmail && hasPasskey && !isLastAuth && showConfirmationModal && ( +
+ + Are you sure you want to disable Passkey sign-in? You will not be able to sign in with your passkey anymore. + +
+ + +
+
+ )} +
+
+ ); +}