From 492d266e55adb5ba46b882a3ff20838c4d3d87d6 Mon Sep 17 00:00:00 2001 From: Henry Burgess Date: Fri, 26 Sep 2025 14:49:51 -0500 Subject: [PATCH 1/5] INT-77 Rename `trial` to `trial_number` --- src/classes/factories/ScreenPropFactory.ts | 36 +++++++++++----------- src/index.tsx | 6 ++-- src/plugin.ts | 2 +- types/index.d.ts | 4 +-- types/jsPsych.d.ts | 2 +- types/props.d.ts | 2 +- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/classes/factories/ScreenPropFactory.ts b/src/classes/factories/ScreenPropFactory.ts index 3a7daa8..eba0d34 100644 --- a/src/classes/factories/ScreenPropFactory.ts +++ b/src/classes/factories/ScreenPropFactory.ts @@ -82,7 +82,7 @@ class ScreenPropFactory implements Factory { case "playerChoice2": { // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, isPractice: this.trial.isPractice, spotlight: this.trial.spotlight, @@ -112,7 +112,7 @@ class ScreenPropFactory implements Factory { // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, state: this.trial.state, handler: this.handler.callback.bind(this.handler), @@ -125,7 +125,7 @@ class ScreenPropFactory implements Factory { // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, state: this.trial.state, }; @@ -135,7 +135,7 @@ class ScreenPropFactory implements Factory { case "statusPreview": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, isPartnerHighStatus: this.trial.isPartnerHighStatus, handler: this.handler.callback.bind(this.handler), @@ -159,7 +159,7 @@ class ScreenPropFactory implements Factory { // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, state: this.trial.state || "default", // Default to "default" type if not specified runComputeSetup: this.trial.runComputeSetup, @@ -172,7 +172,7 @@ class ScreenPropFactory implements Factory { case "selection": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.selection.bind(this.handler), }; @@ -182,7 +182,7 @@ class ScreenPropFactory implements Factory { case "inference": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.inference.bind(this.handler), }; @@ -192,7 +192,7 @@ class ScreenPropFactory implements Factory { case "agency": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.agency.bind(this.handler), }; @@ -202,7 +202,7 @@ class ScreenPropFactory implements Factory { case "classification": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.classification.bind(this.handler), }; @@ -212,7 +212,7 @@ class ScreenPropFactory implements Factory { case "status": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.status.bind(this.handler), }; @@ -222,7 +222,7 @@ class ScreenPropFactory implements Factory { case "dass": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, version: Configuration.manipulations.useAdultQuestionnaires ? "adult" : "adolescent", handler: this.handler.dass.bind(this.handler), @@ -233,7 +233,7 @@ class ScreenPropFactory implements Factory { case "screentime": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, handler: this.handler.screentime.bind(this.handler), }; @@ -243,7 +243,7 @@ class ScreenPropFactory implements Factory { case "demographics": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, version: Configuration.manipulations.useAdultQuestionnaires ? "adult" : "adolescent", handler: this.handler.demographics.bind(this.handler), @@ -254,7 +254,7 @@ class ScreenPropFactory implements Factory { case "summary": // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, postPhase: postPhase, handler: this.handler.callback.bind(this.handler), @@ -271,7 +271,7 @@ class ScreenPropFactory implements Factory { // Setup the props returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, }; break; @@ -279,7 +279,7 @@ class ScreenPropFactory implements Factory { // Waiting screen case "waiting": returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, mode: this.trial.mode, handler: this.handler.callback.bind(this.handler), @@ -289,7 +289,7 @@ class ScreenPropFactory implements Factory { // Cyberball screen case "cyberball": returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, isInclusive: this.trial.isInclusive, partnerHighStatus: this.trial.partnerHighStatus, @@ -301,7 +301,7 @@ class ScreenPropFactory implements Factory { // Resources screen case "resources": returned.props = { - trial: this.trial.trial, + trial_number: this.trial.trial_number, display: this.trial.display, callback: this.handler.callback.bind(this.handler), }; diff --git a/src/index.tsx b/src/index.tsx index e8301a5..1fee8e5 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -943,7 +943,7 @@ for (let i = 0; i < dataCollection.length; i++) { const stageOneTrials = shuffle(randomisedTrials.phaseOne); let stageOneCounter = 1; for (const trial of stageOneTrials) { - trial.trial = stageOneCounter; + trial.trial_number = stageOneCounter; stageOneCounter++; } @@ -1286,7 +1286,7 @@ for (let i = 0; i < dataCollection.length; i++) { const stageTwoTrials = shuffle(randomisedTrials.phaseTwo); let stageTwoCounter = 1; for (const trial of stageTwoTrials) { - trial["trial"] = stageTwoCounter; + trial.trial_number = stageTwoCounter; stageTwoCounter++; } @@ -1541,7 +1541,7 @@ for (let i = 0; i < dataCollection.length; i++) { const stageThreeTrials = shuffle(randomisedTrials.phaseThree); let stageThreeCounter = 1; for (const trial of stageThreeTrials) { - trial["trial"] = stageThreeCounter; + trial.trial_number = stageThreeCounter; stageThreeCounter++; } diff --git a/src/plugin.ts b/src/plugin.ts index 1ddce60..9b41eac 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -123,7 +123,7 @@ jsPsych.plugins[Configuration.studyName] = (() => { // Setup the trial data to be stored const dataframe: TrialData = { // Trial identification - trial: trial.trial, + trial_number: trial.trial_number, display: trial.display, participantID: experiment.getState().get("participantID"), diff --git a/types/index.d.ts b/types/index.d.ts index 9f1284c..74e623e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -82,7 +82,7 @@ declare type Options = "Option 1" | "Option 2"; // Trial type to enforce parameters declare type Trial = { // Basic trial identification - trial: number; // Trial number/identifier + trial_number: number; // Trial number/identifier display: Display; // Screen type to display (e.g., "playerChoice", "loading", etc.) // Game option parameters (used by Trial screen) @@ -135,7 +135,7 @@ declare type Trial = { // Data type used to enforce trial data storage format declare type TrialData = { // Trial identification - trial: number; + trial_number: number; display: Display; participantID: string; diff --git a/types/jsPsych.d.ts b/types/jsPsych.d.ts index 5d5b5f3..5f01b8d 100644 --- a/types/jsPsych.d.ts +++ b/types/jsPsych.d.ts @@ -27,7 +27,7 @@ declare type TimelineNode = { show_clickable_nav?: boolean; // Trial plugin - trial?: number; + trial_number?: number; display?: Display | string; optionOneParticipant?: number; optionOnePartner?: number; diff --git a/types/props.d.ts b/types/props.d.ts index d8dfe1f..7fa7ad8 100644 --- a/types/props.d.ts +++ b/types/props.d.ts @@ -76,7 +76,7 @@ declare namespace Props { // Props for 'Screens' declare namespace Screens { type GenericScreenProps = { - trial: number; + trial_number: number; display: Display; }; From d06a644a18fc3c647beea666058505107ef8ccd0 Mon Sep 17 00:00:00 2001 From: Henry Burgess Date: Fri, 26 Sep 2025 15:07:15 -0500 Subject: [PATCH 2/5] INT-77 Update tests to use new variable name --- test/utils/functions.ts | 4 ++-- test/view/components/Wrapper.test.tsx | 2 +- test/view/screens/Agency.test.tsx | 2 +- test/view/screens/Classification.test.tsx | 2 +- test/view/screens/Cyberball.test.tsx | 2 +- test/view/screens/DASS.test.tsx | 4 ++-- test/view/screens/Inference.test.tsx | 2 +- test/view/screens/Loaded.test.tsx | 2 +- test/view/screens/Loading.test.tsx | 8 ++++---- test/view/screens/Screentime.test.tsx | 2 +- test/view/screens/SelectAvatar.test.tsx | 2 +- test/view/screens/Status.test.tsx | 4 ++-- test/view/screens/Summary.test.tsx | 2 +- test/view/screens/Trial.test.tsx | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/test/utils/functions.ts b/test/utils/functions.ts index 54927a6..6004562 100644 --- a/test/utils/functions.ts +++ b/test/utils/functions.ts @@ -21,7 +21,7 @@ import Handler from "src/classes/Handler"; */ export const getTrialConfiguration = (display: Display): Trial => { return { - trial: 1, + trial_number: 1, display: display, optionOneParticipant: 0, optionOnePartner: 0, @@ -46,7 +46,7 @@ export const getTrialConfiguration = (display: Display): Trial => { export const getHandler = (display: Display): Handler => { return new Handler( { - trial: 1, + trial_number: 1, display: display, participantID: "default", playerPoints_option1: NaN, diff --git a/test/view/components/Wrapper.test.tsx b/test/view/components/Wrapper.test.tsx index c85e8c2..a1db605 100644 --- a/test/view/components/Wrapper.test.tsx +++ b/test/view/components/Wrapper.test.tsx @@ -22,7 +22,7 @@ test("loads and displays Wrapper component with Agency screen", async () => { { return; diff --git a/test/view/screens/Agency.test.tsx b/test/view/screens/Agency.test.tsx index 7425f89..bbef342 100644 --- a/test/view/screens/Agency.test.tsx +++ b/test/view/screens/Agency.test.tsx @@ -17,7 +17,7 @@ import Wrapper from "src/view/components/Wrapper"; test("loads and displays Agency screen", async () => { const props: Props.Screens.Agency = { - trial: 0, + trial_number: 0, display: "agency", handler: () => { console.info("Selection handler called"); diff --git a/test/view/screens/Classification.test.tsx b/test/view/screens/Classification.test.tsx index bb5fbe4..c2c8d3a 100644 --- a/test/view/screens/Classification.test.tsx +++ b/test/view/screens/Classification.test.tsx @@ -17,7 +17,7 @@ import Wrapper from "src/view/components/Wrapper"; test("loads and displays Classification screen", async () => { const props: Props.Screens.Classification = { - trial: 0, + trial_number: 0, display: "classification", handler: () => { console.info("Selection handler called"); diff --git a/test/view/screens/Cyberball.test.tsx b/test/view/screens/Cyberball.test.tsx index 07d1bfd..43edf24 100644 --- a/test/view/screens/Cyberball.test.tsx +++ b/test/view/screens/Cyberball.test.tsx @@ -65,7 +65,7 @@ jest.mock("src/configuration", () => ({ describe("Cyberball Screen", () => { const mockHandler = jest.fn(); const mockProps = { - trial: 1, + trial_number: 1, display: "cyberball" as const, isInclusive: true, partnerHighStatus: true, diff --git a/test/view/screens/DASS.test.tsx b/test/view/screens/DASS.test.tsx index c5521cc..bf2bed1 100644 --- a/test/view/screens/DASS.test.tsx +++ b/test/view/screens/DASS.test.tsx @@ -27,7 +27,7 @@ describe("DASS Component", () => { describe("Adult Version", () => { const adultProps = { - trial: 1, + trial_number: 1, display: "dass" as const, version: "adult" as const, handler: mockHandler, @@ -85,7 +85,7 @@ describe("DASS Component", () => { describe("Adolescent Version", () => { const adolescentProps = { - trial: 1, + trial_number: 1, display: "dass" as const, version: "adolescent" as const, handler: mockHandler, diff --git a/test/view/screens/Inference.test.tsx b/test/view/screens/Inference.test.tsx index f752ce6..6af151f 100644 --- a/test/view/screens/Inference.test.tsx +++ b/test/view/screens/Inference.test.tsx @@ -17,7 +17,7 @@ import Wrapper from "src/view/components/Wrapper"; test("loads and displays Inference screen", async () => { const props: Props.Screens.Inference = { - trial: 0, + trial_number: 0, display: "inference", handler: () => { console.info("Selection handler called"); diff --git a/test/view/screens/Loaded.test.tsx b/test/view/screens/Loaded.test.tsx index 85a84f3..fb07610 100644 --- a/test/view/screens/Loaded.test.tsx +++ b/test/view/screens/Loaded.test.tsx @@ -34,7 +34,7 @@ beforeEach(() => { test("loads and displays Loaded screen", async () => { const props: Props.Screens.Loaded = { - trial: 0, + trial_number: 0, display: "loaded", state: "matchingIntentions", handler: () => { return; }, diff --git a/test/view/screens/Loading.test.tsx b/test/view/screens/Loading.test.tsx index c67fed6..f638997 100644 --- a/test/view/screens/Loading.test.tsx +++ b/test/view/screens/Loading.test.tsx @@ -38,7 +38,7 @@ beforeEach(() => { test("loads and displays Loading screen with matching type", async () => { const props: Props.Screens.Loading = { - trial: 0, + trial_number: 0, display: "loading", state: "matchingIntentions", runComputeOperation: false, @@ -55,7 +55,7 @@ test("loads and displays Loading screen with matching type", async () => { test("loads and displays Loading screen with social type", async () => { const props: Props.Screens.Loading = { - trial: 0, + trial_number: 0, display: "loading", state: "social", }; @@ -70,7 +70,7 @@ test("loads and displays Loading screen with social type", async () => { test("loads and displays Loading screen with default type", async () => { const props: Props.Screens.Loading = { - trial: 0, + trial_number: 0, display: "loading", state: "default", }; @@ -83,7 +83,7 @@ test("loads and displays Loading screen with default type", async () => { test("loads and displays Loading screen with default type when no type specified", async () => { const props: Props.Screens.Loading = { - trial: 0, + trial_number: 0, display: "loading", state: "default", }; diff --git a/test/view/screens/Screentime.test.tsx b/test/view/screens/Screentime.test.tsx index 525075d..431b68d 100644 --- a/test/view/screens/Screentime.test.tsx +++ b/test/view/screens/Screentime.test.tsx @@ -16,7 +16,7 @@ import TestWrapper from "test/utils/TestWrapper"; // Mock props const mockProps = { - trial: 1, + trial_number: 1, display: "screentime" as const, handler: jest.fn(), }; diff --git a/test/view/screens/SelectAvatar.test.tsx b/test/view/screens/SelectAvatar.test.tsx index cdbd667..998bfa4 100644 --- a/test/view/screens/SelectAvatar.test.tsx +++ b/test/view/screens/SelectAvatar.test.tsx @@ -33,7 +33,7 @@ beforeEach(() => { test("loads and displays SelectAvatar screen", async () => { const props: Props.Screens.SelectAvatar = { - trial: 0, + trial_number: 0, display: "selection", handler: () => { console.info("Selection handler called"); diff --git a/test/view/screens/Status.test.tsx b/test/view/screens/Status.test.tsx index 452a868..be23dc8 100644 --- a/test/view/screens/Status.test.tsx +++ b/test/view/screens/Status.test.tsx @@ -17,7 +17,7 @@ import Wrapper from "src/view/components/Wrapper"; test("loads and displays Status screen page 1", async () => { const props: Props.Screens.Status = { - trial: 0, + trial_number: 0, display: "status", handler: () => { console.info("Status handler called"); @@ -55,7 +55,7 @@ test("loads and displays Status screen page 1", async () => { test("loads and displays Status screen page 2", async () => { const props: Props.Screens.Status = { - trial: 0, + trial_number: 0, display: "status", handler: () => { console.info("Status handler called"); diff --git a/test/view/screens/Summary.test.tsx b/test/view/screens/Summary.test.tsx index f21a35a..2111413 100644 --- a/test/view/screens/Summary.test.tsx +++ b/test/view/screens/Summary.test.tsx @@ -38,7 +38,7 @@ beforeEach(() => { test("loads and displays Summary screen", async () => { const props: Props.Screens.Summary = { - trial: 0, + trial_number: 0, display: "summary", postPhase: "playerChoice", handler: () => { diff --git a/test/view/screens/Trial.test.tsx b/test/view/screens/Trial.test.tsx index f7a607f..3b8a990 100644 --- a/test/view/screens/Trial.test.tsx +++ b/test/view/screens/Trial.test.tsx @@ -72,7 +72,7 @@ beforeEach(() => { test("loads and displays Trial screen", async () => { const props: Props.Screens.Trial = { - trial: 0, + trial_number: 0, display: "playerChoice", isPractice: false, participantPoints: 5, @@ -106,7 +106,7 @@ const createTrialProps = ( display: Display, isPractice = false ): Props.Screens.Trial => ({ - trial: 0, + trial_number: 0, display, isPractice, participantPoints: 5, From 76fc77d89be617c40ece76333be27416e7d0f960 Mon Sep 17 00:00:00 2001 From: Henry Burgess Date: Fri, 26 Sep 2025 16:04:11 -0500 Subject: [PATCH 3/5] INT-77 Refactor some types --- src/classes/Handler.ts | 6 +- src/classes/factories/ScreenPropFactory.ts | 6 +- src/plugin.ts | 6 +- test/utils/functions.ts | 2 +- types/data.d.ts | 77 ++++++++++++ types/index.d.ts | 131 --------------------- types/jsPsych.d.ts | 120 ++++++++++++------- 7 files changed, 164 insertions(+), 184 deletions(-) create mode 100644 types/data.d.ts diff --git a/src/classes/Handler.ts b/src/classes/Handler.ts index 650154d..7f53a8c 100644 --- a/src/classes/Handler.ts +++ b/src/classes/Handler.ts @@ -23,7 +23,7 @@ import consola from "consola"; * used by the screens of the game */ class Handler { - private dataframe: TrialData; + private dataframe: Dataframe; public callback: () => void; /** @@ -32,7 +32,7 @@ class Handler { * @param {function} callback default callback after the handlers * @constructor */ - constructor(dataframe: TrialData, callback: () => void) { + constructor(dataframe: Dataframe, callback: () => void) { this.dataframe = dataframe; this.callback = callback; } @@ -41,7 +41,7 @@ class Handler { * Get the dataframe being modified * @return {Data} */ - public getDataframe(): TrialData { + public getDataframe(): Dataframe { return this.dataframe; } diff --git a/src/classes/factories/ScreenPropFactory.ts b/src/classes/factories/ScreenPropFactory.ts index eba0d34..0e46458 100644 --- a/src/classes/factories/ScreenPropFactory.ts +++ b/src/classes/factories/ScreenPropFactory.ts @@ -28,18 +28,18 @@ import Handler from "src/classes/Handler"; */ class ScreenPropFactory implements Factory { // jsPsych trial data - private trial: Trial; + private trial: IntentionsNode; // Callback function from 'Handler' class private handler: Handler; /** * Default constructor - * @param {Trial} trial jsPsych trial data + * @param {IntentionsNode} trial jsPsych trial data * @param {Handler} handler callback function from 'Handler' class * @constructor */ - constructor(trial: Trial, handler: Handler) { + constructor(trial: IntentionsNode, handler: Handler) { this.trial = trial; this.handler = handler; } diff --git a/src/plugin.ts b/src/plugin.ts index 9b41eac..40c28ca 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -34,7 +34,7 @@ import { saveToLocalStorage, setCompleted } from "./util"; jsPsych.plugins[Configuration.studyName] = (() => { const plugin = { info: {}, - trial: (_displayElement: HTMLElement, _trial: Trial) => { + trial: (_displayElement: HTMLElement, _trial: IntentionsNode) => { // Should raise an error consola.error(`Not implemented.`); }, @@ -116,12 +116,12 @@ jsPsych.plugins[Configuration.studyName] = (() => { }, }; - plugin.trial = (displayElement: HTMLElement, trial: Trial) => { + plugin.trial = (displayElement: HTMLElement, trial: IntentionsNode) => { // Get the global 'Experiment' instance const experiment = window.Experiment; // Setup the trial data to be stored - const dataframe: TrialData = { + const dataframe: Dataframe = { // Trial identification trial_number: trial.trial_number, display: trial.display, diff --git a/test/utils/functions.ts b/test/utils/functions.ts index 6004562..65195fc 100644 --- a/test/utils/functions.ts +++ b/test/utils/functions.ts @@ -19,7 +19,7 @@ import Handler from "src/classes/Handler"; * @param {Display} display the display type being tested * @return {any} */ -export const getTrialConfiguration = (display: Display): Trial => { +export const getTrialConfiguration = (display: Display): IntentionsNode => { return { trial_number: 1, display: display, diff --git a/types/data.d.ts b/types/data.d.ts new file mode 100644 index 0000000..168a9c3 --- /dev/null +++ b/types/data.d.ts @@ -0,0 +1,77 @@ +// Declare CSV module type +declare module "*.csv"; + +// CSV data row types +declare type Row = { + randomise_blocks: string; + randomise_trials: number; + display: Display; + ANSWER: Options; + Option1_PPT: number; + Option1_Partner: number; + Option2_PPT: number; + Option2_Partner: number; + ShowProgressBar: number; + Type1: Partner; + Type2: Partner; + Difference1: number; + Difference2: number; +}; + +// Data type used to enforce trial data storage format +declare type Dataframe = { + // Trial identification + trial_number: number; + display: Display; + participantID: string; + + // Points + playerPoints_option1: number; + partnerPoints_option1: number; + playerPoints_option2: number; + partnerPoints_option2: number; + playerPoints_selected: number; + partnerPoints_selected: number; + + // Trial state + selectedOption_player: NaN | 1 | 2; // uses 1 and 2 rather than strings + realAnswer: Options; + trialDuration: number; + correctGuess: NaN | 0 | 1; // 0 incorrect; 1 correct + + // Model parameters + server_alpha_ppt: number; + server_beta_ppt: number; + server_alpha_par: number; + server_beta_par: number; + setupDuration: number; + operationDuration: number; + + // Signal timestamps + signalTimestamps: number[]; + + // Cyberball data + cyberballTossCount: number; + cyberballParticipantTossCount: number; + cyberballParticipantCatchCount: number; + + // Questionnaire responses + questionnaireResponseInferenceSelfish: number; + questionnaireResponseInferenceHarm: number; + questionnaireResponseAgency: number; + questionnaireResponseClassification: string; + questionnaireResponseCloseFriends: number; + questionnaireResponsePartyInvitations: number; + questionnaireResponseMeanPeople: number; + questionnaireResponseSocialMediaFollowers: number; + questionnaireResponseSocialMediaFollowing: number; + questionnaireResponsesDASS: number[]; + questionnaireResponsesScreentime: number[]; + questionnaireResponsesDemographicsAge: number; + questionnaireResponsesDemographicsGender: string; + questionnaireResponsesDemographicsEthnicity: string; + questionnaireResponsesDemographicsHouseholdIncome: string; + questionnaireResponsesDemographicsEducation: string; + questionnaireResponsesDemographicsSocialMediaDaily: boolean; + questionnaireResponsesDemographicsSocialMediaPlatforms: string; +}; diff --git a/types/index.d.ts b/types/index.d.ts index 74e623e..b083a0a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -7,26 +7,6 @@ // Module declaration declare module "intentions-game" {} -// Declare CSV module type -declare module "*.csv"; - -// CSV data row types -declare type Row = { - randomise_blocks: string; - randomise_trials: number; - display: Display; - ANSWER: Options; - Option1_PPT: number; - Option1_Partner: number; - Option2_PPT: number; - Option2_Partner: number; - ShowProgressBar: number; - Type1: Partner; - Type2: Partner; - Difference1: number; - Difference2: number; -}; - // 'Factory' interface interface Factory { generate(...args); @@ -79,117 +59,6 @@ declare type AvatarStyles = // Selection options declare type Options = "Option 1" | "Option 2"; -// Trial type to enforce parameters -declare type Trial = { - // Basic trial identification - trial_number: number; // Trial number/identifier - display: Display; // Screen type to display (e.g., "playerChoice", "loading", etc.) - - // Game option parameters (used by Trial screen) - optionOneParticipant: number; // Points for participant in Option 1 - optionOnePartner: number; // Points for partner in Option 1 - optionTwoParticipant: number; // Points for participant in Option 2 - optionTwoPartner: number; // Points for partner in Option 2 - - // Partner type information - typeOne: string; // Partner type for Option 1 - typeTwo: string; // Partner type for Option 2 - - // Avatar selection (used by SelectAvatar screen) - avatar: 0; // Avatar index (currently hardcoded to 0) - - // Game logic - answer: Options; // Correct answer for the trial ("Option 1" or "Option 2") - isPractice: boolean; // Whether this is a practice trial - - // Loading screen configuration (used by Loading screen) - state?: "matchingIntentions" | "matchingCyberball" | "social" | "default"; // Type of loading: "matchingIntentions" (partner matching), "matchingCyberball" (cyberball partners), "social" (status generation), or "default" (generic loading) - runComputeSetup?: boolean; // Whether to run WebR setup - runComputeOperation?: boolean; // Whether to fetch data from server (only used when state is "matchingIntentions") - - // Status preview screen configuration (used by StatusPreview screen) - isPartnerHighStatus?: boolean; // Used for the `StatusPreview` screen - - // Waiting screen configuration (used by Waiting screen) - mode: "facilitator" | "mri"; - - // Spotlight configuration (used by Trial screen) - spotlight?: { - enabled: boolean; - target: "status" | "options" | "none"; - message: string; - }; - - // Cyberball screen - isInclusive?: boolean; - partnerHighStatus?: boolean; - probabilities?: { - inclusion: number; - exclusion: { - partnerA: number; - partnerB: number; - }; - }; -}; - -// Data type used to enforce trial data storage format -declare type TrialData = { - // Trial identification - trial_number: number; - display: Display; - participantID: string; - - // Points - playerPoints_option1: number; - partnerPoints_option1: number; - playerPoints_option2: number; - partnerPoints_option2: number; - playerPoints_selected: number; - partnerPoints_selected: number; - - // Trial state - selectedOption_player: NaN | 1 | 2; // uses 1 and 2 rather than strings - realAnswer: Options; - trialDuration: number; - correctGuess: NaN | 0 | 1; // 0 incorrect; 1 correct - - // Model parameters - server_alpha_ppt: number; - server_beta_ppt: number; - server_alpha_par: number; - server_beta_par: number; - setupDuration: number; - operationDuration: number; - - // Signal timestamps - signalTimestamps: number[]; - - // Cyberball data - cyberballTossCount: number; - cyberballParticipantTossCount: number; - cyberballParticipantCatchCount: number; - - // Questionnaire responses - questionnaireResponseInferenceSelfish: number; - questionnaireResponseInferenceHarm: number; - questionnaireResponseAgency: number; - questionnaireResponseClassification: string; - questionnaireResponseCloseFriends: number; - questionnaireResponsePartyInvitations: number; - questionnaireResponseMeanPeople: number; - questionnaireResponseSocialMediaFollowers: number; - questionnaireResponseSocialMediaFollowing: number; - questionnaireResponsesDASS: number[]; - questionnaireResponsesScreentime: number[]; - questionnaireResponsesDemographicsAge: number; - questionnaireResponsesDemographicsGender: string; - questionnaireResponsesDemographicsEthnicity: string; - questionnaireResponsesDemographicsHouseholdIncome: string; - questionnaireResponsesDemographicsEducation: string; - questionnaireResponsesDemographicsSocialMediaDaily: boolean; - questionnaireResponsesDemographicsSocialMediaPlatforms: string; -}; - // Type to represent the active state of a trial declare type TrialState = { hasSelected: boolean; diff --git a/types/jsPsych.d.ts b/types/jsPsych.d.ts index 5f01b8d..847643c 100644 --- a/types/jsPsych.d.ts +++ b/types/jsPsych.d.ts @@ -6,18 +6,17 @@ // Declare jsPsych declare const jsPsych; -// Timeline collection type -declare type Timeline = TimelineNode[]; - -// Timeline node type, representing different timeline -// element parameter types -declare type TimelineNode = { +declare type GenericNode = { type?: string; +}; +declare type FullscreenNode = { // Fullscreen plugin message?: string; fullscreen_mode?: boolean; +}; +declare type InstructionsNode = { // Instructions plugin pages?: string[] | string[]; allow_keys?: boolean; @@ -25,44 +24,9 @@ declare type TimelineNode = { key_backward?: string; show_page_number?: boolean; show_clickable_nav?: boolean; +}; - // Trial plugin - trial_number?: number; - display?: Display | string; - optionOneParticipant?: number; - optionOnePartner?: number; - optionTwoParticipant?: number; - optionTwoPartner?: number; - typeOne?: string; - typeTwo?: string; - answer?: string; - isPractice?: boolean; - spotlight?: { - enabled: boolean; - target: "status" | "options" | "none"; - message: string; - }; - - // Loading and loaded screens - runComputeSetup?: boolean; - runComputeOperation?: boolean; - state?: "matchingIntentions" | "matchingCyberball" | "social" | "default"; - isPartnerHighStatus?: boolean; - - // Waiting screen - mode?: "facilitator" | "mri"; - - // Cyberball screen - probabilities?: { - inclusion: number; - exclusion: { - partnerA: number; - partnerB: number; - }; - }; - isInclusive?: boolean; - partnerHighStatus?: boolean; - +declare type ComprehensionNode = { // Attention-check plugin prompt?: string; style?: "default" | "radio"; @@ -76,12 +40,82 @@ declare type TimelineNode = { previous: string | null; }; confirm_continue?: boolean; +}; +declare type LoopNode = { // Loop nodes timeline?: any[]; conditional_function?: () => boolean; +}; +declare type InputNode = { // HTML input plugin preamble?: string; html?: string; }; + +declare type IntentionsNode = { + // Basic trial identification + trial_number: number; // Trial number/identifier + display: Display; // Screen type to display (e.g., "playerChoice", "loading", etc.) + + // Game option parameters (used by Trial screen) + optionOneParticipant: number; // Points for participant in Option 1 + optionOnePartner: number; // Points for partner in Option 1 + optionTwoParticipant: number; // Points for participant in Option 2 + optionTwoPartner: number; // Points for partner in Option 2 + + // Partner type information + typeOne: string; // Partner type for Option 1 + typeTwo: string; // Partner type for Option 2 + + // Avatar selection (used by SelectAvatar screen) + avatar: 0; // Avatar index (currently hardcoded to 0) + + // Game logic + answer: Options; // Correct answer for the trial ("Option 1" or "Option 2") + isPractice: boolean; // Whether this is a practice trial + + // Loading screen configuration (used by Loading screen) + state?: "matchingIntentions" | "matchingCyberball" | "social" | "default"; // Type of loading: "matchingIntentions" (partner matching), "matchingCyberball" (cyberball partners), "social" (status generation), or "default" (generic loading) + runComputeSetup?: boolean; // Whether to run WebR setup + runComputeOperation?: boolean; // Whether to fetch data from server (only used when state is "matchingIntentions") + + // Status preview screen configuration (used by StatusPreview screen) + isPartnerHighStatus?: boolean; // Used for the `StatusPreview` screen + + // Waiting screen configuration (used by Waiting screen) + mode: "facilitator" | "mri"; + + // Spotlight configuration (used by Trial screen) + spotlight?: { + enabled: boolean; + target: "status" | "options" | "none"; + message: string; + }; + + // Cyberball screen + isInclusive?: boolean; + partnerHighStatus?: boolean; + probabilities?: { + inclusion: number; + exclusion: { + partnerA: number; + partnerB: number; + }; + }; +}; + +// Timeline collection type +declare type Timeline = TimelineNode[]; + +// Timeline node type, representing different timeline +// element parameter types +declare type TimelineNode = GenericNode & ( + | FullscreenNode + | InstructionsNode + | ComprehensionNode + | LoopNode + | InputNode + | IntentionsNode +); From 71e279dc2f02a827298e026c790f2af2ef48f051 Mon Sep 17 00:00:00 2001 From: Henry Burgess Date: Mon, 29 Sep 2025 11:40:09 -0500 Subject: [PATCH 4/5] INT-77 Refactor props and types --- src/classes/factories/ScreenPropFactory.ts | 2 +- src/view/components/Card/index.tsx | 6 +- src/view/components/Character/index.tsx | 6 +- src/view/components/Option/index.tsx | 6 +- src/view/components/Slider/index.tsx | 6 +- src/view/components/Status/index.tsx | 6 +- src/view/components/Wrapper/index.tsx | 113 ++--- src/view/screens/Cyberball/index.tsx | 6 +- src/view/screens/End/index.tsx | 1 - src/view/screens/Loaded/index.tsx | 4 +- src/view/screens/Loading/index.tsx | 6 +- .../screens/Questionnaires/Agency/index.tsx | 6 +- .../Questionnaires/Classification/index.tsx | 6 +- .../screens/Questionnaires/DASS/index.tsx | 6 +- .../Questionnaires/Demographics/index.tsx | 6 +- .../Questionnaires/Inference/index.tsx | 10 +- .../Questionnaires/Screentime/index.tsx | 6 +- .../screens/Questionnaires/Status/index.tsx | 6 +- src/view/screens/Resources/index.tsx | 8 +- src/view/screens/SelectAvatar/index.tsx | 6 +- src/view/screens/StatusPreview/index.tsx | 4 +- src/view/screens/Summary/index.tsx | 6 +- src/view/screens/Trial/index.tsx | 10 +- src/view/screens/Waiting/index.tsx | 4 +- test/view/components/Status.test.tsx | 4 +- test/view/screens/Agency.test.tsx | 2 +- test/view/screens/Classification.test.tsx | 2 +- test/view/screens/Inference.test.tsx | 2 +- test/view/screens/Loaded.test.tsx | 2 +- test/view/screens/Loading.test.tsx | 8 +- test/view/screens/SelectAvatar.test.tsx | 2 +- test/view/screens/Status.test.tsx | 4 +- test/view/screens/Summary.test.tsx | 2 +- test/view/screens/Trial.test.tsx | 4 +- types/index.d.ts | 2 +- types/props.d.ts | 415 +++++++++--------- 36 files changed, 354 insertions(+), 341 deletions(-) diff --git a/src/classes/factories/ScreenPropFactory.ts b/src/classes/factories/ScreenPropFactory.ts index 0e46458..72cca57 100644 --- a/src/classes/factories/ScreenPropFactory.ts +++ b/src/classes/factories/ScreenPropFactory.ts @@ -303,7 +303,7 @@ class ScreenPropFactory implements Factory { returned.props = { trial_number: this.trial.trial_number, display: this.trial.display, - callback: this.handler.callback.bind(this.handler), + handler: this.handler.callback.bind(this.handler), }; break; diff --git a/src/view/components/Card/index.tsx b/src/view/components/Card/index.tsx index 90cef0b..ef715fe 100644 --- a/src/view/components/Card/index.tsx +++ b/src/view/components/Card/index.tsx @@ -27,15 +27,15 @@ import { Money } from "grommet-icons"; /** * @summary Generate a 'Card' component that displays player information including name, avatar and points - * @param {Props.Components.Card} props component props containing: + * @param {Components.Card} props component props containing: * - name: {string} Display name for the player * - avatar: {string} Unique identifier for the avatar * - points: {string} Current points total * - gridArea: {string} Grid area name for positioning * @return {ReactElement} 'Card' component with player info arranged vertically in a Box */ -const Card: FC = ( - props: Props.Components.Card +const Card: FC = ( + props: Components.Card ): ReactElement => { return ( void} props.setState - Function to update selected avatar * @returns {ReactElement} Clickable avatar component with selection state handling */ -const Character: FC = ( - props: Props.Components.Character +const Character: FC = ( + props: Components.Character ): ReactElement => { return ( = ( - props: Props.Components.Option +const Option: FC = ( + props: Components.Option ): ReactElement => { return ( void} Optional callback to update value externally * @return {ReactElement} 'Slider' component with a labeled range input */ -const Slider: FC = ( - props: Props.Components.Slider +const Slider: FC = ( + props: Components.Slider ): ReactElement => { // Value presented by the slide const [value, setValue] = useState(props.max / 2); diff --git a/src/view/components/Status/index.tsx b/src/view/components/Status/index.tsx index ce1959e..3ee4c3e 100644 --- a/src/view/components/Status/index.tsx +++ b/src/view/components/Status/index.tsx @@ -21,13 +21,13 @@ import { Configuration } from "src/configuration"; /** * @summary Generate a 'Status' component that displays social status positions - * @param {Props.Components.Status} props component props containing: + * @param {Components.Status} props component props containing: * - participantStatus: {number} Social status value for participant (0-100) * - partnerStatus: {number} Social status value for partner (0-100) * @return {ReactElement} 'Status' component with horizontal scale and avatar indicators */ -const Status: FC = ( - props: Props.Components.Status +const Status: FC = ( + props: Components.Status ): ReactElement => { const [participantStatus] = useState(props.participantStatus); const [partnerStatus] = useState(props.partnerStatus); diff --git a/src/view/components/Wrapper/index.tsx b/src/view/components/Wrapper/index.tsx index 3547724..1f36c6c 100644 --- a/src/view/components/Wrapper/index.tsx +++ b/src/view/components/Wrapper/index.tsx @@ -45,23 +45,23 @@ import Cyberball from "../../screens/Cyberball"; /** * @summary Generate a 'Wrapper' component that acts as a container for all React screens and components, * providing Grommet theming and styling context - * @param {Props.Components.Wrapper} props Props containing: + * @param {Components.Wrapper} props Props containing: * - display: {string} The current screen to display - * - props: {Props.Screens.Trial | Props.Screens.Inference | Props.Screens.Classification | - * Props.Screens.SelectAvatar | Props.Screens.Loaded | Props.Screens.Matching | - * Props.Screens.End | Props.Screens.Summary} Props for the child screen component + * - props: {Screens.Trial | Screens.Inference | Screens.Classification | + * Screens.SelectAvatar | Screens.Loaded | Screens.Matching | + * Screens.End | Screens.Summary} Props for the child screen component * @return {ReactElement} 'Wrapper' component containing the themed child screen */ -const Wrapper: FC = ( - props: Props.Components.Wrapper +const Wrapper: FC = ( + props: Components.Wrapper ): ReactElement => { - const [activeDisplay, setActiveDisplay] = useState(props.display); + const [display, setDisplay] = useState(props.display); useEffect(() => { - if (activeDisplay !== props.display) { - setActiveDisplay(props.display); + if (display !== props.display) { + setDisplay(props.display); } - }, [props.display, activeDisplay]); + }, [props.display, display]); // Return a styled Grommet instance with the global theme extension return ( @@ -82,82 +82,97 @@ const Wrapper: FC = ( > {/* Trial stages */} - {activeDisplay === "playerChoice" && ( - + {display === "playerChoice" && ( + )} - {activeDisplay === "playerChoicePractice" && ( - + {display === "playerChoicePractice" && ( + )} - {activeDisplay === "playerGuess" && ( - + {display === "playerGuess" && ( + )} - {activeDisplay === "playerGuessPractice" && ( - + {display === "playerGuessPractice" && ( + )} - {activeDisplay === "playerChoice2" && ( - + {display === "playerChoice2" && ( + )} {/* Inference trials */} - {activeDisplay === "inference" && ( - + {display === "inference" && ( + )} {/* Agency questions */} - {activeDisplay === "agency" && ( - + {display === "agency" && ( + )} {/* Status questions */} - {activeDisplay === "status" && ( - + {display === "status" && ( + )} - {activeDisplay === "dass" && ( - + {/* DASS questionnaire */} + {display === "dass" && ( + )} - {activeDisplay === "screentime" && ( - + {/* Screentime questionnaire */} + {display === "screentime" && ( + )} - {activeDisplay === "demographics" && ( - + {/* Demographics questionnaire */} + {display === "demographics" && ( + )} - {activeDisplay === "classification" && ( - + {/* Classification questionnaire */} + {display === "classification" && ( + )} - {activeDisplay === "selection" && ( - + {/* Avatar selection */} + {display === "selection" && ( + )} - {activeDisplay === "loaded" && } + {/* Loaded screen */} + {display === "loaded" && ( + + )} - {activeDisplay === "statusPreview" && ( - + {/* Status preview screen */} + {display === "statusPreview" && ( + )} - {activeDisplay === "loading" && ( - + {/* Loading screen */} + {display === "loading" && ( + )} - {activeDisplay === "summary" && ( - + {/* Summary screen */} + {display === "summary" && ( + )} - {activeDisplay === "waiting" && ( - + {/* Waiting screen */} + {display === "waiting" && ( + )} - {activeDisplay === "cyberball" && ( - + {/* Cyberball screen */} + {display === "cyberball" && ( + )} - {activeDisplay === "resources" && } + {display === "resources" && ( + + )} - {activeDisplay === "end" && } + {display === "end" && } ); diff --git a/src/view/screens/Cyberball/index.tsx b/src/view/screens/Cyberball/index.tsx index d4b7d63..bcc840f 100644 --- a/src/view/screens/Cyberball/index.tsx +++ b/src/view/screens/Cyberball/index.tsx @@ -25,12 +25,12 @@ import { Configuration } from "src/configuration"; /** * Cyberball screen component that implements the social exclusion paradigm * @component - * @param {Props.Screens.Cyberball} props Component props + * @param {Screens.Cyberball} props Component props * @param {(tossCount: number, participantTossCount: number, participantCatchCount: number) => void} props.handler Callback function when game completes * @returns {ReactElement} Cyberball game screen */ -const Cyberball: FC = ( - props: Props.Screens.Cyberball +const Cyberball: FC = ( + props: Screens.Cyberball ): ReactElement => { // Access the experiment instance const experiment = window.Experiment; diff --git a/src/view/screens/End/index.tsx b/src/view/screens/End/index.tsx index 66c8454..664bc76 100644 --- a/src/view/screens/End/index.tsx +++ b/src/view/screens/End/index.tsx @@ -19,7 +19,6 @@ import { Box, Heading, Layer, Paragraph, WorldMap } from "grommet"; /** * @summary Generate an 'End' screen that displays a completion message to the participant - * @param {FC} props Empty props object as this component takes no props * @return {ReactElement} 'End' screen with completion message and redirect countdown */ const End: FC = (): ReactElement => { diff --git a/src/view/screens/Loaded/index.tsx b/src/view/screens/Loaded/index.tsx index fec5567..53f307a 100644 --- a/src/view/screens/Loaded/index.tsx +++ b/src/view/screens/Loaded/index.tsx @@ -31,10 +31,10 @@ import { generatePartnerID } from "src/util"; /** * @summary Generate a 'Loaded' screen containing a card with the partner avatar for the subsequent phase of the game - * @param {FC} props Empty props object as this component takes no props + * @param {Screens.Loaded} props Component props * @return {ReactElement} 'Loaded' screen with partner avatar and success message */ -const Loaded: FC = (props: Props.Screens.Loaded): ReactElement => { +const Loaded: FC = (props: Screens.Loaded): ReactElement => { // Get the current partner avatar const experiment = window.Experiment; const currentPartner = experiment.getState().get("partnerAvatar"); diff --git a/src/view/screens/Loading/index.tsx b/src/view/screens/Loading/index.tsx index afd5db1..f95a341 100644 --- a/src/view/screens/Loading/index.tsx +++ b/src/view/screens/Loading/index.tsx @@ -27,15 +27,15 @@ const MIN_OPERATION_DURATION = 12000; // 12 seconds /** * @summary Generate a 'Loading' screen presenting a loading indicator and text based on the current state - * @param {Props.Screens.Loading} props Component props containing: + * @param {Screens.Loading} props Component props containing: * - state: {"matchingIntentions" | "matchingCyberball" | "social" | "default"} The loading state to display * - runComputeSetup?: {boolean} Flag indicating whether to setup the compute instance * - runComputeOperation?: {boolean} Flag indicating whether to compute participant and partner parameters * - handler?: {(participantParams: ModelParameters, partnerParams: ModelParameters, setupDuration: number, operationDuration: number) => void} Callback to handle model parameters * @return {ReactElement} 'Loading' screen with loading indicator and state-specific status message */ -const Loading: FC = ( - props: Props.Screens.Loading +const Loading: FC = ( + props: Screens.Loading ): ReactElement => { const experiment = window.Experiment; diff --git a/src/view/screens/Questionnaires/Agency/index.tsx b/src/view/screens/Questionnaires/Agency/index.tsx index 474aa1c..1fa5a3b 100644 --- a/src/view/screens/Questionnaires/Agency/index.tsx +++ b/src/view/screens/Questionnaires/Agency/index.tsx @@ -32,15 +32,15 @@ const SLIDER_DEFAULT = 50; // Sets the 'thumb' to the middle of the slider /** * @summary Generate an 'Agency' screen component containing a slider and question that requires participant response - * @param {Props.Screens.Agency} props Component props containing: + * @param {Screens.Agency} props Component props containing: * - question: {string} The question text to display * - leftLabel: {string} Label for the left side of the slider * - rightLabel: {string} Label for the right side of the slider * - onContinue: {() => void} Callback function when participant continues * @return {ReactElement} 'Agency' screen with interactive slider and question */ -const Agency: FC = ( - props: Props.Screens.Agency +const Agency: FC = ( + props: Screens.Agency ): ReactElement => { // Slider states, monitor if they have been interacted with // Top slider diff --git a/src/view/screens/Questionnaires/Classification/index.tsx b/src/view/screens/Questionnaires/Classification/index.tsx index 945c443..53e2767 100644 --- a/src/view/screens/Questionnaires/Classification/index.tsx +++ b/src/view/screens/Questionnaires/Classification/index.tsx @@ -26,12 +26,12 @@ import { BINDINGS } from "src/bindings"; /** * @summary Generate a 'Classification' screen containing radio buttons for participants to classify their partner's behavior - * @param {Props.Screens.Classification} props Component props containing: + * @param {Screens.Classification} props Component props containing: * - onContinue: {() => void} Callback function when participant continues * @return {ReactElement} 'Classification' screen with radio button options for partner classification */ -const Classification: FC = ( - props: Props.Screens.Classification +const Classification: FC = ( + props: Screens.Classification ): ReactElement => { // Configure relevant states const [classification, setClassification] = useState(""); diff --git a/src/view/screens/Questionnaires/DASS/index.tsx b/src/view/screens/Questionnaires/DASS/index.tsx index faec870..32f460f 100644 --- a/src/view/screens/Questionnaires/DASS/index.tsx +++ b/src/view/screens/Questionnaires/DASS/index.tsx @@ -83,13 +83,13 @@ const SCORING = [ /** * @summary Generate a 'DASS' screen component with two pages for collecting DASS-21 responses - * @param {Props.Screens.DASS} props Component props containing: + * @param {Screens.DASS} props Component props containing: * - version: {"adult" | "adolescent"} Which version of DASS to use * - handler: {(responses: number[]) => void} Callback function when participant continues * @return {ReactElement} 'DASS' screen with two pages */ -const DASS: FC = ( - props: Props.Screens.DASS +const DASS: FC = ( + props: Screens.DASS ): ReactElement => { // Page state const [currentPage, setCurrentPage] = useState(1); diff --git a/src/view/screens/Questionnaires/Demographics/index.tsx b/src/view/screens/Questionnaires/Demographics/index.tsx index fa08a8d..40fb78a 100644 --- a/src/view/screens/Questionnaires/Demographics/index.tsx +++ b/src/view/screens/Questionnaires/Demographics/index.tsx @@ -33,13 +33,13 @@ import { LinkNext } from "grommet-icons"; /** * @summary Generate a 'Demographics' screen component with multiple pages for collecting demographic information - * @param {Props.Screens.Demographics} props Component props containing: + * @param {Screens.Demographics} props Component props containing: * - version: "adult" | "adolescent" - Determines question wording and options * - handler: {(responses: DemographicsResponses) => void} Callback function when participant continues * @return {ReactElement} 'Demographics' screen with multiple pages of questions */ -const Demographics: FC = ( - props: Props.Screens.Demographics +const Demographics: FC = ( + props: Screens.Demographics ): ReactElement => { // Page state const [currentPage, setCurrentPage] = useState(1); diff --git a/src/view/screens/Questionnaires/Inference/index.tsx b/src/view/screens/Questionnaires/Inference/index.tsx index d9a735a..3d0c6e9 100644 --- a/src/view/screens/Questionnaires/Inference/index.tsx +++ b/src/view/screens/Questionnaires/Inference/index.tsx @@ -32,7 +32,7 @@ const SLIDER_DEFAULT = 50; /** * @summary Generate an 'Inference' screen presenting two sliders for participant interaction - * @param {Props.Screens.Inference} props Component props containing: + * @param {Screens.Inference} props Component props containing: * - firstQuestion: {string} Question text for first slider * - secondQuestion: {string} Question text for second slider * - firstLeftLabel: {string} Left label for first slider @@ -42,8 +42,8 @@ const SLIDER_DEFAULT = 50; * - onContinue: {() => void} Callback function when participant continues * @return {ReactElement} 'Inference' screen with two interactive sliders and questions */ -const Inference: FC = ( - props: Props.Screens.Inference +const Inference: FC = ( + props: Screens.Inference ): ReactElement => { // Slider states, monitor if they have been interacted with // Top slider @@ -130,7 +130,7 @@ const Inference: FC = ( {/* First question */} Please use the slider below to indicate the extent to which you - believe your partner's decisions are driven by their desire to earn + believe your partner's decisions are driven by their desire to earn points in this game. = ( {/* Second question */} Please use the slider below to indicate the extent to which you - believe your partner's decisions are driven by their desire to reduce + believe your partner's decisions are driven by their desire to reduce your bonus in this game. void} Callback function when participant continues * @return {ReactElement} 'Screentime' screen with two questions */ -const Screentime: FC = ( - props: Props.Screens.Screentime +const Screentime: FC = ( + props: Screens.Screentime ): ReactElement => { // Response state const [weekdayTime, setWeekdayTime] = useState(-1); diff --git a/src/view/screens/Questionnaires/Status/index.tsx b/src/view/screens/Questionnaires/Status/index.tsx index 837ad26..8249d0b 100644 --- a/src/view/screens/Questionnaires/Status/index.tsx +++ b/src/view/screens/Questionnaires/Status/index.tsx @@ -27,12 +27,12 @@ import { LinkNext } from "grommet-icons"; /** * @summary Generate a 'Status' screen component with two pages for collecting social status information - * @param {Props.Screens.Status} props Component props containing: + * @param {Screens.Status} props Component props containing: * - handler: {(closeFriends: number, partyInvitations: number, meanPeople: number, socialMediaFollowers: number, socialMediaFollowing: number) => void} Callback function when participant continues * @return {ReactElement} 'Status' screen with two pages of questions */ -const Status: FC = ( - props: Props.Screens.Status +const Status: FC = ( + props: Screens.Status ): ReactElement => { // Page state const [currentPage, setCurrentPage] = useState(1); diff --git a/src/view/screens/Resources/index.tsx b/src/view/screens/Resources/index.tsx index a8601a8..c8c0b97 100644 --- a/src/view/screens/Resources/index.tsx +++ b/src/view/screens/Resources/index.tsx @@ -20,10 +20,10 @@ import { LinkNext } from "grommet-icons"; /** * @summary Generate a 'Resources' screen that displays mental health resources - * @param {FC} props Props containing callback function to proceed to next screen + * @param {Screens.Resources} props Props containing callback function to proceed to next screen * @return {ReactElement} Multi-page Resources screen with UK and US mental health information */ -const Resources: FC<{ callback?: () => void }> = ({ callback }): ReactElement => { +const Resources: FC = (props: Screens.Resources): ReactElement => { const [currentPage, setCurrentPage] = useState<'uk' | 'us'>('uk'); const UKResources = () => ( @@ -171,8 +171,8 @@ const Resources: FC<{ callback?: () => void }> = ({ callback }): ReactElement => color="button" label="Continue" onClick={() => { - if (callback) { - callback(); + if (props.handler) { + props.handler(); } }} margin="small" diff --git a/src/view/screens/SelectAvatar/index.tsx b/src/view/screens/SelectAvatar/index.tsx index 58d9199..19d589c 100644 --- a/src/view/screens/SelectAvatar/index.tsx +++ b/src/view/screens/SelectAvatar/index.tsx @@ -29,12 +29,12 @@ import { BINDINGS } from "src/bindings"; /** * @summary Generate a 'SelectAvatar' screen presenting a row of six avatars for participant selection - * @param {Props.Screens.SelectAvatar} props Component props containing: + * @param {Screens.SelectAvatar} props Component props containing: * - onContinue: {() => void} Callback function when participant continues * @return {ReactElement} 'SelectAvatar' screen with avatar selection grid and continue button */ -const SelectAvatar: FC = ( - props: Props.Screens.SelectAvatar +const SelectAvatar: FC = ( + props: Screens.SelectAvatar ): ReactElement => { // Get the global 'Experiment' instance const experiment = window.Experiment; diff --git a/src/view/screens/StatusPreview/index.tsx b/src/view/screens/StatusPreview/index.tsx index 902565c..e775405 100644 --- a/src/view/screens/StatusPreview/index.tsx +++ b/src/view/screens/StatusPreview/index.tsx @@ -28,7 +28,7 @@ import { Configuration } from "src/configuration"; * - handler: {function} Function to handle the continue button click * @return {ReactElement} 'StatusPreview' screen with partner avatar and success message */ -const Loaded: FC = (props: Props.Screens.StatusPreview): ReactElement => { +const StatusPreview: FC = (props: Screens.StatusPreview): ReactElement => { // Get the current partner avatar and social standing const experiment = window.Experiment; const partnerStatus = props.isPartnerHighStatus ? experiment.getState().get("partnerHighStatus") : experiment.getState().get("partnerLowStatus"); @@ -73,4 +73,4 @@ const Loaded: FC = (props: Props.Screens.StatusPrev ); }; -export default Loaded; +export default StatusPreview; diff --git a/src/view/screens/Summary/index.tsx b/src/view/screens/Summary/index.tsx index 16a522c..1d76904 100644 --- a/src/view/screens/Summary/index.tsx +++ b/src/view/screens/Summary/index.tsx @@ -40,13 +40,13 @@ import { BINDINGS } from "src/bindings"; /** * @summary Generate a 'Summary' screen presenting two cards - one showing the participant's avatar and points, * and one showing their partner's avatar and points. Displays total points accumulated across all game phases. - * @param {Props.Screens.Summary} props Component props containing: + * @param {Screens.Summary} props Component props containing: * - postPhase: {string} The phase to calculate points from * - handler: {() => void} Callback function when participant continues * @return {ReactElement} 'Summary' screen with avatar cards, point totals, and continue button */ -const Summary: FC = ( - props: Props.Screens.Summary +const Summary: FC = ( + props: Screens.Summary ): ReactElement => { consola.debug(`Summary screen for '${props.postPhase}'`); diff --git a/src/view/screens/Trial/index.tsx b/src/view/screens/Trial/index.tsx index a669075..80b2827 100644 --- a/src/view/screens/Trial/index.tsx +++ b/src/view/screens/Trial/index.tsx @@ -50,17 +50,17 @@ import { BINDINGS } from "src/bindings"; * Trial screen component that displays two options and avatar cards for point-splitting decisions * or guessing partner's choices. Supports both practice and real trials. * @component - * @param {Props.Screens.Trial} props - Component props + * @param {Screens.Trial} props - Component props * @param {string} props.display - Type of trial display ("playerGuess", "playerChoice", "playerChoice2") * @param {boolean} props.isPractice - Whether this is a practice trial * @param {string} props.answer - The correct answer for guess trials ("Option 1" or "Option 2") - * @param {Props.Components.Options} props.options - Configuration for the two point-splitting options + * @param {Components.Options} props.options - Configuration for the two point-splitting options * @param {number} props.trial - Current trial number (1-based) * @param {(state: TrialState) => void} props.handler - Callback function when trial completes * @returns {ReactElement} Trial screen with options, avatar cards, and points display */ -const Trial: FC = ( - props: Props.Screens.Trial +const Trial: FC = ( + props: Screens.Trial ): ReactElement => { // Get the Experiment instance const experiment = window.Experiment; @@ -156,7 +156,7 @@ const Trial: FC = ( // Update the values stored for the points const partnerChoices = experiment.getState().get("partnerChoices"); // 'PARd' -> partner decisions - const trialData = partnerChoices[props.trial - 1]; + const trialData = partnerChoices[props.trial_number - 1]; // Switch participant and partner points displayPoints.options.one.participant = trialData["par1"]; diff --git a/src/view/screens/Waiting/index.tsx b/src/view/screens/Waiting/index.tsx index 9658eaa..a1ead1c 100644 --- a/src/view/screens/Waiting/index.tsx +++ b/src/view/screens/Waiting/index.tsx @@ -12,8 +12,8 @@ import { Box, Heading, Layer, WorldMap, Paragraph } from "grommet"; import consola from "consola"; import { BINDINGS } from "src/bindings"; -const Waiting: FC = ( - props: Props.Screens.Waiting +const Waiting: FC = ( + props: Screens.Waiting ): ReactElement => { useEffect(() => { const keyListener = (event: KeyboardEvent) => { diff --git a/test/view/components/Status.test.tsx b/test/view/components/Status.test.tsx index 2ab9f7d..4779938 100644 --- a/test/view/components/Status.test.tsx +++ b/test/view/components/Status.test.tsx @@ -57,7 +57,7 @@ Object.defineProperty(window, "Experiment", { describe("Status Component", () => { test("renders with participant and partner status values", () => { - const props: Props.Components.Status = { + const props: Components.Status = { participantStatus: 75, partnerStatus: 25, }; @@ -73,7 +73,7 @@ describe("Status Component", () => { }); test("renders with different status values", () => { - const props: Props.Components.Status = { + const props: Components.Status = { participantStatus: 50, partnerStatus: 50, }; diff --git a/test/view/screens/Agency.test.tsx b/test/view/screens/Agency.test.tsx index bbef342..a9fb1fb 100644 --- a/test/view/screens/Agency.test.tsx +++ b/test/view/screens/Agency.test.tsx @@ -16,7 +16,7 @@ import { render } from "test/utils/functions"; import Wrapper from "src/view/components/Wrapper"; test("loads and displays Agency screen", async () => { - const props: Props.Screens.Agency = { + const props: Screens.Agency = { trial_number: 0, display: "agency", handler: () => { diff --git a/test/view/screens/Classification.test.tsx b/test/view/screens/Classification.test.tsx index c2c8d3a..c7e3588 100644 --- a/test/view/screens/Classification.test.tsx +++ b/test/view/screens/Classification.test.tsx @@ -16,7 +16,7 @@ import { render } from "test/utils/functions"; import Wrapper from "src/view/components/Wrapper"; test("loads and displays Classification screen", async () => { - const props: Props.Screens.Classification = { + const props: Screens.Classification = { trial_number: 0, display: "classification", handler: () => { diff --git a/test/view/screens/Inference.test.tsx b/test/view/screens/Inference.test.tsx index 6af151f..7d241e3 100644 --- a/test/view/screens/Inference.test.tsx +++ b/test/view/screens/Inference.test.tsx @@ -16,7 +16,7 @@ import { render } from "test/utils/functions"; import Wrapper from "src/view/components/Wrapper"; test("loads and displays Inference screen", async () => { - const props: Props.Screens.Inference = { + const props: Screens.Inference = { trial_number: 0, display: "inference", handler: () => { diff --git a/test/view/screens/Loaded.test.tsx b/test/view/screens/Loaded.test.tsx index fb07610..fbf6a1a 100644 --- a/test/view/screens/Loaded.test.tsx +++ b/test/view/screens/Loaded.test.tsx @@ -33,7 +33,7 @@ beforeEach(() => { }); test("loads and displays Loaded screen", async () => { - const props: Props.Screens.Loaded = { + const props: Screens.Loaded = { trial_number: 0, display: "loaded", state: "matchingIntentions", diff --git a/test/view/screens/Loading.test.tsx b/test/view/screens/Loading.test.tsx index f638997..2c1dae4 100644 --- a/test/view/screens/Loading.test.tsx +++ b/test/view/screens/Loading.test.tsx @@ -37,7 +37,7 @@ beforeEach(() => { }); test("loads and displays Loading screen with matching type", async () => { - const props: Props.Screens.Loading = { + const props: Screens.Loading = { trial_number: 0, display: "loading", state: "matchingIntentions", @@ -54,7 +54,7 @@ test("loads and displays Loading screen with matching type", async () => { }); test("loads and displays Loading screen with social type", async () => { - const props: Props.Screens.Loading = { + const props: Screens.Loading = { trial_number: 0, display: "loading", state: "social", @@ -69,7 +69,7 @@ test("loads and displays Loading screen with social type", async () => { }); test("loads and displays Loading screen with default type", async () => { - const props: Props.Screens.Loading = { + const props: Screens.Loading = { trial_number: 0, display: "loading", state: "default", @@ -82,7 +82,7 @@ test("loads and displays Loading screen with default type", async () => { }); test("loads and displays Loading screen with default type when no type specified", async () => { - const props: Props.Screens.Loading = { + const props: Screens.Loading = { trial_number: 0, display: "loading", state: "default", diff --git a/test/view/screens/SelectAvatar.test.tsx b/test/view/screens/SelectAvatar.test.tsx index 998bfa4..ed74ce7 100644 --- a/test/view/screens/SelectAvatar.test.tsx +++ b/test/view/screens/SelectAvatar.test.tsx @@ -32,7 +32,7 @@ beforeEach(() => { }); test("loads and displays SelectAvatar screen", async () => { - const props: Props.Screens.SelectAvatar = { + const props: Screens.SelectAvatar = { trial_number: 0, display: "selection", handler: () => { diff --git a/test/view/screens/Status.test.tsx b/test/view/screens/Status.test.tsx index be23dc8..4ed7504 100644 --- a/test/view/screens/Status.test.tsx +++ b/test/view/screens/Status.test.tsx @@ -16,7 +16,7 @@ import { render } from "test/utils/functions"; import Wrapper from "src/view/components/Wrapper"; test("loads and displays Status screen page 1", async () => { - const props: Props.Screens.Status = { + const props: Screens.Status = { trial_number: 0, display: "status", handler: () => { @@ -54,7 +54,7 @@ test("loads and displays Status screen page 1", async () => { }); test("loads and displays Status screen page 2", async () => { - const props: Props.Screens.Status = { + const props: Screens.Status = { trial_number: 0, display: "status", handler: () => { diff --git a/test/view/screens/Summary.test.tsx b/test/view/screens/Summary.test.tsx index 2111413..ecd1489 100644 --- a/test/view/screens/Summary.test.tsx +++ b/test/view/screens/Summary.test.tsx @@ -37,7 +37,7 @@ beforeEach(() => { }); test("loads and displays Summary screen", async () => { - const props: Props.Screens.Summary = { + const props: Screens.Summary = { trial_number: 0, display: "summary", postPhase: "playerChoice", diff --git a/test/view/screens/Trial.test.tsx b/test/view/screens/Trial.test.tsx index 3b8a990..65c617c 100644 --- a/test/view/screens/Trial.test.tsx +++ b/test/view/screens/Trial.test.tsx @@ -71,7 +71,7 @@ beforeEach(() => { }); test("loads and displays Trial screen", async () => { - const props: Props.Screens.Trial = { + const props: Screens.Trial = { trial_number: 0, display: "playerChoice", isPractice: false, @@ -105,7 +105,7 @@ test("loads and displays Trial screen", async () => { const createTrialProps = ( display: Display, isPractice = false -): Props.Screens.Trial => ({ +): Screens.Trial => ({ trial_number: 0, display, isPractice, diff --git a/types/index.d.ts b/types/index.d.ts index b083a0a..ad9bb8d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -14,7 +14,7 @@ interface Factory { // Type for the 'ScreenPropFactory' return declare type ScreenProps = { - props: Props.Screens; + props: Screens; callback: (...args) => void; duration: number; }; diff --git a/types/props.d.ts b/types/props.d.ts index 7fa7ad8..2ca4c6c 100644 --- a/types/props.d.ts +++ b/types/props.d.ts @@ -3,215 +3,214 @@ * @author Henry Burgess */ -// Declare a 'Components' namespace to define props for each -// of the components used in the experiment. -declare namespace Props { - // Props for 'Components' - declare namespace Components { - // Wrapper component - type Wrapper = { - display: Display; - props: - | Screens.Loaded - | Screens.Loading - | Screens.Trial - | Screens.SelectAvatar - | Screens.Inference - | Screens.Agency - | Screens.Classification - | Screens.Status - | Screens.DASS - | Screens.Screentime - | Screens.Demographics - | Screens.Summary - | Screens.Waiting - | Screens.Cyberball; - }; - - // Option component - type Option = { - optionKey: string; - optionName: string; - pointsParticipant: number; - pointsPartner: number; - }; - - // Card component - type Card = { - gridArea: string; - name: string; - points: string; - avatar: string; - }; - - // Slider component - type Slider = { - min: number; - max: number; - value: number; - setValue: (value: number) => void; - leftLabel: string; - rightLabel: string; - onChange?: () => any; - isFocused: boolean; - }; - - // Character component - type Character = { - size: number; - name: string; - state: string; - setState: (avatar: string) => void; - }; - - // Status componet - type Status = { - participantStatus: number; - partnerStatus: number; - isPractice?: boolean; - hidePartner?: boolean; - }; - } - - // Props for 'Screens' - declare namespace Screens { - type GenericScreenProps = { - trial_number: number; - display: Display; - }; - - // End screen - type End = GenericScreenProps; - - // Loaded screen - type Loaded = GenericScreenProps & { - state: "matchingIntentions" | "matchingCyberball" | "social"; - handler: () => void; - }; - - // Loading screen - type Loading = GenericScreenProps & { - state: "matchingIntentions" | "matchingCyberball" | "social" | "default"; - runComputeSetup?: boolean; - runComputeOperation?: boolean; - handler?: ( - storeParameters: boolean, - participantParameters: number[], - partnerParameters: number[], - setupDuration: number, - operationDuration: number - ) => void; - }; - - // Trial screen - type Trial = GenericScreenProps & { - isPractice: boolean; - participantPoints: number; - partnerPoints: number; - options: Points; - answer: Options; - spotlight?: { - enabled: boolean; - target: "status" | "options" | "none"; - message: string; - }; - handler: ( - selection: Options, - points: { options: Points }, - answer: Options - ) => void; - }; - - // SelectAvatar screen - type SelectAvatar = GenericScreenProps & { - handler: (selectedIndex: number) => void; - }; - - // Inference screen - type Inference = GenericScreenProps & { - handler: (firstValue: number, secondValue: number) => void; - }; - - // Agency screen - type Agency = GenericScreenProps & { - handler: (firstValue: number) => void; - }; - - // Classification screen - type Classification = GenericScreenProps & { - handler: (classification: string) => void; - }; - - // Status screen - type Status = GenericScreenProps & { - handler: ( - closeFriends: number, - partyInvitations: number, - meanPeople: number, - socialMediaFollowers: number, - socialMediaFollowing: number - ) => void; - }; - - // Status preview screen - type StatusPreview = GenericScreenProps & { - isPartnerHighStatus: boolean; - handler: () => void; - }; - - // DASS screen - type DASS = GenericScreenProps & { - version: "adult" | "adolescent"; - handler: (responses: number[]) => void; - }; - - // Screentime screen - type Screentime = GenericScreenProps & { - handler: (weekdayTime: number, weekendTime: number) => void; - }; - - // Demographics screen - type Demographics = GenericScreenProps & { - version: "adult" | "adolescent"; - handler: ( - age: number, - genderIdentity: string, - ethnicity: string, - householdIncome: string, - education: string, - socialMediaDaily: boolean, - socialMediaPlatforms: string, - ) => void; - }; - - // Summary screen - type Summary = GenericScreenProps & { - postPhase: Display; - handler: () => void; - }; - - // Waiting screen - type Waiting = GenericScreenProps & { - mode: "facilitator" | "mri"; - handler: () => void; - }; +// Props for 'Components' +declare namespace Components { + // Wrapper component + type Wrapper = { + display: Display; + props: + | Screens.Loaded + | Screens.Loading + | Screens.Trial + | Screens.SelectAvatar + | Screens.Inference + | Screens.Agency + | Screens.Classification + | Screens.Status + | Screens.DASS + | Screens.Screentime + | Screens.Demographics + | Screens.Summary + | Screens.Waiting + | Screens.Cyberball + | Screens.Resources; + }; + + // Option component + type Option = { + optionKey: string; + optionName: string; + pointsParticipant: number; + pointsPartner: number; + }; + + // Card component + type Card = { + gridArea: string; + name: string; + points: string; + avatar: string; + }; + + // Slider component + type Slider = { + min: number; + max: number; + value: number; + setValue: (value: number) => void; + leftLabel: string; + rightLabel: string; + onChange?: () => any; + isFocused: boolean; + }; + + // Character component + type Character = { + size: number; + name: string; + state: string; + setState: (avatar: string) => void; + }; + + // Status componet + type Status = { + participantStatus: number; + partnerStatus: number; + isPractice?: boolean; + hidePartner?: boolean; + }; +} - // Cyberball screen - type Cyberball = GenericScreenProps & { - isInclusive: boolean; // Operate exclusively as inclusive or exclusive - partnerHighStatus: boolean; // Partner A is high status or low status - probabilities: { - inclusion: number; // Probability of partners passing to participant - exclusion: { - partnerA: number; // Probability of partner A passing to participant - partnerB: number; // Probability of partner B passing to participant - }; +// Props for 'Screens' +declare namespace Screens { + type GenericScreenProps = { + trial_number: number; + display: Display; + }; + + // Loaded screen + type Loaded = GenericScreenProps & { + state: "matchingIntentions" | "matchingCyberball" | "social"; + handler: () => void; + }; + + // Loading screen + type Loading = GenericScreenProps & { + state: "matchingIntentions" | "matchingCyberball" | "social" | "default"; + runComputeSetup?: boolean; + runComputeOperation?: boolean; + handler?: ( + storeParameters: boolean, + participantParameters: number[], + partnerParameters: number[], + setupDuration: number, + operationDuration: number + ) => void; + }; + + // Trial screen + type Trial = GenericScreenProps & { + isPractice: boolean; + participantPoints: number; + partnerPoints: number; + options: Points; + answer: Options; + spotlight?: { + enabled: boolean; + target: "status" | "options" | "none"; + message: string; + }; + handler: ( + selection: Options, + points: { options: Points }, + answer: Options + ) => void; + }; + + // SelectAvatar screen + type SelectAvatar = GenericScreenProps & { + handler: (selectedIndex: number) => void; + }; + + // Inference screen + type Inference = GenericScreenProps & { + handler: (firstValue: number, secondValue: number) => void; + }; + + // Agency screen + type Agency = GenericScreenProps & { + handler: (firstValue: number) => void; + }; + + // Classification screen + type Classification = GenericScreenProps & { + handler: (classification: string) => void; + }; + + // Status screen + type Status = GenericScreenProps & { + handler: ( + closeFriends: number, + partyInvitations: number, + meanPeople: number, + socialMediaFollowers: number, + socialMediaFollowing: number + ) => void; + }; + + // Status preview screen + type StatusPreview = GenericScreenProps & { + isPartnerHighStatus: boolean; + handler: () => void; + }; + + // DASS screen + type DASS = GenericScreenProps & { + version: "adult" | "adolescent"; + handler: (responses: number[]) => void; + }; + + // Screentime screen + type Screentime = GenericScreenProps & { + handler: (weekdayTime: number, weekendTime: number) => void; + }; + + // Demographics screen + type Demographics = GenericScreenProps & { + version: "adult" | "adolescent"; + handler: ( + age: number, + genderIdentity: string, + ethnicity: string, + householdIncome: string, + education: string, + socialMediaDaily: boolean, + socialMediaPlatforms: string, + ) => void; + }; + + // Summary screen + type Summary = GenericScreenProps & { + postPhase: Display; + handler: () => void; + }; + + // Waiting screen + type Waiting = GenericScreenProps & { + mode: "facilitator" | "mri"; + handler: () => void; + }; + + // Resources screen + type Resources = GenericScreenProps & { + handler: () => void; + }; + + // Cyberball screen + type Cyberball = GenericScreenProps & { + isInclusive: boolean; // Operate exclusively as inclusive or exclusive + partnerHighStatus: boolean; // Partner A is high status or low status + probabilities: { + inclusion: number; // Probability of partners passing to participant + exclusion: { + partnerA: number; // Probability of partner A passing to participant + partnerB: number; // Probability of partner B passing to participant }; - handler: ( - tossCount: number, - participantTossCount: number, - participantCatchCount: number - ) => void; }; - } + handler: ( + tossCount: number, + participantTossCount: number, + participantCatchCount: number + ) => void; + }; } From 11d3b372ac54425c7196358b6ee0eec9cfdb79c1 Mon Sep 17 00:00:00 2001 From: Henry Burgess Date: Mon, 29 Sep 2025 11:58:56 -0500 Subject: [PATCH 5/5] INT-77 Fix tests --- test/classes/factories/ScreenPropFactory.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/classes/factories/ScreenPropFactory.test.ts b/test/classes/factories/ScreenPropFactory.test.ts index 7cfb31d..74e9632 100644 --- a/test/classes/factories/ScreenPropFactory.test.ts +++ b/test/classes/factories/ScreenPropFactory.test.ts @@ -36,7 +36,7 @@ test("generate props for Agency screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("agency"); expect(generated.props).toHaveProperty("handler"); }); @@ -52,7 +52,7 @@ test("generate props for Classification screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("classification"); expect(generated.props).toHaveProperty("handler"); }); @@ -68,7 +68,7 @@ test("generate props for End screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("end"); expect(generated.props).not.toHaveProperty("handler"); }); @@ -84,7 +84,7 @@ test("generate props for Inference screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("inference"); expect(generated.props).toHaveProperty("handler"); }); @@ -100,7 +100,7 @@ test("generate props for Loaded screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("loaded"); expect(generated.props.state).toBe("matchingIntentions"); expect(generated.props).not.toHaveProperty("handler"); @@ -122,7 +122,7 @@ test("generate props for Loading screen with matching type", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("loading"); expect(generated.props.state).toBe("matchingIntentions"); expect(generated.props.runComputeOperation).toBe(false); @@ -140,7 +140,7 @@ test("generate props for Summary screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("summary"); expect(generated.props.postPhase).toBe("playerChoice"); expect(generated.props).toHaveProperty("handler"); @@ -157,7 +157,7 @@ test("generate props for Trial screen", async () => { const generated = screenPropFactory.generate(); // Check contents of props - expect(generated.props.trial).toBe(1); + expect(generated.props.trial_number).toBe(1); expect(generated.props.display).toBe("playerChoice"); expect(generated.props.isPractice).toBe(false); expect(generated.props.participantPoints).toBe(0);