// auth-login.jsx — login screen (pilih nama + PIN) const { useState: useSL, useEffect: useEL } = React; function Login({ onLogin }) { const [emps, setEmps] = useSL(null); const [sel, setSel] = useSL(null); const [pickerOpen, setPickerOpen] = useSL(false); const [pin, setPin] = useSL(''); const [err, setErr] = useSL(''); const [busy, setBusy] = useSL(false); const [q, setQ] = useSL(''); useEL(() => { MA.getEmployees().then(r => setEmps(r.ok ? r.employees : [])); }, []); const submit = async (code) => { if (!sel) { setErr('Pilih nama dulu'); return; } setBusy(true); setErr(''); const r = await MA.login(sel.id, code); setBusy(false); if (r.ok) { MA.saveSession(r.user); onLogin(r.user); } else { setErr(r.err || 'Login gagal'); setPin(''); } }; const tapKey = (d) => { if (busy) return; setErr(''); if (d === 'del') { setPin(p => p.slice(0, -1)); return; } setPin(p => { const np = (p + d).slice(0, 4); if (np.length === 4) setTimeout(() => submit(np), 120); return np; }); }; const list = (emps || []).filter(e => e.name.toLowerCase().includes(q.toLowerCase()) || e.jabatan.toLowerCase().includes(q.toLowerCase())); return (
{/* hero */}
MOTOART
Absensi Karyawan
{MA.DEALER.branch}
{/* name field */}
Nama Karyawan
{/* PIN */}
Masukkan PIN
{[0, 1, 2, 3].map(i => (
i ? 'var(--accent)' : 'var(--surface-3)', border: pin.length > i ? 'none' : '2px solid var(--border-2)', transition: 'all .15s' }}>
))}
{busy ? 'Memeriksa…' : err}
{/* keypad */}
{['1','2','3','4','5','6','7','8','9'].map(d => ( ))}
{MA.DEMO && (
Mode Demo · PIN karyawan 1234, pemilik 0000
)}
{/* name picker sheet */} {pickerOpen && (
setPickerOpen(false)}>
e.stopPropagation()} style={{ maxHeight: '78%', display: 'flex', flexDirection: 'column' }}>
Pilih Nama
setQ(e.target.value)} placeholder="Cari nama…" style={{ border: 'none', outline: 'none', background: 'transparent', flex: 1, fontSize: 14, color: 'var(--text)', fontFamily: 'inherit' }} />
{emps === null &&
Memuat…
} {list.map(e => ( ))}
)}
); } const keyStyle = { height: 58, borderRadius: 16, background: 'var(--surface)', border: '1px solid var(--border)', boxShadow: 'var(--shadow-sm)', fontSize: 24, fontWeight: 700, color: 'var(--text)', }; window.Login = Login;