Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix <Experiment /> layout when JsPsych is running the experiment #261

Merged
merged 9 commits into from
Sep 1, 2023
61 changes: 28 additions & 33 deletions src/JsPsych/timeline.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// TODO 204: @ import for language
import { language } from "./language";
// import { language } from "./language";

// TODO 204: @ import for trials
import { Preamble, createCountdownTrial, EndExperiment } from "./trials/examples";
import { createHoneycombBlock } from "./trials/honeycombBlock";
import { Preamble, EndExperiment } from "./trials/examples";
// import { Preamble, createCountdownTrial, EndExperiment } from "./trials/examples";
// import { createHoneycombBlock } from "./trials/honeycombBlock";

/**
* Create your custom JsPsych options here. These settings will applied experiment wide.
Expand All @@ -25,44 +26,38 @@ export const JSPSYCH_OPTIONS = {
* @returns array of trials
*/
// TODO 207: Eslint warning is causing build to fail
// eslint-disable-next-line
export function buildTimeline(jsPsych) {
// Get slider text from the language file and create the trials
// const sliderLanguage = language.quiz.direction.slider;
// const sliderLeft = createSliderTrial(sliderLanguage.left);
// const sliderRight = createSliderTrial(sliderLanguage.right);

export function buildTimeline() {
// Get countdown txt from the language fil and create the trials+
const countdownLanguage = language.countdown;
const firstBlockCountdown = createCountdownTrial({ message: countdownLanguage.first });
const secondBlockCountdown = createCountdownTrial({ message: countdownLanguage.second });
// const countdownLanguage = language.countdown;
// const firstBlockCountdown = createCountdownTrial({ message: countdownLanguage.first });
// const secondBlockCountdown = createCountdownTrial({ message: countdownLanguage.second });

// Create a tutorial block of Honeycomb's custom task
const honeycombTutorialBlock = createHoneycombBlock({
isTutorial: true,
photodiodeActive: false,
});
// // Create a tutorial block of Honeycomb's custom task
// const honeycombTutorialBlock = createHoneycombBlock({
// isTutorial: true,
// photodiodeActive: false,
// });

// Create a practice block of Honeycomb's custom task
const honeycombPracticeBlock = createHoneycombBlock({
conditions: ["m", "n"],
repeatsPerCondition: 1,
isPractice: true,
});
// // Create a practice block of Honeycomb's custom task
// const honeycombPracticeBlock = createHoneycombBlock({
// conditions: ["m", "n"],
// repeatsPerCondition: 1,
// isPractice: true,
// });

// Create an experiment block
const honeycombBlock1 = createHoneycombBlock({
repeatsPerCondition: 2,
});
// // Create an experiment block
// const honeycombBlock1 = createHoneycombBlock({
// repeatsPerCondition: 2,
// });

// Build the timeline
const timeline = [
Preamble,
honeycombTutorialBlock,
firstBlockCountdown,
honeycombPracticeBlock,
secondBlockCountdown,
honeycombBlock1,
// honeycombTutorialBlock,
// firstBlockCountdown,
// honeycombPracticeBlock,
// secondBlockCountdown,
// honeycombBlock1,
EndExperiment, // Task complete message
];
return timeline;
Expand Down
13 changes: 8 additions & 5 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import "bootstrap/dist/css/bootstrap.css";

import { addToFirebase, validateParticipant } from "../firebase";

import JsPsychExperiment from "./JsPsychExperiment";
import Experiment from "./Experiment";
import Login from "./Login";
import Error from "./Error";

Expand All @@ -13,6 +13,9 @@ import { getQueryVariable } from "../utils";

import { TASK_VERSION } from "../JsPsych/constants";

// Additional options passed by the user
import { JSPSYCH_OPTIONS } from "../JsPsych/timeline";

/** Top-level React component for Honeycomb.
*
* This component stores the state of the app.
Expand Down Expand Up @@ -189,11 +192,10 @@ function App() {
setLoggedIn(true);
}, []);

if (isError) {
return <Error />;
} else {
if (isError) return <Error />;
else {
return loggedIn ? (
<JsPsychExperiment
<Experiment
config={OLD_CONFIG}
studyID={studyID}
participantID={participantID}
Expand All @@ -214,6 +216,7 @@ function App() {
default: defaultFinishFunction,
}[currentMethod]
}
jsPsychOptions={JSPSYCH_OPTIONS}
/>
) : (
// Not logged in - display login screen
Expand Down
55 changes: 55 additions & 0 deletions src/components/Experiment.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { initJsPsych } from "jspsych";
import React, { useEffect } from "react";

import { initParticipant } from "../firebase";

// These will be passed in as props to the package once it's split
import { buildTimeline } from "../JsPsych/timeline";

const EXPERIMENT_ID = "jspsych-experiment-window";

// Based on https://react.dev/reference/react/useEffect#controlling-a-non-react-widget
export default function Experiment({
config,
studyID,
participantID,
taskVersion,
dataUpdateFunction,
dataFinishFunction,
jsPsychOptions,
}) {
// Initialize and run JsPsych on first render
useEffect(() => {
// Start date of the experiment - used as the UID
// TODO 169: JsPsych has a built in timestamp function
const startDate = new Date().toISOString();

// Write the initial record to Firestore
if (config.USE_FIREBASE) initParticipant(studyID, participantID, startDate);

// Initialize experiment, user passed options are merged with defaults
const jsPsych = initJsPsych({
display_element: EXPERIMENT_ID,
on_data_update: (data) => dataUpdateFunction(data),
on_finish: (data) => dataFinishFunction(data),
...jsPsychOptions,
});
// Add experiment data to the trials
jsPsych.data.addProperties({
study_id: studyID,
participant_id: participantID,
start_date: startDate,
task_version: taskVersion,
});

// Run the experiment
jsPsych.run(buildTimeline()).then(() => {
// TODO: Return to home page after experiment completes
// TODO: Need to update the electron code to save data here, not
console.log("FINISHED EXPERIMENT");
window.location.reload();
});
}, []);

return <div id={EXPERIMENT_ID} />;
}
94 changes: 0 additions & 94 deletions src/components/JsPsychExperiment.jsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/firebase/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ export async function initParticipant(studyID, participantID, startDate) {
await experiment.set({
start_time: startDate,
// TODO 173: app_version and app_platform are deprecated
// TODO: Pass taskVersion into this function from <Experiment />
app_version: window.navigator.appVersion,
app_platform: window.navigator.platform,
// TODO 175: Store participantID and studyID here, not on each trial
});
console.log("Initialized experiment:", studyID, participantID, startDate);
return true;
Expand Down