118 lines
4.6 KiB
TypeScript
118 lines
4.6 KiB
TypeScript
import { useState, FormEvent } from 'react'
|
|
import { useRouter } from 'next/router'
|
|
import { useApp } from '@/lib/context'
|
|
import Head from 'next/head'
|
|
|
|
export default function LoginPage() {
|
|
const { login, user, loading } = useApp()
|
|
const router = useRouter()
|
|
const [email, setEmail] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [error, setError] = useState('')
|
|
const [busy, setBusy] = useState(false)
|
|
|
|
if (!loading && user) {
|
|
const dest = { ADMIN: '/admin', QC: '/qc', PRODUCTION: '/fill', PRODUCTION_LEAD: '/fill', LOGISTICS_LEAD: '/qc/shipments', MANAGEMENT: '/management' }
|
|
router.replace(dest[user.role] || '/qc')
|
|
return null
|
|
}
|
|
|
|
const submit = async (e: FormEvent) => {
|
|
e.preventDefault()
|
|
setBusy(true)
|
|
setError('')
|
|
const err = await login(email, password)
|
|
if (err) { setError(err); setBusy(false) }
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Head><title>Sign in — V11 QMS</title></Head>
|
|
<div style={{
|
|
minHeight: '100vh', background: '#F8F7FD',
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '24px'
|
|
}}>
|
|
<div style={{ width: '100%', maxWidth: '380px' }}>
|
|
<div style={{ textAlign: 'center', marginBottom: '32px' }}>
|
|
<div style={{
|
|
width: '44px', height: '44px', borderRadius: '12px',
|
|
background: '#534AB7', display: 'inline-flex', alignItems: 'center',
|
|
justifyContent: 'center', marginBottom: '12px'
|
|
}}>
|
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2">
|
|
<path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/>
|
|
</svg>
|
|
</div>
|
|
<h1 style={{ fontSize: '20px', fontWeight: '600', color: '#1a1a1a', margin: '0 0 4px' }}>
|
|
V11 Enterprise QMS
|
|
</h1>
|
|
<p style={{ fontSize: '13px', color: '#888', margin: 0 }}>Sign in to your account</p>
|
|
</div>
|
|
|
|
<form onSubmit={submit} style={{
|
|
background: 'white', borderRadius: '12px',
|
|
border: '0.5px solid #e8e8e8', padding: '24px'
|
|
}}>
|
|
{error && (
|
|
<div style={{
|
|
background: '#FCEBEB', color: '#791F1F', border: '0.5px solid #F09595',
|
|
borderRadius: '8px', padding: '9px 12px', fontSize: '12px', marginBottom: '16px'
|
|
}}>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div style={{ marginBottom: '14px' }}>
|
|
<label style={{ display: 'block', fontSize: '11px', color: '#666', marginBottom: '4px', fontWeight: '500' }}>
|
|
Email address
|
|
</label>
|
|
<input
|
|
type="email" required value={email}
|
|
onChange={e => setEmail(e.target.value)}
|
|
placeholder="you@company.com"
|
|
style={{
|
|
width: '100%', padding: '9px 11px', fontSize: '13px',
|
|
border: '0.5px solid #ddd', borderRadius: '8px',
|
|
outline: 'none', fontFamily: 'inherit', background: 'transparent'
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<label style={{ display: 'block', fontSize: '11px', color: '#666', marginBottom: '4px', fontWeight: '500' }}>
|
|
Password
|
|
</label>
|
|
<input
|
|
type="password" required value={password}
|
|
onChange={e => setPassword(e.target.value)}
|
|
placeholder="••••••••"
|
|
style={{
|
|
width: '100%', padding: '9px 11px', fontSize: '13px',
|
|
border: '0.5px solid #ddd', borderRadius: '8px',
|
|
outline: 'none', fontFamily: 'inherit', background: 'transparent'
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
type="submit" disabled={busy}
|
|
style={{
|
|
width: '100%', padding: '10px', fontSize: '13px', fontWeight: '500',
|
|
background: busy ? '#AFA9EC' : '#534AB7', color: 'white',
|
|
border: 'none', borderRadius: '8px', cursor: busy ? 'not-allowed' : 'pointer',
|
|
fontFamily: 'inherit', transition: 'background 0.1s'
|
|
}}
|
|
>
|
|
{busy ? 'Signing in…' : 'Sign in'}
|
|
</button>
|
|
</form>
|
|
|
|
<p style={{ textAlign: 'center', fontSize: '11px', color: '#aaa', marginTop: '16px' }}>
|
|
No account? Ask your system administrator.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|