femto-webapp/src/app/auth/pages/LoginPage.tsx

129 lines
4 KiB
TypeScript

import { useRef, useState, FormEvent, useEffect } from 'react'
import SingleColumnLayout from '../../../layouts/SingleColumnLayout.tsx'
import TextInput from '../../../components/inputs/TextInput.tsx'
import Button from '../../../components/buttons/Button.tsx'
import { AuthService } from '../authService.ts'
import { useNavigate } from 'react-router-dom'
import { useUser } from '../../user/user.ts'
import NavBar from '../../../components/NavBar.tsx'
import NavButton from '../../../components/buttons/NavButton.tsx'
import LinkButton from '../../../components/buttons/LinkButton.tsx'
import { useTranslations } from '../../i18n/translations.ts'
interface LoginPageProps {
authService: AuthService
}
export default function LoginPage({ authService }: LoginPageProps) {
const { t } = useTranslations()
const [isSubmitting, setIsSubmitting] = useState(false)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [rememberMe, setRememberMe] = useState(false)
const [error, setError] = useState<string | null>(null)
const usernameInputRef = useRef<HTMLInputElement | null>(null)
const passwordInputRef = useRef<HTMLInputElement | null>(null)
const navigate = useNavigate()
const user = useUser()
useEffect(() => {
if (user) {
const search = new URLSearchParams(window.location.search)
navigate(search.get('t') || '/')
}
}, [user, navigate])
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (!username) {
setError("it's not username :(")
return
}
if (!password) {
setError("it's not password :(")
return
}
setError(null)
setIsSubmitting(true)
try {
await authService.login(username, password, rememberMe)
} catch (error: unknown) {
setError(error instanceof Error ? error.message : 'something went terribly wrong')
} finally {
setIsSubmitting(false)
}
}
return (
<SingleColumnLayout
navbar={
<NavBar>
<NavButton to={'/'}>{t('nav.home')}</NavButton>
</NavBar>
}
>
<main className="w-full mx-auto p-4">
<div className="mt-12">
<form className="flex flex-col gap-4 max-w-md" onSubmit={onSubmit}>
<div className="flex flex-col gap-1">
<label htmlFor="username" className="text-sm text-gray-600">
{t('auth.username.label')}
</label>
<TextInput
ref={usernameInputRef}
id="username"
value={username}
onInput={setUsername}
className={'mb-4'}
/>
</div>
<div className="flex flex-col gap-1">
<label htmlFor="password" className="text-sm text-gray-600">
{t('auth.password.label')}
</label>
<TextInput
ref={passwordInputRef}
type="password"
id="password"
value={password}
onInput={setPassword}
className={'mb-4'}
/>
</div>
<div className="flex items-center gap-2 mt-2 hidden">
<input
type="checkbox"
id="rememberMe"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="h-4 w-4"
/>
<label htmlFor="rememberMe" className="text-sm text-gray-600">
{t('auth.remember_me.label')}
</label>
</div>
<Button className="mt-4" disabled={isSubmitting} type="submit">
{isSubmitting ? t('misc.loading') : t('auth.login.cta')}
</Button>
<LinkButton secondary to={{ pathname: '/signup', search: window.location.search }}>
{t('auth.login.register_instead')}
</LinkButton>
<span className={'text-xs h-3 text-red-500'}>{error}</span>
</form>
</div>
</main>
</SingleColumnLayout>
)
}