diff --git a/@empirica-mocks/core/mocks.js b/@empirica-mocks/core/mocks.js
index 48412c3..b633cb1 100644
--- a/@empirica-mocks/core/mocks.js
+++ b/@empirica-mocks/core/mocks.js
@@ -80,7 +80,9 @@ export function useStage() {
templatesMap,
setTemplatesMap,
selectedTreatmentIndex,
- setSelectedTreatmentIndex
+ setSelectedTreatmentIndex,
+ refData,
+ setRefData,
} = useContext(StageContext)
// const stage1 = useContext(StageContext);
// console.log("useStageMock", stage1)
@@ -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) {
@@ -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;
}
diff --git a/cypress/fixtures/testTemplates3.yaml b/cypress/fixtures/testTemplates3.yaml
index ccbe19c..b5368c7 100644
--- a/cypress/fixtures/testTemplates3.yaml
+++ b/cypress/fixtures/testTemplates3.yaml
@@ -8,7 +8,6 @@ templates:
file: projects/example/multipleChoiceColors.md
- type: submitButton
buttonText: ${submitButtonText}
-
treatments:
- name: simple template test
@@ -17,4 +16,3 @@ treatments:
- template: testGameStagesTemplate
fields:
submitButtonText: TestButtonTextProceed
-
diff --git a/src/app/editor/components/EditElement.tsx b/src/app/editor/components/EditElement.tsx
index 3dbe6e8..be110da 100644
--- a/src/app/editor/components/EditElement.tsx
+++ b/src/app/editor/components/EditElement.tsx
@@ -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,
@@ -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: [],
diff --git a/src/app/editor/components/ElementCard.tsx b/src/app/editor/components/ElementCard.tsx
index 4a56db9..1333da0 100644
--- a/src/app/editor/components/ElementCard.tsx
+++ b/src/app/editor/components/ElementCard.tsx
@@ -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'
@@ -12,6 +12,7 @@ export function ElementCard({
stageIndex,
elementIndex,
elementOptions,
+ isTemplate,
}: {
element: any
scale: number
@@ -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,
@@ -49,22 +58,25 @@ export function ElementCard({
{Object.keys(element).map((key) => (
- {key}: {element[key]}
+ {key}: {element[key].toString()}
))}
-
+
+ {!isElementTemplate && !isTemplate && (
+
+ )}
diff --git a/src/app/editor/components/ReferenceData.tsx b/src/app/editor/components/ReferenceData.tsx
index 1f27d31..66ff515 100644
--- a/src/app/editor/components/ReferenceData.tsx
+++ b/src/app/editor/components/ReferenceData.tsx
@@ -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) => {
@@ -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)
+ )
}
}
}
@@ -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] = ''
@@ -70,16 +81,18 @@ const ReferenceData = ({ treatment, stageIndex }: ReferenceDataProps) => {
const [jsonData, setJsonData] = useState({})
const [inputValues, setInputValues] = useState({})
+ 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 }))
}
@@ -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))
}
@@ -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) {
diff --git a/src/app/editor/components/StageCard.tsx b/src/app/editor/components/StageCard.tsx
index 2e527fa..d43387e 100644
--- a/src/app/editor/components/StageCard.tsx
+++ b/src/app/editor/components/StageCard.tsx
@@ -13,6 +13,7 @@ import { setCurrentStageIndex } from './utils'
import { useStage } from '../../../../@empirica-mocks/core/mocks'
import { StageContext } from '../stageContext.jsx'
import { Droppable, Draggable, DragDropContext } from '@hello-pangea/dnd'
+import { i } from 'node_modules/@empirica/core/dist/context-302225e8'
export function StageCard({
title,
@@ -22,6 +23,7 @@ export function StageCard({
sequence,
stageIndex,
setRenderPanelStage,
+ isTemplate,
}: {
title: string
elements: any[]
@@ -30,6 +32,7 @@ export function StageCard({
sequence: string
stageIndex: number
setRenderPanelStage: any
+ isTemplate: boolean
}) {
const {
currentStageIndex,
@@ -121,20 +124,22 @@ export function StageCard({
>
{title}
-
+ {!isTemplate && (
+
+ )}
@@ -154,32 +159,49 @@ export function StageCard({
{...provided.droppableProps}
>
{elements !== undefined &&
- elements.map((element, index) => (
-
- {(provided) => (
-
-
-
- )}
-
- ))}
+ elements.map((element, index) =>
+ isTemplate ? (
+
+
+
+ ) : (
+
+ {(provided) => (
+
+
+
+ )}
+
+ )
+ )}
{provided.placeholder}
)}
@@ -187,25 +209,27 @@ export function StageCard({
{/* Add Element Button*/}
-
-
+ {!isTemplate && (
+
+
-
-
-
-
+
+
+
+
+ )}
)
}
diff --git a/src/app/editor/components/Timeline.tsx b/src/app/editor/components/Timeline.tsx
index e203253..8c3f3c2 100644
--- a/src/app/editor/components/Timeline.tsx
+++ b/src/app/editor/components/Timeline.tsx
@@ -226,33 +226,56 @@ export default function Timeline({
ref={provided.innerRef}
className="flex flex-row gap-x-1"
>
- {filterStages(
- treatment?.treatments?.[selectedTreatmentIndex]
- )?.map((obj: any, index: any) => (
-
- {(provided) => (
-
-
-
- )}
-
- ))}
+ {filterStages(treatment?.treatments?.[selectedTreatmentIndex])?.map(
+ (obj: any, index: any) => (
+
+ {(provided) => (
+
+ {obj.stage.name && (
+
+ )}
+ {obj.stage.template && (
+
+ )}
+
+ )}
+
+ )
+ )}
{provided.placeholder}
)}
diff --git a/src/app/editor/stageContext.jsx b/src/app/editor/stageContext.jsx
index 2ef8631..491676c 100644
--- a/src/app/editor/stageContext.jsx
+++ b/src/app/editor/stageContext.jsx
@@ -25,6 +25,7 @@ const StageProvider = ({ children }) => {
const [selectedIntroSequenceIndex, setSelectedIntroSequenceIndex] =
useState(0)
const player = usePlayer()
+ const [refData, setRefData] = useState({})
// for updating code editor, requires reload
const editTreatment = useCallback((newTreatment) => {
@@ -48,6 +49,8 @@ const StageProvider = ({ children }) => {
setSelectedTreatmentIndex,
selectedIntroSequenceIndex,
setSelectedIntroSequenceIndex,
+ refData,
+ setRefData,
}), [
currentStageIndex,
setCurrentStageIndex,
@@ -63,6 +66,8 @@ const StageProvider = ({ children }) => {
setSelectedTreatmentIndex,
selectedIntroSequenceIndex,
setSelectedIntroSequenceIndex,
+ refData,
+ setRefData,
])
// expose context values to the window object