diff --git a/README.md b/README.md index 5cc3598..4bc444c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ A modern, idiomatic Elixir/Phoenix port of the original PHP-based component inve - **Category Organization**: Hierarchical category system for better organization - **Datasheet Links**: Direct links to component datasheets - **Position Tracking**: Track component storage locations +- **Real-time Updates**: All changes are immediately reflected in the interface ## Setup @@ -110,6 +111,7 @@ The application uses a simple password-based authentication system: | `getItems.php` | `Inventory.list_components/1` | Type-safe, composable queries | | `getCategories.php` | `Inventory.list_categories/0` | Proper associations, hierarchical support | | `addItem.php` | `Inventory.create_component/1` | Built-in validation, changesets | +| Manual editing | `Inventory.update_component/2` | **NEW**: Full edit functionality with validation | | `changeAmount.php` | `Inventory.update_component_count/2` | Atomic operations, constraints | | `imageUpload.php` | (Future: Phoenix file uploads) | Planned improvement | | Session management | Phoenix sessions + LiveView | Built-in CSRF protection | diff --git a/lib/components_elixir_web/live/components_live.ex b/lib/components_elixir_web/live/components_live.ex index 4663be5..3b20ece 100644 --- a/lib/components_elixir_web/live/components_live.ex +++ b/lib/components_elixir_web/live/components_live.ex @@ -28,6 +28,8 @@ defmodule ComponentsElixirWeb.ComponentsLive do |> assign(:has_more, false) |> assign(:loading, false) |> assign(:show_add_form, false) + |> assign(:show_edit_form, false) + |> assign(:editing_component, nil) |> assign(:form, nil) |> load_components()} end @@ -136,6 +138,26 @@ defmodule ComponentsElixirWeb.ComponentsLive do |> assign(:form, nil)} end + def handle_event("show_edit_form", %{"id" => id}, socket) do + component = Inventory.get_component!(id) + changeset = Inventory.change_component(component) + form = to_form(changeset) + + {:noreply, + socket + |> assign(:show_edit_form, true) + |> assign(:editing_component, component) + |> assign(:form, form)} + end + + def handle_event("hide_edit_form", _params, socket) do + {:noreply, + socket + |> assign(:show_edit_form, false) + |> assign(:editing_component, nil) + |> assign(:form, nil)} + end + def handle_event("save_component", %{"component" => component_params}, socket) do case Inventory.create_component(component_params) do {:ok, _component} -> @@ -151,6 +173,22 @@ defmodule ComponentsElixirWeb.ComponentsLive do end end + def handle_event("save_edit", %{"component" => component_params}, socket) do + case Inventory.update_component(socket.assigns.editing_component, component_params) do + {:ok, _component} -> + {:noreply, + socket + |> put_flash(:info, "Component updated successfully") + |> assign(:show_edit_form, false) + |> assign(:editing_component, nil) + |> assign(:form, nil) + |> load_components()} + + {:error, changeset} -> + {:noreply, assign(socket, :form, to_form(changeset))} + end + end + defp load_components(socket, opts \\ []) do append = Keyword.get(opts, :append, false) @@ -164,11 +202,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do %{components: new_components, has_more: has_more} = Inventory.paginate_components(filters) - components = if append do - socket.assigns.components ++ new_components - else - new_components - end + components = + if append do + socket.assigns.components ++ new_components + else + new_components + end socket |> assign(:components, components) @@ -188,9 +227,9 @@ defmodule ComponentsElixirWeb.ComponentsLive do defp category_options(categories) do [{"Select a category", nil}] ++ - Enum.map(categories, fn category -> - {category.name, category.id} - end) + Enum.map(categories, fn category -> + {category.name, category.id} + end) end @impl true @@ -206,7 +245,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do Components Inventory
- <%= @stats.total_components %> components • <%= @stats.total_stock %> items in stock + {@stats.total_components} components • {@stats.total_stock} items in stock
@@ -214,23 +253,21 @@ defmodule ComponentsElixirWeb.ComponentsLive do phx-click="show_add_form" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" > - <.icon name="hero-plus" class="w-4 h-4 mr-2" /> - Add Component + <.icon name="hero-plus" class="w-4 h-4 mr-2" /> Add Component <.link href="/logout" method="post" class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" > - <.icon name="hero-arrow-right-on-rectangle" class="w-4 h-4 mr-2" /> - Logout + <.icon name="hero-arrow-right-on-rectangle" class="w-4 h-4 mr-2" /> Logout
- +
@@ -250,19 +287,25 @@ defmodule ComponentsElixirWeb.ComponentsLive do name="sort_criteria" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" > - + - + - +
- + <%= if @show_add_form do %>
@@ -285,7 +328,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
- <.input field={@form[:category_id]} type="select" options={category_options(@categories)} required /> + <.input + field={@form[:category_id]} + type="select" + options={category_options(@categories)} + required + />
@@ -336,7 +384,86 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<% end %> - + + <%= if @show_edit_form do %> +
+
+
+
+

Edit Component

+ +
+ + <.form for={@form} phx-submit="save_edit" class="space-y-4"> +
+ + <.input field={@form[:name]} type="text" required /> +
+ +
+ + <.input + field={@form[:category_id]} + type="select" + options={category_options(@categories)} + required + /> +
+ +
+ + <.input field={@form[:description]} type="textarea" /> +
+ +
+
+ + <.input field={@form[:keywords]} type="text" /> +
+
+ + <.input field={@form[:position]} type="text" /> +
+
+ +
+
+ + <.input field={@form[:count]} type="number" min="0" /> +
+
+ + <.input field={@form[:datasheet_url]} type="url" /> +
+
+ +
+ + +
+ +
+
+
+ <% end %> + +
    @@ -347,17 +474,21 @@ defmodule ComponentsElixirWeb.ComponentsLive do

    <%= if component.datasheet_url do %> - - <%= component.name %> + + {component.name} <.icon name="hero-arrow-top-right-on-square" class="w-4 h-4 inline ml-1" /> <% else %> - <%= component.name %> + {component.name} <% end %>

    - <%= component.category.name %> + {component.category.name}

    @@ -365,22 +496,22 @@ defmodule ComponentsElixirWeb.ComponentsLive do

    <%= if component.description do %> - <%= component.description %> + {component.description} <% end %>

    <%= if component.position do %>

    - Position: <%= component.position %> + Position: {component.position}

    <% end %>

    - Count: <%= component.count %> + Count: {component.count}

    <%= if @sort_criteria == "all" or @sort_criteria == "id" do %>

    - ID: <%= component.id %> + ID: {component.id}

    <% end %>
    @@ -388,7 +519,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do <%= if component.keywords do %>

    - Keywords: <%= component.keywords %> + Keywords: {component.keywords}

    <% end %> @@ -408,6 +539,13 @@ defmodule ComponentsElixirWeb.ComponentsLive do > <.icon name="hero-minus" class="w-4 h-4" /> +