import { useState, useEffect } from 'react' import { ExperimentModal } from './ExperimentModal' import { RepetitionScheduleModal } from './RepetitionScheduleModal' import { experimentManagement, repetitionManagement, userManagement } from '../lib/supabase' import type { Experiment, ExperimentRepetition, User, ScheduleStatus, ResultsStatus, ExperimentPhase } from '../lib/supabase' interface PhaseExperimentsProps { phase: ExperimentPhase onBack: () => void } export function PhaseExperiments({ phase, onBack }: PhaseExperimentsProps) { const [experiments, setExperiments] = useState([]) const [experimentRepetitions, setExperimentRepetitions] = useState>({}) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showModal, setShowModal] = useState(false) const [editingExperiment, setEditingExperiment] = useState(undefined) const [currentUser, setCurrentUser] = useState(null) const [showRepetitionScheduleModal, setShowRepetitionScheduleModal] = useState(false) const [schedulingRepetition, setSchedulingRepetition] = useState<{ experiment: Experiment; repetition: ExperimentRepetition } | undefined>(undefined) useEffect(() => { loadData() }, [phase.id]) const loadData = async () => { try { setLoading(true) setError(null) const [experimentsData, userData] = await Promise.all([ experimentManagement.getExperimentsByPhaseId(phase.id), userManagement.getCurrentUser() ]) setExperiments(experimentsData) setCurrentUser(userData) // Load repetitions for each experiment const repetitionsMap: Record = {} for (const experiment of experimentsData) { try { const repetitions = await repetitionManagement.getExperimentRepetitions(experiment.id) repetitionsMap[experiment.id] = repetitions } catch (err) { console.error(`Failed to load repetitions for experiment ${experiment.id}:`, err) repetitionsMap[experiment.id] = [] } } setExperimentRepetitions(repetitionsMap) } catch (err: any) { setError(err.message || 'Failed to load experiments') console.error('Load experiments error:', err) } finally { setLoading(false) } } const canManageExperiments = currentUser?.roles.includes('admin') || currentUser?.roles.includes('conductor') const handleCreateExperiment = () => { setEditingExperiment(undefined) setShowModal(true) } const handleEditExperiment = (experiment: Experiment) => { setEditingExperiment(experiment) setShowModal(true) } const handleExperimentSaved = async (experiment: Experiment) => { if (editingExperiment) { // Update existing experiment setExperiments(prev => prev.map(exp => exp.id === experiment.id ? experiment : exp)) } else { // Add new experiment and create all its repetitions setExperiments(prev => [experiment, ...prev]) try { // Create all repetitions for the new experiment const repetitions = await repetitionManagement.createAllRepetitions(experiment.id) setExperimentRepetitions(prev => ({ ...prev, [experiment.id]: repetitions })) } catch (err) { console.error('Failed to create repetitions:', err) } } setShowModal(false) setEditingExperiment(undefined) } const handleScheduleRepetition = (experiment: Experiment, repetition: ExperimentRepetition) => { setSchedulingRepetition({ experiment, repetition }) setShowRepetitionScheduleModal(true) } const handleRepetitionScheduleUpdated = (updatedRepetition: ExperimentRepetition) => { setExperimentRepetitions(prev => ({ ...prev, [updatedRepetition.experiment_id]: prev[updatedRepetition.experiment_id]?.map(rep => rep.id === updatedRepetition.id ? updatedRepetition : rep ) || [] })) setShowRepetitionScheduleModal(false) setSchedulingRepetition(undefined) } const handleCreateRepetition = async (experiment: Experiment, repetitionNumber: number) => { try { const newRepetition = await repetitionManagement.createRepetition({ experiment_id: experiment.id, repetition_number: repetitionNumber, }) setExperimentRepetitions(prev => ({ ...prev, [experiment.id]: [...(prev[experiment.id] || []), newRepetition].sort((a, b) => a.repetition_number - b.repetition_number) })) } catch (err: any) { setError(err.message || 'Failed to create repetition') } } const handleDeleteExperiment = async (experiment: Experiment) => { if (!currentUser?.roles.includes('admin')) { alert('Only administrators can delete experiments.') return } if (!confirm(`Are you sure you want to delete Experiment #${experiment.experiment_number}? This action cannot be undone.`)) { return } try { await experimentManagement.deleteExperiment(experiment.id) setExperiments(prev => prev.filter(exp => exp.id !== experiment.id)) } catch (err: any) { alert(`Failed to delete experiment: ${err.message}`) console.error('Delete experiment error:', err) } } const getRepetitionStatusSummary = (repetitions: ExperimentRepetition[]) => { const scheduled = repetitions.filter(r => r.scheduled_date).length const pending = repetitions.filter(r => !r.scheduled_date).length const completed = repetitions.filter(r => r.completion_status).length return { scheduled, pending, completed, total: repetitions.length } } const getStatusBadgeColor = (status: ScheduleStatus | ResultsStatus | string) => { switch (status) { case 'pending': return 'bg-yellow-100 text-yellow-800' case 'scheduled': return 'bg-blue-100 text-blue-800' case 'canceled': return 'bg-red-100 text-red-800' case 'aborted': return 'bg-red-100 text-red-800' case 'valid': return 'bg-green-100 text-green-800' case 'invalid': return 'bg-red-100 text-red-800' default: return 'bg-gray-100 text-gray-800' } } if (loading) { return (
) } return (
{/* Header */}

{phase.name}

{phase.description && (

{phase.description}

)}

Manage experiments within this phase

{canManageExperiments && ( )}
{/* Error Message */} {error && (
{error}
)} {/* Experiments Table */}

Experiments ({experiments.length})

{canManageExperiments ? 'Click on any experiment to edit details' : 'View experiment definitions and status'}

{canManageExperiments && ( )} {canManageExperiments && ( )} {experiments.map((experiment) => ( handleEditExperiment(experiment) : undefined} > {canManageExperiments && ( )} {canManageExperiments && ( )} ))}
Experiment # Reps Required Experiment Parameters Repetitions Status Manage Repetitions Results Status Completion Created Actions
#{experiment.experiment_number} {experiment.reps_required}
Soaking: {experiment.soaking_duration_hr}h
Drying: {experiment.air_drying_time_min}min
Frequency: {experiment.plate_contact_frequency_hz}Hz
{(() => { const repetitions = experimentRepetitions[experiment.id] || [] const summary = getRepetitionStatusSummary(repetitions) return (
{summary.total} total • {summary.scheduled} scheduled • {summary.pending} pending
{summary.scheduled > 0 && ( {summary.scheduled} scheduled )} {summary.pending > 0 && ( {summary.pending} pending )}
) })()}
{(() => { const repetitions = experimentRepetitions[experiment.id] || [] return repetitions.map((repetition) => (
Rep #{repetition.repetition_number}
{repetition.scheduled_date ? 'scheduled' : 'pending'}
)) })()} {(() => { const repetitions = experimentRepetitions[experiment.id] || [] const missingReps = experiment.reps_required - repetitions.length if (missingReps > 0) { return ( ) } return null })()}
{experiment.results_status} {experiment.completion_status ? 'Completed' : 'In Progress'} {new Date(experiment.created_at).toLocaleDateString()}
{currentUser?.roles.includes('admin') && ( )}
{experiments.length === 0 && (

No experiments found in this phase

Get started by creating your first experiment in this phase.

{canManageExperiments && (
)}
)}
{/* Experiment Modal */} {showModal && ( setShowModal(false)} onExperimentSaved={handleExperimentSaved} phaseId={phase.id} /> )} {/* Repetition Schedule Modal */} {showRepetitionScheduleModal && schedulingRepetition && ( setShowRepetitionScheduleModal(false)} onScheduleUpdated={handleRepetitionScheduleUpdated} /> )}
) }