diff --git a/management-dashboard-web-app/src/components/Scheduling.tsx b/management-dashboard-web-app/src/components/Scheduling.tsx index 40d31cc..aa23073 100644 --- a/management-dashboard-web-app/src/components/Scheduling.tsx +++ b/management-dashboard-web-app/src/components/Scheduling.tsx @@ -300,6 +300,7 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } const [phases, setPhases] = useState([]) const [expandedPhaseIds, setExpandedPhaseIds] = useState>(new Set()) + const [conductorsExpanded, setConductorsExpanded] = useState(true) const [experimentsByPhase, setExperimentsByPhase] = useState>({}) const [repetitionsByExperiment, setRepetitionsByExperiment] = useState>({}) const [selectedRepetitionIds, setSelectedRepetitionIds] = useState>(new Set()) @@ -410,10 +411,13 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } return } - // Assign consistent colors per selected conductor + // Assign consistent colors per conductor based on their position in the full conductors array + // This ensures the same conductor always gets the same color, matching the checkbox list const newColorMap: Record = {} - selectedIds.forEach((conductorId, index) => { - newColorMap[conductorId] = colorPalette[index % colorPalette.length] + conductors.forEach((conductor, index) => { + if (selectedIds.includes(conductor.id)) { + newColorMap[conductor.id] = colorPalette[index % colorPalette.length] + } }) setConductorColorMap(newColorMap) @@ -537,8 +541,8 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } } } else { next.add(repId) - // Auto-spawn when checked - spawnSingleRepetition(repId) + // Auto-spawn when checked - pass the updated set to ensure correct stagger calculation + spawnSingleRepetition(repId, next) // Re-stagger all existing repetitions to prevent overlap reStaggerRepetitions([...next, repId]) } @@ -572,8 +576,8 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } const next = new Set(prev) allRepetitions.forEach(rep => { next.add(rep.id) - // Auto-spawn when checked - spawnSingleRepetition(rep.id) + // Auto-spawn when checked - pass the updated set to ensure correct stagger calculation + spawnSingleRepetition(rep.id, next) }) return next } @@ -653,7 +657,7 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } } // Spawn a single repetition in calendar - const spawnSingleRepetition = (repId: string) => { + const spawnSingleRepetition = (repId: string, updatedSelectedIds?: Set) => { const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) tomorrow.setHours(9, 0, 0, 0) // Default to 9 AM tomorrow @@ -674,9 +678,11 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void } if (experiment && soaking && airdrying) { // Stagger the positioning to avoid overlap when multiple repetitions are selected - const selectedReps = Array.from(selectedRepetitionIds) + // Use the updated set if provided, otherwise use current state (may be stale) + const selectedReps = updatedSelectedIds ? Array.from(updatedSelectedIds) : Array.from(selectedRepetitionIds) const repIndex = selectedReps.indexOf(repId) - const staggerMinutes = repIndex * 15 // 15 minutes between each repetition's time points + // If repId not found in selectedReps, use the count of scheduled repetitions as fallback + const staggerMinutes = repIndex >= 0 ? repIndex * 15 : Object.keys(scheduledRepetitions).length * 15 const soakingStart = new Date(tomorrow.getTime() + (staggerMinutes * 60000)) const airdryingStart = new Date(soakingStart.getTime() + (soaking.soaking_duration_minutes * 60000)) @@ -1038,51 +1044,71 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void }

Conductors

Select to consider for scheduling - {/* Select All checkbox for conductors */} -
- -
-
- {conductors.length === 0 && ( +
+ {conductors.length === 0 ? (
No conductors found.
- )} - {conductors.map((c, index) => { - const name = [c.first_name, c.last_name].filter(Boolean).join(' ') || c.email - const hasFuture = conductorIdsWithFutureAvailability.has(c.id) - const checked = selectedConductorIds.has(c.id) - const conductorColor = checked ? colorPalette[index % colorPalette.length] : null - - return ( - - ) - })} + )} +
+ )}
@@ -1255,7 +1281,39 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void }

Selected Conductors' Availability & Experiment Scheduling

-
+
+ {/* Day-by-day navigation buttons (only show in week view) */} + {calendarView === Views.WEEK && ( +
+ + + Day +
+ )} Marker Style:
- {/* Select All checkbox for conductors */} -
- -
-
- {conductors.length === 0 && ( +
+ {conductors.length === 0 ? (
No conductors found.
- )} - {conductors.map((c, index) => { - const name = [c.first_name, c.last_name].filter(Boolean).join(' ') || c.email - const hasFuture = conductorIdsWithFutureAvailability.has(c.id) - const checked = selectedConductorIds.has(c.id) - const conductorColor = checked ? colorPalette[index % colorPalette.length] : null - - return ( - - ) - })} + )} +
+ )}
@@ -1251,7 +1277,39 @@ function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => void }

Selected Conductors' Availability & Experiment Scheduling

-
+
+ {/* Day-by-day navigation buttons (only show in week view) */} + {calendarView === Views.WEEK && ( +
+ + + Day +
+ )} Marker Style: