diff --git a/lib/bike_brigade_web/live/community_fridge_live/form_component.ex b/lib/bike_brigade_web/live/community_fridge_live/form_component.ex index e63130fd..3f821db7 100644 --- a/lib/bike_brigade_web/live/community_fridge_live/form_component.ex +++ b/lib/bike_brigade_web/live/community_fridge_live/form_component.ex @@ -1,7 +1,17 @@ defmodule BikeBrigadeWeb.CommunityFridgeLive.FormComponent do use BikeBrigadeWeb, :live_component - alias BikeBrigade.Locations + alias BikeBrigade.{Locations, MediaStorage} + + @impl true + def mount(socket) do + {:ok, + allow_upload(socket, :photo, + accept: ~w(.gif .png .jpg .jpeg), + max_entries: 1, + max_file_size: 10_000_000 + )} + end @impl true def update(%{community_fridge: community_fridge} = assigns, socket) do @@ -24,9 +34,35 @@ defmodule BikeBrigadeWeb.CommunityFridgeLive.FormComponent do end def handle_event("save", %{"community_fridge" => params}, socket) do + params = + case consume_uploaded_entries(socket, :photo, fn %{path: path}, + %{client_type: content_type} -> + {:ok, MediaStorage.upload_file!(path, content_type)} + end) do + [%{url: url}] -> Map.put(params, "photo", url) + [] -> Map.update(params, "photo", nil, &if(&1 == "", do: nil, else: &1)) + end + save_community_fridge(socket, socket.assigns.action, params) end + def handle_event("delete_photo", _params, socket) do + changeset = + socket.assigns.community_fridge + |> Locations.change_community_fridge(%{photo: nil}) + |> Map.put(:action, :validate) + + {:noreply, assign(socket, :changeset, changeset)} + end + + def handle_event("cancel_upload", %{"ref" => ref}, socket) do + {:noreply, cancel_upload(socket, :photo, ref)} + end + + defp error_to_string(:too_large), do: "Too large" + defp error_to_string(:too_many_files), do: "You have selected too many files" + defp error_to_string(:not_accepted), do: "You have selected an unacceptable file type" + defp save_community_fridge(socket, :edit, params) do case Locations.update_community_fridge(socket.assigns.community_fridge, params) do {:ok, _community_fridge} -> diff --git a/lib/bike_brigade_web/live/community_fridge_live/form_component.html.heex b/lib/bike_brigade_web/live/community_fridge_live/form_component.html.heex index 7741fd21..2c21fcfd 100644 --- a/lib/bike_brigade_web/live/community_fridge_live/form_component.html.heex +++ b/lib/bike_brigade_web/live/community_fridge_live/form_component.html.heex @@ -12,7 +12,63 @@ <.input type="textarea" field={f[:description]} label="Description" /> - <.input type="text" field={f[:photo]} label="Photo URL" /> +
+ + +
+ +
+ <.button + color={:lightred} + size={:xsmall} + phx-click={JS.push("delete_photo", target: @myself)} + type="button" + > + Delete + +
+
+
+
+ +
+ +

or drag and drop

+
+

PNG, JPG, GIF up to 10MB

+
+
+
+
+ <.live_img_preview entry={entry} class="w-16 rounded" /> +
{entry.client_name}
+ +

+ {error_to_string(err)} +

+
+
+
<.input type="checkbox" diff --git a/test/bike_brigade_web/live/community_fridge_live_test.exs b/test/bike_brigade_web/live/community_fridge_live_test.exs index 3a172463..b9cc4e38 100644 --- a/test/bike_brigade_web/live/community_fridge_live_test.exs +++ b/test/bike_brigade_web/live/community_fridge_live_test.exs @@ -2,7 +2,7 @@ defmodule BikeBrigadeWeb.CommunityFridgeLiveTest do use BikeBrigadeWeb.ConnCase import Phoenix.LiveViewTest - alias BikeBrigade.Locations + alias BikeBrigade.MediaStorage.FakeMediaStorage describe "Community Fridges index (dispatcher)" do setup [:login] @@ -83,6 +83,61 @@ defmodule BikeBrigadeWeb.CommunityFridgeLiveTest do end end + describe "Community Fridge photo upload" do + setup [:login] + + test "shows existing photo in edit form", ctx do + fridge = + fixture(:community_fridge, %{ + name: "Photo Fridge", + photo: "https://example.com/fridge.jpg" + }) + + {:ok, _view, html} = live(ctx.conn, ~p"/community_fridges/#{fridge.id}/edit") + + assert html =~ "https://example.com/fridge.jpg" + end + + test "renders upload dropzone", ctx do + fixture(:community_fridge, %{name: "Upload Fridge"}) + {:ok, view, _html} = live(ctx.conn, ~p"/community_fridges/new") + + html = render(view) + assert html =~ "Upload a file" + assert html =~ "or drag and drop" + assert html =~ "PNG, JPG, GIF" + end + + test "shows pending upload preview after file is selected", ctx do + {:ok, view, _html} = live(ctx.conn, ~p"/community_fridges/new") + + upload = + file_input(view, "#community-fridge-form", :photo, [ + %{name: "fridge.jpg", content: <<0, 1, 2>>, type: "image/jpeg"} + ]) + + render_upload(upload, "fridge.jpg", 100) + + html = render(view) + assert html =~ "fridge.jpg" + end + + test "can cancel a pending upload", ctx do + {:ok, view, _html} = live(ctx.conn, ~p"/community_fridges/new") + + upload = + file_input(view, "#community-fridge-form", :photo, [ + %{name: "fridge.jpg", content: <<0, 1, 2>>, type: "image/jpeg"} + ]) + + render_upload(upload, "fridge.jpg", 100) + assert render(view) =~ "fridge.jpg" + + view |> element("button[aria-label='cancel']") |> render_click() + refute render(view) =~ "fridge.jpg" + end + end + describe "Community Fridges access control" do setup [:login_as_rider]