diff --git a/client/src/components/EmployeeModal.jsx b/client/src/components/EmployeeModal.jsx index aca7091..4706e87 100755 --- a/client/src/components/EmployeeModal.jsx +++ b/client/src/components/EmployeeModal.jsx @@ -2,6 +2,8 @@ import React, { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import CpasBadge, { getTier } from './CpasBadge'; import NegateModal from './NegateModal'; +import EditEmployeeModal from './EditEmployeeModal'; +import AmendViolationModal from './AmendViolationModal'; const s = { overlay: { @@ -18,10 +20,15 @@ const s = { padding: '24px 28px', position: 'sticky', top: 0, zIndex: 10, borderBottom: '1px solid #222', }, + headerRow: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }, closeBtn: { float: 'right', background: 'none', border: 'none', color: 'white', fontSize: '22px', cursor: 'pointer', lineHeight: 1, marginTop: '-2px', }, + editEmpBtn: { + background: 'none', border: '1px solid #555', color: '#ccc', borderRadius: '5px', + padding: '4px 10px', fontSize: '11px', cursor: 'pointer', marginTop: '8px', fontWeight: 600, + }, body: { padding: '24px 28px', flex: 1 }, scoreRow: { display: 'flex', gap: '12px', flexWrap: 'wrap', marginBottom: '24px' }, scoreCard: { @@ -62,19 +69,31 @@ const s = { borderRadius: '4px', padding: '3px 8px', fontSize: '11px', cursor: 'pointer', fontWeight: 600, }, + amendBtn: { + background: 'none', border: '1px solid #4db6ac', color: '#4db6ac', + borderRadius: '4px', padding: '3px 8px', fontSize: '11px', + cursor: 'pointer', marginRight: '4px', fontWeight: 600, + }, deleteConfirm: { background: '#3c1114', border: '1px solid #f5c6cb', borderRadius: '6px', padding: '12px', marginTop: '8px', fontSize: '12px', color: '#ffb3b8', }, + amendBadge: { + display: 'inline-block', marginLeft: '4px', padding: '1px 5px', borderRadius: '8px', + fontSize: '9px', fontWeight: 700, background: '#0e2a2a', color: '#4db6ac', + border: '1px solid #1a4a4a', verticalAlign: 'middle', + }, }; export default function EmployeeModal({ employeeId, onClose }) { - const [employee, setEmployee] = useState(null); - const [score, setScore] = useState(null); + const [employee, setEmployee] = useState(null); + const [score, setScore] = useState(null); const [violations, setViolations] = useState([]); - const [loading, setLoading] = useState(true); - const [negating, setNegating] = useState(null); + const [loading, setLoading] = useState(true); + const [negating, setNegating] = useState(null); const [confirmDel, setConfirmDel] = useState(null); + const [editingEmp, setEditingEmp] = useState(false); + const [amending, setAmending] = useState(null); // violation object const load = useCallback(() => { setLoading(true); @@ -96,9 +115,9 @@ export default function EmployeeModal({ employeeId, onClose }) { const handleDownloadPdf = async (violId, empName, date) => { const response = await axios.get(`/api/violations/${violId}/pdf`, { responseType: 'blob' }); - const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/pdf' })); + const url = window.URL.createObjectURL(new Blob([response.data], { type: 'application/pdf' })); const link = document.createElement('a'); - link.href = url; + link.href = url; link.download = `CPAS_${(empName || '').replace(/[^a-z0-9]/gi, '_')}_${date}.pdf`; document.body.appendChild(link); link.click(); @@ -119,39 +138,42 @@ export default function EmployeeModal({ employeeId, onClose }) { }; const handleNegate = async ({ resolution_type, details, resolved_by }) => { - await axios.patch(`/api/violations/${negating.id}/negate`, { - resolution_type, details, resolved_by, - }); + await axios.patch(`/api/violations/${negating.id}/negate`, { resolution_type, details, resolved_by }); setNegating(null); setConfirmDel(null); load(); }; - const tier = score ? getTier(score.active_points) : null; - const active = violations.filter((v) => !v.negated); + const tier = score ? getTier(score.active_points) : null; + const active = violations.filter((v) => !v.negated); const negated = violations.filter((v) => v.negated); - // FIX: overlay click only closes if clicking the backdrop itself, NOT children - const handleOverlayClick = (e) => { - if (e.target === e.currentTarget) onClose(); - }; + const handleOverlayClick = (e) => { if (e.target === e.currentTarget) onClose(); }; return ( - // FIX: panel uses onClick stopPropagation to prevent bubbling to overlay