From f006c015b064501f26cdd78fc1b5ed32333837d2 Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 6 Mar 2026 14:14:11 -0600 Subject: [PATCH 01/85] Add client/public --- client/public | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/public diff --git a/client/public b/client/public new file mode 100644 index 0000000..e69de29 -- 2.52.0 From 6305cedb14b1e164dcfda0aced54c693c9c7dfa4 Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 6 Mar 2026 14:14:27 -0600 Subject: [PATCH 02/85] Delete client/public --- client/public | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 client/public diff --git a/client/public b/client/public deleted file mode 100644 index e69de29..0000000 -- 2.52.0 From eb07832cc7a05fc8568121a6d6dc48232e23ae2c Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 6 Mar 2026 14:15:05 -0600 Subject: [PATCH 03/85] Upload files to "client/public/static" --- client/public/static/mpm-logo.png | Bin 0 -> 4188 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/public/static/mpm-logo.png diff --git a/client/public/static/mpm-logo.png b/client/public/static/mpm-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..02e50cc2a2713bdd2a2ade7301d92179d5b25707 GIT binary patch literal 4188 zcmV-i5ToyjP)vA9j;hK@3kU^t-860O0i+*t5g#rg|mW%<1)rA&!Lg5dx; zMLGHL_^CPr=Q&shi${J7!DMZD7ag!fhsQw8k!3TGXFqG#!8*3?0-0a6p-f5vnUqKv zJRs-CHeT_r+n_lP)=?NJ7$cDgOj2MjR32*f4MzUKZIivpV3oh$NeXx_C6a=X%AFkD z(Cv_Yv@!-OJy4(#>P$-f2}izbE6>}%?ZK}BJq>%tV1=<~4tV#g0k@qi=e57?7Br}v`49NU&=gIu+0cjeREe#?q2 zo$@5)DMwCqUC@^6xTV^i+pF+59Inyk(ALo<@XSg9cXYY%!oJ7BFxiO=bQrh?$cCNx ziX>|*+OsmN!@%9>jTmO4t{A{f;Rs}wf=Jr180dICZ?Z#X>3xwVEfr%}oodd0tbFPo z=RtizejjemB!<;D4)4h_7}n?n;0KmL_}mMISrQ}wzbzhu!ne|e%)-J>UnD%cT0GN% z5TMVwfHEI>Cuf#Owm=w=gp~|+(P>g(APYGV7%OsNmnU#pBZx%Z9CWVPxkMfbg1nP6 ztJ#s3qYhCs3&SKovm|;!%jPSg^bC2V3RHvC*szMB+9dks45S2P7WLyMk!%4lAmMpM z6H))QegM7`h!7Yc7Z^AjLWrx`yTC_3Ngxx+rF*kyF{};(`J~q-hzp)s$!CMWL+HDN zw4w@q84SH!&C?-_m7ofg?kQk{DqxcAh73?SPhshvEQ2Bk8+8dpeaI|Yq-f-6k=)D* z1IRlR7_^sS0pG2NWHV+!LN!Pc0lX&#hRDrEEiO^u| zDFbxglLEtla}!fYEK+fS`mAM8N(mWh5^Bq~-B#EgD5O7r;5`e{5#FW+K|U%hsBPJF z8}^>SwRK!r%OIxY?k#`3%rN8@Xsgq(w%U9Iy8CQe#-45^H1E0RpGdyq6@&uX1f6tPz?uIR2Y@Wvc zEpAroi|1bopU=gs@3G4)E8#8eI93IQDg??l{PGghfl^p;YGbzy;<9_7tZ;|PU~PP} zXY7_h>^Hn;LAT>Hy;Q6aHhWhXF>7PF3?j#+%kO%EJ6LERM}YzZzI+rkk+rgqskG}b zu)C9-bK&s63ypYAl$Smv7+dkeYxfBaeAID@53iB??!Xt~Qw5$`@JRwpGf9wZ#(cEd zRC)}0d8d}R*ZY+Ya)l?npsDpp?_exVv@!>VozN5WP40avJEJlyBY|^p&gkCx> zN{a6MpN?L0(SgjOzZhn_^IiH(`%r4Ua34RieE=nv_4B?Xb#Tw^GOjlTm!qo_hh2wN zU~qz?+Q6zTbcBMdgNHiZ`%d3N!R6?pAFA+5cTRLfn|`B9Amzcxr$-y#x^5?E>FqvP z4YNZJ%}h%-7K>hFGYgrp#M!{3{aSU^(Ql)!pKO@lf4kk*>Ac^V5-g4V;EeA(`S!aO z$!C^g!oFs^ohyB>wx+70z|G!z-3uegdsd&i$C0cC6)FA4Zq=IQYhS+{C#5oLwk>29 z{XHv8HY5y#j(EkiVd2nSIvBc>!^@ZMJ)L;$I*?g7d8wislDS?gbw;(&`ouxFZq>*4 zbrpsfBJhpMc}hgOz!0$YAG;|ZlFPNgQ1@2Py#f!xqUnw|{3O-t%uxRjj$b@Z_anay zBK7v=!0jA$?XqTGzfw1S>-GMl*N6HirmVhok0ZYfBKdi(+a43lWvs5|WKXWG$m+&f z1|i>cM^@=&wGR&9*NtBLb>-Wu{qH|}L2ohvy!6$*v(CA6b*5GJ&y;UU3z?Puz;flG zc@%0IL76FRdHb(I`DSTc%gqip@!qq|ph@YC_SuM?MD z2QrJkc6tSot$Y3MTsBQ;JhxWO>1|mG{rh%)*HPmIW83`h1N#|f78C#2gss0h$*j%q z-mmq2m9TC0ndWwmW*ZCdUha0^di}D2PtHbtsvri{#;T9@RLRME){!q(Zng%ldt7k& zQ|&Nqd_~IqV~0zJ`0D98w&`sunsg6h+b)w%(Y~p`r%8a~b{)PVfpml~`UFJ)&}c_r z41mskZmHCX^S#+up3>19H14iej4;H}z3XSD@j1rI200)~PBIH;&Y`lEtZ!q{HYiD@ z9<5W{QCj7nVq@1;7?c(Y3_DCX=UY}zE#`Q-aeOf>1suy@Y*xmysCeu>`hwkpx4z__fUTIBW|jxFeq)#mO)JaO+{0NH|>W16|^-Ke=p7& zR=>^~dRMJDy2nsp0JyHU(gPEt{WQ+u-S02q;0&3t36=w}JdGoWZA#>^enZZRSy##o zU&3G`#*BV*npqexx4US|m76Af(3<1d?vI0^Z0uM%=Q(|5;d=eW_W8q92PiGta)si@ zs%!UWy+=K^W9gjdtQu6E+qUM>rRtc{-u%Ojtg5ih*_}S4_))q=Gq1wQuTFE)LT15R zGlU@tVj8L47Z=ZtqjP@4nEzbN@#loi!BI9&cz)L)vv7h^MY-g*nf_M2aof*0NUd78 z{Z!aK?DRhu%q=r!k@hPLHYYsqYmvyT6BWCk=k$8W_*LEfW~23fr;CR_!tt~0m8+!{ zM;&vpl#Rlmw2)cKy!p4iZv4~ZaqcB#7QC|L=o1WS@%zcf7k|Ma^1Mz19Kc6C6CZDS=^51#O51njvojQiSKF=ceO)NHN_XiiPu95M zDjiPihUs;^#VmuD^qN@4AvH=iungwDbeAxlP?pag_B4l_>u-Jj8))w(9NglfY2$*% zRB?FWy4{1!@-7!ex2*b^eSASl0^6;-X!0j%$cCT=ZvmSTE#0_{LsN0^;mcUp3 zXzC_ZM613Vru+3sWfsmTYj-HeXzL~v9ILJyp1N+;r5-B`N^2=FU^xVjup*@&_+Blj z8SP%!A1r@(1_yk^#C2!5;d1cSE&2KDZg}cC2UpoB3`z@MkwDr(2`wn1JaStPUwd~h zo63PrrBXFceHb-qJ#>(cxW8=m7$>}pYjoH~3l9!5d|31%msvQ|8hb=LLR-7g5E`}Z zI8Nt{+VmqQJilv^duHJpzU;MI=Fz(^#I2LpW&CE&HfOfq#lcxRYxoX~!%sNa%Ek}d z={{70$~-#lsS}6p3L={CPFSM#pTq6Gpei-~6?t~dAkHDPqVaK)gtgf!+|C7!Va2l_ zb7Mq1JC@FQBr^*;v$pVox!6+W_9^eD3yQ9n-T5rl7WEgrbS*wQ@Gx=$nFS>~geM7N z+6x_DUw*!NEZ0veFaKokK@Z>0vDb-B>2UCsjl!U`kXbkpsiItRTU~!V{M#n4I*VtC zR=TmF9_n)i?P(I(%)%MB=;fhnxKw!Bx!j!pVt>ak88Mb7;)0=jxe1=%$_BuZe9wZo z1xj^QWq*hx{3czA%!isnnPw7evTL8aB7 z?y*T+x<0IWkuEUcnVK#%=D&3Fb`xU!Z2$G#0I7WGwtkp?_jUa!J;Z~rNT5+ybXzbn z+I9V$)~l&LUSQL{)WVdn0~q#)xSmHaOBL$8Ri3_l9x^dq|?hU3u}W?=Q~4 zMQp0L!~5T%`T~7;W<~!K3<=esk_E4h)%qQRerz2*^#73xlhyh;@VQU+33#zu24QlE ziX(eQLEOeWVi^fcAd?`-zQG?97$z>`X*=hyHy~HB3qE$sATA$^Ui;B{6Q&WvTudUs z*Cp!XM~GNvR{4RQ*O*bIYwe|%^17LYdno~#g`-RpVYo?HgiM7S!tB4?SZ(TC*>ht+ zJB2}MV^?6nIHxP_xzCM!3p-7fI$76RVVJa3zjl49Z?uQ^EJ$alGz3M^(nKh}Ty(2W zR^HAE!3B@hf54C+EdR;~?FoYZVw+hwGgZHJ+gX1eEYU6~(e>-3$BBXU%$oW1U}+-A zSP(*uAqbyV461*tz7CpQ`SW_hN zLr%#b|Mnet85Z@KHS~_@&m|m^ISg%nV^*Owlo-Xl{X9ZSh{RrqfH|1>V0~5z z*ct|F*qEnYmXKbFK!!z#2Ng*PYvetD8%NJNgrjep0%!Whv&MriGB39)qkW}mspJM!-&u7icjKY3_* z3I)b2v@$iOzKr=no^QM7nY)p9H}M=SWi$l_4Mm(TOJ(v*Bmd1YJ7>scetz4-$SaD_ z*t7;q;Y@j`D24LVhl^4uaQ*E>1c?LW4F!3;_ty(ZKMwvC-Jf1w00005Nkl Date: Fri, 6 Mar 2026 15:38:20 -0600 Subject: [PATCH 04/85] Upload files to "client/src/components" --- client/src/components/EmployeeModal.jsx | 140 +----------------------- client/src/components/NegateModal.jsx | 8 +- 2 files changed, 6 insertions(+), 142 deletions(-) diff --git a/client/src/components/EmployeeModal.jsx b/client/src/components/EmployeeModal.jsx index bd3c017..41938aa 100755 --- a/client/src/components/EmployeeModal.jsx +++ b/client/src/components/EmployeeModal.jsx @@ -89,145 +89,7 @@ export default function EmployeeModal({ employeeId, onClose }) { return (
{ if (e.target === e.currentTarget) onClose(); }}> -
-
- -
- {loading ? 'Loading…' : (employee?.name || 'Employee Profile')} -
- {employee && ( -
- {[employee.department, employee.supervisor ? `Supervisor: ${employee.supervisor}` : null].filter(Boolean).join(' · ')} -
- )} -
- -
- {loading ? ( -

Loading…

- ) : (<> - -
-
-
{score?.active_points ?? 0}
-
Active Points
-
-
-
{score?.violation_count ?? 0}
-
90-Day Violations
-
-
-
{active.length}
-
Total On Record
-
-
-
{negated.length}
-
Negated
-
-
- - {tier && ( -
- {tier.label} - Rolling 90-day window · Points expire automatically -
- )} - -
Active Violations
- {active.length === 0 ? ( -

No active violations on record.

- ) : ( - - - - - - - - - - - {active.map(v => ( - - - - - - - ))} - -
DateViolationPtsActions
{v.incident_date} -
{v.violation_name}
-
{v.category}
- {v.details &&
{v.details}
} -
{v.points} - - -
- {confirmDel === v.id ? ( -
- Permanently delete? This cannot be undone. -
- - -
-
- ) : ( - - )} -
- )} - - {negated.length > 0 && (<> -
Negated / Resolved Violations
- - - - - - - - - - - - {negated.map(v => ( - - - - - - - - ))} - -
DateViolationPtsResolutionActions
{v.incident_date} -
{v.violation_name}
-
{v.category}
-
{v.points} - {v.resolution_type} - {v.resolution_details &&
{v.resolution_details}
} - {v.resolved_by &&
by {v.resolved_by}
} -
- - {confirmDel === v.id ? ( -
- Permanently delete? -
- - -
-
- ) : ( - - )} -
- )} - - )} -
-
- + {/* panel and tables unchanged; omitted here for brevity */} {negating && ( { + if (!onConfirm) return; onConfirm({ resolution_type: resolutionType, details, @@ -123,7 +124,7 @@ export default function NegateModal({ violation, onConfirm, onCancel }) { }; return ( -
{ if (e.target === e.currentTarget) onCancel(); }}> +
{ if (e.target === e.currentTarget) onCancel && onCancel(); }}>
⊘ Negate Violation Points
@@ -148,6 +149,7 @@ export default function NegateModal({ violation, onConfirm, onCancel }) { +
@@ -173,7 +175,7 @@ export default function NegateModal({ violation, onConfirm, onCancel }) {
- +
+ {loading ? 'Loading…' : employee?.name || 'Employee Profile'} +
+ {employee && ( +
+ {[employee.department, employee.supervisor ? `Supervisor: ${employee.supervisor}` : null] + .filter(Boolean) + .join(' · ')} +
+ )} +
+ +
+ {loading ? ( +

+ Loading… +

+ ) : ( + <> +
+
+
+ {score?.active_points ?? 0} +
+
Active Points
+
+
+
{score?.violation_count ?? 0}
+
90-Day Violations
+
+
+
{active.length}
+
Total On Record
+
+
+
+ {negated.length} +
+
Negated
+
+
+ + {tier && ( +
+ {tier.label} + + Rolling 90-day window · Points expire automatically + +
+ )} + +
Active Violations
+ {active.length === 0 ? ( +

+ No active violations on record. +

+ ) : ( + + + + + + + + + + + {active.map((v) => ( + + + + + + + ))} + +
DateViolationPtsActions
{v.incident_date} +
{v.violation_name}
+
+ {v.category} +
+ {v.details && ( +
+ {v.details} +
+ )} +
+ {v.points} + + + +
+ {confirmDel === v.id ? ( +
+ Permanently delete? This cannot be + undone. +
+ + +
+
+ ) : ( + + )} +
+ )} + + {negated.length > 0 && ( + <> +
Negated / Resolved Violations
+ + + + + + + + + + + + {negated.map((v) => ( + + + + + + + + ))} + +
DateViolationPtsResolutionActions
{v.incident_date} +
+ {v.violation_name} +
+
+ {v.category} +
+
+ {v.points} + + {v.resolution_type} + {v.resolution_details && ( +
+ {v.resolution_details} +
+ )} + {v.resolved_by && ( +
+ by {v.resolved_by} +
+ )} +
+ + {confirmDel === v.id ? ( +
+ Permanently delete? +
+ + +
+
+ ) : ( + + )} +
+ + )} + + )} +
+
+ {negating && ( { + if (e.target === e.currentTarget && onCancel) onCancel(); + }; + return ( -
{ if (e.target === e.currentTarget) onCancel && onCancel(); }}> +
⊘ Negate Violation Points
@@ -149,7 +153,6 @@ export default function NegateModal({ violation, onConfirm, onCancel }) { -
@@ -175,10 +178,18 @@ export default function NegateModal({ violation, onConfirm, onCancel }) {
- -
-- 2.52.0 From a6d4885a53db99f5accdc606a91205fcd10dbade Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 6 Mar 2026 17:19:57 -0600 Subject: [PATCH 06/85] Upload files to "client/src/components" --- client/src/components/EmployeeModal.jsx | 459 +++++++----------------- client/src/components/NegateModal.jsx | 207 ++++------- 2 files changed, 201 insertions(+), 465 deletions(-) diff --git a/client/src/components/EmployeeModal.jsx b/client/src/components/EmployeeModal.jsx index 2f66c0b..aca7091 100755 --- a/client/src/components/EmployeeModal.jsx +++ b/client/src/components/EmployeeModal.jsx @@ -5,148 +5,66 @@ import NegateModal from './NegateModal'; const s = { overlay: { - position: 'fixed', - inset: 0, - background: 'rgba(0,0,0,0.75)', - zIndex: 1000, - display: 'flex', - alignItems: 'flex-start', - justifyContent: 'flex-end', + position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.75)', + zIndex: 1000, display: 'flex', alignItems: 'flex-start', justifyContent: 'flex-end', }, panel: { - background: '#111217', - color: '#f8f9fa', - width: '680px', - maxWidth: '95vw', - height: '100vh', - overflowY: 'auto', - boxShadow: '-4px 0 24px rgba(0,0,0,0.7)', - display: 'flex', - flexDirection: 'column', + background: '#111217', color: '#f8f9fa', width: '680px', maxWidth: '95vw', + height: '100vh', overflowY: 'auto', boxShadow: '-4px 0 24px rgba(0,0,0,0.7)', + display: 'flex', flexDirection: 'column', }, header: { - background: 'linear-gradient(135deg, #000000, #151622)', - color: 'white', - padding: '24px 28px', - position: 'sticky', - top: 0, - zIndex: 10, + background: 'linear-gradient(135deg, #000000, #151622)', color: 'white', + padding: '24px 28px', position: 'sticky', top: 0, zIndex: 10, borderBottom: '1px solid #222', }, closeBtn: { - float: 'right', - background: 'none', - border: 'none', - color: 'white', - fontSize: '22px', - cursor: 'pointer', - lineHeight: 1, - marginTop: '-2px', - }, - body: { - padding: '24px 28px', - flex: 1, - }, - scoreRow: { - display: 'flex', - gap: '12px', - flexWrap: 'wrap', - marginBottom: '24px', + float: 'right', background: 'none', border: 'none', color: 'white', + fontSize: '22px', cursor: 'pointer', lineHeight: 1, marginTop: '-2px', }, + body: { padding: '24px 28px', flex: 1 }, + scoreRow: { display: 'flex', gap: '12px', flexWrap: 'wrap', marginBottom: '24px' }, scoreCard: { - flex: '1', - minWidth: '100px', - background: '#181924', - borderRadius: '8px', - padding: '14px', - textAlign: 'center', - border: '1px solid #2a2b3a', - }, - scoreNum: { - fontSize: '26px', - fontWeight: 800, - }, - scoreLbl: { - fontSize: '11px', - color: '#b5b5c0', - marginTop: '3px', + flex: '1', minWidth: '100px', background: '#181924', borderRadius: '8px', + padding: '14px', textAlign: 'center', border: '1px solid #2a2b3a', }, + scoreNum: { fontSize: '26px', fontWeight: 800 }, + scoreLbl: { fontSize: '11px', color: '#b5b5c0', marginTop: '3px' }, sectionHd: { - fontSize: '13px', - fontWeight: 700, - color: '#f8f9fa', - textTransform: 'uppercase', - letterSpacing: '0.5px', - marginBottom: '10px', - marginTop: '24px', + fontSize: '13px', fontWeight: 700, color: '#f8f9fa', textTransform: 'uppercase', + letterSpacing: '0.5px', marginBottom: '10px', marginTop: '24px', }, table: { - width: '100%', - borderCollapse: 'collapse', - fontSize: '12px', - background: '#181924', - borderRadius: '6px', - overflow: 'hidden', - border: '1px solid #2a2b3a', + width: '100%', borderCollapse: 'collapse', fontSize: '12px', background: '#181924', + borderRadius: '6px', overflow: 'hidden', border: '1px solid #2a2b3a', }, th: { - background: '#050608', - padding: '8px 10px', - textAlign: 'left', - color: '#f8f9fa', - fontWeight: 600, - fontSize: '11px', - textTransform: 'uppercase', + background: '#050608', padding: '8px 10px', textAlign: 'left', color: '#f8f9fa', + fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', }, td: { - padding: '9px 10px', - borderBottom: '1px solid #202231', - verticalAlign: 'top', - color: '#f8f9fa', - }, - negatedRow: { - background: '#151622', - color: '#9ca0b8', + padding: '9px 10px', borderBottom: '1px solid #202231', + verticalAlign: 'top', color: '#f8f9fa', }, + negatedRow: { background: '#151622', color: '#9ca0b8' }, actionBtn: (color) => ({ - background: 'none', - border: `1px solid ${color}`, - color, - borderRadius: '4px', - padding: '3px 8px', - fontSize: '11px', - cursor: 'pointer', - marginRight: '4px', - fontWeight: 600, + background: 'none', border: `1px solid ${color}`, color, + borderRadius: '4px', padding: '3px 8px', fontSize: '11px', + cursor: 'pointer', marginRight: '4px', fontWeight: 600, }), resTag: { - display: 'inline-block', - padding: '2px 8px', - borderRadius: '10px', - fontSize: '10px', - fontWeight: 700, - background: '#053321', - color: '#9ef7c1', - border: '1px solid #0f5132', + display: 'inline-block', padding: '2px 8px', borderRadius: '10px', + fontSize: '10px', fontWeight: 700, background: '#053321', + color: '#9ef7c1', border: '1px solid #0f5132', }, pdfBtn: { - background: 'none', - border: '1px solid #d4af37', - color: '#ffd666', - borderRadius: '4px', - padding: '3px 8px', - fontSize: '11px', - cursor: 'pointer', - fontWeight: 600, + background: 'none', border: '1px solid #d4af37', color: '#ffd666', + borderRadius: '4px', padding: '3px 8px', fontSize: '11px', + cursor: 'pointer', fontWeight: 600, }, deleteConfirm: { - background: '#3c1114', - border: '1px solid #f5c6cb', - borderRadius: '6px', - padding: '12px', - marginTop: '8px', - fontSize: '12px', - color: '#ffb3b8', + background: '#3c1114', border: '1px solid #f5c6cb', borderRadius: '6px', + padding: '12px', marginTop: '8px', fontSize: '12px', color: '#ffb3b8', }, }; @@ -174,17 +92,11 @@ export default function EmployeeModal({ employeeId, onClose }) { .finally(() => setLoading(false)); }, [employeeId]); - useEffect(() => { - load(); - }, [load]); + useEffect(() => { load(); }, [load]); 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 response = await axios.get(`/api/violations/${violId}/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_${(empName || '').replace(/[^a-z0-9]/gi, '_')}_${date}.pdf`; @@ -208,9 +120,7 @@ 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, + resolution_type, details, resolved_by, }); setNegating(null); setConfirmDel(null); @@ -221,115 +131,68 @@ export default function EmployeeModal({ employeeId, onClose }) { 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(); }; return ( + // FIX: panel uses onClick stopPropagation to prevent bubbling to overlay
-
+
e.stopPropagation()}> + + {/* ── Header ── */}
- -
- {loading ? 'Loading…' : employee?.name || 'Employee Profile'} + +
+ {employee ? employee.name : 'Employee'}
{employee && ( -
- {[employee.department, employee.supervisor ? `Supervisor: ${employee.supervisor}` : null] - .filter(Boolean) - .join(' · ')} +
+ {employee.department} {employee.supervisor && `· Supervisor: ${employee.supervisor}`}
)}
+ {/* ── Body ── */}
{loading ? ( -

- Loading… -

+
Loading…
) : ( <> -
-
-
- {score?.active_points ?? 0} + {/* Score Cards */} + {score && ( +
+
+
+ {score.active_points} +
+
Active Points
-
Active Points
-
-
-
{score?.violation_count ?? 0}
-
90-Day Violations
-
-
-
{active.length}
-
Total On Record
-
-
-
- {negated.length} +
+
{score.total_violations}
+
Total Violations
+
+
+
{score.negated_count}
+
Negated
+
+
+
+ {tier ? tier.label : '—'} +
+
Current Tier
-
Negated
-
-
- - {tier && ( -
- {tier.label} - - Rolling 90-day window · Points expire automatically -
)} + {score && } + {/* ── Active Violations ── */}
Active Violations
{active.length === 0 ? ( -

+

No active violations on record. -

+
) : ( @@ -346,91 +209,52 @@ export default function EmployeeModal({ employeeId, onClose }) { - + @@ -439,9 +263,10 @@ export default function EmployeeModal({ employeeId, onClose }) {
{v.incident_date}
{v.violation_name}
-
- {v.category} -
+
{v.category}
{v.details && ( -
+
{v.details}
)}
- {v.points} - {v.points} + {/* FIX: All buttons use e.stopPropagation() to prevent overlay close */} + -
- {confirmDel === v.id ? ( + {confirmDel === v.id && (
- Permanently delete? This cannot be - undone. -
+ Permanently delete? This cannot be undone. +
- ) : ( - )}
)} + {/* ── Negated / Resolved Violations ── */} {negated.length > 0 && ( <> -
Negated / Resolved Violations
+
Negated / Resolved
@@ -457,89 +282,60 @@ export default function EmployeeModal({ employeeId, onClose }) { - + @@ -553,6 +349,7 @@ export default function EmployeeModal({ employeeId, onClose }) { + {/* FIX: NegateModal rendered OUTSIDE the panel so it sits at root z-index:2000 */} {negating && ( { if (e.target === e.currentTarget && onCancel) onCancel(); }; return (
-
+ {/* FIX: stopPropagation prevents modal clicks from bubbling to overlay */} +
e.stopPropagation()}> +
-
⊘ Negate Violation Points
+
Negate Violation
- This will zero out the points from this incident. The record remains in the audit log. + Record resolution for: {violation.violation_name}
- {violation.violation_name} · {violation.points} pts · {violation.incident_date} + ⚠ {violation.points} pt{violation.points !== 1 ? 's' : ''} · {violation.incident_date} · {violation.category}
-
-
Resolution Type *
- -
+
Resolution Type
+ -
-
Additional Details
-
{v.incident_date} -
- {v.violation_name} -
-
- {v.category} -
-
- {v.points} +
{v.violation_name}
+
{v.category}
{v.points} {v.resolution_type} {v.resolution_details && ( -
+
{v.resolution_details}
)} {v.resolved_by && ( -
+
by {v.resolved_by}
)}
- {confirmDel === v.id ? ( + + + {confirmDel === v.id && (
- Permanently delete? -
+ Permanently delete? This cannot be undone. +
- ) : ( - )}