Skip to content

Commit

Permalink
update timings and templates (#893)
Browse files Browse the repository at this point in the history
* update timings and templates

* fix tests

* add finalPayoffs to postflight report

* update tests
  • Loading branch information
JamesPHoughton authored Sep 17, 2024
1 parent 3a39175 commit d4126fe
Show file tree
Hide file tree
Showing 25 changed files with 241 additions and 131 deletions.
8 changes: 4 additions & 4 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"@hello-pangea/dnd": "^16.3.0",
"@sentry/react": "^7.1.1",
"@sentry/tracing": "^7.1.1",
"@watts-lab/surveys": "^1.17.4",
"@watts-lab/surveys": "^1.17.5",
"axios": "^1.3.3",
"detect-browser": "5.3.0",
"js-yaml": "^4.1.0",
Expand Down
12 changes: 9 additions & 3 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function InnerParticipant() {
introSequence.introSteps.forEach((step, index) => {
const { name, elements } = step;
const introStep = ({ next }) =>
GenericIntroExitStep({ name, elements, index, next });
GenericIntroExitStep({ name, elements, index, next, phase: "intro" });
steps.push(introStep);
});
}
Expand Down Expand Up @@ -107,7 +107,13 @@ function InnerParticipant() {
treatment.exitSequence.forEach((step, index) => {
const { name, elements } = step;
const exitStep = ({ next }) =>
GenericIntroExitStep({ name, elements, index, next });
GenericIntroExitStep({
name,
elements,
index,
next,
phase: "exit",
});
steps.push(exitStep);
});
}
Expand Down Expand Up @@ -161,7 +167,7 @@ export default function App() {
<div
className="h-screen relative overflow-auto"
key={playerKey}
test-player-id={playerKey}
test-player-id={playerKey} // Todo: make this a "data" attribute throughout all tests
id={playerKey}
>
<EmpiricaParticipant
Expand Down
19 changes: 16 additions & 3 deletions client/src/Stage.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useStage, usePlayer } from "@empirica/core/player/classic/react";
import React, { useEffect } from "react";
import React, { useEffect, useMemo } from "react";
import {
TimeConditionalRender,
PositionConditionalRender,
Expand All @@ -13,9 +13,22 @@ export function Stage() {
const stage = useStage();
const player = usePlayer();

const progressLabel = useMemo(
() =>
`game_${stage.get("index")}_${stage
.get("name")
.trim()
.replace(/ /g, "_")}`, // replace ALL spaces with underscores
[stage]
); // memoize so we don't trigger the useEffect on every render

useEffect(() => {
console.log(`Stage ${stage.get("index")}: ${stage.get("name")}`);
}, [stage, player]);
if (player.get("progressLabel") !== progressLabel) {
console.log(`Starting ${progressLabel}`);
player.set("progressLabel", progressLabel);
player.set("localStageStartTime", undefined); // force use of stageTimer
}
}, [progressLabel, player]);

const discussion = stage?.get("discussion");
const elements = stage?.get("elements") || [];
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/ConditionalRender.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ export function DevConditionalRender({ children }) {

export function TimeConditionalRender({ displayTime, hideTime, children }) {
const timer = useStageTimer();
if (!timer) return null;
const player = usePlayer();

const msElapsed = timer
? timer.elapsed // game
: Date.now() - player.get("localStageStartTime"); // intro/exit
const elapsed = msElapsed / 1000;

const elapsed = timer.elapsed / 1000;
if (displayTime && elapsed < displayTime) return null;
if (hideTime && elapsed > hideTime) return null;

Expand Down
5 changes: 2 additions & 3 deletions client/src/components/ReportMissing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
} from "@empirica/core/player/classic/react";
import { Button } from "./Button";
import { RadioGroup } from "./RadioGroup";
import { useProgressLabel } from "./hooks";

const MODAL_STYLES = {
position: "fixed",
Expand Down Expand Up @@ -38,7 +37,7 @@ function MissingParticipantRespond({ timeout, gracePeriod }) {
const game = useGame();
const stageTimer = useStageTimer();
const stageElapsed = (stageTimer?.elapsed || 0) / 1000;
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");

if (!player || !game) return null; // wait for hooks to load

Expand Down Expand Up @@ -125,7 +124,7 @@ function ReportParticipantMissing({ timeout, gracePeriod }) {
const game = useGame();
const stageTimer = useStageTimer();
const stageElapsed = (stageTimer?.elapsed || 0) / 1000;
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");

const [modalOpen, setModalOpen] = useState(false);
const [waitingToastOpen, setWaitingToastOpen] = useState(false);
Expand Down
9 changes: 4 additions & 5 deletions client/src/components/TextChat.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useEffect, useRef, useState } from "react";
import { usePlayer, useStageTimer } from "@empirica/core/player/classic/react";
import { Loading } from "@empirica/core/player/react";
import { useProgressLabel } from "./hooks";

function relTime(date) {
const difference = (new Date().getTime() - date.getTime()) / 1000;
Expand All @@ -22,10 +21,10 @@ export function TextChat({
showTitle,
}) {
const player = usePlayer();
const progressLabel = useProgressLabel();
const timer = useStageTimer();
if (!timer) return null;
const elapsed = (timer?.elapsed || 0) / 1000;
const progressLabel = player.get("progressLabel");
const stageTimer = useStageTimer();
if (!stageTimer) return null;
const elapsed = (stageTimer?.elapsed || 0) / 1000;

if (!scope || !player) {
return <Loading />;
Expand Down
3 changes: 1 addition & 2 deletions client/src/components/VideoCall.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ import {
} from "@empirica/core/player/classic/react";
import DailyIframe from "@daily-co/daily-js";
import React, { useState, useRef, useEffect, useReducer } from "react";
import { useProgressLabel } from "./hooks";

export function VideoCall({ showNickname, showTitle }) {
// empirica objects
const stageTimer = useStageTimer();
const player = usePlayer();
const stage = useStage();
const game = useGame();
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");

// refs
const dailyElement = useRef(null);
Expand Down
28 changes: 0 additions & 28 deletions client/src/components/hooks.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,13 @@
/* eslint-disable default-case */
import {
usePlayer,
useStage,
useGame,
usePlayers,
} from "@empirica/core/player/classic/react";
import { useGlobal } from "@empirica/core/player/react";
import axios from "axios";
import { useState, useEffect } from "react";

export function useProgressLabel() {
const player = usePlayer();
const game = useGame();
const stage = useStage();

if (!player) {
return "unknown";
}

if (!player.get("introDone")) {
const introStep = player.get("intro");
return `intro_${introStep}`;
}

if (!game || !stage) {
return "unknown_postIntro";
}

if (!game.get("ended")) {
const stageIndex = stage.get("index");
return `stage_${stageIndex}`;
}

const exitStep = player.get("exitStep");
return `exit_${exitStep}`;
}

const cdnList = {
// test: "deliberation-assets",
test: "http://localhost:9091",
Expand Down
4 changes: 2 additions & 2 deletions client/src/elements/Prompt.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { Markdown } from "../components/Markdown";
import { RadioGroup } from "../components/RadioGroup";
import { CheckboxGroup } from "../components/CheckboxGroup";
import { TextArea } from "../components/TextArea";
import { useProgressLabel, useText, usePermalink } from "../components/hooks";
import { useText, usePermalink } from "../components/hooks";
import { SharedNotepad } from "../components/SharedNotepad";
import { ListSorter } from "../components/ListSorter";

export function Prompt({ file, name, shared }) {
const player = usePlayer();
const game = useGame();
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");
const promptString = useText({ file });
const permalink = usePermalink(file);
const [responses, setResponses] = React.useState([]);
Expand Down
3 changes: 1 addition & 2 deletions client/src/elements/Qualtrics.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@

import React, { useEffect, useReducer } from "react";
import { usePlayer } from "@empirica/core/player/classic/react";
import { useProgressLabel } from "../components/hooks";

export function Qualtrics({ url, params, onSubmit }) {
const player = usePlayer();
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");

const reducer = (state, action) => {
if (!action.type) return state;
Expand Down
3 changes: 1 addition & 2 deletions client/src/elements/SubmitButton.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import { usePlayer, useStageTimer } from "@empirica/core/player/classic/react";
import { Button } from "../components/Button";
import { useProgressLabel } from "../components/hooks";

// buttonText changes based on what the treatment yaml file specifies
// if no buttonText is specified, the default is "Next"
Expand All @@ -11,7 +10,7 @@ import { useProgressLabel } from "../components/hooks";
export function SubmitButton({ onSubmit, name, buttonText = "Next" }) {
const player = usePlayer();
const stageTimer = useStageTimer();
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");
const [loadedTime, setLoadedTime] = useState(-1);
const buttonName = name || progressLabel;

Expand Down
5 changes: 2 additions & 3 deletions client/src/elements/Survey.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
import { usePlayer } from "@empirica/core/player/classic/react";
import React, { useEffect } from "react";
import * as surveys from "@watts-lab/surveys";
import { useProgressLabel } from "../components/hooks";

export function Survey({ surveyName, name, onSubmit }) {
const player = usePlayer();
const progressLabel = useProgressLabel();
const progressLabel = player.get("progressLabel");
const gameID = player.get("gameID") || "noGameId";
const LoadedSurvey = surveys[surveyName];
const saveName = name || `${surveyName}_${progressLabel}`;

useEffect(() => {
console.log(`${progressLabel}: Survey ${surveyName}`);
}, []);
}, [progressLabel, surveyName]);

function onComplete(record) {
const newRecord = record;
Expand Down
22 changes: 12 additions & 10 deletions client/src/intro-exit/GenericIntroExitStep.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,31 @@
Takes the role of "stage" in intro and exit steps, as a place where elements are combined
into a page, and submit responses are defined.
*/
import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo } from "react";
import { usePlayer } from "@empirica/core/player/classic/react";
import { Element } from "../elements/Element";
import {
ConditionsConditionalRender,
PositionConditionalRender,
} from "../components/ConditionalRender";

export function GenericIntroExitStep({ name, elements, index, next }) {
export function GenericIntroExitStep({ name, elements, index, next, phase }) {
const player = usePlayer();
const [loadedTime, setLoadedTime] = useState(-1);
const progressLabel = useMemo(
() => `${phase}_${index}_${name.trim().replace(/ /g, "_")}`,
[phase, index, name]
); // memoize so we don't trigger the useEffect on every render

useEffect(() => {
setLoadedTime(Date.now());
if (player.get("introDone")) {
console.log(`Exit sequence step ${index}: ${name}`);
} else {
console.log(`Intro sequence step ${index}: ${name}`);
if (player.get("progressLabel") !== progressLabel) {
console.log(`Starting ${progressLabel}`);
player.set("progressLabel", progressLabel);
player.set("localStageStartTime", Date.now());
}
}, [name, index, player]); // both name and index should be constant for a given step
}, [progressLabel, player]);

const onSubmit = () => {
const elapsed = (Date.now() - loadedTime) / 1000;
const elapsed = (Date.now() - player.get("localStageStartTime")) / 1000;
player.set(`duration_${name}`, { time: elapsed });
next();
};
Expand Down
Loading

0 comments on commit d4126fe

Please sign in to comment.