import { useState, type FormEvent } from 'react' import { Link, useNavigate, useSearch } from '@tanstack/react-router' import { AuthCard } from '@/components/auth/AuthCard' import { Alert } from '@/components/ui/Alert' import { Button, buttonClasses } from '@/components/ui/Button' import { Divider } from '@/components/ui/Divider' import { TextField } from '@/components/ui/TextField' import { API_BASE, errorMessage } from '@/lib/api' import { useLogin, useProviders } from '@/lib/auth' import { safeRedirectPath } from '@/lib/redirect' // Server-initiated redirect (not a fetch): the browser navigates to the Go // handler, which 302s to the IdP. const OIDC_LOGIN_URL = `${API_BASE}/auth/oidc/login` // Messages for the ?error= codes the OIDC callback redirects back with. const callbackErrors: Record = { oidc: 'Single sign-on did not complete. Please try again.', oidc_unavailable: 'The single sign-on provider is currently unavailable.', state: 'Your sign-in attempt expired. Please start again.', no_email: 'Your identity provider did not share an email address, which pansy needs.', email_unverified: 'Your email address is not verified with the identity provider.', oidc_conflict: 'That single sign-on identity conflicts with an existing account.', } export function LoginPage() { const search = useSearch({ from: '/login' }) const navigate = useNavigate() const providers = useProviders() const login = useLogin() const [email, setEmail] = useState('') const [password, setPassword] = useState('') const dest = safeRedirectPath(search.redirect) const callbackError = search.error ? (callbackErrors[search.error] ?? callbackErrors.oidc) : null async function onSubmit(e: FormEvent) { e.preventDefault() try { await login.mutateAsync({ email, password }) await navigate({ to: dest }) } catch { // Shown below via login.error. } } const local = providers.data?.local ?? false const oidc = providers.data?.oidc ?? false return (
{callbackError && {callbackError}} {providers.isPending &&

Loading…

} {providers.isError && Could not load sign-in options. Please refresh.} {oidc && ( {providers.data?.oidcLabel || 'Sign in with SSO'} )} {oidc && local && or} {local && (
setEmail(e.target.value)} /> setPassword(e.target.value)} /> {login.isError && {errorMessage(login.error, 'Could not sign in.')}} )} {providers.isSuccess && !local && !oidc && ( No sign-in methods are configured on this server. )} {local && (

No account?{' '} Create one

)}
) }