File size: 4,209 Bytes
769d6f8 dff8593 769d6f8 b283b34 7d72a03 769d6f8 7d72a03 769d6f8 7d72a03 769d6f8 dff8593 b00f0f1 769d6f8 dff8593 769d6f8 7447362 b283b34 769d6f8 763e887 769d6f8 7d72a03 769d6f8 7d72a03 769d6f8 b283b34 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | 'use client'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useRouter } from 'next/navigation'
import { loginSchema, type LoginForm } from 'lib/validations/auth'
import { emitAuthChanged } from 'hooks/useAuth'
import { getSupabaseBrowserConfig, isSupabaseBrowserConfigured } from 'lib/supabase/publicEnv'
export function LoginForm() {
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const supabaseReady = isSupabaseBrowserConfigured()
const supabaseEnv = getSupabaseBrowserConfig()
const router = useRouter()
const {
register,
handleSubmit,
formState: { errors }
} = useForm<LoginForm>({
resolver: zodResolver(loginSchema)
})
const onSubmit = async (data: LoginForm) => {
console.info('[login] submit', { supabaseReady, email: data.email, supabaseUrl: supabaseEnv.url })
try {
setLoading(true)
setError(null)
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
credentials: 'include'
})
const json = await res.json().catch(() => ({}))
if (!res.ok) {
setError(json?.error || 'Neplatné přihlašovací údaje')
return
}
// store token from public cookie as fallback for environments where HttpOnly cookie isn't sent
try {
if (typeof window !== 'undefined') {
const match = document.cookie.split(';').map(s => s.trim()).find(c => c.startsWith('letschat_session_pub='))
if (match) {
const token = match.split('=')[1]
window.localStorage.setItem('letschat_session', token)
}
}
} catch (e) {
// ignore
}
emitAuthChanged()
router.push('/dashboard')
} catch (e: any) {
console.error('Login error:', e)
setError(e?.message || 'Došlo k neočekávané chybě při přihlášení')
} finally {
setLoading(false)
}
}
return (
<form id="form-login" action="#" method="post" className="form" onSubmit={handleSubmit(onSubmit)}>
<div className="input">
<div className="text">E-mail</div>
<div className="insert">
<input
{...register('email')}
type="email"
maxLength={255}
placeholder="E-mailová adresa"
autoComplete="email"
/>
<div className="error">{errors.email?.message}</div>
</div>
</div>
<div className="input">
<div className="text">Heslo</div>
<div className="insert">
<input
{...register('password')}
type="password"
maxLength={255}
placeholder="Heslo k přihlášení"
autoComplete="current-password"
/>
<div className="error">{errors.password?.message}</div>
<div className="visible" data-input="password"></div>
</div>
</div>
<div className="input">
<div className="text"></div>
<div className="insert">
{error ? (
<div
className="error"
style={{
marginBottom: 12,
padding: '10px 12px',
background: '#FEE2E2',
color: '#991B1B',
borderRadius: 8,
fontWeight: 600
}}
>
{error}
</div>
) : null}
<input
type="submit"
value={loading ? 'Přihlašuji…' : 'Přihlásit'}
disabled={loading}
onClick={() => console.info('[login] button click', { supabaseReady, supabaseUrl: supabaseEnv.url })}
/>
{!supabaseReady ? (
<div className="error" style={{ marginTop: 8 }}>
Přidejte Supabase klíče do prostředí Space (NEXT_PUBLIC_SUPABASE_URL a NEXT_PUBLIC_SUPABASE_ANON_KEY) a znovu
spusťte build.
</div>
) : null}
</div>
</div>
</form>
)
}
|