From 9bcb5c203e7b524263f4a85bf1d2b5aed5b4d230 Mon Sep 17 00:00:00 2001 From: salirezav Date: Mon, 9 Mar 2026 13:53:03 -0400 Subject: [PATCH] Refactor Experiment and Phase components for improved state management and UI consistency - Resolved merge conflicts and cleaned up code in ExperimentForm, enhancing initial state handling and validation logic. - Updated PhaseForm to reflect correct placeholder text for descriptions. - Simplified Sidebar component by removing unused props and ensuring consistent behavior across expanded and collapsed states. - Adjusted Scheduling component to streamline repetition management and improve user experience. --- docs/SUPABASE_DOCKER_COMPOSE.md | 4 - .../src/components/ExperimentForm.tsx | 72 ----- .../src/components/PhaseForm.tsx | 4 - .../src/components/Sidebar.tsx | 57 ---- .../src/components/Scheduling.tsx | 251 ------------------ 5 files changed, 388 deletions(-) diff --git a/docs/SUPABASE_DOCKER_COMPOSE.md b/docs/SUPABASE_DOCKER_COMPOSE.md index a17aedb..f9a073a 100644 --- a/docs/SUPABASE_DOCKER_COMPOSE.md +++ b/docs/SUPABASE_DOCKER_COMPOSE.md @@ -51,11 +51,7 @@ VITE_SUPABASE_ANON_KEY= The default anon key for local development is: ``` -<<<<<<< HEAD [REDACTED] -======= -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0 ->>>>>>> old-github/main ``` ### Migrations diff --git a/management-dashboard-web-app/src/components/ExperimentForm.tsx b/management-dashboard-web-app/src/components/ExperimentForm.tsx index 0a77752..8329411 100755 --- a/management-dashboard-web-app/src/components/ExperimentForm.tsx +++ b/management-dashboard-web-app/src/components/ExperimentForm.tsx @@ -3,11 +3,7 @@ import type { CreateExperimentRequest, UpdateExperimentRequest, ScheduleStatus, import { experimentPhaseManagement, machineTypeManagement } from '../lib/supabase' interface ExperimentFormProps { -<<<<<<< HEAD - initialData?: Partial -======= initialData?: Partial & { phase_id?: string | null } ->>>>>>> old-github/main onSubmit: (data: CreateExperimentRequest | UpdateExperimentRequest) => Promise onCancel: () => void isEditing?: boolean @@ -16,28 +12,6 @@ interface ExperimentFormProps { } export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = false, loading = false, phaseId }: ExperimentFormProps) { -<<<<<<< HEAD - const [formData, setFormData] = useState({ - experiment_number: initialData?.experiment_number || 0, - reps_required: initialData?.reps_required || 1, - weight_per_repetition_lbs: (initialData as any)?.weight_per_repetition_lbs || 1, - soaking_duration_hr: initialData?.soaking_duration_hr || 0, - air_drying_time_min: initialData?.air_drying_time_min || 0, - plate_contact_frequency_hz: initialData?.plate_contact_frequency_hz || 1, - throughput_rate_pecans_sec: initialData?.throughput_rate_pecans_sec || 1, - crush_amount_in: initialData?.crush_amount_in || 0, - entry_exit_height_diff_in: initialData?.entry_exit_height_diff_in || 0, - // Meyer-specific (UI only) - motor_speed_hz: (initialData as any)?.motor_speed_hz || 1, - jig_displacement_inches: (initialData as any)?.jig_displacement_inches || 0, - spring_stiffness_nm: (initialData as any)?.spring_stiffness_nm || 1, - schedule_status: initialData?.schedule_status || 'pending schedule', - results_status: initialData?.results_status || 'valid', - completion_status: initialData?.completion_status || false, - phase_id: initialData?.phase_id || phaseId - }) - -======= const getInitialFormState = (d: any) => ({ experiment_number: d?.experiment_number ?? 0, reps_required: d?.reps_required ?? 1, @@ -61,14 +35,11 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa const [formData, setFormData] = useState(() => getInitialFormState(initialData)) ->>>>>>> old-github/main const [errors, setErrors] = useState>({}) const [phase, setPhase] = useState(null) const [crackingMachine, setCrackingMachine] = useState(null) const [metaLoading, setMetaLoading] = useState(false) -<<<<<<< HEAD -======= // When initialData loads with phase config (edit mode), sync form state useEffect(() => { if ((initialData as any)?.id) { @@ -76,7 +47,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } }, [initialData]) ->>>>>>> old-github/main useEffect(() => { const loadMeta = async () => { if (!phaseId) return @@ -116,19 +86,11 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } -<<<<<<< HEAD - if (formData.soaking_duration_hr < 0) { - newErrors.soaking_duration_hr = 'Soaking duration cannot be negative' - } - - if (formData.air_drying_time_min < 0) { -======= if ((formData.soaking_duration_hr ?? 0) < 0) { newErrors.soaking_duration_hr = 'Soaking duration cannot be negative' } if ((formData.air_drying_time_min ?? 0) < 0) { ->>>>>>> old-github/main newErrors.air_drying_time_min = 'Air drying time cannot be negative' } @@ -141,11 +103,7 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa if (!formData.throughput_rate_pecans_sec || formData.throughput_rate_pecans_sec <= 0) { newErrors.throughput_rate_pecans_sec = 'Throughput rate must be positive' } -<<<<<<< HEAD - if (formData.crush_amount_in < 0) { -======= if ((formData.crush_amount_in ?? 0) < 0) { ->>>>>>> old-github/main newErrors.crush_amount_in = 'Crush amount cannot be negative' } } @@ -162,8 +120,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } } -<<<<<<< HEAD -======= // Shelling: if provided, must be positive if (phase?.has_shelling) { if (formData.ring_gap_inches != null && (typeof formData.ring_gap_inches !== 'number' || formData.ring_gap_inches <= 0)) { @@ -174,7 +130,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } } ->>>>>>> old-github/main setErrors(newErrors) return Object.keys(newErrors).length === 0 } @@ -187,20 +142,13 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } try { -<<<<<<< HEAD - // Prepare data for submission -======= // Prepare data: include all phase params so they are stored in experiment_soaking, experiment_airdrying, experiment_cracking, experiment_shelling ->>>>>>> old-github/main const submitData = isEditing ? formData : { experiment_number: formData.experiment_number, reps_required: formData.reps_required, weight_per_repetition_lbs: formData.weight_per_repetition_lbs, results_status: formData.results_status, completion_status: formData.completion_status, -<<<<<<< HEAD - phase_id: formData.phase_id -======= phase_id: formData.phase_id, soaking_duration_hr: formData.soaking_duration_hr, air_drying_time_min: formData.air_drying_time_min, @@ -213,7 +161,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa spring_stiffness_nm: (formData as any).spring_stiffness_nm, ring_gap_inches: formData.ring_gap_inches ?? undefined, drum_rpm: formData.drum_rpm ?? undefined ->>>>>>> old-github/main } await onSubmit(submitData) @@ -222,11 +169,7 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa } } -<<<<<<< HEAD - const handleInputChange = (field: keyof typeof formData, value: string | number | boolean) => { -======= const handleInputChange = (field: keyof typeof formData, value: string | number | boolean | null | undefined) => { ->>>>>>> old-github/main setFormData(prev => ({ ...prev, [field]: value @@ -529,20 +472,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa

Shelling

-<<<<<<< HEAD - - handleInputChange('shelling_start_offset_min' as any, parseInt(e.target.value) || 0)} - className="max-w-xs px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-sm" - placeholder="0" - min="0" - step="1" - /> -======= @@ -577,7 +506,6 @@ export function ExperimentForm({ initialData, onSubmit, onCancel, isEditing = fa {errors.drum_rpm && (

{errors.drum_rpm}

)} ->>>>>>> old-github/main
diff --git a/management-dashboard-web-app/src/components/PhaseForm.tsx b/management-dashboard-web-app/src/components/PhaseForm.tsx index 8727071..7bd19b6 100644 --- a/management-dashboard-web-app/src/components/PhaseForm.tsx +++ b/management-dashboard-web-app/src/components/PhaseForm.tsx @@ -147,11 +147,7 @@ export function PhaseForm({ onSubmit, onCancel, loading = false }: PhaseFormProp onChange={(e) => handleInputChange('description', e.target.value)} rows={3} className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" -<<<<<<< HEAD - placeholder="Optional description of this experiment phase" -======= placeholder="Optional description of this experiment book" ->>>>>>> old-github/main disabled={loading} /> diff --git a/management-dashboard-web-app/src/components/Sidebar.tsx b/management-dashboard-web-app/src/components/Sidebar.tsx index 7168205..6673e15 100755 --- a/management-dashboard-web-app/src/components/Sidebar.tsx +++ b/management-dashboard-web-app/src/components/Sidebar.tsx @@ -7,11 +7,6 @@ interface SidebarProps { onViewChange: (view: string) => void isExpanded?: boolean isMobileOpen?: boolean -<<<<<<< HEAD - isHovered?: boolean - setIsHovered?: (hovered: boolean) => void -======= ->>>>>>> old-github/main } interface MenuItem { @@ -26,15 +21,8 @@ export function Sidebar({ user, currentView, onViewChange, -<<<<<<< HEAD - isExpanded = true, - isMobileOpen = false, - isHovered = false, - setIsHovered -======= isExpanded = false, isMobileOpen = false ->>>>>>> old-github/main }: SidebarProps) { const [openSubmenu, setOpenSubmenu] = useState(null) const [subMenuHeight, setSubMenuHeight] = useState>({}) @@ -178,11 +166,7 @@ export function Sidebar({ className={`menu-item group ${openSubmenu === index ? "menu-item-active" : "menu-item-inactive" -<<<<<<< HEAD - } cursor-pointer ${!isExpanded && !isHovered -======= } cursor-pointer ${!isExpanded ->>>>>>> old-github/main ? "lg:justify-center" : "lg:justify-start" }`} @@ -195,17 +179,10 @@ export function Sidebar({ > {nav.icon} -<<<<<<< HEAD - {(isExpanded || isHovered || isMobileOpen) && ( - {nav.name} - )} - {(isExpanded || isHovered || isMobileOpen) && ( -======= {(isExpanded || isMobileOpen) && ( {nav.name} )} {(isExpanded || isMobileOpen) && ( ->>>>>>> old-github/main {nav.icon} -<<<<<<< HEAD - {(isExpanded || isHovered || isMobileOpen) && ( -======= {(isExpanded || isMobileOpen) && ( ->>>>>>> old-github/main {nav.name} )} )} -<<<<<<< HEAD - {nav.subItems && (isExpanded || isHovered || isMobileOpen) && ( -======= {nav.subItems && (isExpanded || isMobileOpen) && ( ->>>>>>> old-github/main
{ subMenuRefs.current[`submenu-${index}`] = el @@ -292,23 +261,6 @@ export function Sidebar({ className={`fixed mt-16 flex flex-col lg:mt-0 top-0 px-5 left-0 bg-white dark:bg-gray-900 dark:border-gray-800 text-gray-900 h-screen transition-all duration-300 ease-in-out z-50 border-r border-gray-200 ${isExpanded || isMobileOpen ? "w-[290px]" -<<<<<<< HEAD - : isHovered - ? "w-[290px]" - : "w-[90px]" - } - ${isMobileOpen ? "translate-x-0" : "-translate-x-full"} - lg:translate-x-0`} - onMouseEnter={() => !isExpanded && setIsHovered && setIsHovered(true)} - onMouseLeave={() => setIsHovered && setIsHovered(false)} - > -
-
- {isExpanded || isHovered || isMobileOpen ? ( -======= : "w-[90px]" } ${isMobileOpen ? "translate-x-0" : "-translate-x-full"} @@ -320,7 +272,6 @@ export function Sidebar({ >
{isExpanded || isMobileOpen ? ( ->>>>>>> old-github/main <>

Pecan Experiments

Research Dashboard

@@ -338,20 +289,12 @@ export function Sidebar({

>>>>>> old-github/main ? "lg:justify-center" : "justify-start" }`} > -<<<<<<< HEAD - {isExpanded || isHovered || isMobileOpen ? ( -======= {isExpanded || isMobileOpen ? ( ->>>>>>> old-github/main "Menu" ) : ( diff --git a/scheduling-remote/src/components/Scheduling.tsx b/scheduling-remote/src/components/Scheduling.tsx index 0d774f1..fcdd8cb 100644 --- a/scheduling-remote/src/components/Scheduling.tsx +++ b/scheduling-remote/src/components/Scheduling.tsx @@ -70,11 +70,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => // Track repetitions that have been dropped/moved and should show time points const [repetitionsWithTimes, setRepetitionsWithTimes] = useState>(new Set()) -<<<<<<< HEAD - // Track which repetitions are locked (prevent dragging) - const [lockedSchedules, setLockedSchedules] = useState>(new Set()) -======= ->>>>>>> old-github/main // Track which repetitions are currently being scheduled const [schedulingRepetitions, setSchedulingRepetitions] = useState>(new Set()) // Track conductor assignments for each phase marker (markerId -> conductorIds[]) @@ -256,46 +251,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => } const toggleRepetition = (repId: string) => { -<<<<<<< HEAD - setSelectedRepetitionIds(prev => { - const next = new Set(prev) - if (next.has(repId)) { - next.delete(repId) - // Remove from scheduled repetitions when unchecked - setScheduledRepetitions(prevScheduled => { - const newScheduled = { ...prevScheduled } - delete newScheduled[repId] - return newScheduled - }) - // Clear all related state when unchecked - setRepetitionsWithTimes(prev => { - const next = new Set(prev) - next.delete(repId) - return next - }) - setLockedSchedules(prev => { - const next = new Set(prev) - next.delete(repId) - return next - }) - setSchedulingRepetitions(prev => { - const next = new Set(prev) - next.delete(repId) - return next - }) - // Re-stagger remaining repetitions - const remainingIds = Array.from(next).filter(id => id !== repId) - if (remainingIds.length > 0) { - reStaggerRepetitions(remainingIds) - } - } else { - next.add(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 - // Note: reStaggerRepetitions will automatically skip locked repetitions - reStaggerRepetitions([...next, repId]) -======= // Checking/unchecking should only control visibility on the timeline. // It must NOT clear scheduling info or conductor assignments. setSelectedRepetitionIds(prev => { @@ -312,7 +267,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => // spawnSingleRepetition will position the new repetition relative to existing ones // without resetting existing positions spawnSingleRepetition(repId, next) ->>>>>>> old-github/main } return next }) @@ -327,22 +281,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => const allSelected = allRepetitions.every(rep => prev.has(rep.id)) if (allSelected) { -<<<<<<< HEAD - // Deselect all repetitions in this phase - const next = new Set(prev) - allRepetitions.forEach(rep => { - next.delete(rep.id) - // Remove from scheduled repetitions - setScheduledRepetitions(prevScheduled => { - const newScheduled = { ...prevScheduled } - delete newScheduled[rep.id] - return newScheduled - }) - }) - return next - } else { - // Select all repetitions in this phase -======= // Deselect all repetitions in this phase (hide from timeline only) const next = new Set(prev) allRepetitions.forEach(rep => { @@ -351,7 +289,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => return next } else { // Select all repetitions in this phase (show on timeline) ->>>>>>> old-github/main const next = new Set(prev) allRepetitions.forEach(rep => { next.add(rep.id) @@ -389,11 +326,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => // Re-stagger all repetitions to prevent overlap // IMPORTANT: Skip locked repetitions to prevent them from moving -<<<<<<< HEAD - const reStaggerRepetitions = useCallback((repIds: string[]) => { -======= const reStaggerRepetitions = useCallback((repIds: string[], onlyResetWithoutCustomTimes: boolean = false) => { ->>>>>>> old-github/main const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) tomorrow.setHours(9, 0, 0, 0) @@ -401,16 +334,11 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => setScheduledRepetitions(prev => { const newScheduled = { ...prev } -<<<<<<< HEAD - // Filter out locked repetitions - they should not be moved - const unlockedRepIds = repIds.filter(repId => !lockedSchedules.has(repId)) -======= // If onlyResetWithoutCustomTimes is true, filter out repetitions that have custom times set let unlockedRepIds = repIds if (onlyResetWithoutCustomTimes) { unlockedRepIds = unlockedRepIds.filter(repId => !repetitionsWithTimes.has(repId)) } ->>>>>>> old-github/main // Calculate stagger index only for unlocked repetitions let staggerIndex = 0 @@ -452,11 +380,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => return newScheduled }) -<<<<<<< HEAD - }, [lockedSchedules, repetitionsByExperiment, experimentsByPhase, soakingByExperiment, airdryingByExperiment]) -======= }, [repetitionsByExperiment, experimentsByPhase, soakingByExperiment, airdryingByExperiment, repetitionsWithTimes]) ->>>>>>> old-github/main // Spawn a single repetition in calendar const spawnSingleRepetition = (repId: string, updatedSelectedIds?: Set) => { @@ -526,18 +450,11 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => let newScheduled = { ...prev } const clampToReasonableHours = (d: Date) => { -<<<<<<< HEAD - const min = new Date(d) - min.setHours(5, 0, 0, 0) - const max = new Date(d) - max.setHours(23, 0, 0, 0) -======= // Allow full 24 hours (midnight to midnight) const min = new Date(d) min.setHours(0, 0, 0, 0) const max = new Date(d) max.setHours(23, 59, 59, 999) ->>>>>>> old-github/main const t = d.getTime() return new Date(Math.min(Math.max(t, min.getTime()), max.getTime())) } @@ -593,20 +510,10 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => const repetition = repetitionsByExperiment[scheduled.experimentId]?.find(r => r.id === scheduled.repetitionId) if (experiment && repetition && scheduled.soakingStart) { -<<<<<<< HEAD - const isLocked = lockedSchedules.has(scheduled.repetitionId) - const lockIcon = isLocked ? '🔒' : '🔓' - - // Soaking marker - events.push({ - id: `${scheduled.repetitionId}-soaking`, - title: `${lockIcon} 💧 Soaking - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, -======= // Soaking marker events.push({ id: `${scheduled.repetitionId}-soaking`, title: `💧 Soaking - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, ->>>>>>> old-github/main start: scheduled.soakingStart, end: new Date(scheduled.soakingStart.getTime() + 15 * 60000), // 15 minute duration for better visibility resource: 'soaking' @@ -616,11 +523,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => if (scheduled.airdryingStart) { events.push({ id: `${scheduled.repetitionId}-airdrying`, -<<<<<<< HEAD - title: `${lockIcon} 🌬️ Airdrying - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, -======= title: `🌬️ Airdrying - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, ->>>>>>> old-github/main start: scheduled.airdryingStart, end: new Date(scheduled.airdryingStart.getTime() + 15 * 60000), // 15 minute duration for better visibility resource: 'airdrying' @@ -631,11 +534,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => if (scheduled.crackingStart) { events.push({ id: `${scheduled.repetitionId}-cracking`, -<<<<<<< HEAD - title: `${lockIcon} ⚡ Cracking - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, -======= title: `⚡ Cracking - Exp ${experiment.experiment_number} Rep ${repetition.repetition_number}`, ->>>>>>> old-github/main start: scheduled.crackingStart, end: new Date(scheduled.crackingStart.getTime() + 15 * 60000), // 15 minute duration for better visibility resource: 'cracking' @@ -645,11 +544,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => }) return events -<<<<<<< HEAD - }, [scheduledRepetitions, experimentsByPhase, repetitionsByExperiment, lockedSchedules]) -======= }, [scheduledRepetitions, experimentsByPhase, repetitionsByExperiment]) ->>>>>>> old-github/main // Memoize the calendar events const calendarEvents = useMemo(() => { @@ -685,17 +580,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => return moment(date).format('MMM D, h:mm A') } -<<<<<<< HEAD - const toggleScheduleLock = (repId: string) => { - setLockedSchedules(prev => { - const next = new Set(prev) - if (next.has(repId)) { - next.delete(repId) - } else { - next.add(repId) - } - return next -======= // Remove all conductor assignments from a repetition const removeRepetitionAssignments = (repId: string) => { const markerIdPrefix = repId @@ -706,7 +590,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => delete newAssignments[`${markerIdPrefix}-airdrying`] delete newAssignments[`${markerIdPrefix}-cracking`] return newAssignments ->>>>>>> old-github/main }) } @@ -714,34 +597,16 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => // Only make repetition markers draggable, not availability events const resource = event.resource as string if (resource === 'soaking' || resource === 'airdrying' || resource === 'cracking') { -<<<<<<< HEAD - // Check if the repetition is locked - const eventId = event.id as string - const repId = eventId.split('-')[0] - const isLocked = lockedSchedules.has(repId) - return !isLocked - } - return false - }, [lockedSchedules]) -======= return true } return false }, []) ->>>>>>> old-github/main const eventPropGetter = useCallback((event: any) => { const resource = event.resource as string // Styling for repetition markers (foreground events) if (resource === 'soaking' || resource === 'airdrying' || resource === 'cracking') { -<<<<<<< HEAD - const eventId = event.id as string - const repId = eventId.split('-')[0] - const isLocked = lockedSchedules.has(repId) - -======= ->>>>>>> old-github/main const colors = { soaking: '#3b82f6', // blue airdrying: '#10b981', // green @@ -751,13 +616,8 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => return { style: { -<<<<<<< HEAD - backgroundColor: isLocked ? '#9ca3af' : color, // gray if locked - borderColor: isLocked ? color : color, // border takes original color when locked -======= backgroundColor: color, borderColor: color, ->>>>>>> old-github/main color: 'white', borderRadius: '8px', border: '2px solid', @@ -778,28 +638,17 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', -<<<<<<< HEAD - cursor: isLocked ? 'not-allowed' : 'grab', - boxShadow: isLocked ? '0 1px 2px rgba(0,0,0,0.1)' : '0 2px 4px rgba(0,0,0,0.2)', - transition: 'all 0.2s ease', - opacity: isLocked ? 0.7 : 1 -======= cursor: 'grab', boxShadow: '0 2px 4px rgba(0,0,0,0.2)', transition: 'all 0.2s ease', opacity: 1 ->>>>>>> old-github/main } } } // Default styling for other events return {} -<<<<<<< HEAD - }, [lockedSchedules]) -======= }, []) ->>>>>>> old-github/main const scheduleRepetition = async (repId: string, experimentId: string) => { setSchedulingRepetitions(prev => new Set(prev).add(repId)) @@ -871,8 +720,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => } } -<<<<<<< HEAD -======= // Unschedule a repetition: clear its scheduling info and unassign all conductors. const unscheduleRepetition = async (repId: string, experimentId: string) => { setSchedulingRepetitions(prev => new Set(prev).add(repId)) @@ -918,7 +765,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => } } ->>>>>>> old-github/main // Restore scroll position after scheduledRepetitions changes useEffect(() => { if (scrollPositionRef.current) { @@ -969,22 +815,15 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => phase: 'soaking' | 'airdrying' | 'cracking' startTime: Date assignedConductors: string[] -<<<<<<< HEAD - locked: boolean -======= ->>>>>>> old-github/main }> = [] Object.values(scheduledRepetitions).forEach(scheduled => { const repId = scheduled.repetitionId -<<<<<<< HEAD -======= // Only include markers for repetitions that are checked (selected) if (!selectedRepetitionIds.has(repId)) { return } ->>>>>>> old-github/main const markerIdPrefix = repId if (scheduled.soakingStart) { @@ -994,12 +833,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => experimentId: scheduled.experimentId, phase: 'soaking', startTime: scheduled.soakingStart, -<<<<<<< HEAD - assignedConductors: conductorAssignments[`${markerIdPrefix}-soaking`] || [], - locked: lockedSchedules.has(repId) -======= assignedConductors: conductorAssignments[`${markerIdPrefix}-soaking`] || [] ->>>>>>> old-github/main }) } @@ -1010,12 +844,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => experimentId: scheduled.experimentId, phase: 'airdrying', startTime: scheduled.airdryingStart, -<<<<<<< HEAD - assignedConductors: conductorAssignments[`${markerIdPrefix}-airdrying`] || [], - locked: lockedSchedules.has(repId) -======= assignedConductors: conductorAssignments[`${markerIdPrefix}-airdrying`] || [] ->>>>>>> old-github/main }) } @@ -1026,12 +855,7 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => experimentId: scheduled.experimentId, phase: 'cracking', startTime: scheduled.crackingStart, -<<<<<<< HEAD - assignedConductors: conductorAssignments[`${markerIdPrefix}-cracking`] || [], - locked: lockedSchedules.has(repId) -======= assignedConductors: conductorAssignments[`${markerIdPrefix}-cracking`] || [] ->>>>>>> old-github/main }) } }) @@ -1042,9 +866,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => conductorAvailabilities, phaseMarkers } -<<<<<<< HEAD - }, [selectedConductorIds, conductors, conductorColorMap, colorPalette, availabilityEvents, scheduledRepetitions, conductorAssignments, lockedSchedules, calendarStartDate, calendarZoom]) -======= }, [selectedConductorIds, conductors, conductorColorMap, colorPalette, availabilityEvents, scheduledRepetitions, conductorAssignments, calendarStartDate, calendarZoom, selectedRepetitionIds]) // Build repetition metadata mapping for timeline display @@ -1105,7 +926,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => element.scrollIntoView({ behavior: 'smooth', block: 'center' }) } }, [repetitionsByExperiment, experimentsByPhase, phases, expandedPhaseIds, togglePhaseExpand]) ->>>>>>> old-github/main // Handlers for horizontal calendar const handleHorizontalMarkerDrag = useCallback((markerId: string, newTime: Date) => { @@ -1127,24 +947,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => })) }, []) -<<<<<<< HEAD - const handleHorizontalMarkerLockToggle = useCallback((markerId: string) => { - // Marker ID format: ${repId}-${phase} where repId is a UUID with hyphens - // Split by '-' and take all but the last segment as repId - const parts = markerId.split('-') - const repId = parts.slice(0, -1).join('-') - setLockedSchedules(prev => { - const next = new Set(prev) - if (next.has(repId)) { - next.delete(repId) - } else { - next.add(repId) - } - return next - }) - }, []) -======= ->>>>>>> old-github/main return ( @@ -1279,13 +1081,9 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => phaseMarkers={horizontalCalendarData.phaseMarkers} onMarkerDrag={handleHorizontalMarkerDrag} onMarkerAssignConductors={handleHorizontalMarkerAssignConductors} -<<<<<<< HEAD - onMarkerLockToggle={handleHorizontalMarkerLockToggle} -======= repetitionMetadata={repetitionMetadata} onScrollToRepetition={handleScrollToRepetition} onScheduleRepetition={scheduleRepetition} ->>>>>>> old-github/main timeStep={15} minHour={6} maxHour={22} @@ -1454,13 +1252,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => const checked = selectedRepetitionIds.has(rep.id) const hasTimes = repetitionsWithTimes.has(rep.id) const scheduled = scheduledRepetitions[rep.id] -<<<<<<< HEAD - const isLocked = lockedSchedules.has(rep.id) - const isScheduling = schedulingRepetitions.has(rep.id) - - return ( -
-======= const isScheduling = schedulingRepetitions.has(rep.id) // Check if there are any conductor assignments @@ -1476,7 +1267,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => id={`repetition-${rep.id}`} className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded p-3" > ->>>>>>> old-github/main {/* Checkbox row */} -<<<<<<< HEAD - {/* Time points (shown only if has been dropped/moved) */} - {hasTimes && scheduled && ( -
-
- 💧 - Soaking: {formatTime(scheduled.soakingStart)} -
-
- 🌬️ - Airdrying: {formatTime(scheduled.airdryingStart)} -
-
- - Cracking: {formatTime(scheduled.crackingStart)} -
- - {/* Lock checkbox and Schedule button */} -
- - -======= {/* Time points (shown whenever the repetition has scheduled times) */} {scheduled && (
@@ -1611,7 +1361,6 @@ export function ScheduleExperiment({ user, onBack }: { user: User; onBack: () => {isScheduling ? 'Scheduling...' : 'Schedule'} )} ->>>>>>> old-github/main
)}