diff --git a/package.json b/package.json index 0ae406e..e3501a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "task_intentions", - "version": "1.7.10", + "version": "1.7.11", "description": "Intentions Game", "private": true, "main": "dist/index.js", diff --git a/src/classes/Handler.ts b/src/classes/Handler.ts index f6def12..9b69af1 100644 --- a/src/classes/Handler.ts +++ b/src/classes/Handler.ts @@ -220,8 +220,14 @@ class Handler { // Store social status const experiment = window.Experiment; this.dataframe.participantDefaultStatus = experiment.getState().get("participantDefaultStatus"); - this.dataframe.partnerLowStatus = experiment.getState().get("partnerLowStatus"); - this.dataframe.partnerHighStatus = experiment.getState().get("partnerHighStatus"); + this.dataframe.partnerCyberballLowStatus = experiment.getState().get("partnerCyberballLowStatus"); + this.dataframe.partnerCyberballHighStatus = experiment.getState().get("partnerCyberballHighStatus"); + this.dataframe.partnerOneLowStatus = experiment.getState().get("partnerOneLowStatus"); + this.dataframe.partnerOneHighStatus = experiment.getState().get("partnerOneHighStatus"); + this.dataframe.partnerTwoLowStatus = experiment.getState().get("partnerTwoLowStatus"); + this.dataframe.partnerTwoHighStatus = experiment.getState().get("partnerTwoHighStatus"); + this.dataframe.partnerThreeLowStatus = experiment.getState().get("partnerThreeLowStatus"); + this.dataframe.partnerThreeHighStatus = experiment.getState().get("partnerThreeHighStatus"); // Finish trial this.callback(); diff --git a/src/classes/factories/ScreenPropFactory.ts b/src/classes/factories/ScreenPropFactory.ts index 72cca57..93194b2 100644 --- a/src/classes/factories/ScreenPropFactory.ts +++ b/src/classes/factories/ScreenPropFactory.ts @@ -137,7 +137,8 @@ class ScreenPropFactory implements Factory { returned.props = { trial_number: this.trial.trial_number, display: this.trial.display, - isPartnerHighStatus: this.trial.isPartnerHighStatus, + nextPhase: this.trial.nextPhase, + isPreviewPartnerHighStatus: this.trial.isPreviewPartnerHighStatus, handler: this.handler.callback.bind(this.handler), }; break; @@ -292,7 +293,7 @@ class ScreenPropFactory implements Factory { trial_number: this.trial.trial_number, display: this.trial.display, isInclusive: this.trial.isInclusive, - partnerHighStatus: this.trial.partnerHighStatus, + isCyberballPartnerHighStatus: this.trial.isCyberballPartnerHighStatus, probabilities: this.trial.probabilities, handler: this.handler.cyberball.bind(this.handler), }; diff --git a/src/configuration.ts b/src/configuration.ts index b5303fd..2ab7506 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -101,8 +101,12 @@ export const Configuration = { signalTimestamps: [], experimentID: "", participantDefaultStatus: 0, - partnerHighStatus: 0, - partnerLowStatus: 0, + partnerOneHighStatus: 0, + partnerOneLowStatus: 0, + partnerTwoHighStatus: 0, + partnerTwoLowStatus: 0, + partnerThreeHighStatus: 0, + partnerThreeLowStatus: 0, }, // Set the logging level diff --git a/src/index.tsx b/src/index.tsx index 1fee8e5..a611592 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -100,12 +100,28 @@ experiment.getState().set("experimentID", experimentID); initializeLocalStorage(experimentID); // Generate status values for participant and partner during actual trials -const { participantStatus: participantDefaultStatus, partnerLowStatus, partnerHighStatus } = generateStatuses(); +const { + participantDefaultStatus, + partnerCyberballLowStatus, + partnerCyberballHighStatus, + partnerOneLowStatus, + partnerOneHighStatus, + partnerTwoLowStatus, + partnerTwoHighStatus, + partnerThreeLowStatus, + partnerThreeHighStatus, +} = generateStatuses(); // Store status values in the experiment state experiment.getState().set("participantDefaultStatus", participantDefaultStatus); -experiment.getState().set("partnerLowStatus", partnerLowStatus); -experiment.getState().set("partnerHighStatus", partnerHighStatus); +experiment.getState().set("partnerCyberballLowStatus", partnerCyberballLowStatus); +experiment.getState().set("partnerCyberballHighStatus", partnerCyberballHighStatus); +experiment.getState().set("partnerOneLowStatus", partnerOneLowStatus); +experiment.getState().set("partnerOneHighStatus", partnerOneHighStatus); +experiment.getState().set("partnerTwoLowStatus", partnerTwoLowStatus); +experiment.getState().set("partnerTwoHighStatus", partnerTwoHighStatus); +experiment.getState().set("partnerThreeLowStatus", partnerThreeLowStatus); +experiment.getState().set("partnerThreeHighStatus", partnerThreeHighStatus); // Setup the Compute instance window.Compute = new Compute(); @@ -486,7 +502,7 @@ if (Configuration.manipulations.enableCyberball === true) { type: Configuration.studyName, display: "cyberball", isInclusive: Configuration.manipulations.cyberballIsInclusive, - partnerHighStatus: Configuration.manipulations.cyberballIsPartnerHighStatus, + isCyberballPartnerHighStatus: Configuration.manipulations.cyberballIsPartnerHighStatus, probabilities: { inclusion: 0.5, exclusion: { @@ -900,7 +916,8 @@ if (Configuration.manipulations.enableStatusPhaseOne === true) { timeline.push({ type: Configuration.studyName, display: "statusPreview", - isPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseOne, + nextPhase: "phaseOne", + isPreviewPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseOne, }) } @@ -1275,7 +1292,8 @@ for (let i = 0; i < dataCollection.length; i++) { timeline.push({ type: Configuration.studyName, display: "statusPreview", - isPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseTwo, + nextPhase: "phaseTwo", + isPreviewPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseTwo, }) } @@ -1467,7 +1485,8 @@ for (let i = 0; i < dataCollection.length; i++) { timeline.push({ type: Configuration.studyName, display: "statusPreview", - isPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseThree, + nextPhase: "phaseThree", + isPreviewPartnerHighStatus: Configuration.manipulations.isPartnerHighStatusPhaseThree, }) } diff --git a/src/util.ts b/src/util.ts index 960e2cf..8d74d52 100644 --- a/src/util.ts +++ b/src/util.ts @@ -256,20 +256,54 @@ export const generatePartnerID = (): string => { * Generate the participant and partner statuses using uniform distributions * @returns Object containing participant status (40-60%), partner low status (10-25%), and partner high status (75-90%) */ -export const generateStatuses = (): { participantStatus: number, partnerLowStatus: number, partnerHighStatus: number } => { +export const generateStatuses = (): { + participantDefaultStatus: number; + partnerCyberballLowStatus: number; + partnerCyberballHighStatus: number; + partnerOneLowStatus: number; + partnerOneHighStatus: number; + partnerTwoLowStatus: number; + partnerTwoHighStatus: number; + partnerThreeLowStatus: number; + partnerThreeHighStatus: number; +} => { // Create uniform distribution generators const participantRandom = randomUniform(40, 60); const partnerLowRandom = randomUniform(10, 25); const partnerHighRandom = randomUniform(75, 90); // Generate the statuses using uniform distributions - const participantStatus = Math.round(participantRandom() * 10) / 10; // Round to 1 decimal place - const partnerLowStatus = Math.round(partnerLowRandom() * 10) / 10; - const partnerHighStatus = Math.round(partnerHighRandom() * 10) / 10; + const participantDefaultStatus = Math.round(participantRandom() * 10) / 10; // Round to 1 decimal place + + // Cyberball partner statuses + const partnerCyberballLowStatus = Math.round(partnerLowRandom() * 10) / 10; + const partnerCyberballHighStatus = Math.round(partnerHighRandom() * 10) / 10; + + // Phase One partner statuses + const partnerOneLowStatus = Math.round(partnerLowRandom() * 10) / 10; + const partnerOneHighStatus = Math.round(partnerHighRandom() * 10) / 10; + + // Phase Two partner statuses + const partnerTwoLowStatus = Math.round(partnerLowRandom() * 10) / 10; + const partnerTwoHighStatus = Math.round(partnerHighRandom() * 10) / 10; + + // Phase Three partner statuses + const partnerThreeLowStatus = Math.round(partnerLowRandom() * 10) / 10; + const partnerThreeHighStatus = Math.round(partnerHighRandom() * 10) / 10; // Log the statuses - consola.info(`Generated statuses - Participant: ${participantStatus}%, Partner Low: ${partnerLowStatus}%, Partner High: ${partnerHighStatus}%`); + consola.info(`Generated statuses:\nParticipant: ${participantDefaultStatus}%\nPartner Cyberball Low: ${partnerCyberballLowStatus}%, Partner Cyberball High: ${partnerCyberballHighStatus}%\nPartner One Low: ${partnerOneLowStatus}%, Partner One High: ${partnerOneHighStatus}%\nPartner Two Low: ${partnerTwoLowStatus}%, Partner Two High: ${partnerTwoHighStatus}%\nPartner Three Low: ${partnerThreeLowStatus}%, Partner Three High: ${partnerThreeHighStatus}%`); // Return all three statuses - return { participantStatus, partnerLowStatus, partnerHighStatus }; + return { + participantDefaultStatus, + partnerCyberballLowStatus, + partnerCyberballHighStatus, + partnerOneLowStatus, + partnerOneHighStatus, + partnerTwoLowStatus, + partnerTwoHighStatus, + partnerThreeLowStatus, + partnerThreeHighStatus, + }; }; diff --git a/src/view/components/Card/index.tsx b/src/view/components/Card/index.tsx index ef715fe..6af854c 100644 --- a/src/view/components/Card/index.tsx +++ b/src/view/components/Card/index.tsx @@ -46,6 +46,7 @@ const Card: FC = ( id="playerInfo" margin={{ left: "small", right: "small" }} align="center" + justify="center" > {props.name} @@ -59,7 +60,7 @@ const Card: FC = ( - + = ( // Generate the strings to determine the participant and partner statuses const participantStatus = experiment.getState().get("participantDefaultStatus"); - const partnerStatus = props.partnerHighStatus ? experiment.getState().get("partnerHighStatus") : experiment.getState().get("partnerLowStatus"); + const partnerStatus = props.isCyberballPartnerHighStatus ? experiment.getState().get("partnerCyberballHighStatus") : experiment.getState().get("partnerCyberballLowStatus"); // Force re-render mechanism const [, forceUpdate] = useReducer(x => x + 1, 0); @@ -243,6 +243,7 @@ const Cyberball: FC = ( position: "absolute", top: "-70px", left: "50%", + width: "100%", transform: "translateX(-50%)", zIndex: 1000, }} diff --git a/src/view/screens/StatusPreview/index.tsx b/src/view/screens/StatusPreview/index.tsx index e775405..f46dc12 100644 --- a/src/view/screens/StatusPreview/index.tsx +++ b/src/view/screens/StatusPreview/index.tsx @@ -31,7 +31,18 @@ import { Configuration } from "src/configuration"; 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"); + + // Determine the partner status + let partnerStatus = 0; + if (props.nextPhase === "cyberball") { + partnerStatus = props.isPreviewPartnerHighStatus ? experiment.getState().get("partnerCyberballHighStatus") : experiment.getState().get("partnerCyberballLowStatus"); + } else if (props.nextPhase === "phaseOne") { + partnerStatus = props.isPreviewPartnerHighStatus ? experiment.getState().get("partnerOneHighStatus") : experiment.getState().get("partnerOneLowStatus"); + } else if (props.nextPhase === "phaseTwo") { + partnerStatus = props.isPreviewPartnerHighStatus ? experiment.getState().get("partnerTwoHighStatus") : experiment.getState().get("partnerTwoLowStatus"); + } else if (props.nextPhase === "phaseThree") { + partnerStatus = props.isPreviewPartnerHighStatus ? experiment.getState().get("partnerThreeHighStatus") : experiment.getState().get("partnerThreeLowStatus"); + } // Get the updated partner avatar const partnerAvatar = Configuration.avatars.names.partner[ diff --git a/src/view/screens/Trial/index.tsx b/src/view/screens/Trial/index.tsx index 80b2827..88db994 100644 --- a/src/view/screens/Trial/index.tsx +++ b/src/view/screens/Trial/index.tsx @@ -193,27 +193,18 @@ const Trial: FC = ( // Initialize participant and partner statuses const participantStatus = experiment.getState().get("participantDefaultStatus"); // Default for all trials - let partnerStatus = experiment.getState().get("partnerLowStatus"); + let partnerStatus = experiment.getState().get("partnerCyberballLowStatus"); // Default to the Cyberball low status if (Flags.isEnabled("enableStatusDisplay") && props.isPractice === false) { // If status display is enabled, interpret and apply the manipulations - if ( - props.display === "playerChoice" && - Configuration.manipulations.isPartnerHighStatusPhaseOne - ) { + if (props.display === "playerChoice") { // Phase One: If `isHighStatusPhaseOne` is true, then the participant is low status and the partner is high status - partnerStatus = experiment.getState().get("partnerHighStatus"); - } else if ( - props.display === "playerGuess" && - Configuration.manipulations.isPartnerHighStatusPhaseTwo - ) { + partnerStatus = Configuration.manipulations.isPartnerHighStatusPhaseOne ? experiment.getState().get("partnerOneHighStatus") : experiment.getState().get("partnerOneLowStatus"); + } else if (props.display === "playerGuess") { // Phase Two: If `isHighStatusPhaseTwo` is true, then the participant is low status and the partner is high status - partnerStatus = experiment.getState().get("partnerHighStatus"); - } else if ( - props.display === "playerChoice2" && - Configuration.manipulations.isPartnerHighStatusPhaseThree - ) { + partnerStatus = Configuration.manipulations.isPartnerHighStatusPhaseTwo ? experiment.getState().get("partnerTwoHighStatus") : experiment.getState().get("partnerTwoLowStatus"); + } else if (props.display === "playerChoice2") { // Phase Three: If `isHighStatusPhaseThree` is true, then the participant is low status and the partner is high status - partnerStatus = experiment.getState().get("partnerHighStatus"); + partnerStatus = Configuration.manipulations.isPartnerHighStatusPhaseThree ? experiment.getState().get("partnerThreeHighStatus") : experiment.getState().get("partnerThreeLowStatus"); } } diff --git a/test/utils/functions.ts b/test/utils/functions.ts index a60c7a7..a9a507c 100644 --- a/test/utils/functions.ts +++ b/test/utils/functions.ts @@ -56,8 +56,14 @@ export const getHandler = (display: Display): Handler => { playerPoints_selected: NaN, partnerPoints_selected: NaN, participantDefaultStatus: 0, - partnerLowStatus: 0, - partnerHighStatus: 0, + partnerCyberballLowStatus: 0, + partnerCyberballHighStatus: 0, + partnerOneLowStatus: 0, + partnerOneHighStatus: 0, + partnerTwoLowStatus: 0, + partnerTwoHighStatus: 0, + partnerThreeLowStatus: 0, + partnerThreeHighStatus: 0, selectedOption_player: NaN, realAnswer: "Option 1", questionnaireResponseInferenceSelfish: NaN, diff --git a/test/view/screens/Cyberball.test.tsx b/test/view/screens/Cyberball.test.tsx index 43edf24..854f785 100644 --- a/test/view/screens/Cyberball.test.tsx +++ b/test/view/screens/Cyberball.test.tsx @@ -68,7 +68,7 @@ describe("Cyberball Screen", () => { trial_number: 1, display: "cyberball" as const, isInclusive: true, - partnerHighStatus: true, + isCyberballPartnerHighStatus: true, probabilities: { inclusion: 0.7, exclusion: { @@ -176,9 +176,9 @@ describe("Cyberball Screen", () => { expect(screen.getByText("High")).toBeInTheDocument(); }); - it("shows correct status positioning based on partnerHighStatus prop", () => { + it("shows correct status positioning based on isCyberballPartnerHighStatus prop", () => { // Test with high status partner - const highStatusProps = { ...mockProps, partnerHighStatus: true }; + const highStatusProps = { ...mockProps, isCyberballPartnerHighStatus: true }; const { rerender } = render(); // Check that the status label is present @@ -186,7 +186,7 @@ describe("Cyberball Screen", () => { expect(screen.getByText("High")).toBeInTheDocument(); // Test with low status partner - const lowStatusProps = { ...mockProps, partnerHighStatus: false }; + const lowStatusProps = { ...mockProps, isCyberballPartnerHighStatus: false }; rerender(); // Check that the status label is still present diff --git a/types/data.d.ts b/types/data.d.ts index 0bf43fe..e38b06e 100644 --- a/types/data.d.ts +++ b/types/data.d.ts @@ -49,8 +49,14 @@ declare type Dataframe = { // Social status participantDefaultStatus: number; - partnerLowStatus: number; - partnerHighStatus: number; + partnerCyberballLowStatus: number; + partnerCyberballHighStatus: number; + partnerOneLowStatus: number; + partnerOneHighStatus: number; + partnerTwoLowStatus: number; + partnerTwoHighStatus: number; + partnerThreeLowStatus: number; + partnerThreeHighStatus: number; // Signal timestamps signalTimestamps: number[]; diff --git a/types/jsPsych.d.ts b/types/jsPsych.d.ts index 847643c..29818cc 100644 --- a/types/jsPsych.d.ts +++ b/types/jsPsych.d.ts @@ -82,7 +82,8 @@ declare type IntentionsNode = { 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 + nextPhase?: "cyberball" | "phaseOne" | "phaseTwo" | "phaseThree"; + isPreviewPartnerHighStatus?: boolean; // Used for the `StatusPreview` screen // Waiting screen configuration (used by Waiting screen) mode: "facilitator" | "mri"; @@ -96,7 +97,7 @@ declare type IntentionsNode = { // Cyberball screen isInclusive?: boolean; - partnerHighStatus?: boolean; + isCyberballPartnerHighStatus?: boolean; probabilities?: { inclusion: number; exclusion: { diff --git a/types/props.d.ts b/types/props.d.ts index 2ca4c6c..4c28db7 100644 --- a/types/props.d.ts +++ b/types/props.d.ts @@ -150,7 +150,8 @@ declare namespace Screens { // Status preview screen type StatusPreview = GenericScreenProps & { - isPartnerHighStatus: boolean; + nextPhase: "cyberball" | "phaseOne" | "phaseTwo" | "phaseThree"; + isPreviewPartnerHighStatus: boolean; handler: () => void; }; @@ -199,7 +200,7 @@ declare namespace Screens { // Cyberball screen type Cyberball = GenericScreenProps & { isInclusive: boolean; // Operate exclusively as inclusive or exclusive - partnerHighStatus: boolean; // Partner A is high status or low status + isCyberballPartnerHighStatus: boolean; // Partner A is high status or low status probabilities: { inclusion: number; // Probability of partners passing to participant exclusion: {