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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
106 changes: 102 additions & 4 deletions @empirica-mocks/core/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export function useStage() {
setTreatment,
templatesMap,
setTemplatesMap,
refData,
setRefData,
} = useContext(StageContext)
// const stage1 = useContext(StageContext);
// console.log("useStageMock", stage1)
Expand All @@ -80,20 +82,116 @@ 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") {
var elements = treatment.treatments[0]?.gameStages[currentStageIndex]?.elements
elements = elements.flatMap((element) => {
var elements
if (tempStage) {
elements = tempStage.elements;
} else {
elements = treatment.treatments[0]?.gameStages[currentStageIndex]?.elements;
}

console.log("CURRELEMENTS", elements)

// TODO: change to template if needed
// map to templates first
elements = elements.flatMap((element) => {
if (element.template) {
return templatesMap.get(element.template);
} else {
return element;
}
})

//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];
});
console.log("revised elements", elements)
return elements;
} else if (varName === "discussion") {
return treatment.treatments[0]?.gameStages[currentStageIndex]?.discussion
if (tempStage) {
return tempStage.discussion || [];
}

return treatment.treatments[0]?.gameStages[currentStageIndex]?.discussion || [];
} else if (varName === "name") {
if (tempStage) {
return tempStage.name;
}
return treatment.treatments[0]?.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 @@ -24,6 +24,13 @@ export function EditElement({
setTemplatesMap,
} = 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 @@ -33,13 +40,17 @@ export function EditElement({
} = useForm({
defaultValues: {
name:
treatment?.treatments?.[0].gameStages[stageIndex]?.elements[
elementIndex
]?.name || '',
stageTemplateName == ''
? treatment?.treatments[0].gameStages[stageIndex]?.elements?.[
elementIndex
]?.name || ''
: '',
selectedOption:
treatment?.treatments?.[0].gameStages[stageIndex]?.elements[
elementIndex
]?.type || 'Pick one',
stageTemplateName == ''
? treatment?.treatments[0].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 @@ -47,22 +56,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