rmaps-online/src/components/AuthButton.tsx

98 lines
3.1 KiB
TypeScript

'use client';
import { useState } from 'react';
import { useAuthStore } from '@/stores/auth';
export function AuthButton() {
const { isAuthenticated, username, did, loading, login, register, logout } = useAuthStore();
const [showRegister, setShowRegister] = useState(false);
const [regUsername, setRegUsername] = useState('');
const [error, setError] = useState('');
if (isAuthenticated) {
return (
<div className="flex items-center gap-3">
<div className="text-sm">
<span className="text-white/60">Signed in as </span>
<span className="text-rmaps-primary font-medium">{username || did?.slice(0, 16) + '...'}</span>
</div>
<button
onClick={logout}
className="text-xs text-white/40 hover:text-white/60 transition-colors"
>
Sign out
</button>
</div>
);
}
if (showRegister) {
return (
<div className="flex items-center gap-2">
<input
type="text"
value={regUsername}
onChange={(e) => setRegUsername(e.target.value)}
placeholder="Choose a username"
className="input text-sm py-1 px-2 w-40"
maxLength={20}
/>
<button
onClick={async () => {
if (!regUsername.trim()) return;
setError('');
try {
await register(regUsername.trim());
} catch (e: any) {
setError(e.message || 'Registration failed');
}
}}
disabled={loading || !regUsername.trim()}
className="btn-primary text-sm py-1 px-3"
>
{loading ? '...' : 'Register'}
</button>
<button
onClick={() => setShowRegister(false)}
className="text-xs text-white/40 hover:text-white/60"
>
Cancel
</button>
{error && <span className="text-xs text-red-400">{error}</span>}
</div>
);
}
return (
<div className="flex items-center gap-2">
<button
onClick={async () => {
setError('');
try {
await login();
} catch (e: any) {
// Any WebAuthn error (NotAllowedError, SecurityError, AbortError)
// should show register form — user likely has no passkey yet
if (e.name === 'NotAllowedError' || e.name === 'SecurityError' || e.name === 'AbortError') {
setShowRegister(true);
} else {
setError(e.message || 'Sign in failed');
}
}
}}
disabled={loading}
className="text-sm text-white/60 hover:text-rmaps-primary transition-colors flex items-center gap-1"
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className="w-4 h-4">
<circle cx={12} cy={10} r={3} />
<path d="M12 13v8" />
<path d="M9 18h6" />
<circle cx={12} cy={10} r={7} />
</svg>
{loading ? 'Signing in...' : 'Sign in with Passkey'}
</button>
{error && <span className="text-xs text-red-400">{error}</span>}
</div>
);
}