Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add instructions #20

Merged
merged 17 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/assets/click.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions src/components/Ending.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FC, useEffect } from "react";
import { Box, Divider, Typography } from "@mui/material";

export const Ending: FC = () => {
useEffect(() => {
sessionStorage.clear();
}, []);

return (
<>
<Box marginX="auto" position="absolute" top="10%" width="85%" sx={{ transform: "translateX(-50%)" }}>
<Typography variant="h4" textAlign="initial" fontWeight="bold" marginBottom={1}>
Congratulations
</Typography>
<Divider />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
You have completed the test. Thank you for participating.
</Typography>
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
You may now close the tab.
</Typography>
</Box>
</>
);
};
32 changes: 26 additions & 6 deletions src/components/GeneralDirection.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
import { FC, useContext } from "react";
import { Button } from "@mui/material";
import { Box, Button, Divider, Typography } from "@mui/material";
import { GeneralContext, Stage } from "../contexts/general.context";

export const GeneralDirection: FC = () => {
const cxt = useContext(GeneralContext);

const continueButtonHandler = () => {
cxt?.setStage(Stage.SOUND_CHECK);
cxt?.setStage(Stage.TRANSITION);
};

return (
<>
<h2>General Direction Placeholder</h2>
<Button variant="contained" onClick={continueButtonHandler}>
Continue
</Button>
<Box marginX="auto" position="absolute" top="10%" width="85%" sx={{ transform: "translateX(-50%)" }}>
<Typography variant="h4" textAlign="initial" fontWeight="bold" marginBottom={1}>
Directions
</Typography>
<Divider />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
Please do <strong>NOT</strong> use paper! Solve all questions in your mind. Click "Begin Test" to proceed.
</Typography>
</Box>
<Box
sx={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
display: "flex",
justifyContent: "center",
p: 1,
}}
>
<Button variant="contained" sx={{ fontSize: 18, padding: 1.5 }} fullWidth onClick={continueButtonHandler}>
Begin Test
</Button>
</Box>
</>
);
};
13 changes: 7 additions & 6 deletions src/components/SoundCheck.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Grid, IconButton, Typography } from "@mui/material";
import { Box, Divider, Grid, IconButton, Typography } from "@mui/material";
import { FC, useContext, useEffect, useState } from "react";
import { soundCheckConfig as uiConfig } from "../config/ui.config";
import { GeneralContext, Stage } from "../contexts/general.context";
Expand Down Expand Up @@ -89,7 +89,7 @@ export const SoundCheck: FC = () => {

if (index === cxt?.soundCheckNumber) {
setTimeout(() => {
cxt?.setStage(Stage.TRANSITION);
cxt?.setStage(Stage.GENERAL_DIRECTION);
}, 2000);
} else {
setTimeout(() => {
Expand Down Expand Up @@ -126,18 +126,19 @@ export const SoundCheck: FC = () => {
};

return (
<Box marginX="auto">
<Box marginX="auto" position="absolute" top="10%" width="85%" sx={{ transform: "translateX(-50%)" }}>
<Typography variant="h4" textAlign="initial" fontWeight="bold" marginBottom={1}>
Sound Check
</Typography>
<Typography variant="body1" fontSize={20} textAlign="initial" width="80vw">
<Divider />
<Typography variant="body1" fontSize={18} textAlign="initial" marginTop={2}>
If you can hear this message, click the announced number.
</Typography>
<Typography variant="body1" fontSize={20} textAlign="initial" width="80vw">
<Typography variant="body1" fontSize={18} textAlign="initial" marginBottom={2}>
Otherwise, please increase your speaks volume.
</Typography>
<OverlayWrapper>
<Grid container direction="column" spacing={1} marginTop={1}>
<Grid container direction="column" spacing={1} marginTop={1} marginX="auto">
{Array.from({ length: 3 }).map((_, rowIndex) => (
<Grid container item spacing={1} key={rowIndex}>
{Array.from({ length: 3 }).map((_, colIndex) => {
Expand Down
43 changes: 37 additions & 6 deletions src/components/Transition.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FC, useContext } from "react";
import { FC, useContext, useState } from "react";
import { GeneralContext } from "../contexts/general.context";
import { generalConfig as testConfig } from "../config/test.config";
import { ProgressTracker } from "./ProgressTracker";
import { Button } from "@mui/material";
import { Box, Button } from "@mui/material";
import { InstructionContainer, instructionComponents } from "./instructions/InstructionContainer";

interface TransitionProps {
handleTransition: () => void;
Expand All @@ -11,12 +12,42 @@ interface TransitionProps {
export const Transition: FC<TransitionProps> = ({ handleTransition }) => {
const cxt = useContext(GeneralContext);

const [displayInstructions, setDisplayInstructions] = useState<boolean>(false);

return (
<>
<ProgressTracker id={testConfig.testOrder.findIndex((phase) => phase === cxt!.testPhase)} />
<Button variant="contained" onClick={handleTransition}>
Continue
</Button>
{!displayInstructions && (
<Box marginX="auto" position="absolute" top="5%" width="85%" sx={{ transform: "translateX(-50%)" }}>
<ProgressTracker id={testConfig.testOrder.findIndex((phase) => phase === cxt!.testPhase)} />
</Box>
)}
{displayInstructions && <InstructionContainer phase={cxt!.testPhase} handleTransition={handleTransition} />}
<Box
sx={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
display: "flex",
justifyContent: "center",
p: 1,
}}
>
{instructionComponents[cxt!.testPhase]!.length <= 0 ? (
<Button variant="contained" sx={{ fontSize: 18, padding: 1.5 }} fullWidth onClick={handleTransition}>
Start
</Button>
) : (
<Button
variant="contained"
sx={{ fontSize: 18, padding: 1.5 }}
fullWidth
onClick={() => setDisplayInstructions(true)}
>
Continue
</Button>
)}
</Box>
</>
);
};
72 changes: 72 additions & 0 deletions src/components/instructions/ChoiceReactionTime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Box, Typography } from "@mui/material";
import { FC } from "react";
import { choiceReactionTimeConfig as uiConfig } from "../../config/ui.config";
import { generalConfig as testConfig } from "../../config/test.config";

const color0 = uiConfig.choiceColor.color0;
const color1 = uiConfig.choiceColor.color1;

interface CRTVisualProps {
symbols: string[];
colors: string[];
}

const CRTVisual: FC<CRTVisualProps> = ({ symbols, colors }) => (
<Box display="flex" flexDirection="column" alignItems="center" marginY={2}>
{symbols.map((symbol, index) => (
<Box
key={index}
width={60}
height={60}
display="flex"
alignItems="center"
justifyContent="center"
border={1}
marginY={1}
sx={{
backgroundColor: colors[index],
}}
>
<Typography variant="h3" fontWeight="bold" color="black">
{symbol}
</Typography>
</Box>
))}
</Box>
);

export const crtInstructions: JSX.Element[] = [
<>
<CRTVisual symbols={[">", "<", ">"]} colors={[color0, color1, color1]} />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginTop={2}>
Look at the 3 colored squares.
</Typography>
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginBottom={2}>
Two squares are the same color, one is different (ODD-COLOR).
</Typography>
</>,
<>
<CRTVisual symbols={[">", "<", ">"]} colors={[color0, color1, color1]} />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginTop={2}>
Now look at the ARROW inside the ODD-COLOR.
</Typography>
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginBottom={2}>
When the odd-color arrow points <strong>right</strong>, tap the <strong>RIGHT-ARROW</strong> button at the{" "}
<strong>bottom</strong> of the screen with your <strong>right</strong> hand.
</Typography>
</>,
<>
<CRTVisual symbols={[">", "<", "<"]} colors={[color0, color0, color1]} />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
When the odd-color arrow points <strong>left</strong>, tap the <strong>LEFT-ARROW</strong> button at the{" "}
<strong>bottom</strong> of the screen with your <strong>left</strong> hand.
</Typography>
</>,
<>
<CRTVisual symbols={[">", "<", "<"]} colors={[color0, color0, color1]} />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
You will see {Object.keys(testConfig.choiceReactionTimeAns).length} sets of ARROWs. Please response as fast as you
can.
</Typography>
</>,
];
64 changes: 64 additions & 0 deletions src/components/instructions/DigitSymbolMatching.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Divider, Grid, Typography } from "@mui/material";
import { FC } from "react";
import { Cell } from "../tests/DigitSymbolMatchingMain";
import { digitSymbolConfig as testConfig } from "../../config/test.config";
import { generalConfig } from "../../config/test.config";
import { digitSymbolConfig as uiConfig } from "../../config/ui.config";

const DSMVisual: FC = () => (
<Grid container spacing={0} display="flex" justifyContent="center" marginY={2}>
{testConfig.symbolPairs.map((symbol, index) => (
<Grid item key={index}>
<Cell
leftBox={index === 0}
rightBox={index === testConfig.symbolPairs.length - 1}
display="flex"
flexDirection="column"
justifyContent="center"
alignItems="center"
>
<img
src={symbol.image}
style={{
marginLeft: 1,
marginRight: 1,
marginTop: 2,
marginBottom: 2,
height: "8vw",
}}
/>
<Divider sx={{ width: "100%", borderBottom: "1px solid black" }} />
<Typography variant="h3" margin="5px" fontSize={uiConfig.listFontSize}>
{symbol.num}
</Typography>
</Cell>
</Grid>
))}
</Grid>
);

export const dsmInstructions: JSX.Element[] = [
<>
<DSMVisual />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginY={2}>
Each <strong>symbol</strong> has a <strong>number</strong>.
</Typography>
</>,
<>
<img src={testConfig.symbolPairs[0].image} style={{ marginTop: "1rem", height: "14vw" }} />
<DSMVisual />
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginBottom={2}>
When a symbol appears at the top, press its number on the <strong>number pad</strong> at the{" "}
<strong>bottom</strong> of the screen (here it is 1).
</Typography>
</>,
<>
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginTop={2}>
You will see {Object.keys(generalConfig.digitSymbolAns).length} questions in this test.
</Typography>
<Typography variant="body1" gutterBottom fontSize={18} textAlign="initial" marginBottom={2}>
Your score will be how many correct responeses you make, so try to be <strong>accurate</strong> and{" "}
<strong>quick</strong>!
</Typography>
</>,
];
83 changes: 83 additions & 0 deletions src/components/instructions/InstructionContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { FC, useState } from "react";
import { TestPhase } from "../../contexts/general.context";
import { Box, Button, Divider, Typography } from "@mui/material";
import { vpmInstructions, vprInstructions } from "./VisualPairs";
import { crtInstructions } from "./ChoiceReactionTime";
import { dsmInstructions } from "./DigitSymbolMatching";
import { smInstructions } from "./SpatialMemory";
import { mrdInstructions, mriInstructions } from "./MemoryRecall";

const titleMapping: { [key in TestPhase]?: string } = {
[TestPhase.MEMORY_RECALL_IMMEDIATE]: "Memory - Immediate Recall",
[TestPhase.VISUAL_PAIRS_MEMORIZE]: "Visual Paired Associates - Learn",
[TestPhase.CHOICE_REACTION_TIME]: "Choice Reaction Time",
[TestPhase.VISUAL_PAIRS_RECALL]: "Visual Paired Associates - Test",
[TestPhase.DIGIT_SYMBOL_MATCHING]: "Digit Symbol Matching",
[TestPhase.SPATIAL_MEMORY]: "Spatial Memory",
[TestPhase.MEMORY_RECALL_DELAYED]: "Memory - Delayed Recall",
};

export const instructionComponents: { [key in TestPhase]?: JSX.Element[] } = {
[TestPhase.MEMORY_RECALL_IMMEDIATE]: mriInstructions,
[TestPhase.VISUAL_PAIRS_MEMORIZE]: vpmInstructions,
[TestPhase.CHOICE_REACTION_TIME]: crtInstructions,
[TestPhase.VISUAL_PAIRS_RECALL]: vprInstructions,
[TestPhase.DIGIT_SYMBOL_MATCHING]: dsmInstructions,
[TestPhase.SPATIAL_MEMORY]: smInstructions,
[TestPhase.MEMORY_RECALL_DELAYED]: mrdInstructions,
};

interface InstructionContainerProps {
phase: TestPhase;
handleTransition: () => void;
}

export const InstructionContainer: FC<InstructionContainerProps> = ({ phase, handleTransition }) => {
const [instructionIdx, setInstructionIdx] = useState<number>(0);

return (
<>
<Box marginX="auto" position="absolute" top="10%" width="85%" sx={{ transform: "translateX(-50%)" }}>
<Typography variant="h5" textAlign="initial" fontWeight="bold" marginBottom={1}>
{titleMapping[phase]}
</Typography>
<Divider />
{instructionComponents[phase]![instructionIdx]}
</Box>
<Box
sx={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
display: "flex",
justifyContent: "center",
p: 1,
zIndex: 100,
}}
>
{instructionIdx + 1 < instructionComponents[phase]!.length ? (
<Button
variant="contained"
color="inherit"
sx={{ fontSize: 18, padding: 1.5 }}
fullWidth
onClick={() => setInstructionIdx((idx) => idx + 1)}
>
Tap here to Continue
</Button>
) : (
<Button
variant="contained"
color="primary"
sx={{ fontSize: 18, padding: 1.5 }}
fullWidth
onClick={handleTransition}
>
Start
</Button>
)}
</Box>
</>
);
};
Loading