diff --git a/frontend/src/components/Calendar/WorkloadHeatmap.jsx b/frontend/src/components/Calendar/WorkloadHeatmap.jsx index 1f6be5d..6ba61a2 100644 --- a/frontend/src/components/Calendar/WorkloadHeatmap.jsx +++ b/frontend/src/components/Calendar/WorkloadHeatmap.jsx @@ -20,12 +20,43 @@ const STATUS_COLOR = { overdue: 'text-red-400', } -function getCellClass(baseDensity, statusCounts) { - const total = Object.values(statusCounts).reduce((a, b) => a + b, 0) - if (total === 0) return 'bg-surface border-surface-border' - if (baseDensity === 1) return 'bg-gold/25 border-gold/40' - if (baseDensity === 2) return 'bg-gold/55 border-gold/70' - return 'bg-gold border-gold shadow-gold' +// Cell colors per status, three density levels: low / mid / high +const STATUS_CELL_COLORS = { + upcoming: [ + 'bg-blue-400/20 border-blue-400/30', + 'bg-blue-400/55 border-blue-400/70', + 'bg-blue-400 border-blue-400 shadow-[0_0_4px_rgba(96,165,250,0.6)]', + ], + in_progress: [ + 'bg-amber-400/20 border-amber-400/30', + 'bg-amber-400/55 border-amber-400/70', + 'bg-amber-400 border-amber-400 shadow-[0_0_4px_rgba(251,191,36,0.6)]', + ], + completed: [ + 'bg-green-400/20 border-green-400/30', + 'bg-green-400/55 border-green-400/70', + 'bg-green-400 border-green-400 shadow-[0_0_4px_rgba(74,222,128,0.6)]', + ], + overdue: [ + 'bg-red-400/20 border-red-400/30', + 'bg-red-400/55 border-red-400/70', + 'bg-red-400 border-red-400 shadow-[0_0_4px_rgba(248,113,113,0.6)]', + ], +} + +const STATUS_HOVER_RING = { + upcoming: 'hover:ring-1 hover:ring-blue-300/80', + in_progress: 'hover:ring-1 hover:ring-amber-300/80', + completed: 'hover:ring-1 hover:ring-green-300/80', + overdue: 'hover:ring-1 hover:ring-red-400/90', +} + +function getCellClass(count, statusKey) { + if (count === 0) return 'bg-surface border-surface-border' + const colors = STATUS_CELL_COLORS[statusKey] || STATUS_CELL_COLORS.upcoming + if (count === 1) return colors[0] + if (count === 2) return colors[1] + return colors[2] } export default function WorkloadHeatmap() { @@ -104,7 +135,7 @@ export default function WorkloadHeatmap() {

{STATUS_LABEL[statusKey]}

- {/* Heatmap for this status */} + {/* Heatmap filtered to this status */}
{/* Day labels */} @@ -135,22 +166,15 @@ export default function WorkloadHeatmap() { {weeks.map((week, wi) => (
{week.map(({ date, key, items, statusCounts }) => { - const countForStatus = (statusCounts || {})[statusKey] || 0 - const baseDensity = countForStatus - const hoverRing = - statusKey === 'upcoming' ? 'hover:ring-blue-300/80 hover:shadow-[0_0_0_1px_rgba(147,197,253,0.8)]' : - statusKey === 'in_progress' ? 'hover:ring-amber-300/80 hover:shadow-[0_0_0_1px_rgba(252,211,77,0.8)]' : - statusKey === 'completed' ? 'hover:ring-green-300/80 hover:shadow-[0_0_0_1px_rgba(74,222,128,0.8)]' : - statusKey === 'overdue' ? 'hover:ring-red-400/90 hover:shadow-[0_0_0_1px_rgba(248,113,113,0.9)]' : - 'hover:ring-white/60' + const count = (statusCounts || {})[statusKey] || 0 return (
0 ? STATUS_HOVER_RING[statusKey] : ''} `} onClick={() => { if (!items || !items.length) return @@ -159,13 +183,13 @@ export default function WorkloadHeatmap() { }} onMouseEnter={(e) => { const filtered = (items || []).filter(({ deliverable }) => deliverable.status === statusKey) - const showItems = filtered.length ? filtered : items || [] + if (!filtered.length) return setTooltip({ x: e.clientX, y: e.clientY, date, statusKey, - items: showItems, + items: filtered, }) }} onMouseLeave={() => setTooltip(null)} @@ -191,7 +215,7 @@ export default function WorkloadHeatmap() {

{isToday(tooltip.date) ? 'Today \u2014 ' : ''}{format(tooltip.date, 'EEE, MMM d, yyyy')}

-

+

{STATUS_LABEL[tooltip.statusKey]} \u00b7 {tooltip.items.length} task{tooltip.items.length !== 1 ? 's' : ''}

{tooltip.items.length === 0 ? (