This commit is contained in:
Joyce
2026-02-05 20:35:19 -05:00
parent b4a8029fb0
commit d6115dc30d
5 changed files with 257 additions and 162 deletions

View File

@@ -156,6 +156,23 @@ export const AvailabilityHeatmapV2 = ({
});
};
// Move hooks to top level to avoid conditional hook execution error
const tzOffsetDiff = useMemo(() => {
try {
const now = new Date();
const p = parseInt(new Intl.DateTimeFormat('en-US', { timeZone: displayTimezone, hour: 'numeric', hour12: false }).format(now));
const s = parseInt(new Intl.DateTimeFormat('en-US', { timeZone: secondaryTimezone, hour: 'numeric', hour12: false }).format(now));
let diff = s - p;
if (diff > 12) diff -= 24;
if (diff < -12) diff += 24;
return diff;
} catch {
return 0;
}
}, [displayTimezone, secondaryTimezone]);
const timeColWidth = showSecondaryTimezone ? "120px" : "80px";
if (selectedParticipants.length === 0) {
return (
<div className="flex flex-col items-center justify-center p-12 border-2 border-dashed border-border/50 rounded-xl bg-muted/20 animate-fade-in">
@@ -245,9 +262,15 @@ export const AvailabilityHeatmapV2 = ({
<div className="overflow-auto max-h-[600px] w-full relative">
<div className="min-w-[700px]">
{/* Grid Header */}
<div className="grid grid-cols-[80px_repeat(5,1fr)] sticky top-0 z-30 bg-card border-b border-border shadow-sm">
<div className="sticky left-0 z-40 bg-card text-xs font-semibold text-muted-foreground self-center p-3 text-right border-r border-border/50">
TIME
<div
className="grid sticky top-0 z-30 bg-card border-b border-border shadow-sm"
style={{ gridTemplateColumns: `${timeColWidth} repeat(5, 1fr)` }}
>
<div className="sticky left-0 z-40 bg-card text-xs font-semibold text-muted-foreground self-center p-3 text-right border-r border-border/50 flex flex-col items-end gap-1">
<span>{formatTimezoneDisplay(displayTimezone)}</span>
{showSecondaryTimezone && (
<span className="text-[10px] text-muted-foreground/60 font-normal">{formatTimezoneDisplay(secondaryTimezone)}</span>
)}
</div>
{weekDates.map(date => {
const isToday = new Date().toDateString() === date.toDateString();
@@ -269,27 +292,41 @@ export const AvailabilityHeatmapV2 = ({
<div className="relative">
{activeHours.map((hour) => {
const isNight = hour < 8 || hour >= 18;
// Calculate secondary time
let secondaryHour = hour + tzOffsetDiff;
if (secondaryHour >= 24) secondaryHour -= 24;
if (secondaryHour < 0) secondaryHour += 24;
return (
<div
key={hour}
className={cn(
"grid grid-cols-[80px_repeat(5,1fr)] group items-stretch transition-colors border-b border-border/30 last:border-0",
"grid group items-stretch transition-colors border-b border-border/30 last:border-0",
isNight ? "bg-muted/30" : "bg-card",
"hover:bg-muted/10"
)}
style={{ gridTemplateColumns: `${timeColWidth} repeat(5, 1fr)` }}
>
{/* Time Label - Sticky Left */}
<div className={cn(
"text-xs text-muted-foreground font-medium text-right pr-4 py-3 flex items-center justify-end gap-1.5",
"text-xs text-muted-foreground font-medium text-right pr-4 py-3 flex flex-col items-end justify-center gap-0.5",
"sticky left-0 z-20 border-r border-border/50",
isNight ? "bg-muted/30 backdrop-blur-md" : "bg-card"
)}>
{isNight ? (
<Moon className="w-3 h-3 text-slate-400/50" />
) : (
<Sun className="w-3 h-3 text-amber-500/50" />
<div className="flex items-center gap-1.5">
{isNight ? (
<Moon className="w-3 h-3 text-slate-400/50" />
) : (
<Sun className="w-3 h-3 text-amber-500/50" />
)}
<span>{formatHour(hour)}</span>
</div>
{showSecondaryTimezone && (
<span className="text-[10px] text-muted-foreground/60 font-mono">
{formatHour(secondaryHour)}
</span>
)}
{formatHour(hour)}
</div>
{/* Days */}