Skip to content

Commit

Permalink
exit code for failing equipment check (#956)
Browse files Browse the repository at this point in the history
* Add a reference to whether the discussion failed

* Allow selecting customIDInstructions from URL params

* fix tests

* validate auto-populated ID

* exit code for failing equipment check

* Add copy code buttons

* Log sources from url params

* Update validateBatchConfig.test.js
  • Loading branch information
JamesPHoughton authored Dec 18, 2024
1 parent e586ac6 commit f8ea467
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 30 deletions.
54 changes: 38 additions & 16 deletions client/src/intro-exit/Debrief.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { usePlayer } from "@empirica/core/player/classic/react";
import { Loading } from "@empirica/core/player/react";
import { Markdown } from "../components/Markdown";
import { useIdleContext } from "../components/IdleProvider";
import { Button } from "../components/Button";

export function Debrief() {
const player = usePlayer();
Expand All @@ -31,34 +32,55 @@ export function Debrief() {

const exitCodes = player.get("exitCodes");

const debriefStatements = `
# Finished 🎉
## Thank you for participating!
${
exitCodes &&
exitCodes !== "none" &&
`Please enter the following completion code on your recruitment platform:
> ${exitCodes?.complete}`
}
const copyToClipboard = () => {
navigator.clipboard.writeText(exitCodes.complete);
// eslint-disable-next-line no-alert
alert(
`Copied "${exitCodes.complete}" to clipboard. Please enter this code for a partial payment, then close the experiment window.`
);
};

const debriefStatements = `
### About this study
_Social scientists have tested different ways to improve small group conversations, like using a facilitator, setting an agenda, or creating ground rules. While some methods work better than others, it’s challenging to know which will be the most effective. What we do know is that different types of conversations need different kinds of support._
_Instead of looking for one solution that works for all conversations, our research team is mapping out what helps each specific type of conversation. Your participation in this study provides valuable data that, combined with data from other discussions, will help us understand how the context of a discussion shapes its outcomes._
_For any additional questions, please contact the University of Pennsylvania research team by
emailing **[[email protected]](mailto:[email protected])**._
`;

${
exitCodes !== "none"
? `👉 After copying the payment code above, you may close this window.`
: ""
}
`;
return (
<div className="grid justify-center">
<h1>
<span role="img" aria-label="Party popper">
Finished! 🎉
</span>{" "}
Thank you for participating!
</h1>
{exitCodes !== "none" && (
<div>
<h3>
Please enter the following completion code on your recruitment
platform:
</h3>
<div className="mt-4">
<span className="font-bold font-mono text-center mr-2">
{exitCodes?.complete}
</span>
<Button
handleClick={copyToClipboard}
className="px-2 py-1 bg-blue-500 text-white text-xs rounded"
>
Copy to clipboard
</Button>
</div>
</div>
)}

<Markdown text={debriefStatements} />

<h3>You may now close this window.</h3>
</div>
);
}
32 changes: 27 additions & 5 deletions client/src/intro-exit/EquipmentCheck.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ function SoundCheckMessage({ headphonesOnly, successCallback }) {
function FailureMessage() {
const player = usePlayer();
const exitCodes = player?.get("exitCodes");

const copyToClipboard = () => {
navigator.clipboard.writeText(exitCodes.failedEquipmentCheck);
// eslint-disable-next-line no-alert
alert(
`Copied "${exitCodes.failedEquipmentCheck}" to clipboard. Please enter this code for a partial payment, then close the experiment window.`
);
};

return (
<div>
<h1>😳 Equipment and/or Connection Check Failed. </h1>
Expand All @@ -183,13 +192,26 @@ function FailureMessage() {
<li>Try incognito/private browsing mode.</li>
<li>Try a different browser.</li>
</ol>
<p>
<h3>
If we are still unable to detect your equipment, you will not be able to
participate today.{" "}
{exitCodes !== "none" &&
`Please enter the following code to be paid for your
time: ${exitCodes.lobbyTimeout}`}
</p>
</h3>
{exitCodes !== "none" && (
<div>
<p>Please enter the following code to be paid for your time:</p>
<div className="mt-4">
<span className="font-bold font-mono text-center mr-2">
{exitCodes.failedEquipmentCheck}
</span>
<Button
handleClick={copyToClipboard}
className="px-2 py-1 bg-blue-500 text-white text-xs rounded"
>
Copy to clipboard
</Button>
</div>
</div>
)}
</div>
);
}
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/01_Normal_Paths_Omnibus.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ describe(
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
}
}`;

Expand Down
6 changes: 4 additions & 2 deletions cypress/e2e/02_Batch_Canceled.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const configJsonA = `{
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
}
}`;

Expand All @@ -58,7 +59,8 @@ const configJsonB = `{
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
},
"videoStorage": {
"bucket": "deliberation-lab-recordings-test",
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/12_Not_Matched.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const configJson = `{
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
}
}`;

Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/13_Constrained_Assignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const configJson = `{
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
}
}`;

Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/14_Templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const configJson = `{
"exitCodes": {
"complete": "cypressComplete",
"error": "cypressError",
"lobbyTimeout": "cypressLobbyTimeout"
"lobbyTimeout": "cypressLobbyTimeout",
"failedEquipmentCheck": "cypressFailedEquipmentCheck"
}
Expand Down
3 changes: 2 additions & 1 deletion cypress/fixtures/mockCDN/projects/example/demo.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"exitCodes": {
"complete": "demoComplete",
"error": "demoError",
"lobbyTimeout": "demoLobbyTimeout"
"lobbyTimeout": "demoLobbyTimeout",
"failedEquipmentCheck": "demoFailedEquipmentCheck"
}
}
7 changes: 5 additions & 2 deletions docs/batchConfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ Batch options are supplied as a custom batch JSON. For example:
"exitCodes": {
"complete": "demoCompleteExitCode",
"error": "demoErrorExitCode",
"lobbyTimeout": "demoLobbyTimeoutExitCode"
"lobbyTimeout": "demoLobbyTimeoutExitCode",
"failedEquipmentCheck": "demoFailedEquipmentCheck"
}
}
```
Expand Down Expand Up @@ -218,14 +219,16 @@ You can specify exit codes for the different ways that participants can leave th
"exitCodes": {
"complete": "goodJob2001",
"error": "ohNo404whoops",
"lobbyTimeout": "youGotTiredOfWaiting408"
"lobbyTimeout": "youGotTiredOfWaiting408",
"failedEquipmentCheck": "youFailedEquipmentCheck"
}
}
```

- "complete" will be displayed to the participant when they get all the way through the exit steps
- "error" will be shown in case of server error or premature batch termination
- "lobbyTimeout" will be shown if it takes more than 5 minutes to match participants, giving them the option to leave and be paid only for the intro sequence.
- "failedEquipmentCheck" will be shown if the participants can't get their webcams working

If you do not wish to supply exit codes, enter `"exitCodes": "none"`.

Expand Down
1 change: 1 addition & 0 deletions server/src/preFlight/validateBatchConfig.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const passingConfig = {
complete: "complete_code",
error: "error_code",
lobbyTimeout: "lobby_timeout_code",
failedEquipmentCheck: "failed_equipment_code",
},
customIdInstructions: "mturkIdInstructions.md",
platformConsent: "US",
Expand Down
1 change: 1 addition & 0 deletions server/src/preFlight/validateBatchConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const batchConfigSchema = z
complete: z.string(),
error: z.string(),
lobbyTimeout: z.string(),
failedEquipmentCheck: z.string(),
})
.or(
z.literal("none", {
Expand Down
13 changes: 13 additions & 0 deletions server/src/utils/logging.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ export function logPlayerCounts(ctx) {
let nPlayersInExitSequence = 0;
let nPlayersCompleted = 0;

const introSources = {};
const countdownSources = {};
const lobbySources = {};

players.forEach((player) => {
const urlParams = player.get("urlParams");
const source = urlParams?.source || "unknown";

if (player.get("exitStatus") === "complete") {
nPlayersCompleted += 1;
} else if (player.get("gameFinished") && player.get("connected")) {
Expand All @@ -25,10 +32,13 @@ export function logPlayerCounts(ctx) {
nPlayersInGame += 1;
} else if (player.get("introDone") && player.get("connected")) {
nPlayersInLobby += 1;
lobbySources[source] = (lobbySources[source] || 0) + 1;
} else if (player.get("inCountdown") && player.get("connected")) {
nPlayersInCountdown += 1;
countdownSources[source] = (countdownSources[source] || 0) + 1;
} else if (player.get("connected")) {
nPlayersInIntroSequence += 1;
introSources[source] = (introSources[source] || 0) + 1;
} else if (!player.get("connected")) {
nPlayersDisconnected += 1;
} else {
Expand All @@ -39,6 +49,9 @@ export function logPlayerCounts(ctx) {
info(
`== ${nPlayersInIntroSequence} in intro steps, ${nPlayersInCountdown} in countdown, ${nPlayersInLobby} in lobby, ${nPlayersInGame} in games, ${nPlayersInExitSequence} in exit sequence, ${nPlayersCompleted} completed, ${nPlayersDisconnected} disconnected incomplete`
);
info("== Intro Sources:", introSources);
info("== Countdown Sources:", countdownSources);
info("== Lobby Sources:", lobbySources);
} catch (e) {
error("Caught error in logPlayerCounts:", e);
}
Expand Down

0 comments on commit f8ea467

Please sign in to comment.