Compare commits
2 Commits
2a42e335ca
...
1533d9aeab
| Author | SHA1 | Date | |
|---|---|---|---|
| 1533d9aeab | |||
| 1991c105b7 |
@@ -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)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user