86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
// frontend\src\components\ui\login\PasskeyPanel.tsx
|
|
|
|
import Button from '../Button'
|
|
|
|
function passkeyUnsupportedReason() {
|
|
if (typeof window === 'undefined') {
|
|
return 'Passkeys sind in dieser Umgebung nicht verfügbar.'
|
|
}
|
|
|
|
if (!window.isSecureContext) {
|
|
return (
|
|
'Passkeys sind nur über HTTPS oder über localhost verfügbar. ' +
|
|
'Wenn du die App per IP öffnest, z. B. http://10.0.1.25:9999, blockiert der Browser Passkeys.'
|
|
)
|
|
}
|
|
|
|
if (typeof window.PublicKeyCredential === 'undefined') {
|
|
return 'Dein Browser unterstützt Passkeys/WebAuthn aktuell nicht.'
|
|
}
|
|
|
|
return 'Passkeys sind aktuell nicht verfügbar.'
|
|
}
|
|
|
|
export default function PasskeyPanel(props: {
|
|
supported: boolean
|
|
busy: boolean
|
|
mode: 'login' | 'register'
|
|
onLogin?: () => void
|
|
onRegister?: () => void
|
|
}) {
|
|
if (props.mode === 'login') {
|
|
return (
|
|
<div className="space-y-2">
|
|
<div className="relative flex items-center py-1">
|
|
<div className="h-px flex-1 bg-gray-200 dark:bg-white/10" />
|
|
<span className="px-3 text-xs text-gray-500 dark:text-gray-400">oder</span>
|
|
<div className="h-px flex-1 bg-gray-200 dark:bg-white/10" />
|
|
</div>
|
|
|
|
{props.supported ? (
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
className="w-full rounded-lg"
|
|
disabled={props.busy}
|
|
onClick={props.onLogin}
|
|
>
|
|
Mit Passkey anmelden
|
|
</Button>
|
|
) : (
|
|
<div className="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200">
|
|
{passkeyUnsupportedReason()}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="rounded-lg border border-gray-200 bg-white/70 p-3 dark:border-white/10 dark:bg-white/5">
|
|
<div className="text-sm font-semibold text-gray-900 dark:text-white">
|
|
Optional: Passkey hinzufügen
|
|
</div>
|
|
|
|
<div className="mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300">
|
|
Danach kannst du dich mit Fingerabdruck, Face ID, Windows Hello oder einem Sicherheitsschlüssel anmelden.
|
|
</div>
|
|
|
|
{props.supported ? (
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
className="mt-3 w-full rounded-lg"
|
|
disabled={props.busy}
|
|
onClick={props.onRegister}
|
|
>
|
|
Passkey hinzufügen
|
|
</Button>
|
|
) : (
|
|
<div className="mt-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200">
|
|
{passkeyUnsupportedReason()}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
} |