2026-03-06 12:53:40 -06:00
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
|
|
|
|
|
const s = {
|
2026-03-06 15:25:48 -06:00
|
|
|
overlay: {
|
|
|
|
|
position: 'fixed',
|
|
|
|
|
inset: 0,
|
|
|
|
|
background: 'rgba(0,0,0,0.75)',
|
|
|
|
|
display: 'flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
justifyContent: 'center',
|
2026-03-06 15:38:20 -06:00
|
|
|
zIndex: 2000,
|
2026-03-06 15:25:48 -06:00
|
|
|
},
|
|
|
|
|
modal: {
|
|
|
|
|
width: '480px',
|
|
|
|
|
maxWidth: '95vw',
|
|
|
|
|
background: '#111217',
|
|
|
|
|
borderRadius: '12px',
|
|
|
|
|
boxShadow: '0 16px 40px rgba(0,0,0,0.8)',
|
|
|
|
|
color: '#f8f9fa',
|
|
|
|
|
overflow: 'hidden',
|
|
|
|
|
border: '1px solid #2a2b3a',
|
|
|
|
|
},
|
|
|
|
|
header: {
|
|
|
|
|
padding: '18px 24px',
|
|
|
|
|
borderBottom: '1px solid #222',
|
|
|
|
|
background: 'linear-gradient(135deg, #000000, #151622)',
|
|
|
|
|
},
|
|
|
|
|
title: {
|
|
|
|
|
fontSize: '18px',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
},
|
|
|
|
|
subtitle: {
|
|
|
|
|
fontSize: '12px',
|
|
|
|
|
color: '#c0c2d6',
|
|
|
|
|
marginTop: '4px',
|
|
|
|
|
},
|
|
|
|
|
body: {
|
|
|
|
|
padding: '18px 24px 8px 24px',
|
|
|
|
|
},
|
|
|
|
|
pill: {
|
|
|
|
|
background: '#3b2e00',
|
|
|
|
|
borderRadius: '6px',
|
|
|
|
|
padding: '8px 10px',
|
|
|
|
|
fontSize: '12px',
|
|
|
|
|
color: '#ffd666',
|
|
|
|
|
border: '1px solid #d4af37',
|
|
|
|
|
marginBottom: '14px',
|
|
|
|
|
},
|
|
|
|
|
label: {
|
|
|
|
|
fontSize: '13px',
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
marginBottom: '4px',
|
|
|
|
|
color: '#e5e7f1',
|
|
|
|
|
},
|
|
|
|
|
input: {
|
|
|
|
|
width: '100%',
|
|
|
|
|
padding: '9px 10px',
|
|
|
|
|
borderRadius: '6px',
|
|
|
|
|
border: '1px solid #333544',
|
|
|
|
|
background: '#050608',
|
|
|
|
|
color: '#f8f9fa',
|
|
|
|
|
fontSize: '13px',
|
|
|
|
|
fontFamily: 'inherit',
|
|
|
|
|
marginBottom: '14px',
|
|
|
|
|
},
|
|
|
|
|
textarea: {
|
|
|
|
|
width: '100%',
|
|
|
|
|
minHeight: '80px',
|
|
|
|
|
resize: 'vertical',
|
|
|
|
|
padding: '9px 10px',
|
|
|
|
|
borderRadius: '6px',
|
|
|
|
|
border: '1px solid #333544',
|
|
|
|
|
background: '#050608',
|
|
|
|
|
color: '#f8f9fa',
|
|
|
|
|
fontSize: '13px',
|
|
|
|
|
fontFamily: 'inherit',
|
|
|
|
|
marginBottom: '14px',
|
|
|
|
|
},
|
|
|
|
|
footer: {
|
|
|
|
|
display: 'flex',
|
|
|
|
|
justifyContent: 'flex-end',
|
|
|
|
|
gap: '10px',
|
|
|
|
|
padding: '16px 24px 20px 24px',
|
|
|
|
|
background: '#0c0d14',
|
|
|
|
|
borderTop: '1px solid #222',
|
|
|
|
|
},
|
|
|
|
|
btnCancel: {
|
|
|
|
|
padding: '10px 20px',
|
|
|
|
|
borderRadius: '6px',
|
|
|
|
|
border: '1px solid #333544',
|
|
|
|
|
background: '#050608',
|
|
|
|
|
color: '#f8f9fa',
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
fontSize: '13px',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
},
|
|
|
|
|
btnConfirm: {
|
|
|
|
|
padding: '10px 22px',
|
|
|
|
|
borderRadius: '6px',
|
|
|
|
|
border: 'none',
|
|
|
|
|
background: 'linear-gradient(135deg, #d4af37 0%, #ffdf8a 100%)',
|
|
|
|
|
color: '#000',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
fontSize: '13px',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
textTransform: 'uppercase',
|
|
|
|
|
},
|
2026-03-06 12:53:40 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function NegateModal({ violation, onConfirm, onCancel }) {
|
2026-03-06 15:25:48 -06:00
|
|
|
const [resolutionType, setResolutionType] = useState('Corrective Training Completed');
|
|
|
|
|
const [details, setDetails] = useState('');
|
|
|
|
|
const [resolvedBy, setResolvedBy] = useState('');
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
if (!violation) return null;
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
const handleConfirm = () => {
|
2026-03-06 15:38:20 -06:00
|
|
|
if (!onConfirm) return;
|
2026-03-06 15:25:48 -06:00
|
|
|
onConfirm({
|
|
|
|
|
resolution_type: resolutionType,
|
|
|
|
|
details,
|
|
|
|
|
resolved_by: resolvedBy,
|
|
|
|
|
});
|
|
|
|
|
};
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:44:15 -06:00
|
|
|
const handleOverlayClick = (e) => {
|
|
|
|
|
if (e.target === e.currentTarget && onCancel) onCancel();
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
return (
|
2026-03-06 15:44:15 -06:00
|
|
|
<div style={s.overlay} onClick={handleOverlayClick}>
|
2026-03-06 15:25:48 -06:00
|
|
|
<div style={s.modal}>
|
|
|
|
|
<div style={s.header}>
|
|
|
|
|
<div style={s.title}>⊘ Negate Violation Points</div>
|
|
|
|
|
<div style={s.subtitle}>
|
|
|
|
|
This will zero out the points from this incident. The record remains in the audit log.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
<div style={s.body}>
|
|
|
|
|
<div style={s.pill}>
|
|
|
|
|
{violation.violation_name} · {violation.points} pts · {violation.incident_date}
|
|
|
|
|
</div>
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
<div>
|
|
|
|
|
<div style={s.label}>Resolution Type *</div>
|
|
|
|
|
<select
|
|
|
|
|
style={s.input}
|
|
|
|
|
value={resolutionType}
|
|
|
|
|
onChange={e => setResolutionType(e.target.value)}
|
|
|
|
|
>
|
|
|
|
|
<option>Corrective Training Completed</option>
|
|
|
|
|
<option>Documentation Error</option>
|
|
|
|
|
<option>Policy Clarification / Exception</option>
|
|
|
|
|
<option>Management Discretion</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
<div>
|
|
|
|
|
<div style={s.label}>Additional Details</div>
|
|
|
|
|
<textarea
|
|
|
|
|
style={s.textarea}
|
|
|
|
|
value={details}
|
|
|
|
|
onChange={e => setDetails(e.target.value)}
|
|
|
|
|
placeholder="Briefly describe why points are being negated..."
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
<div>
|
|
|
|
|
<div style={s.label}>Resolved By</div>
|
|
|
|
|
<input
|
|
|
|
|
style={s.input}
|
|
|
|
|
value={resolvedBy}
|
|
|
|
|
onChange={e => setResolvedBy(e.target.value)}
|
|
|
|
|
placeholder="Supervisor or HR"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-06 12:53:40 -06:00
|
|
|
|
2026-03-06 15:25:48 -06:00
|
|
|
<div style={s.footer}>
|
2026-03-06 15:44:15 -06:00
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
style={s.btnCancel}
|
|
|
|
|
onClick={() => onCancel && onCancel()}
|
|
|
|
|
>
|
2026-03-06 15:25:48 -06:00
|
|
|
Cancel
|
|
|
|
|
</button>
|
2026-03-06 15:44:15 -06:00
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
style={s.btnConfirm}
|
|
|
|
|
onClick={handleConfirm}
|
|
|
|
|
>
|
2026-03-06 15:25:48 -06:00
|
|
|
Confirm Negation
|
|
|
|
|
</button>
|
2026-03-06 12:53:40 -06:00
|
|
|
</div>
|
2026-03-06 15:25:48 -06:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-03-06 12:53:40 -06:00
|
|
|
}
|