Skip to content

Commit 019790c

Browse files
committed
docs: add mp3 example
1 parent 00c3f18 commit 019790c

10 files changed

Lines changed: 211 additions & 112 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useState } from '/runtime/v1/react@18.x';
2+
3+
import catVideo from './cat-video.mp4';
4+
5+
export const CatVideo: React.FC<{ onNext: (isCorrect: boolean) => void }> = ({ onNext }) => {
6+
const [value, setValue] = useState('');
7+
return (
8+
<div style={{ display: 'flex', flexDirection: 'column', gap: '32px' }}>
9+
<div style={{ display: 'flex', flexDirection: 'column' }}>
10+
<label htmlFor="animal-select">Which Animal Did You See?</label>
11+
<select
12+
id="animal-select"
13+
value={value}
14+
onChange={(event) => {
15+
setValue(event.target.value);
16+
}}
17+
>
18+
<option value="">--Please choose an option--</option>
19+
<option value="dog">Dog</option>
20+
<option value="cat">Cat</option>
21+
<option value="hamster">Hamster</option>
22+
<option value="parrot">Parrot</option>
23+
<option value="cow">Cow</option>
24+
<option value="spider">Spider</option>
25+
<option value="goldfish">Goldfish</option>
26+
</select>
27+
</div>
28+
<video controls>
29+
<source src={catVideo} type="video/mp4" />
30+
</video>
31+
<button disabled={!value} type="button" onClick={() => onNext(value === 'cat')}>
32+
Next
33+
</button>
34+
</div>
35+
);
36+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useState } from '/runtime/v1/react@18.x';
2+
3+
import cowMoo from './cow-moo.mp3';
4+
5+
export const CowAudio: React.FC<{ onNext: (isCorrect: boolean) => void }> = ({ onNext }) => {
6+
const [value, setValue] = useState('');
7+
return (
8+
<div style={{ display: 'flex', flexDirection: 'column', gap: '32px' }}>
9+
<div style={{ display: 'flex', flexDirection: 'column' }}>
10+
<label htmlFor="animal-select">Which Animal Did You Hear?</label>
11+
<select
12+
id="animal-select"
13+
value={value}
14+
onChange={(event) => {
15+
setValue(event.target.value);
16+
}}
17+
>
18+
<option value="">--Please choose an option--</option>
19+
<option value="dog">Dog</option>
20+
<option value="cat">Cat</option>
21+
<option value="hamster">Hamster</option>
22+
<option value="parrot">Parrot</option>
23+
<option value="cow">Cow</option>
24+
<option value="spider">Spider</option>
25+
<option value="goldfish">Goldfish</option>
26+
</select>
27+
</div>
28+
<audio controls>
29+
<source src={cowMoo} type="audio/mpeg" />
30+
</audio>
31+
<button disabled={!value} type="button" onClick={() => onNext(value === 'cow')}>
32+
Next
33+
</button>
34+
</div>
35+
);
36+
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { useEffect, useState } from '/runtime/v1/react@18.x';
2+
import { match } from '/runtime/v1/ts-pattern@5.x';
3+
import { z } from '/runtime/v1/zod@3.23.x';
4+
5+
import { CatVideo } from './CatVideo.tsx';
6+
import { CowAudio } from './CowAudio.tsx';
7+
8+
export const $TaskData = z.object({
9+
identifiedCat: z.boolean(),
10+
identifiedCow: z.boolean(),
11+
seconds: z.number().int().nonnegative()
12+
});
13+
14+
export type TaskData = z.infer<typeof $TaskData>;
15+
16+
export const Task: React.FC<{ done: (data: TaskData) => void }> = ({ done }) => {
17+
const [index, setIndex] = useState<0 | 1 | 2>(0);
18+
const [seconds, setSeconds] = useState(0);
19+
const [identifiedCow, setIdentifiedCow] = useState<boolean>();
20+
21+
useEffect(() => {
22+
if (index === 0) {
23+
return;
24+
}
25+
const interval = setInterval(() => {
26+
setSeconds((seconds) => seconds + 1);
27+
}, 1000);
28+
return () => clearInterval(interval);
29+
}, [index]);
30+
31+
return (
32+
<div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh', padding: '0px 10px' }}>
33+
{index > 0 && <p>Time Elapsed: {seconds}</p>}
34+
<div
35+
style={{
36+
alignItems: 'center',
37+
display: 'flex',
38+
flexDirection: 'column',
39+
flexGrow: 1,
40+
justifyContent: 'center'
41+
}}
42+
>
43+
{match(index)
44+
.with(0, () => (
45+
<>
46+
<h1 style={{ textAlign: 'center' }}>Welcome</h1>
47+
<button
48+
style={{
49+
backgroundColor: 'blue',
50+
border: 'none',
51+
borderRadius: '8px',
52+
color: 'white',
53+
cursor: 'pointer',
54+
padding: '8px 24px'
55+
}}
56+
type="button"
57+
onClick={() => {
58+
setIndex(1);
59+
}}
60+
>
61+
Begin
62+
</button>
63+
</>
64+
))
65+
.with(1, () => (
66+
<CowAudio
67+
onNext={(identifiedCow) => {
68+
setIdentifiedCow(identifiedCow);
69+
setIndex(2);
70+
}}
71+
/>
72+
))
73+
.with(2, () => (
74+
<CatVideo
75+
onNext={(identifiedCat) => {
76+
done({ identifiedCat, identifiedCow: identifiedCow!, seconds });
77+
}}
78+
/>
79+
))
80+
.exhaustive()}
81+
</div>
82+
</div>
83+
);
84+
};

apps/playground/src/instruments/examples/interactive/Interactive-With-Embedded-Video/cat-video.mp4 renamed to apps/playground/src/instruments/examples/interactive/Interactive-With-Embedded-Media/cat-video.mp4

File renamed without changes.
Binary file not shown.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core';
2+
import { createRoot } from '/runtime/v1/react-dom@18.x/client.js';
3+
4+
import { $TaskData, Task } from './Task.tsx';
5+
6+
import './styles.css';
7+
8+
export default defineInstrument({
9+
clientDetails: {
10+
estimatedDuration: 1,
11+
instructions: ['Please follow the instructions on the screen.']
12+
},
13+
content: {
14+
render(done) {
15+
const rootElement = document.createElement('div');
16+
document.body.appendChild(rootElement);
17+
const root = createRoot(rootElement);
18+
root.render(<Task done={done} />);
19+
}
20+
},
21+
details: {
22+
authors: ['Joshua Unrau'],
23+
description: 'This test assesses whether a person can identify various animals',
24+
license: 'Apache-2.0',
25+
title: 'Interactive With Embedded Media'
26+
},
27+
internal: {
28+
edition: 1,
29+
name: 'CAT_VIDEO_TASK'
30+
},
31+
kind: 'INTERACTIVE',
32+
language: 'en',
33+
measures: {
34+
score: {
35+
kind: 'computed',
36+
label: 'Percentage Correct',
37+
value: (data) => {
38+
return Object.values(data).filter(Boolean).length / Object.keys(data).length;
39+
},
40+
visibility: 'visible'
41+
},
42+
seconds: {
43+
kind: 'const',
44+
label: 'Seconds to Complete',
45+
ref: 'seconds',
46+
visibility: 'visible'
47+
}
48+
},
49+
tags: ['Interactive', 'React'],
50+
validationSchema: $TaskData
51+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
body {
2+
margin: 0px;
3+
padding: 0px;
4+
}

apps/playground/src/instruments/examples/interactive/Interactive-With-Embedded-Video/config.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

apps/playground/src/instruments/examples/interactive/Interactive-With-Embedded-Video/index.tsx

Lines changed: 0 additions & 93 deletions
This file was deleted.

apps/playground/src/instruments/examples/interactive/Multilingual-Interactive/translations.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)