\ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { violationData, violationGroups } from '../data/violations'; import useEmployeeIntelligence from '../hooks/useEmployeeIntelligence'; import CpasBadge from './CpasBadge'; import TierWarning from './TierWarning'; import ViolationHistory from './ViolationHistory'; const s = { content: { padding: '32px 40px', background: '#111217', borderRadius: '10px', color: '#f8f9fa' }, section: { background: '#181924', borderLeft: '4px solid #d4af37', padding: '20px', marginBottom: '30px', borderRadius: '4px', border: '1px solid #2a2b3a' }, sectionTitle: { color: '#f8f9fa', fontSize: '20px', marginBottom: '15px', fontWeight: 700 }, grid: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '15px', marginTop: '15px' }, item: { display: 'flex', flexDirection: 'column' }, label: { fontWeight: 600, color: '#e5e7f1', marginBottom: '5px', fontSize: '13px' }, input: { padding: '10px', border: '1px solid #333544', borderRadius: '4px', fontSize: '14px', fontFamily: 'inherit', background: '#050608', color: '#f8f9fa' }, fullCol: { gridColumn: '1 / -1' }, contextBox: { background: '#141623', border: '1px solid #333544', borderRadius: '4px', padding: '10px', fontSize: '12px', color: '#d1d3e0', marginTop: '4px' }, repeatBadge: { display: 'inline-block', marginLeft: '8px', padding: '1px 7px', borderRadius: '10px', fontSize: '11px', fontWeight: 700, background: '#3b2e00', color: '#ffd666', border: '1px solid #d4af37' }, repeatWarn: { background: '#3b2e00', border: '1px solid #d4af37', borderRadius: '4px', padding: '8px 12px', marginTop: '6px', fontSize: '12px', color: '#ffdf8a' }, pointBox: { background: '#181200', border: '2px solid #d4af37', padding: '15px', borderRadius: '6px', marginTop: '15px', textAlign: 'center' }, pointValue: { fontSize: '24px', fontWeight: 'bold', color: '#ffd666', margin: '10px 0' }, scoreRow: { display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '14px', flexWrap: 'wrap' }, btnRow: { display: 'flex', gap: '15px', justifyContent: 'center', marginTop: '30px', flexWrap: 'wrap' }, btnPrimary: { padding: '15px 40px', fontSize: '16px', fontWeight: 600, border: 'none', borderRadius: '6px', cursor: 'pointer', background: 'linear-gradient(135deg, #d4af37 0%, #ffdf8a 100%)', color: '#000', textTransform: 'uppercase' }, btnPdf: { padding: '15px 40px', fontSize: '16px', fontWeight: 600, border: 'none', borderRadius: '6px', cursor: 'pointer', background: 'linear-gradient(135deg, #e74c3c 0%, #c0392b 100%)', color: 'white', textTransform: 'uppercase' }, btnSecondary: { padding: '15px 40px', fontSize: '16px', fontWeight: 600, border: '1px solid #333544', borderRadius: '6px', cursor: 'pointer', background: '#050608', color: '#f8f9fa', textTransform: 'uppercase' }, note: { background: '#141623', borderLeft: '4px solid #2196F3', padding: '15px', margin: '20px 0', borderRadius: '4px', fontSize: '13px', color: '#d1d3e0' }, statusOk: { marginTop: '15px', padding: '15px', borderRadius: '6px', textAlign: 'center', fontWeight: 600, background: '#053321', color: '#9ef7c1', border: '1px solid #0f5132' }, statusErr: { marginTop: '15px', padding: '15px', borderRadius: '6px', textAlign: 'center', fontWeight: 600, background: '#3c1114', color: '#ffb3b8', border: '1px solid #f5c6cb' }, }; const EMPTY_FORM = { employeeId: '', employeeName: '', department: '', supervisor: '', witnessName: '', violationType: '', incidentDate: '', incidentTime: '', amount: '', minutesLate: '', location: '', additionalDetails: '', points: 1, }; export default function ViolationForm() { const [employees, setEmployees] = useState([]); const [form, setForm] = useState(EMPTY_FORM); const [violation, setViolation] = useState(null); const [status, setStatus] = useState(null); const [lastViolId, setLastViolId] = useState(null); const [pdfLoading, setPdfLoading] = useState(false); const intel = useEmployeeIntelligence(form.employeeId || null); useEffect(() => { axios.get('/api/employees').then(r => setEmployees(r.data)).catch(() => {}); }, []); useEffect(() => { if (!violation || !form.violationType) return; const allTime = intel.countsAllTime[form.violationType]; if (allTime && allTime.count >= 1 && violation.minPoints !== violation.maxPoints) { setForm(prev => ({ ...prev, points: violation.maxPoints })); } else { setForm(prev => ({ ...prev, points: violation.minPoints })); } }, [form.violationType, violation, intel.countsAllTime]); const handleEmployeeSelect = e => { const emp = employees.find(x => x.id === parseInt(e.target.value)); if (!emp) return; setForm(prev => ({ ...prev, employeeId: emp.id, employeeName: emp.name, department: emp.department || '', supervisor: emp.supervisor || '' })); }; const handleViolationChange = e => { const key = e.target.value; const v = violationData[key] || null; setViolation(v); setForm(prev => ({ ...prev, violationType: key, points: v ? v.minPoints : 1 })); }; const handleChange = e => setForm(prev => ({ ...prev, [e.target.name]: e.target.value })); const handleSubmit = async e => { e.preventDefault(); if (!form.violationType) return setStatus({ ok: false, msg: 'Please select a violation type.' }); if (!form.employeeName) return setStatus({ ok: false, msg: 'Please enter an employee name.' }); try { const empRes = await axios.post('/api/employees', { name: form.employeeName, department: form.department, supervisor: form.supervisor }); const employeeId = empRes.data.id; const violRes = await axios.post('/api/violations', { employee_id: employeeId, violation_type: form.violationType, violation_name: violation?.name || form.violationType, category: violation?.category || 'General', points: parseInt(form.points), incident_date: form.incidentDate, incident_time: form.incidentTime || null, location: form.location || null, details: form.additionalDetails || null, witness_name: form.witnessName || null, }); const newId = violRes.data.id; setLastViolId(newId); const empList = await axios.get('/api/employees'); setEmployees(empList.data); setStatus({ ok: true, msg: `✓ Violation #${newId} recorded — click Download PDF to save the document.` }); setForm(EMPTY_FORM); setViolation(null); } catch (err) { setStatus({ ok: false, msg: '✗ Error: ' + (err.response?.data?.error || err.message) }); } }; const handleDownloadPdf = async () => { if (!lastViolId) return; setPdfLoading(true); try { const response = await axios.get(`/api/violations/${lastViolId}/pdf`, { responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/pdf' })); const link = document.createElement('a'); link.href = url; link.download = `CPAS_Violation_${lastViolId}.pdf`; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); } catch (err) { setStatus({ ok: false, msg: '✗ PDF generation failed: ' + err.message }); } finally { setPdfLoading(false); } }; const showField = f => violation?.fields?.includes(f); const priorCount90 = key => intel.counts90[key] || 0; const isRepeat = key => (intel.countsAllTime[key]?.count || 0) >= 1; return (