Skip to content

Commit 8335bd0

Browse files
committed
Nevermind.
1 parent 072a3ba commit 8335bd0

3 files changed

Lines changed: 27 additions & 104 deletions

File tree

demo/lib/demo_web/live/odyssey_showcase_live.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,10 @@ defmodule DemoWeb.OdysseyShowcaseLive do
645645

646646
defp sample_products do
647647
[
648-
%{id: "prod_1", name: "Wine Tasting", color_hex: "#8B5CF6"},
649-
%{id: "prod_2", name: "Cooking Class", color_hex: "#F59E0B"},
650-
%{id: "prod_3", name: "City Tour", color_hex: "#10B981"},
651-
%{id: "prod_4", name: "Sunset Cruise", color_hex: "#3B82F6"}
648+
%{id: "prod_1", name: "Wine Tasting", color: "#8B5CF6"},
649+
%{id: "prod_2", name: "Cooking Class", color: "#F59E0B"},
650+
%{id: "prod_3", name: "City Tour", color: "#10B981"},
651+
%{id: "prod_4", name: "Sunset Cruise", color: "#3B82F6"}
652652
]
653653
end
654654

lib/peek_app_sdk/ui/odyssey/product_picker.ex

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,18 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPicker do
55
66
Integrates with forms via a hidden input field and a JS hook.
77
8+
Products must conform to `%{id: string, name: string, color: string}` (atom keys).
9+
Callers are responsible for mapping their data to this shape before passing it in.
10+
811
When `selected_ids` is not provided, the component automatically extracts IDs
912
from the form field's value. It handles lists of structs/maps with an `:id` or
1013
`"id"` key, as well as `Ecto.Changeset` structs (via `get_change(:id)`).
1114
1215
## Examples
1316
14-
# Auto-extract selected_ids from field value:
1517
<.odyssey_product_picker
1618
field={@form[:whitelisted_products]}
17-
products={@products}
18-
/>
19-
20-
# Or pass them explicitly:
21-
<.odyssey_product_picker
22-
field={@form[:whitelisted_products]}
23-
products={@products}
24-
selected_ids={["prod_1", "prod_2"]}
19+
products={Enum.map(@raw_products, &%{id: &1.id, name: &1.name, color: &1.colorHex})}
2520
/>
2621
"""
2722

@@ -107,22 +102,21 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPicker do
107102
id={"#{@id}_checkboxes"}
108103
>
109104
<div :for={product <- @products} class="flex items-center gap-3">
110-
<% product_id = product[@id_key] %>
111105
<input
112106
type="checkbox"
113-
id={"#{@id}_product_#{product_id}"}
114-
checked={product_id in @selected_ids}
115-
data-product-id={product_id}
107+
id={"#{@id}_product_#{product.id}"}
108+
checked={product.id in @selected_ids}
109+
data-product-id={product.id}
116110
disabled={@disabled}
117111
class="checkbox checkbox-sm product-picker-checkbox"
118112
/>
119113
<div
120114
class="w-3 h-3 rounded-sm flex-shrink-0"
121-
style={"background-color: #{product[@color_key] || "#888888"}"}
115+
style={"background-color: #{product.color}"}
122116
>
123117
</div>
124-
<label for={"#{@id}_product_#{product_id}"} class="text-sm text-gray-700 cursor-pointer">
125-
{product[@name_key]}
118+
<label for={"#{@id}_product_#{product.id}"} class="text-sm text-gray-700 cursor-pointer">
119+
{product.name}
126120
</label>
127121
</div>
128122
</div>
@@ -151,9 +145,6 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPicker do
151145
{:noreply, socket}
152146
end
153147

154-
defp to_existing_atom(value) when is_atom(value), do: value
155-
defp to_existing_atom(value) when is_binary(value), do: String.to_existing_atom(value)
156-
157148
defp encode_selected_products([]), do: ""
158149
defp encode_selected_products(ids), do: Enum.join(ids, ",")
159150

@@ -179,13 +170,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPicker do
179170
attr :field, :any, required: true, doc: "a Phoenix.HTML.FormField struct"
180171
attr :id, :string, doc: "component id, defaults to form_field_product_picker"
181172

182-
attr :products, :list, required: true, doc: "list of product maps"
183-
173+
attr :products, :list, required: true, doc: "list of %{id: string, name: string, color: string} maps"
184174
attr :selected_ids, :list, doc: "list of pre-selected product IDs (auto-extracted from field value when omitted)"
185-
186-
attr :id_key, :atom, default: :id, doc: "key to read product ID from each product map"
187-
attr :name_key, :atom, default: :name, doc: "key to read product name from each product map"
188-
attr :color_key, :atom, default: :color_hex, doc: "key to read product color hex from each product map"
189175
attr :all_label, :string, default: "All Products", doc: "label for the 'all' toggle option"
190176
attr :specific_label, :string, default: "Specific Products", doc: "label for the 'specific' toggle option"
191177
attr :label, :string, required: false, doc: "label for the toggle button"
@@ -198,9 +184,6 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPicker do
198184
"#{field.form.name}_#{field.field}_product_picker"
199185
end)
200186
|> assign_new(:label, fn -> nil end)
201-
|> assign(:id_key, to_existing_atom(assigns[:id_key] || :id))
202-
|> assign(:name_key, to_existing_atom(assigns[:name_key] || :name))
203-
|> assign(:color_key, to_existing_atom(assigns[:color_key] || :color_hex))
204187
|> assign(:module, __MODULE__)
205188

206189
~H"""

test/peek_app_sdk/ui/odyssey/product_picker_test.exs

Lines changed: 12 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
1010
form = to_form(%{"whitelisted_products" => nil}, as: :campaign)
1111

1212
products = [
13-
%{id: "p1", name: "Kayak Tour", color_hex: "#FF5733"},
14-
%{id: "p2", name: "Snorkel Trip", color_hex: "#33FF57"}
13+
%{id: "p1", name: "Kayak Tour", color: "#FF5733"},
14+
%{id: "p2", name: "Snorkel Trip", color: "#33FF57"}
1515
]
1616

1717
html =
@@ -36,8 +36,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
3636
form = to_form(%{"whitelisted_products" => nil}, as: :campaign)
3737

3838
products = [
39-
%{id: "p1", name: "Kayak Tour", color_hex: "#FF5733"},
40-
%{id: "p2", name: "Snorkel Trip", color_hex: "#33FF57"}
39+
%{id: "p1", name: "Kayak Tour", color: "#FF5733"},
40+
%{id: "p2", name: "Snorkel Trip", color: "#33FF57"}
4141
]
4242

4343
html =
@@ -86,7 +86,7 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
8686
test "renders disabled state" do
8787
form = to_form(%{"products" => nil}, as: :test)
8888

89-
products = [%{id: "p1", name: "Tour", color_hex: "#000"}]
89+
products = [%{id: "p1", name: "Tour", color: "#000"}]
9090

9191
html =
9292
render_component(
@@ -158,8 +158,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
158158
form = to_form(%{"products" => nil}, as: :test)
159159

160160
products = [
161-
%{id: "p1", name: "Tour A", color_hex: "#111"},
162-
%{id: "p2", name: "Tour B", color_hex: "#222"}
161+
%{id: "p1", name: "Tour A", color: "#111"},
162+
%{id: "p2", name: "Tour B", color: "#222"}
163163
]
164164

165165
html =
@@ -184,8 +184,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
184184
form = to_form(%{"products" => field_value}, as: :test)
185185

186186
products = [
187-
%{id: "p1", name: "Tour A", color_hex: "#111"},
188-
%{id: "p2", name: "Tour B", color_hex: "#222"}
187+
%{id: "p1", name: "Tour A", color: "#111"},
188+
%{id: "p2", name: "Tour B", color: "#222"}
189189
]
190190

191191
html =
@@ -207,8 +207,8 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
207207
form = to_form(%{"products" => field_value}, as: :test)
208208

209209
products = [
210-
%{id: "p1", name: "Tour A", color_hex: "#111"},
211-
%{id: "p2", name: "Tour B", color_hex: "#222"}
210+
%{id: "p1", name: "Tour A", color: "#111"},
211+
%{id: "p2", name: "Tour B", color: "#222"}
212212
]
213213

214214
html =
@@ -231,7 +231,7 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
231231
]
232232

233233
form = to_form(%{"products" => changeset_like}, as: :test)
234-
products = [%{id: "p1", name: "A", color_hex: "#111"}, %{id: "p2", name: "B", color_hex: "#222"}]
234+
products = [%{id: "p1", name: "A", color: "#111"}, %{id: "p2", name: "B", color: "#222"}]
235235

236236
html =
237237
render_component(
@@ -247,66 +247,6 @@ defmodule PeekAppSDK.UI.Odyssey.ProductPickerTest do
247247
end
248248
end
249249

250-
describe "custom key attrs" do
251-
test "uses custom color_key" do
252-
form = to_form(%{"p" => nil}, as: :t)
253-
products = [%{id: "1", name: "A", hex: "#AA0000"}]
254-
255-
html =
256-
render_component(
257-
fn assigns ->
258-
~H"""
259-
<.odyssey_product_picker field={@form[:p]} products={@products} selected_ids={["1"]} color_key={:hex} />
260-
"""
261-
end,
262-
%{form: form, products: products}
263-
)
264-
265-
assert html =~ "background-color: #AA0000"
266-
end
267-
268-
test "uses custom id_key and name_key" do
269-
form = to_form(%{"p" => nil}, as: :t)
270-
products = [%{product_id: "x1", title: "Kayak", color_hex: "#000"}]
271-
272-
html =
273-
render_component(
274-
fn assigns ->
275-
~H"""
276-
<.odyssey_product_picker
277-
field={@form[:p]}
278-
products={@products}
279-
selected_ids={["x1"]}
280-
id_key={:product_id}
281-
name_key={:title}
282-
/>
283-
"""
284-
end,
285-
%{form: form, products: products}
286-
)
287-
288-
assert html =~ "Kayak"
289-
assert html =~ "data-product-id=\"x1\""
290-
end
291-
292-
test "falls back to #888888 when color key is missing" do
293-
form = to_form(%{"p" => nil}, as: :t)
294-
products = [%{id: "1", name: "A"}]
295-
296-
html =
297-
render_component(
298-
fn assigns ->
299-
~H"""
300-
<.odyssey_product_picker field={@form[:p]} products={@products} selected_ids={["1"]} />
301-
"""
302-
end,
303-
%{form: form, products: products}
304-
)
305-
306-
assert html =~ "background-color: #888888"
307-
end
308-
end
309-
310250
describe "extract_ids_from_field/1" do
311251
alias PeekAppSDK.UI.Odyssey.ProductPicker
312252

0 commit comments

Comments
 (0)