158 lines
4.1 KiB
JavaScript
158 lines
4.1 KiB
JavaScript
import React from 'react';
|
|
import CpasBadge, { getTier } from './CpasBadge';
|
|
|
|
const AT_RISK_THRESHOLD = 2;
|
|
|
|
const TIERS = [
|
|
{ min: 0, max: 4 },
|
|
{ min: 5, max: 9 },
|
|
{ min: 10, max: 14 },
|
|
{ min: 15, max: 19 },
|
|
{ min: 20, max: 24 },
|
|
{ min: 25, max: 29 },
|
|
{ min: 30, max: 999 },
|
|
];
|
|
|
|
function nextTierBoundary(points) {
|
|
for (const t of TIERS) {
|
|
if (points >= t.min && points <= t.max && t.max < 999) return t.max + 1;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function isAtRisk(points) {
|
|
const boundary = nextTierBoundary(points);
|
|
return boundary !== null && (boundary - points) <= AT_RISK_THRESHOLD;
|
|
}
|
|
|
|
const s = {
|
|
card: {
|
|
background: '#181924',
|
|
border: '1px solid #2a2b3a',
|
|
borderRadius: '10px',
|
|
padding: '16px',
|
|
marginBottom: '12px',
|
|
boxShadow: '0 1px 4px rgba(0,0,0,0.4)',
|
|
},
|
|
cardAtRisk: {
|
|
background: '#181200',
|
|
border: '1px solid #d4af37',
|
|
},
|
|
row: {
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
padding: '8px 0',
|
|
borderBottom: '1px solid rgba(255,255,255,0.05)',
|
|
},
|
|
rowLast: {
|
|
borderBottom: 'none',
|
|
},
|
|
label: {
|
|
fontSize: '11px',
|
|
fontWeight: 600,
|
|
color: '#9ca0b8',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: '0.5px',
|
|
},
|
|
value: {
|
|
fontSize: '14px',
|
|
fontWeight: 600,
|
|
color: '#f8f9fa',
|
|
textAlign: 'right',
|
|
},
|
|
name: {
|
|
fontSize: '16px',
|
|
fontWeight: 700,
|
|
color: '#d4af37',
|
|
marginBottom: '8px',
|
|
cursor: 'pointer',
|
|
textDecoration: 'underline dotted',
|
|
background: 'none',
|
|
border: 'none',
|
|
padding: 0,
|
|
textAlign: 'left',
|
|
width: '100%',
|
|
},
|
|
atRiskBadge: {
|
|
display: 'inline-block',
|
|
marginTop: '4px',
|
|
padding: '3px 8px',
|
|
borderRadius: '10px',
|
|
fontSize: '10px',
|
|
fontWeight: 700,
|
|
background: '#3b2e00',
|
|
color: '#ffd666',
|
|
border: '1px solid #d4af37',
|
|
},
|
|
points: {
|
|
fontSize: '28px',
|
|
fontWeight: 800,
|
|
textAlign: 'center',
|
|
margin: '8px 0',
|
|
},
|
|
};
|
|
|
|
export default function DashboardMobile({ employees, onEmployeeClick }) {
|
|
if (!employees || employees.length === 0) {
|
|
return (
|
|
<div style={{ padding: '20px', textAlign: 'center', color: '#77798a', fontStyle: 'italic' }}>
|
|
No employees found.
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div style={{ padding: '12px' }}>
|
|
{employees.map((emp) => {
|
|
const risk = isAtRisk(emp.active_points);
|
|
const tier = getTier(emp.active_points);
|
|
const boundary = nextTierBoundary(emp.active_points);
|
|
const cardStyle = risk ? { ...s.card, ...s.cardAtRisk } : s.card;
|
|
|
|
return (
|
|
<div key={emp.id} style={cardStyle}>
|
|
<button style={s.name} onClick={() => onEmployeeClick(emp.id)}>
|
|
{emp.name}
|
|
</button>
|
|
{risk && (
|
|
<div style={s.atRiskBadge}>
|
|
⚠ {boundary - emp.active_points} pt{boundary - emp.active_points > 1 ? 's' : ''} to {getTier(boundary).label.split('—')[0].trim()}
|
|
</div>
|
|
)}
|
|
|
|
<div style={{ ...s.row, marginTop: '12px' }}>
|
|
<span style={s.label}>Tier / Standing</span>
|
|
<span style={s.value}><CpasBadge points={emp.active_points} /></span>
|
|
</div>
|
|
|
|
<div style={s.row}>
|
|
<span style={s.label}>Active Points</span>
|
|
<span style={{ ...s.points, color: tier.color }}>{emp.active_points}</span>
|
|
</div>
|
|
|
|
<div style={s.row}>
|
|
<span style={s.label}>90-Day Violations</span>
|
|
<span style={s.value}>{emp.violation_count}</span>
|
|
</div>
|
|
|
|
{emp.department && (
|
|
<div style={s.row}>
|
|
<span style={s.label}>Department</span>
|
|
<span style={{ ...s.value, color: '#c0c2d6' }}>{emp.department}</span>
|
|
</div>
|
|
)}
|
|
|
|
{emp.supervisor && (
|
|
<div style={{ ...s.row, ...s.rowLast }}>
|
|
<span style={s.label}>Supervisor</span>
|
|
<span style={{ ...s.value, color: '#c0c2d6' }}>{emp.supervisor}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|