Hotfixes #7

Merged
jason merged 1 commits from p4 into master 2026-03-06 13:46:46 -06:00
2 changed files with 22 additions and 37 deletions
Showing only changes of commit 1991c105b7 - Show all commits

View File

@@ -24,20 +24,13 @@ const s = {
deleteConfirm: { background: '#f8d7da', border: '1px solid #f5c6cb', borderRadius: '6px', padding: '12px', marginTop: '8px', fontSize: '12px' }, deleteConfirm: { background: '#f8d7da', border: '1px solid #f5c6cb', borderRadius: '6px', padding: '12px', marginTop: '8px', fontSize: '12px' },
}; };
const RESOLUTION_TYPES = [
'Corrective Training Completed',
'Management Discretion',
'Data Entry Error',
'Successfully Appealed',
];
export default function EmployeeModal({ employeeId, onClose }) { export default function EmployeeModal({ employeeId, onClose }) {
const [employee, setEmployee] = useState(null); const [employee, setEmployee] = useState(null);
const [score, setScore] = useState(null); const [score, setScore] = useState(null);
const [violations, setViolations] = useState([]); const [violations, setViolations] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [negating, setNegating] = useState(null); // violation object being soft-negated const [negating, setNegating] = useState(null);
const [confirmDel, setConfirmDel] = useState(null); // violation id pending hard delete const [confirmDel, setConfirmDel] = useState(null);
const load = useCallback(() => { const load = useCallback(() => {
setLoading(true); setLoading(true);
@@ -70,12 +63,18 @@ export default function EmployeeModal({ employeeId, onClose }) {
const handleHardDelete = async (id) => { const handleHardDelete = async (id) => {
await axios.delete(`/api/violations/${id}`); await axios.delete(`/api/violations/${id}`);
setConfirmDel(null); setConfirmDel(null);
load(); load(); // ← refetch employee list, score, and violations
}; };
const handleRestore = async (id) => { const handleRestore = async (id) => {
await axios.patch(`/api/violations/${id}/restore`); await axios.patch(`/api/violations/${id}/restore`);
load(); load(); // ← refetch employee list, score, and violations
};
const handleNegate = async ({ resolution_type, details, resolved_by }) => {
await axios.patch(`/api/violations/${negating.id}/negate`, { resolution_type, details, resolved_by });
setNegating(null);
load(); // ← CRITICAL FIX: refetch score immediately after negation
}; };
const tier = score ? getTier(score.active_points) : null; const tier = score ? getTier(score.active_points) : null;
@@ -232,11 +231,7 @@ export default function EmployeeModal({ employeeId, onClose }) {
{negating && ( {negating && (
<NegateModal <NegateModal
violation={negating} violation={negating}
onConfirm={async ({ resolution_type, details, resolved_by }) => { onConfirm={handleNegate}
await axios.patch(`/api/violations/${negating.id}/negate`, { resolution_type, details, resolved_by });
setNegating(null);
load();
}}
onCancel={() => setNegating(null)} onCancel={() => setNegating(null)}
/> />
)} )}

View File

@@ -51,17 +51,6 @@ function buildHtml(v, score) {
dateStyle: 'full', timeStyle: 'short' dateStyle: 'full', timeStyle: 'short'
}); });
// Map violation_type to handbook chapter reference (loaded from violations.js in frontend)
// Since we're in backend, we'll reconstruct key descriptions from the violation_name
// The database already stores violation_name (e.g., "Tardy Core Hours") and category
// Build a contextual description block
const contextBlock = v.details
? `<div style="background:#f8f9fa; border-left:3px solid #667eea; padding:12px 16px; margin:12px 0; font-size:12px; color:#444;">
<strong>Context:</strong> ${v.details}
</div>`
: '';
return `<!DOCTYPE html> return `<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@@ -111,13 +100,14 @@ function buildHtml(v, score) {
.points-display .pts { font-size: 36px; font-weight: 800; color: #667eea; } .points-display .pts { font-size: 36px; font-weight: 800; color: #667eea; }
.points-display .lbl { font-size: 12px; color: #666; } .points-display .lbl { font-size: 12px; color: #666; }
.sig-section { margin-top: 30px; } .sig-section { margin-top: 40px; page-break-inside: avoid; }
.sig-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 16px; } .sig-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-top: 24px; }
.sig-block { border-top: 1px solid #333; padding-top: 6px; } .sig-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 60px; }
.sig-label { font-size: 11px; color: #555; } .sig-label { font-size: 11px; color: #555; font-weight: 600; }
.sig-date-block { border-top: 1.5px solid #333; padding-top: 8px; min-height: 50px; margin-top: 32px; }
.footer-bar { .footer-bar {
margin-top: 30px; padding: 10px 0; margin-top: 40px; padding: 10px 0;
border-top: 2px solid #2c3e50; border-top: 2px solid #2c3e50;
font-size: 10px; color: #888; text-align: center; font-size: 10px; color: #888; text-align: center;
} }
@@ -249,11 +239,11 @@ function buildHtml(v, score) {
Chapter 4, Section 5. This document should be reviewed with the employee and signed by all parties. Chapter 4, Section 5. This document should be reviewed with the employee and signed by all parties.
</div> </div>
<!-- Signatures --> <!-- Signatures — EXPANDED VERTICAL SPACING -->
<div class="sig-section"> <div class="sig-section">
<div class="section-title" style="background:#34495e; color:white; padding:8px 14px; border-radius:4px; font-size:14px; font-weight:700;">Acknowledgement & Signatures</div> <div class="section-title" style="background:#34495e; color:white; padding:8px 14px; border-radius:4px; font-size:14px; font-weight:700;">Acknowledgement & Signatures</div>
<div style="padding: 12px 0;"> <div style="padding: 16px 0;">
<p style="font-size:12px; color:#555; margin-bottom:20px;"> <p style="font-size:12px; color:#555; margin-bottom:28px; line-height:1.6;">
By signing below, the employee acknowledges receipt of this violation record. By signing below, the employee acknowledges receipt of this violation record.
Acknowledgement does not imply agreement. The employee may submit a written Acknowledgement does not imply agreement. The employee may submit a written
response within 5 business days. response within 5 business days.
@@ -263,7 +253,7 @@ function buildHtml(v, score) {
<div class="sig-block"> <div class="sig-block">
<div class="sig-label">Employee Signature</div> <div class="sig-label">Employee Signature</div>
</div> </div>
<div style="margin-top:20px;" class="sig-block"> <div class="sig-date-block">
<div class="sig-label">Date</div> <div class="sig-label">Date</div>
</div> </div>
</div> </div>
@@ -271,7 +261,7 @@ function buildHtml(v, score) {
<div class="sig-block"> <div class="sig-block">
<div class="sig-label">Supervisor / Documenting Officer Signature</div> <div class="sig-label">Supervisor / Documenting Officer Signature</div>
</div> </div>
<div style="margin-top:20px;" class="sig-block"> <div class="sig-date-block">
<div class="sig-label">Date</div> <div class="sig-label">Date</div>
</div> </div>
</div> </div>