Compare commits

..

2 Commits

View File

@@ -77,6 +77,10 @@ export default function Dashboard() {
const maxPoints = employees.reduce((m, e) => Math.max(m, e.active_points), 0); const maxPoints = employees.reduce((m, e) => Math.max(m, e.active_points), 0);
return ( return (
// FIX: Fragment wraps both s.wrap AND EmployeeModal so the modal is
// outside the s.wrap div — React synthetic events will no longer bubble
// from inside the modal up through the Dashboard's DOM tree.
<>
<div style={s.wrap}> <div style={s.wrap}>
<div style={s.header}> <div style={s.header}>
<div> <div>
@@ -84,7 +88,12 @@ export default function Dashboard() {
<div style={s.subtitle}>Click any employee name to view their full profile</div> <div style={s.subtitle}>Click any employee name to view their full profile</div>
</div> </div>
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}> <div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
<input style={s.search} placeholder="Search name, dept, supervisor…" value={search} onChange={e => setSearch(e.target.value)} /> <input
style={s.search}
placeholder="Search name, dept, supervisor…"
value={search}
onChange={e => setSearch(e.target.value)}
/>
<button style={s.refreshBtn} onClick={load}> Refresh</button> <button style={s.refreshBtn} onClick={load}> Refresh</button>
</div> </div>
</div> </div>
@@ -129,17 +138,26 @@ export default function Dashboard() {
</thead> </thead>
<tbody> <tbody>
{filtered.length === 0 && ( {filtered.length === 0 && (
<tr><td colSpan={7} style={{ ...s.td, textAlign: 'center', ...s.zeroRow }}>No employees found.</td></tr> <tr>
<td colSpan={7} style={{ ...s.td, textAlign: 'center', ...s.zeroRow }}>
No employees found.
</td>
</tr>
)} )}
{filtered.map((emp, i) => { {filtered.map((emp, i) => {
const risk = isAtRisk(emp.active_points); const risk = isAtRisk(emp.active_points);
const tier = getTier(emp.active_points); const tier = getTier(emp.active_points);
const boundary = nextTierBoundary(emp.active_points); const boundary = nextTierBoundary(emp.active_points);
return ( return (
<tr key={emp.id} style={{ background: risk ? '#181200' : i % 2 === 0 ? '#111217' : '#151622' }}> <tr
key={emp.id}
style={{ background: risk ? '#181200' : i % 2 === 0 ? '#111217' : '#151622' }}
>
<td style={{ ...s.td, color: '#77798a', fontSize: '12px' }}>{i + 1}</td> <td style={{ ...s.td, color: '#77798a', fontSize: '12px' }}>{i + 1}</td>
<td style={s.td}> <td style={s.td}>
<button style={s.nameBtn} onClick={() => setSelectedId(emp.id)}>{emp.name}</button> <button style={s.nameBtn} onClick={() => setSelectedId(emp.id)}>
{emp.name}
</button>
{risk && ( {risk && (
<span style={s.atRiskBadge}> <span style={s.atRiskBadge}>
{boundary - emp.active_points} pt{boundary - emp.active_points > 1 ? 's' : ''} to {getTier(boundary).label.split('—')[0].trim()} {boundary - emp.active_points} pt{boundary - emp.active_points > 1 ? 's' : ''} to {getTier(boundary).label.split('—')[0].trim()}
@@ -149,7 +167,9 @@ export default function Dashboard() {
<td style={{ ...s.td, color: '#c0c2d6' }}>{emp.department || '—'}</td> <td style={{ ...s.td, color: '#c0c2d6' }}>{emp.department || '—'}</td>
<td style={{ ...s.td, color: '#c0c2d6' }}>{emp.supervisor || '—'}</td> <td style={{ ...s.td, color: '#c0c2d6' }}>{emp.supervisor || '—'}</td>
<td style={s.td}><CpasBadge points={emp.active_points} /></td> <td style={s.td}><CpasBadge points={emp.active_points} /></td>
<td style={{ ...s.td, fontWeight: 700, color: tier.color, fontSize: '16px' }}>{emp.active_points}</td> <td style={{ ...s.td, fontWeight: 700, color: tier.color, fontSize: '16px' }}>
{emp.active_points}
</td>
<td style={{ ...s.td, color: '#c0c2d6' }}>{emp.violation_count}</td> <td style={{ ...s.td, color: '#c0c2d6' }}>{emp.violation_count}</td>
</tr> </tr>
); );
@@ -157,13 +177,17 @@ export default function Dashboard() {
</tbody> </tbody>
</table> </table>
)} )}
</div>
{/* FIX: EmployeeModal is now OUTSIDE <div style={s.wrap}>.
React synthetic events no longer bubble from modal buttons
up through Dashboard's component tree. */}
{selectedId && ( {selectedId && (
<EmployeeModal <EmployeeModal
employeeId={selectedId} employeeId={selectedId}
onClose={() => { setSelectedId(null); load(); }} onClose={() => { setSelectedId(null); load(); }}
/> />
)} )}
</div> </>
); );
} }