Skip to content

Commit

Permalink
"end page changed for the failed training"
Browse files Browse the repository at this point in the history
  • Loading branch information
elizaan committed Aug 26, 2024
2 parents eade378 + f159645 commit 1e647c6
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 158 deletions.
30 changes: 17 additions & 13 deletions public/test-parser-errors/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,30 @@
"components": [
"nestedMissingComponent"
],
"skip": [{
"check": "block",
"condition": "numCorrect",
"value": 1,
"to": "md1"
}]
"skip": [
{
"check": "block",
"condition": "numCorrect",
"value": 1,
"to": "md1"
}
]
},
{
"order": "fixed",
"components": [
"md2"
],
"skip": [{
"check": "block",
"condition": "numCorrect",
"value": 1,
"to": "md2"
}]
"skip": [
{
"check": "block",
"condition": "numCorrect",
"value": 1,
"to": "md2"
}
]
},
"md2"
]
}
}
}
14 changes: 6 additions & 8 deletions public/test-skip-logic/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "file:///Users/jwilburn/projects/revisit-study/src/parser/StudyConfigSchema.json",
"$schema": "https://raw.githubusercontent.com/revisit-studies/study/v1.0.2/src/parser/StudyConfigSchema.json",
"studyMetadata": {
"title": "Using Skip Logic",
"description": "This is a test study to check the functionality of the reVISit' skip logic. This study is not meant to be used for any real data collection.",
Expand Down Expand Up @@ -30,15 +30,16 @@
"prompt": "What is your favorite color?",
"location": "belowStimulus",
"required": true,
"options": [{"label": "Blue", "value": "Blue"}, {"label": "Red", "value": "Red"}, {"label": "Green", "value": "Green"}, {"label": "Yellow", "value": "Yellow"}]
"options": ["Blue", "Red", "Green", "Yellow"]
},
{
"id": "q2",
"type": "radio",
"prompt": "What is your favorite animal?",
"location": "belowStimulus",
"required": true,
"options": [{"label": "Dog", "value": "dog"}, {"label": "Cat", "value": "cat"}, {"label": "Bird", "value": "bird"}, {"label": "Fish", "value": "fish"}]}
"options": ["Dog", "Cat", "Bird", "Fish"]
}
],
"nextButtonLocation": "belowStimulus",
"instruction": "Please answer the following questions...",
Expand All @@ -55,7 +56,7 @@
},
{
"id": "q2",
"answer": "cat"
"answer": "Cat"
}
]
},
Expand All @@ -69,10 +70,7 @@
"prompt": "Are you paying attention?",
"location": "belowStimulus",
"required": true,
"options": [
{"label": "Yes", "value": "Yes"},
{"label": "No", "value": "No"}
]
"options": ["Yes", "No"]
}
],
"correctAnswer": [
Expand Down
6 changes: 5 additions & 1 deletion src/analysis/individualStudy/stats/AnswerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ export default function AnswerPanel({ data, config }: { data: Record<string, Rec
}
}

const categoryData:{option:string, count:number, correct:boolean}[] = (response as RadioResponse).options.map((op) => ({
const categoryData: { option: string, count: number, correct: boolean }[] = (response as RadioResponse).options.map((op) => (typeof op === 'string' ? {
option: op,
count: map.get(op as string) || 0,
correct: op === correctAnswer.find((ans) => ans.id === id)?.answer,
} : {
option: op.value as string,
count: map.get(op.value as string) || 0,
correct: op.value === correctAnswer.find((ans) => ans.id === id)?.answer,
Expand Down
6 changes: 4 additions & 2 deletions src/components/response/CheckBoxInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export default function CheckBoxInput({
secondaryText,
} = response;

const optionsAsStringOptions = options.map((option) => (typeof option === 'string' ? { value: option, label: option } : option));

return (
<Checkbox.Group
label={(
Expand All @@ -37,11 +39,11 @@ export default function CheckBoxInput({
)}
description={secondaryText}
{...answer}
error={generateErrorMessage(response, answer, options)}
error={generateErrorMessage(response, answer, optionsAsStringOptions)}
style={{ '--input-description-size': 'calc(var(--mantine-font-size-md) - calc(0.125rem * var(--mantine-scale)))' }}
>
<Group mt="xs">
{options.map((option) => (
{optionsAsStringOptions.map((option) => (
<Checkbox
key={option.value}
disabled={disabled}
Expand Down
6 changes: 4 additions & 2 deletions src/components/response/DropdownInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export default function DropdownInput({
secondaryText,
} = response;

const optionsAsStringOptions = options.map((option) => (typeof option === 'string' ? { value: option, label: option } : option));

return (
<Select
disabled={disabled}
Expand All @@ -39,11 +41,11 @@ export default function DropdownInput({
)}
description={secondaryText}
placeholder={placeholder}
data={options}
data={optionsAsStringOptions}
radius="md"
size="md"
{...answer}
error={generateErrorMessage(response, answer, options)}
error={generateErrorMessage(response, answer, optionsAsStringOptions)}
/>
);
}
6 changes: 4 additions & 2 deletions src/components/response/RadioInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export default function RadioInput({
secondaryText,
} = response;

const optionsAsStringOptions = options.map((option) => (typeof option === 'string' ? { value: option, label: option } : option));

return (
<Radio.Group
name={`radioInput${response.id}`}
Expand All @@ -42,12 +44,12 @@ export default function RadioInput({
key={response.id}
{...answer}
// This overrides the answers error. Which..is bad?
error={generateErrorMessage(response, answer, options)}
error={generateErrorMessage(response, answer, optionsAsStringOptions)}
style={{ '--input-description-size': 'calc(var(--mantine-font-size-md) - calc(0.125rem * var(--mantine-scale)))' }}
>
<Group mt="xs">
{leftLabel ? <Text style={{ textAlign: 'center' }}>{leftLabel}</Text> : null}
{options.map((radio) => (
{optionsAsStringOptions.map((radio) => (
<Radio
disabled={disabled}
value={radio.value}
Expand Down
2 changes: 1 addition & 1 deletion src/components/response/ResponseBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export default function ResponseBlock({
} else {
let message = '';
if (newAttemptsUsed >= trainingAttempts) {
message = `You've didn't answer this question correctly after ${trainingAttempts} attempts. ${allowFailedTraining ? 'You can continue to the next question.' : 'Unfortunately you have not met the criteria for continuing this study.'}`;
message = `You didn't answer this question correctly after ${trainingAttempts} attempts. ${allowFailedTraining ? 'You can continue to the next question.' : 'Unfortunately you have not met the criteria for continuing this study.'}`;

// If the user has failed the training, wait 5 seconds and redirect to a fail page
if (!allowFailedTraining) {
Expand Down
37 changes: 29 additions & 8 deletions src/parser/StudyConfigSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,12 @@
},
"type": "object"
},
"description": "The baseComponents is an optional set of components which can help template other components. For example, suppose you have a single HTML file that you want to display to the user several times. Instead of having the same component twice in the `components` list, you can have a single baseComponent with all the information that the two HTML components will share. A great example is showing the same HTML component but with two different questions;\n\n Using baseComponents:\n\n```js \"baseComponents\": { \"my-image-component\": { \"instructionLocation\": \"sidebar\", \"nextButtonLocation\": \"sidebar\", \"path\": \"<study-name>/assets/my-image.jpg\", \"response\": [ { \"id\": \"my-image-id\", \"options\": [ { \"label\": \"Europe\", \"value\": \"Europe\" }, { \"label\": \"Japan\", \"value\": \"Japan\" }, { \"label\": \"USA\", \"value\": \"USA\" } ], \"prompt\": \"Your Selected Answer:\", \"type\": \"dropdown\" } ], \"type\": \"image\" } } ``` In the above code snippet, we have a single base component which holds the information about the type of component, the path to the image, and the response (which is a dropdown containing three choices). Any component which contains the `\"baseComponent\":\"my-image-component\"` key-value pair will inherit each of these properties. Thus, if we have three different questions which have the same choices and are concerning the same image, we can define our components like below: ```js \"components\": { \"q1\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with largest GDP\", \"instruction\": \"Which region has the largest GDP?\" }, \"q2\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with lowest GDP\", \"instruction\": \"Which region has the lowest GDP?\" }, \"q3\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with highest exports of Wheat\", \"instruction\": \"Which region had the most Wheat exported in 2022?\" } } ```",
"description": "The baseComponents is an optional set of components which can help template other components. For example, suppose you have a single HTML file that you want to display to the user several times. Instead of having the same component twice in the `components` list, you can have a single baseComponent with all the information that the two HTML components will share. A great example is showing the same HTML component but with two different questions;\n\n Using baseComponents:\n\n```js \"baseComponents\": { \"my-image-component\": { \"instructionLocation\": \"sidebar\", \"nextButtonLocation\": \"sidebar\", \"path\": \"<study-name>/assets/my-image.jpg\", \"response\": [ { \"id\": \"my-image-id\", \"options\": [\"Europe\", \"Japan\", \"USA\"], \"prompt\": \"Your Selected Answer:\", \"type\": \"dropdown\" } ], \"type\": \"image\" } } ``` In the above code snippet, we have a single base component which holds the information about the type of component, the path to the image, and the response (which is a dropdown containing three choices). Any component which contains the `\"baseComponent\":\"my-image-component\"` key-value pair will inherit each of these properties. Thus, if we have three different questions which have the same choices and are concerning the same image, we can define our components like below: ```js \"components\": { \"q1\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with largest GDP\", \"instruction\": \"Which region has the largest GDP?\" }, \"q2\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with lowest GDP\", \"instruction\": \"Which region has the lowest GDP?\" }, \"q3\": { \"baseComponent\": \"my-image-component\", \"description\": \"Choosing section with highest exports of Wheat\", \"instruction\": \"Which region had the most Wheat exported in 2022?\" } } ```",
"type": "object"
},
"CheckboxResponse": {
"additionalProperties": false,
"description": "The CheckboxResponse interface is used to define the properties of a checkbox response. CheckboxResponses render as a checkbox input with user specified options.\n\n```js { \"id\": \"q7\", \"prompt\": \"Checkbox example (not required)\", \"required\": false, \"location\": \"aboveStimulus\", \"type\": \"checkbox\", \"options\": [ { \"label\": \"Option 1\", \"value\": \"opt-1\" }, { \"label\": \"Option 2\", \"value\": \"opt-2\" }, { \"label\": \"Option 3\", \"value\": \"opt-3\" } ] } ```",
"description": "The CheckboxResponse interface is used to define the properties of a checkbox response. CheckboxResponses render as a checkbox input with user specified options.\n\n```js { \"id\": \"q7\", \"prompt\": \"Checkbox example (not required)\", \"required\": false, \"location\": \"aboveStimulus\", \"type\": \"checkbox\", \"options\": [\"Option 1\", \"Option 2\", \"Option 3\"] } ```",
"properties": {
"hidden": {
"description": "Controls whether the response is hidden.",
Expand All @@ -169,7 +169,14 @@
"options": {
"description": "The options that are displayed as checkboxes, provided as an array of objects, with label and value fields.",
"items": {
"$ref": "#/definitions/StringOption"
"anyOf": [
{
"$ref": "#/definitions/StringOption"
},
{
"type": "string"
}
]
},
"type": "array"
},
Expand Down Expand Up @@ -326,7 +333,7 @@
},
"DropdownResponse": {
"additionalProperties": false,
"description": "The DropdownResponse interface is used to define the properties of a dropdown response. DropdownResponses render as a select input with user specified options.\n\nExample: ```js { \"id\": \"q-color\", \"prompt\": \"What is your favorite color?\", \"required\": true, \"location\": \"aboveStimulus\", \"type\": \"dropdown\", \"placeholder\": \"Please choose your favorite color\", \"options\": [ { \"label\": \"Red\", \"value\": \"red\" }, { \"label\": \"Blue\", \"value\": \"blue\" } ] } ```",
"description": "The DropdownResponse interface is used to define the properties of a dropdown response. DropdownResponses render as a select input with user specified options.\n\nExample: ```js { \"id\": \"q-color\", \"prompt\": \"What is your favorite color?\", \"required\": true, \"location\": \"aboveStimulus\", \"type\": \"dropdown\", \"placeholder\": \"Please choose your favorite color\", \"options\": [\"Red\", \"Blue\"] } ```",
"properties": {
"hidden": {
"description": "Controls whether the response is hidden.",
Expand All @@ -343,7 +350,14 @@
"options": {
"description": "The options that are displayed in the dropdown.",
"items": {
"$ref": "#/definitions/StringOption"
"anyOf": [
{
"$ref": "#/definitions/StringOption"
},
{
"type": "string"
}
]
},
"type": "array"
},
Expand Down Expand Up @@ -1018,7 +1032,7 @@
},
"QuestionnaireComponent": {
"additionalProperties": false,
"description": "A QuestionnaireComponent is used to render simple questions that require a response. The main use case of this component type is to ask participants questions when you don't need to render a stimulus. Please note, that even though we're not using a stimulus, the responses still require a `location`. For example this could be used to collect demographic information from a participant using the following snippet:\n\n```js { \"type\": \"questionnaire\", \"response\": [ { \"id\": \"gender\", \"prompt\": \"Gender:\", \"required\": true, \"location\": \"belowStimulus\", \"type\": \"checkbox\", \"options\": [ { \"label\": \"Man\", \"value\": \"Man\" }, { \"label\": \"Woman\", \"value\": \"Woman\" }, { \"label\": \"Genderqueer\", \"value\": \"Genderqueer\" }, { \"label\": \"Third-gender\", \"value\": \"Third-gender\" }, ... etc. ] } ] } ```",
"description": "A QuestionnaireComponent is used to render simple questions that require a response. The main use case of this component type is to ask participants questions when you don't need to render a stimulus. Please note, that even though we're not using a stimulus, the responses still require a `location`. For example this could be used to collect demographic information from a participant using the following snippet:\n\n```js { \"type\": \"questionnaire\", \"response\": [ { \"id\": \"gender\", \"prompt\": \"Gender:\", \"required\": true, \"location\": \"belowStimulus\", \"type\": \"checkbox\", \"options\": [\"Man\", \"Woman\", \"Genderqueer\", \"Third-gender\", ...] } ] } ```",
"properties": {
"allowFailedTraining": {
"description": "Controls whether the component should allow failed training. If not provided, the default is true.",
Expand Down Expand Up @@ -1084,7 +1098,7 @@
},
"RadioResponse": {
"additionalProperties": false,
"description": "The RadioResponse interface is used to define the properties of a radio response. Radios have only one allowable selection. RadioResponses render as a radio input with user specified options, and optionally left and right labels.\n\nExample: ```js { \"id\": \"q-radio\", \"prompt\": \"Radio button example\", \"required\": true, \"location\": \"aboveStimulus\", \"type\": \"radio\", \"options\": [ { \"label\": \"Option 1\", \"value\": \"opt-1\" }, { \"label\": \"Option 2\", \"value\": \"opt-2\" } ] } ```",
"description": "The RadioResponse interface is used to define the properties of a radio response. Radios have only one allowable selection. RadioResponses render as a radio input with user specified options, and optionally left and right labels.\n\nExample: ```js { \"id\": \"q-radio\", \"prompt\": \"Radio button example\", \"required\": true, \"location\": \"aboveStimulus\", \"type\": \"radio\", \"options\": [\"Option 1\", \"Option 2\"] } ```",
"properties": {
"hidden": {
"description": "Controls whether the response is hidden.",
Expand All @@ -1105,7 +1119,14 @@
"options": {
"description": "The options that are displayed as checkboxes, provided as an array of objects, with label and value fields.",
"items": {
"$ref": "#/definitions/StringOption"
"anyOf": [
{
"$ref": "#/definitions/StringOption"
},
{
"type": "string"
}
]
},
"type": "array"
},
Expand Down
Loading

0 comments on commit 1e647c6

Please sign in to comment.