Skip to content

Commit 0c563a5

Browse files
committed
feat: add stroop-task like instrument
1 parent 5a28ef7 commit 0c563a5

3 files changed

Lines changed: 119 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { useEffect, useState } from '/runtime/v1/react@18.x';
2+
3+
const colors = ['red', 'blue', 'green', 'yellow'];
4+
const words = ['RED', 'BLUE', 'GREEN', 'YELLOW'];
5+
6+
function getRandomElement<T>(arr: T[]): T {
7+
return arr[Math.floor(Math.random() * arr.length)]!;
8+
}
9+
10+
type StroopTaskProps = {
11+
done: (data: { score: number }) => void;
12+
};
13+
14+
export const StroopTask: React.FC<StroopTaskProps> = () => {
15+
const [currentWord, setCurrentWord] = useState('');
16+
const [currentColor, setCurrentColor] = useState('');
17+
const [score, setScore] = useState(0);
18+
const [timeLeft, setTimeLeft] = useState(60); // 60 seconds for the task
19+
20+
useEffect(() => {
21+
const interval = setInterval(() => {
22+
setTimeLeft((prevTime) => (prevTime > 0 ? prevTime - 1 : 0));
23+
}, 1000);
24+
return () => clearInterval(interval);
25+
}, []);
26+
27+
useEffect(() => {
28+
if (timeLeft > 0) {
29+
generateNewTask();
30+
}
31+
}, [timeLeft]);
32+
33+
const generateNewTask = () => {
34+
const word = getRandomElement(words);
35+
const color = getRandomElement(colors);
36+
setCurrentWord(word);
37+
setCurrentColor(color);
38+
};
39+
40+
const handleColorClick = (color: string) => {
41+
if (color === currentColor) {
42+
setScore(score + 1);
43+
}
44+
generateNewTask();
45+
};
46+
47+
return (
48+
<div>
49+
<h1>Stroop Task</h1>
50+
<div>
51+
<h2>Time Left: {timeLeft} seconds</h2>
52+
<h2>Score: {score}</h2>
53+
</div>
54+
{timeLeft > 0 ? (
55+
<div>
56+
<h2 style={{ color: currentColor }}>{currentWord}</h2>
57+
<div>
58+
{colors.map((color) => (
59+
<button
60+
key={color}
61+
style={{ backgroundColor: color, color: 'white', margin: '5px', padding: '10px' }}
62+
onClick={() => handleColorClick(color)}
63+
>
64+
{color.toUpperCase()}
65+
</button>
66+
))}
67+
</div>
68+
</div>
69+
) : (
70+
<h2>Time is up! Your final score is {score}</h2>
71+
)}
72+
</div>
73+
);
74+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core';
2+
import { createRoot } from '/runtime/v1/react-dom@18.x/client.js';
3+
import { z } from '/runtime/v1/zod@3.23.x';
4+
5+
import { StroopTask } from './StroopTask.tsx';
6+
7+
import './styles.css';
8+
9+
export default defineInstrument({
10+
content: {
11+
render(done) {
12+
const rootElement = document.createElement('div');
13+
document.body.appendChild(rootElement);
14+
const root = createRoot(rootElement);
15+
root.render(<StroopTask done={(data) => done(data)} />);
16+
}
17+
},
18+
details: {
19+
description: 'The Stroop Task is a psychological test designed to measure cognitive flexibility and attention.',
20+
estimatedDuration: 1,
21+
instructions: ['Please follow the instructions on the screen.'],
22+
license: 'Apache-2.0',
23+
title: 'Stroop Task'
24+
},
25+
internal: {
26+
edition: 1,
27+
name: 'INTERACTIVE_INSTRUMENT'
28+
},
29+
kind: 'INTERACTIVE',
30+
language: 'en',
31+
measures: {
32+
score: {
33+
kind: 'const',
34+
label: 'Score',
35+
ref: 'score'
36+
}
37+
},
38+
tags: ['Interactive'],
39+
validationSchema: z.object({
40+
score: z.number().int()
41+
})
42+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
body {
2+
background-color: white;
3+
}

0 commit comments

Comments
 (0)