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

Template treatment functionality (stages + fields), conditions #111

Closed
wants to merge 10 commits into from
107 changes: 102 additions & 5 deletions @empirica-mocks/core/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ export function useStage() {
templatesMap,
setTemplatesMap,
selectedTreatmentIndex,
setSelectedTreatmentIndex
setSelectedTreatmentIndex,
refData,
setRefData,
} = useContext(StageContext)
// const stage1 = useContext(StageContext);
// console.log("useStageMock", stage1)
Expand All @@ -92,8 +94,46 @@ export function useStage() {

//const treatmentString = localStorage.getItem("treatment");
//const treatment = JSON.parse(treatmentString);
var tempStage = null; // for template stages
const stageTemplateName = treatment.treatments[0]?.gameStages[currentStageIndex]?.template || "";
var fields = treatment.treatments[0]?.gameStages[currentStageIndex]?.fields || [];
if (stageTemplateName !== "") {
tempStage = templatesMap.get(stageTemplateName)[0]
}
console.log("tempStage", tempStage);

//logic to fill in ${} props
// move logic outside get()
const variablePattern = /\${([^}]+)}/;
{tempStage &&
tempStage.elements.forEach(element => {
Object.keys(element).forEach(key => {
const value = element[key];

if (typeof value === "string" && variablePattern.test(value)) {
const match = value.match(variablePattern);
if (match) {
console.log("replaced " + match[1] + " with " + fields[match[1]]);
element[key] = fields[match[1]];
}
}
});
});
}


if (varName === "elements") {
let elements = treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.elements;
var elements
if (tempStage) {
elements = tempStage.elements;
} else {
elements = treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.elements;
}

console.log("CURRELEMENTS", elements)

// TODO: change to template if needed
// map to templates first
if (Array.isArray(elements)) {
elements = elements.flatMap((element) => {
if (element.template) {
Expand All @@ -104,12 +144,69 @@ export function useStage() {
} else {
elements = [];
}
console.log("revised elements", elements)

//console.log("ELEMENTS_TO_DISPLAY", elements)
// check all conditions
elements = elements.flatMap((element) => {
if (element.conditions) {
// TODO: update with other comparators
const conditions = element.conditions;
const comparator = conditions[0]?.comparator || "x";
const reference = conditions[0]?.reference || "x";
const value = conditions[0]?.value || "x";
if (comparator === "x") {
return [element];
} else if (comparator === "exists") {
if (refData[`stage_${currentStageIndex}`]?.[reference]) {
const newElement = {...element};
delete newElement.conditions;
return [newElement];
} else {
return [];
}
} else if (comparator === "equals") {
if (refData[`stage_${currentStageIndex}`]?.[reference] == value) {
const newElement = {...element};
delete newElement.conditions;
return [newElement];
} else {
return [];
}
} else if (comparator === "doesNotEqual") {
if (refData[`stage_${currentStageIndex}`]?.[reference] != value) {
const newElement = {...element};
delete newElement.conditions;
return [newElement];
} else {
return [];
}
}

const condition = conditions.find((condition) => {
if (condition.field) {
return fields[condition.field] === condition.value;
}
return true;
});
if (condition) {
return [element];
}
}
return [element];
});
return elements;
} else if (varName === "discussion") {
return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.discussion;
if (tempStage) {
return tempStage.discussion || [];
}

return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.discussion || [];
} else if (varName === "name") {
return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.name;
if (tempStage) {
return tempStage.name;
}
return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.name

} else if (varName === "index") {
return currentStageIndex;
}
Expand Down
2 changes: 0 additions & 2 deletions cypress/fixtures/testTemplates3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ templates:
file: projects/example/multipleChoiceColors.md
- type: submitButton
buttonText: ${submitButtonText}


treatments:
- name: simple template test
Expand All @@ -17,4 +16,3 @@ treatments:
- template: testGameStagesTemplate
fields:
submitButtonText: TestButtonTextProceed

23 changes: 17 additions & 6 deletions src/app/editor/components/EditElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export function EditElement({
setSelectedTreatmentIndex
} = useContext(StageContext)

const stageTemplateName =
treatment.treatments[0]?.gameStages[currentStageIndex]?.template || ''

console.log("stageTemplateName == ''", stageTemplateName == '')
console.log('stageIndex', stageIndex)
console.log('elementIndex', elementIndex)

const {
register,
watch,
Expand All @@ -35,13 +42,17 @@ export function EditElement({
} = useForm({
defaultValues: {
name:
treatment?.treatments?.[selectedTreatmentIndex].gameStages[stageIndex]?.elements[
elementIndex
]?.name || '',
stageTemplateName == ''
? treatment?.treatments?.[selectedTreatmentIndex].gameStages[stageIndex]?.elements?.[
elementIndex
]?.name || ''
: '',
selectedOption:
treatment?.treatments?.[selectedTreatmentIndex].gameStages[stageIndex]?.elements[
elementIndex
]?.type || 'Pick one',
stageTemplateName == ''
? treatment?.treatments?.[selectedTreatmentIndex].gameStages[stageIndex]?.elements?.[
elementIndex
]?.type || 'Pick one'
: 'Pick one',
file: '',
url: '',
params: [],
Expand Down
40 changes: 26 additions & 14 deletions src/app/editor/components/ElementCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useContext } from 'react'
import React, { useState, useContext, useEffect } from 'react'
import { Modal } from './Modal'
import { EditElement } from './EditElement'
import { TreatmentType } from '../../../../deliberation-empirica/server/src/preFlight/validateTreatmentFile'
Expand All @@ -12,6 +12,7 @@ export function ElementCard({
stageIndex,
elementIndex,
elementOptions,
isTemplate,
}: {
element: any
scale: number
Expand All @@ -20,10 +21,18 @@ export function ElementCard({
stageIndex: number
elementIndex: number
elementOptions: any
isTemplate: boolean
}) {
const startTime = element.displayTime || 0
const endTime = element.hideTime || stageDuration
const [modalOpen, setModalOpen] = useState(false)
const [isElementTemplate, setIsElementTemplate] = useState(false)

useEffect(() => {
if (element.template) {
setIsElementTemplate(true)
}
}, [element])

const {
currentStageIndex,
Expand All @@ -49,22 +58,25 @@ export function ElementCard({
<div>
{Object.keys(element).map((key) => (
<p key={key}>
{key}: {element[key]}
{key}: {element[key].toString()}
</p>
))}
</div>
<button
data-cy={'edit-element-button-' + stageIndex + '-' + elementIndex}
className="btn h-5 flex bg-gray-300"
style={{ minHeight: 'unset' }}
onClick={() =>
(
document.getElementById(editModalId) as HTMLDialogElement | null
)?.showModal()
}
>
Edit
</button>

{!isElementTemplate && !isTemplate && (
<button
data-cy={'edit-element-button-' + stageIndex + '-' + elementIndex}
className="btn h-5 flex bg-gray-300"
style={{ minHeight: 'unset' }}
onClick={() =>
(
document.getElementById(editModalId) as HTMLDialogElement | null
)?.showModal()
}
>
Edit
</button>
)}

<Modal id={editModalId}>
<EditElement stageIndex={stageIndex} elementIndex={elementIndex} />
Expand Down
29 changes: 22 additions & 7 deletions src/app/editor/components/ReferenceData.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useState, useContext } from 'react'
import { StageContext } from '@/editor/stageContext'

// helper to format references
const formatReference = (reference: string) => {
Expand All @@ -15,15 +16,25 @@ const getPlaceholderText = (reference: string) => {
}

// find 'references' in the treatment object by stage (recursively..hopefully runtime not too bad)
const findReferencesByStage = (obj: any): any[] => {
const findReferencesByStage = (obj: any, templatesMap: any): any[] => {
let references: any[] = []

if (typeof obj === 'object' && obj !== null) {
for (const key in obj) {
if (key === 'reference') {
references.push(obj[key])
} else if (key === 'template') {
const templateReferences = templatesMap
.get(obj[key])
.flatMap((templateElement: any) =>
findReferencesByStage(templateElement, templatesMap)
)

references = references.concat(templateReferences)
} else if (typeof obj[key] === 'object') {
references = references.concat(findReferencesByStage(obj[key]))
references = references.concat(
findReferencesByStage(obj[key], templatesMap)
)
}
}
}
Expand All @@ -32,10 +43,10 @@ const findReferencesByStage = (obj: any): any[] => {
}

// initializing json data for each stage
const initializeJsonData = (treatment: any) => {
const initializeJsonData = (treatment: any, templatesMap: any) => {
const jsonData: { [key: string]: any } = {}
treatment?.gameStages?.forEach((stage: any, index: number) => {
const references = findReferencesByStage(stage)
const references = findReferencesByStage(stage, templatesMap)
jsonData[`stage_${index}`] = {}
references.forEach((reference) => {
jsonData[`stage_${index}`][reference] = ''
Expand Down Expand Up @@ -70,16 +81,18 @@ const ReferenceData = ({ treatment, stageIndex }: ReferenceDataProps) => {
const [jsonData, setJsonData] = useState<JsonData>({})
const [inputValues, setInputValues] = useState<InputValues>({})

const { refData, setRefData, templatesMap } = useContext(StageContext)

// load refs for curr stage
useEffect(() => {
if (treatment?.gameStages?.[stageIndex]) {
const stage = treatment.gameStages[stageIndex]
const allReferences = findReferencesByStage(stage)
const allReferences = findReferencesByStage(stage, templatesMap)
setReferences(allReferences)

// load json data for curr stage
if (!jsonData[`stage_${stageIndex}`]) {
const initializedJson = initializeJsonData(treatment)
const initializedJson = initializeJsonData(treatment, templatesMap)
setJsonData((prev) => ({ ...prev, ...initializedJson }))
}

Expand Down Expand Up @@ -123,6 +136,7 @@ const ReferenceData = ({ treatment, stageIndex }: ReferenceDataProps) => {
[`stage_${stageIndex}`]: inputValues[`stage_${stageIndex}`],
}
setJsonData(updatedJson)
setRefData(updatedJson)
localStorage.setItem('jsonData', JSON.stringify(updatedJson))
console.log('Saved JSON Data:', JSON.stringify(updatedJson, null, 2))
}
Expand All @@ -134,6 +148,7 @@ const ReferenceData = ({ treatment, stageIndex }: ReferenceDataProps) => {
if (savedJson) {
console.log('Loaded JSON Data from localStorage:', JSON.parse(savedJson))
setJsonData(JSON.parse(savedJson))
setRefData(JSON.parse(savedJson))
}

if (savedInputValues) {
Expand Down
Loading
Loading