65 lines
2.0 KiB
React
65 lines
2.0 KiB
React
import React, { useState } from 'react'
|
|
import { authClient } from '../api'
|
|
import { IconBusFront } from './icons'
|
|
|
|
export default function Login({ onLogin }) {
|
|
const [userCode, setUserCode] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [error, setError] = useState(null)
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const submit = async (e) => {
|
|
e.preventDefault()
|
|
setError(null)
|
|
setLoading(true)
|
|
try {
|
|
const res = await authClient.post('/login', { userCode, password })
|
|
const token = res.data.token
|
|
const me = await authClient.get('/me', { headers: { Authorization: `Bearer ${token}` } })
|
|
onLogin(token, me.data.user)
|
|
} catch (err) {
|
|
setError(err.response?.data?.error || 'login_failed')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="auth-page">
|
|
<div className="auth-card">
|
|
<div className="auth-brand">
|
|
<div className="brand-mark"><IconBusFront size={26} /></div>
|
|
<div>
|
|
<h1>Transit Beheer</h1>
|
|
<p>Operationeel dashboard voor netwerkbeheer</p>
|
|
</div>
|
|
</div>
|
|
<form onSubmit={submit}>
|
|
<label>
|
|
Gebruikercode
|
|
<input
|
|
value={userCode}
|
|
onChange={(e) => setUserCode(e.target.value)}
|
|
placeholder="Bijv. 1234"
|
|
autoFocus
|
|
/>
|
|
</label>
|
|
<label>
|
|
Wachtwoord
|
|
<input
|
|
type="password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
placeholder="••••••••"
|
|
/>
|
|
</label>
|
|
{error && <div className="error">{error}</div>}
|
|
<button type="submit" className="auth-submit" disabled={loading}>
|
|
{loading ? 'Bezig met inloggen…' : 'Inloggen'}
|
|
</button>
|
|
</form>
|
|
<div className="auth-footer">Alleen beheerders hebben toegang</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
} |