Skip to content

Commit

Permalink
manual evan-timeline merge. template and conditional rendering capabi…
Browse files Browse the repository at this point in the history
…lities
  • Loading branch information
evanping committed Feb 21, 2025
1 parent 34e986f commit 08af800
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 166 deletions.
124 changes: 115 additions & 9 deletions @empirica-mocks/core/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export function useStage() {
setTreatment,
templatesMap,
setTemplatesMap,
refData,
setRefData,
selectedTreatmentIndex,
setSelectedTreatmentIndex
} = useContext(StageContext)
Expand All @@ -92,23 +94,127 @@ export function useStage() {

//const treatmentString = localStorage.getItem("treatment");
//const treatment = JSON.parse(treatmentString);
if (varName === "elements") {
let elements = treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.elements;
if (Array.isArray(elements)) {
elements = elements.flatMap((element) => {
if (element.template) {
return templatesMap.get(element.template);
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]];
}
}
return [element];
});
});
}

if (varName === "elements") {
// MAIN ==>
// let elements = treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.elements;
// if (Array.isArray(elements)) {
// elements = elements.flatMap((element) => {
// if (element.template) {
// return templatesMap.get(element.template);
// }
// return [element];
// });
// } else {
// elements = [];
// }
// console.log("revised elements", elements)
// return elements;

var elements
if (tempStage) {
elements = tempStage.elements;
} else {
elements = [];
elements = treatment.treatments[0]?.gameStages[currentStageIndex]?.elements;
}
console.log("revised elements", 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];
});
return elements;
} else if (varName === "discussion") {
if (tempStage) {
return tempStage.discussion || [];
}
return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.discussion;
} else if (varName === "name") {
if (tempStage) {
return tempStage.name;
}
return treatment.treatments[selectedTreatmentIndex]?.gameStages[currentStageIndex]?.name;
} else if (varName === "index") {
return currentStageIndex;
Expand Down
Binary file added cypress/downloads/downloads.html
Binary file not shown.
43 changes: 43 additions & 0 deletions cypress/fixtures/exampleTreatment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
templates:
- templateName: testA
templateContent:
- type: prompt
file: projects/example/multipleChoiceColors.md
- type: submitButton
buttonText: Finish Stage 1
conditions:
- comparator: exists
reference: prompt.Colors
- templateName: testB
templateContent:
- name: GameStageTemplate
duration: 200
elements:
- type: prompt
file: projects/example/multipleChoiceColors.md
- type: submitButton
buttonText: ${submitButtonText}
treatments:
- name: simple template test
playerCount: 1
gameStages:
- name: TestTemplateA
duration: 150
elements:
- template: testA
- name: TestStage
duration: 300
elements:
- name: ExitTicket
type: prompt
file: projects/example/multipleChoiceColors.md
- name: submitButton
type: submitButton
buttonText: Finish Stage 2
conditions:
- comparator: doesNotEqual
reference: prompt.ExitTicket
value: 1
- template: testB
fields:
submitButtonText: Finish Stage 3
2 changes: 1 addition & 1 deletion deliberation-empirica
2 changes: 1 addition & 1 deletion src/app/editor/components/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function CodeEditor() {
async function fetchDefaultTreatment() {
var data = defaultTreatment
if (defaultTreatment) return // If defaultTreatment is already set, do nothing

const response = await fetch('/defaultTreatment.yaml')
const text = await response.text()
data = yaml.load(text)
Expand Down
38 changes: 21 additions & 17 deletions src/app/editor/components/EditElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ export function EditElement({
templatesMap,
setTemplatesMap,
selectedTreatmentIndex,
setSelectedTreatmentIndex
setSelectedTreatmentIndex,
} = useContext(StageContext)

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

const {
register,
watch,
Expand All @@ -35,13 +38,15 @@ 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 Expand Up @@ -90,13 +95,13 @@ export function EditElement({
}

if (elementIndex === -1) {
updatedTreatment?.treatments[selectedTreatmentIndex].gameStages[stageIndex]?.elements?.push(
inputs
)
updatedTreatment?.treatments[selectedTreatmentIndex].gameStages[
stageIndex
]?.elements?.push(inputs)
} else {
updatedTreatment.treatments[selectedTreatmentIndex].gameStages[stageIndex].elements[
elementIndex
] = inputs
updatedTreatment.treatments[selectedTreatmentIndex].gameStages[
stageIndex
].elements[elementIndex] = inputs
}

editTreatment(updatedTreatment)
Expand All @@ -108,10 +113,9 @@ export function EditElement({
)
if (confirm) {
const updatedTreatment = JSON.parse(JSON.stringify(treatment)) // deep copy
updatedTreatment.treatments[selectedTreatmentIndex].gameStages[stageIndex].elements.splice(
elementIndex,
1
) // delete in place
updatedTreatment.treatments[selectedTreatmentIndex].gameStages[
stageIndex
].elements.splice(elementIndex, 1) // delete in place
editTreatment(updatedTreatment)
}
}
Expand Down
52 changes: 34 additions & 18 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,11 +21,20 @@ 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,
setCurrentStageIndex,
Expand All @@ -47,24 +57,30 @@ export function ElementCard({
tabIndex={0}
>
<div>
{Object.keys(element).map((key) => (
<p key={key}>
{key}: {element[key]}
</p>
))}
{Object.keys(element).map((key) => {
const value = element[key]
return (
<p key={key}>
{key}: {typeof value === 'object' ? JSON.stringify(value) : value}
</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
Loading

0 comments on commit 08af800

Please sign in to comment.