diff --git a/assets/package-lock.json b/assets/package-lock.json index 946dfce9a..8f3303ddc 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -10,6 +10,7 @@ "@fullcalendar/daygrid": "^6.1.0", "@fullcalendar/react": "^6.1.0", "leaflet": "^1.9.4", + "live_select": "file:../deps/live_select", "phoenix": "file:../deps/phoenix", "phoenix_html": "file:../deps/phoenix_html", "phoenix_live_react": "file:../deps/phoenix_live_react", @@ -49,8 +50,12 @@ "typescript": "^5.4.5" } }, + "../deps/live_select": { + "version": "1.3.1", + "license": "Apache License 2.0" + }, "../deps/phoenix": { - "version": "1.7.12", + "version": "1.7.14", "license": "MIT" }, "../deps/phoenix_html": { @@ -61,10 +66,11 @@ "license": "MIT" }, "../deps/phoenix_live_view": { - "version": "0.20.14", + "version": "0.20.17", "license": "MIT", "devDependencies": { - "@playwright/test": "^1.41.0" + "@playwright/test": "^1.43.1", + "monocart-reporter": "^2.3.1" } }, "../deps/react_phoenix": { @@ -7404,6 +7410,10 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/live_select": { + "resolved": "../deps/live_select", + "link": true + }, "node_modules/locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", diff --git a/assets/package.json b/assets/package.json index fccbac9ea..28b457948 100644 --- a/assets/package.json +++ b/assets/package.json @@ -18,6 +18,7 @@ "phoenix_html": "file:../deps/phoenix_html", "phoenix_live_react": "file:../deps/phoenix_live_react", "phoenix_live_view": "file:../deps/phoenix_live_view", + "live_select": "file:../deps/live_select", "react": "^18.3.0", "react-datepicker": "^6.2.0", "react-dom": "^18.3.0", diff --git a/assets/src/app.tsx b/assets/src/app.tsx index 4127441d7..f49d89452 100644 --- a/assets/src/app.tsx +++ b/assets/src/app.tsx @@ -1,6 +1,7 @@ // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. import "phoenix_html" import LiveReact from "./LiveReactPhoenix" +import live_select from "live_select" // Establish Phoenix Socket and LiveView configuration. import { Socket } from "phoenix" import { LiveSocket } from "phoenix_live_view" @@ -21,7 +22,7 @@ declare global { } // https://github.com/fidr/phoenix_live_react -const hooks = { LiveReact } +const hooks = { LiveReact, ...live_select } const csrfToken = document .querySelector("meta[name='csrf-token']")! diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js index 51fd61cd6..4cc3bdb1b 100644 --- a/assets/tailwind.config.js +++ b/assets/tailwind.config.js @@ -6,7 +6,12 @@ const fs = require("fs") const path = require("path") module.exports = { - content: ["./js/**/*.js", "../lib/arrow_web.ex", "../lib/arrow_web/**/*.*ex"], + content: [ + "./js/**/*.js", + "../lib/arrow_web.ex", + "../lib/arrow_web/**/*.*ex", + "../deps/live_select/lib/live_select/component.*ex", + ], theme: { extend: { colors: { diff --git a/lib/arrow/shuttles/shape.ex b/lib/arrow/shuttles/shape.ex index d2d58df29..f2bca192e 100644 --- a/lib/arrow/shuttles/shape.ex +++ b/lib/arrow/shuttles/shape.ex @@ -3,6 +3,8 @@ defmodule Arrow.Shuttles.Shape do use Ecto.Schema import Ecto.Changeset + @derive {Jason.Encoder, only: [:id, :name, :inserted_at, :updated_at]} + @type id :: integer @type t :: %__MODULE__{ id: id, diff --git a/lib/arrow_web.ex b/lib/arrow_web.ex index 543096823..5b9f8c647 100644 --- a/lib/arrow_web.ex +++ b/lib/arrow_web.ex @@ -58,9 +58,12 @@ defmodule ArrowWeb do # Include general helpers for rendering HTML unquote(html_helpers()) + # https://hexdocs.pm/phoenix_html/changelog.html#v4-0-0-2023-12-19 # Use all HTML functionality (forms, tags, etc) # Still needed for old style Phoenix HTML like , - use Phoenix.HTML + import Phoenix.HTML + import Phoenix.HTML.Form + use PhoenixHTMLHelpers import ArrowWeb.ErrorHelpers use Gettext, backend: ArrowWeb.Gettext diff --git a/lib/arrow_web/components/core_components.ex b/lib/arrow_web/components/core_components.ex index a26c5a750..acf92c813 100644 --- a/lib/arrow_web/components/core_components.ex +++ b/lib/arrow_web/components/core_components.ex @@ -400,6 +400,54 @@ defmodule ArrowWeb.CoreComponents do """ end + @doc """ + LiveSelect with styling + """ + attr :field, Phoenix.HTML.FormField, + doc: "a form field struct retrieved from the form, for example: @form[:email]" + + attr :class, :string, default: nil + attr :label, :string + # live-select opts + attr :placeholder, :string + attr :options, :any + attr :value_mapper, :any + attr :allow_clear, :boolean + + def live_select(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do + assigns = + assigns + |> assign(:errors, Enum.map(field.errors, &translate_error(&1))) + |> assign(:live_select_opts, assigns_to_attributes(assigns, [:errors, :label, :class])) + + ~H""" +
+
+ <.label for={@field.id}><%= @label %> + + + <.error :for={msg <- @errors}><%= msg %> +
+
+ """ + end + @doc """ Renders a label. """ diff --git a/lib/arrow_web/controllers/error_helpers.ex b/lib/arrow_web/controllers/error_helpers.ex index 1ee30d840..ee3cea307 100644 --- a/lib/arrow_web/controllers/error_helpers.ex +++ b/lib/arrow_web/controllers/error_helpers.ex @@ -3,7 +3,10 @@ defmodule ArrowWeb.ErrorHelpers do Conveniences for translating and building error messages. """ - use Phoenix.HTML + # https://hexdocs.pm/phoenix_html/changelog.html#v4-0-0-2023-12-19 + # Use all HTML functionality (forms, tags, etc) + # Still needed for old style Phoenix HTML like , + use PhoenixHTMLHelpers @doc """ Generates tag for inlined form input errors. diff --git a/lib/arrow_web/live/shuttle_live/shuttle_live.ex b/lib/arrow_web/live/shuttle_live/shuttle_live.ex index a971852e6..a237d0a5d 100644 --- a/lib/arrow_web/live/shuttle_live/shuttle_live.ex +++ b/lib/arrow_web/live/shuttle_live/shuttle_live.ex @@ -75,12 +75,13 @@ defmodule ArrowWeb.ShuttleViewLive do <.input field={f_route[:direction_desc]} type="text" label="Direction desc" />
- <.input + <.live_select field={f_route[:shape_id]} - type="select" label="Shape" - prompt="Choose a shape" - options={Enum.map(@shapes, &{&1.name, &1.id})} + placeholder="Choose a shape" + options={options_mapper(@shapes)} + value_mapper={&value_mapper/1} + allow_clear={true} />
@@ -163,6 +164,22 @@ defmodule ArrowWeb.ShuttleViewLive do |> Enum.map(&List.first(&1.shapes)) end + defp options_mapper(shapes) do + Enum.map(shapes, &option_mapper/1) + end + + def option_mapper(%{name: name, id: id}) do + {name, value_mapper(id)} + end + + def value_mapper(id) when is_integer(id) do + Integer.to_string(id) + end + + def value_mapper(id) do + id + end + def mount(%{"id" => id} = _params, session, socket) do logout_url = session["logout_url"] shuttle = Shuttles.get_shuttle!(id) @@ -275,6 +292,17 @@ defmodule ArrowWeb.ShuttleViewLive do end end + def handle_event("live_select_change", %{"text" => text, "id" => live_select_id}, socket) do + shapes = + Shuttles.list_shapes() + |> Enum.filter(&(String.downcase(&1.name) |> String.contains?(String.downcase(text)))) + |> Enum.map(&option_mapper/1) + + send_update(LiveSelect.Component, id: live_select_id, options: shapes) + + {:noreply, socket} + end + def handle_event("add_stop", %{"value" => direction_id}, socket) do direction_id = String.to_existing_atom(direction_id) diff --git a/mix.exs b/mix.exs index 63e66fa86..874b96c91 100644 --- a/mix.exs +++ b/mix.exs @@ -62,13 +62,15 @@ defmodule Arrow.MixProject do {:httpoison, "~> 2.2"}, {:ja_serializer, "~> 0.18.0"}, {:jason, "~> 1.0"}, + {:live_select, "~> 1.4"}, {:lcov_ex, "~> 0.2", only: [:dev, :test], runtime: false}, {:mox, "~> 1.2", only: :test}, {:oban, "~> 2.18"}, {:phoenix_ecto, "~> 4.0"}, {:phoenix_live_reload, "~> 1.5", only: :dev}, - {:phoenix_html, "~> 3.0"}, - {:phoenix_live_react, "~> 0.4"}, + {:phoenix_html, "~> 4.0"}, + {:phoenix_html_helpers, "~> 1.0"}, + {:phoenix_live_react, "~> 0.6"}, {:phoenix_live_view, "~> 0.20.14"}, {:phoenix_live_dashboard, "~> 0.7"}, {:phoenix_pubsub, "~> 2.0"}, @@ -79,7 +81,7 @@ defmodule Arrow.MixProject do {:telemetry_metrics, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, # If react_phoenix changes, check assets/src/ReactPhoenix.js, too - {:react_phoenix, "1.3.1"}, + {:react_phoenix, git: "https://github.com/mbta/react-phoenix.git"}, {:tzdata, "~> 1.1"}, {:ueberauth_cognito, "0.4.0"}, {:ueberauth_oidcc, "~> 0.4.0"}, diff --git a/mix.lock b/mix.lock index dd9fddcf3..91211fc10 100644 --- a/mix.lock +++ b/mix.lock @@ -34,6 +34,7 @@ "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, "lcov_ex": {:hex, :lcov_ex, "0.3.3", "1745a88e46606c4f86408299f54878b7d0cd22ea3e9c54b0018b6ed631a9ce87", [:mix], [], "hexpm", "ea373ec4d2df213357c5a464be16ab08d1e58e61ea2de784a483780c22a1e74a"}, + "live_select": {:hex, :live_select, "1.4.3", "ec9706952f589d8e2e6f98a0e1633c5b51ab5b807d503bd0d9622a26c999fb9a", [:mix], [{:ecto, "~> 3.8", [hex: :ecto, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.6.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_html_helpers, "~> 1.0", [hex: :phoenix_html_helpers, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "58f7d702b0f786c73d31e60a342c0a49afaf56ca5a6a078b51babf3490465220"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, @@ -45,9 +46,10 @@ "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "phoenix_html_helpers": {:hex, :phoenix_html_helpers, "1.0.1", "7eed85c52eff80a179391036931791ee5d2f713d76a81d0d2c6ebafe1e11e5ec", [:mix], [{:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cffd2385d1fa4f78b04432df69ab8da63dc5cf63e07b713a4dcf36a3740e3090"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.4", "4508e481f791ce62ec6a096e13b061387158cbeefacca68c6c1928e1305e23ed", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "2984aae96994fbc5c61795a73b8fb58153b41ff934019cfb522343d2d3817d59"}, - "phoenix_live_react": {:hex, :phoenix_live_react, "0.5.0", "8ef46146fcf9957b377e3f3187e85574e6f407b19d822a131501c32e6c16f4b1", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "cb64d778ca26e5cfc89153a0799a43b790cbbb5d6fe025e4e11d97ca5ef8e72d"}, + "phoenix_live_react": {:hex, :phoenix_live_react, "0.6.0", "d6c08632e36be0149d8236953437c6fa1df98c38f0d87a35047ab64b74996b48", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_html_helpers, "~> 1.0", [hex: :phoenix_html_helpers, repo: "hexpm", optional: false]}], "hexpm", "59c0907d98a4840f33577ddb0f0642108ac22d1a896249494af7c20f437e322d"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, @@ -58,7 +60,7 @@ "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, "postgrex": {:hex, :postgrex, "0.19.2", "34d6884a332c7bf1e367fc8b9a849d23b43f7da5c6e263def92784d03f9da468", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "618988886ab7ae8561ebed9a3c7469034bf6a88b8995785a3378746a4b9835ec"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "react_phoenix": {:hex, :react_phoenix, "1.3.1", "b2abb625ce7304a3b2ac5eea3126c30ef1e1c860f9ef27290ee726ab1fa3a87a", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "a10de67f02f6c5cf04f6987cef7413400d671936b4df97e0b9ac3c227ba27e6b"}, + "react_phoenix": {:git, "https://github.com/mbta/react-phoenix.git", "d95a3465c735783cba41b34941b91d4d4a858b37", []}, "sax_map": {:hex, :sax_map, "1.3.0", "d79ce48edf2c25720e79a2f62e3ee091ebd8b918d0e3a16f58010c7014a07d89", [:mix], [{:saxy, "~> 1.3", [hex: :saxy, repo: "hexpm", optional: false]}], "hexpm", "5f9086c757aae9f951a7ef0139a9ae56586a126c0da150b71d5ec6cd25309d85"}, "saxy": {:hex, :saxy, "1.6.0", "02cb4e9bd045f25ac0c70fae8164754878327ee393c338a090288210b02317ee", [:mix], [], "hexpm", "ef42eb4ac983ca77d650fbdb68368b26570f6cc5895f0faa04d34a6f384abad3"}, "sentry": {:hex, :sentry, "10.7.1", "33392222d80ccff99c503f972998d2858b4c1e5aca2219a34269b68dacba8e7d", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "56291312397bf2b6afab6cf4f7aa1f27413b0eb2ceeb63b8aab2d7658aaea882"}, diff --git a/test/arrow_web/live/shuttle_live/shuttle_live_test.exs b/test/arrow_web/live/shuttle_live/shuttle_live_test.exs index df78617b1..451d65138 100644 --- a/test/arrow_web/live/shuttle_live/shuttle_live_test.exs +++ b/test/arrow_web/live/shuttle_live/shuttle_live_test.exs @@ -39,7 +39,6 @@ defmodule ArrowWeb.ShuttleLiveTest do destination: "Broadway", direction_desc: "Southbound", direction_id: "0", - shape_id: "", suffix: "", waypoint: "" }, @@ -48,7 +47,6 @@ defmodule ArrowWeb.ShuttleLiveTest do destination: "Harvard", direction_desc: "Northbound", direction_id: "1", - shape_id: "", suffix: "", waypoint: "" } @@ -57,6 +55,19 @@ defmodule ArrowWeb.ShuttleLiveTest do status: "draft" } + @update_hidden_attrs %{ + routes: %{ + "0" => %{ + shape_id: "", + shape_id_text_input: "" + }, + "1" => %{ + shape_id: "", + shape_id_text_input: "" + } + } + } + @invalid_attrs %{ disrupted_route_id: "", shuttle_name: nil, @@ -106,7 +117,7 @@ defmodule ArrowWeb.ShuttleLiveTest do {:ok, conn} = edit_live |> form("#shuttle-form", shuttle: @update_attrs) - |> render_submit() + |> render_submit(@update_hidden_attrs) |> follow_redirect(conn) assert html_response(conn, 200) =~ ~r/shuttle updated successfully/i @@ -229,6 +240,56 @@ defmodule ArrowWeb.ShuttleLiveTest do end end + describe "shape select" do + setup [:create_shuttle] + + @tag :authenticated_admin + test "sets the selected shape via hidden input values", %{conn: conn, shuttle: shuttle} do + {:ok, edit_live, _html} = live(conn, ~p"/shuttles/#{shuttle}/edit") + + first_route = List.first(shuttle.routes) + second_route = Enum.at(shuttle.routes, 1) + + update_first_shape_attrs = %{ + routes: %{ + "0" => %{ + shape_id: second_route.shape_id, + shape_id_text_input: second_route.shape.name + } + } + } + + # `#` and escaping the brackets doesn't seem to work with this selector format (unlike $() in the browser) + live_component_selector = ~s{[id="shuttle[routes][0]_shape_id_live_select_component"]} + hidden_input_selector = ~s{#shuttle-form_routes_0_shape_id} + displayed_value_selector = ~s{#shuttle-form_routes_0_shape_id_text_input} + + # initially set to original shape + assert edit_live + |> element(live_component_selector) + |> render() =~ ~s{value="#{first_route.shape_id}"} + + assert edit_live + |> element(displayed_value_selector) + |> render() =~ ~s{value="#{first_route.shape.name}"} + + assert edit_live + |> element(hidden_input_selector) + |> render() =~ ~s{value="#{first_route.shape_id}"} + + rendered = + edit_live + |> element("#shuttle-form") + |> render_change(%{shuttle: update_first_shape_attrs}) + + refute rendered =~ "#{first_route.shape.name}" + assert rendered =~ "#{second_route.shape.name}" + + assert rendered =~ + "name=\"shuttle[routes][0][shape_id]\" type=\"hidden\" value=\"#{second_route.shape_id}\"/>" + end + end + defp create_shuttle(_) do shuttle = shuttle_fixture() %{shuttle: shuttle}