Skip to content

Commit fe91ec0

Browse files
committed
feat: add survey js support
1 parent 0e73838 commit fe91ec0

4 files changed

Lines changed: 502 additions & 2 deletions

File tree

‎lib/socho/studies/js_generator.ex‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ defmodule Socho.Studies.JsGenerator do
66
@jspsych_base "/vendor/jspsych"
77
@custom_base "/vendor/custom"
88

9-
def required_stylesheets(_study) do
10-
["#{@jspsych_base}/jspsych.css"]
9+
def required_stylesheets(study) do
10+
survey_css =
11+
if "survey" in collect_plugins(study.trials),
12+
do: ["#{@jspsych_base}/survey.css"],
13+
else: []
14+
15+
["#{@jspsych_base}/jspsych.css"] ++ survey_css
1116
end
1217

1318
def required_inline_css(study) do

‎lib/socho_web/live/study_live/builder.ex‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ defmodule SochoWeb.StudyLive.Builder do
55
alias Socho.Studies
66
alias Socho.Studies.Registry
77
alias Socho.Studies.Templates
8+
alias SochoWeb.StudyLive.SurveyBuilderComponent
89

910
# ── Mount ──────────────────────────────────────────────────────────────────
1011

@@ -140,6 +141,17 @@ defmodule SochoWeb.StudyLive.Builder do
140141
{:noreply, assign(socket, trials: move_node_in_tree(socket.assigns.trials, id, :down))}
141142
end
142143

144+
@impl true
145+
def handle_info({:survey_builder_update, survey_json}, socket) do
146+
with id when not is_nil(id) <- socket.assigns.selected_trial_id,
147+
node when not is_nil(node) <- find_node(socket.assigns.trials, id) do
148+
new_config = Map.put(node.config, "survey_json", survey_json)
149+
{:noreply, assign(socket, trials: update_node_config(socket.assigns.trials, id, new_config))}
150+
else
151+
_ -> {:noreply, socket}
152+
end
153+
end
154+
143155
def handle_event("config_changed", %{"config" => params}, socket) do
144156
with id when not is_nil(id) <- socket.assigns.selected_trial_id,
145157
node when not is_nil(node) <- find_node(socket.assigns.trials, id) do
@@ -473,6 +485,7 @@ defmodule SochoWeb.StudyLive.Builder do
473485
cond do
474486
spec["type"] == "COMPLEX" and spec["array"] -> []
475487
spec["type"] == "COMPLEX" -> %{}
488+
spec["type"] == "OBJECT" -> %{}
476489
spec["type"] == "BOOL" -> spec["default"] || false
477490
spec["default"] != nil -> to_string(spec["default"])
478491
true -> ""
@@ -503,6 +516,17 @@ defmodule SochoWeb.StudyLive.Builder do
503516
"BOOL" ->
504517
val == "true"
505518

519+
"OBJECT" ->
520+
case val do
521+
val when is_map(val) -> val
522+
val when is_binary(val) ->
523+
case Jason.decode(val) do
524+
{:ok, map} when is_map(map) -> map
525+
_ -> %{}
526+
end
527+
_ -> %{}
528+
end
529+
506530
"COMPLEX" ->
507531
if spec["array"] and is_map(val) do
508532
nested_params = spec["nested"] || %{}
@@ -535,6 +559,7 @@ defmodule SochoWeb.StudyLive.Builder do
535559
defp input_kind(%{"type" => "FLOAT"}), do: :number
536560
defp input_kind(%{"type" => "HTML_STRING"}), do: :html
537561
defp input_kind(%{"type" => "COMPLEX", "array" => true}), do: :complex_array
562+
defp input_kind(%{"type" => "OBJECT"}), do: :json
538563
defp input_kind(%{"type" => "FUNCTION"}), do: :skip
539564
defp input_kind(%{"type" => "TIMELINE"}), do: :skip
540565
defp input_kind(_), do: :text
@@ -1480,6 +1505,53 @@ defmodule SochoWeb.StudyLive.Builder do
14801505
"""
14811506
end
14821507

1508+
defp param_field(%{kind: :json, param: "survey_json"} = assigns) do
1509+
field_name = "#{assigns.prefix}[#{assigns.param}]"
1510+
assigns = assign(assigns, field_name: field_name)
1511+
1512+
~H"""
1513+
<div class="form-control">
1514+
<label class="label py-1">
1515+
<span class="label-text">survey_json</span>
1516+
<span class="label-text-alt opacity-50">Survey builder</span>
1517+
</label>
1518+
<.live_component
1519+
module={SurveyBuilderComponent}
1520+
id={"survey-builder-#{@prefix}"}
1521+
value={@value}
1522+
field_name={@field_name}
1523+
/>
1524+
</div>
1525+
"""
1526+
end
1527+
1528+
defp param_field(%{kind: :json} = assigns) do
1529+
json_value =
1530+
case assigns.value do
1531+
nil -> ""
1532+
"" -> ""
1533+
val when is_map(val) -> Jason.encode!(val, pretty: true)
1534+
val when is_binary(val) -> val
1535+
end
1536+
1537+
assigns = assign(assigns, json_value: json_value)
1538+
1539+
~H"""
1540+
<div class="form-control">
1541+
<label class="label py-1">
1542+
<span class="label-text">{@param}</span>
1543+
<span class="label-text-alt opacity-50">JSON</span>
1544+
</label>
1545+
<textarea
1546+
class="textarea textarea-bordered textarea-sm font-mono text-xs"
1547+
name={"#{@prefix}[#{@param}]"}
1548+
rows="10"
1549+
placeholder={"{\n \"elements\": []\n}"}
1550+
>{@json_value}</textarea>
1551+
</div>
1552+
"""
1553+
end
1554+
14831555
defp param_field(assigns) do
14841556
display_value =
14851557
cond do

0 commit comments

Comments
 (0)