An easy-to-use platform for EEG experimentation in the classroom
at main 158 lines 4.5 kB view raw
1import React, { useCallback, useState } from 'react'; 2import { Button } from '../ui/button'; 3import { Link } from 'react-router-dom'; 4import InputCollect from '../InputCollect'; 5import { injectEmotivMarker } from '../../utils/eeg/emotiv'; 6import { injectMuseMarker } from '../../utils/eeg/muse'; 7import { EXPERIMENTS, DEVICES } from '../../constants/constants'; 8import { ExperimentWindow } from '../ExperimentWindow'; 9import { checkFileExists, getImages } from '../../utils/filesystem/storage'; 10import { 11 ExperimentParameters, 12 ExperimentObject, 13} from '../../constants/interfaces'; 14import { ExperimentActions as globalExperimentActions } from '../../actions'; 15 16interface Props { 17 type: EXPERIMENTS; 18 title: string; 19 isRunning: boolean; 20 params: ExperimentParameters; 21 subject: string; 22 experimentObject: ExperimentObject; 23 group: string; 24 session: number; 25 deviceType: DEVICES; 26 isEEGEnabled: boolean; 27 ExperimentActions: typeof globalExperimentActions; 28} 29 30const Run: React.FC<Props> = ({ 31 type, 32 title, 33 isRunning, 34 params, 35 subject, 36 experimentObject, 37 group, 38 session, 39 deviceType, 40 isEEGEnabled, 41 ExperimentActions, 42}) => { 43 const [isInputCollectOpen, setIsInputCollectOpen] = useState( 44 subject.length === 0 45 ); 46 47 const handleStartExperiment = useCallback(async () => { 48 const filename = `${subject}-${group}-${session}-behavior.csv`; 49 const fileExists = await checkFileExists(title, subject, filename); 50 if (fileExists) { 51 const options = { 52 buttons: ['No', 'Yes'], 53 message: 54 'You already have a file with the same name. If you continue the experiment, the current file will be deleted. Do you really want to overwrite the data?', 55 }; 56 const response = await window.electronAPI.showMessageBox(options); 57 if (response.response === 1) { 58 ExperimentActions.Start(); 59 } 60 } else { 61 ExperimentActions.Start(); 62 } 63 }, [subject, group, session, title, ExperimentActions]); 64 65 const handleCloseInputCollect = useCallback( 66 (newSubject: string, newGroup: string, newSession: number) => { 67 ExperimentActions.SetSubject(newSubject); 68 ExperimentActions.SetGroup(newGroup); 69 ExperimentActions.SetSession(newSession); 70 setIsInputCollectOpen(false); 71 }, 72 [ExperimentActions] 73 ); 74 75 const eventCallback = useCallback( 76 (event: string, time: number) => { 77 if (isEEGEnabled) { 78 if (deviceType === 'MUSE') { 79 injectMuseMarker(event, time); 80 } else { 81 injectEmotivMarker(event, time); 82 } 83 } 84 }, 85 [isEEGEnabled, deviceType] 86 ); 87 88 const onFinish = useCallback( 89 (csv) => { 90 ExperimentActions.Stop({ data: csv }); 91 }, 92 [ExperimentActions] 93 ); 94 95 return ( 96 <div 97 className="h-screen p-[3%] bg-gradient-to-b from-[#f9f9f9] to-[#f0f0ff]" 98 data-tid="container" 99 > 100 <div className="h-full"> 101 {!isRunning && ( 102 <div className="h-screen p-[3%] bg-gradient-to-b from-[#f9f9f9] to-[#f0f0ff]"> 103 <div className="text-left"> 104 <h1>{title}</h1> 105 <button 106 className="flex justify-end w-full" 107 onClick={() => setIsInputCollectOpen(true)} 108 aria-label="Edit" 109 > 110 111 </button> 112 <div> 113 Subject ID: <b>{subject}</b> 114 </div> 115 <div> 116 Group Name: <b>{group}</b> 117 </div> 118 <div> 119 Session Number: <b>{session}</b> 120 </div> 121 <div className="mt-6"> 122 <Button 123 variant="default" 124 className="w-full" 125 onClick={handleStartExperiment} 126 disabled={!subject} 127 > 128 Run Experiment 129 </Button> 130 </div> 131 </div> 132 </div> 133 )} 134 135 {isRunning && ( 136 <div className="h-full w-full"> 137 <ExperimentWindow 138 title={title} 139 experimentObject={experimentObject} 140 params={params} 141 eventCallback={eventCallback} 142 onFinish={onFinish} 143 /> 144 </div> 145 )} 146 </div> 147 <InputCollect 148 open={isInputCollectOpen} 149 onClose={handleCloseInputCollect} 150 onExit={() => setIsInputCollectOpen(false)} 151 header="Enter Data" 152 data={{ subject, group, session }} 153 /> 154 </div> 155 ); 156}; 157 158export default Run;