defmodule ComponentsElixirWeb.ComponentsLive do use ComponentsElixirWeb, :live_view alias ComponentsElixir.{Inventory, Auth} alias ComponentsElixir.Inventory.Component @items_per_page 20 @impl true def mount(_params, session, socket) do # Check authentication unless Auth.authenticated?(session) do {:ok, socket |> push_navigate(to: ~p"/login")} else categories = Inventory.list_categories() stats = Inventory.component_stats() {:ok, socket |> assign(:session, session) |> assign(:categories, categories) |> assign(:stats, stats) |> assign(:search, "") |> assign(:sort_criteria, "all_not_id") |> assign(:selected_category, nil) |> assign(:offset, 0) |> assign(:components, []) |> assign(:has_more, false) |> assign(:loading, false) |> assign(:show_add_form, false) |> assign(:form, nil) |> load_components()} end end @impl true def handle_params(params, _uri, socket) do search = Map.get(params, "search", "") criteria = Map.get(params, "criteria", "all_not_id") {:noreply, socket |> assign(:search, search) |> assign(:sort_criteria, criteria) |> assign(:offset, 0) |> load_components()} end @impl true def handle_event("search", %{"search" => search}, socket) do {:noreply, socket |> assign(:search, search) |> assign(:offset, 0) |> load_components() |> push_patch(to: ~p"/?#{build_query_params(socket, %{search: search})}")} end def handle_event("sort_change", %{"sort_criteria" => criteria}, socket) do {:noreply, socket |> assign(:sort_criteria, criteria) |> assign(:offset, 0) |> load_components() |> push_patch(to: ~p"/?#{build_query_params(socket, %{criteria: criteria})}")} end def handle_event("load_more", _params, socket) do new_offset = socket.assigns.offset + @items_per_page {:noreply, socket |> assign(:offset, new_offset) |> load_components(append: true)} end def handle_event("increment_count", %{"id" => id}, socket) do component = Inventory.get_component!(id) case Inventory.increment_component_count(component) do {:ok, _updated_component} -> {:noreply, socket |> put_flash(:info, "Count updated") |> load_components()} {:error, _changeset} -> {:noreply, put_flash(socket, :error, "Failed to update count")} end end def handle_event("decrement_count", %{"id" => id}, socket) do component = Inventory.get_component!(id) case Inventory.decrement_component_count(component) do {:ok, _updated_component} -> {:noreply, socket |> put_flash(:info, "Count updated") |> load_components()} {:error, _changeset} -> {:noreply, put_flash(socket, :error, "Failed to update count")} end end def handle_event("delete_component", %{"id" => id}, socket) do component = Inventory.get_component!(id) case Inventory.delete_component(component) do {:ok, _deleted_component} -> {:noreply, socket |> put_flash(:info, "Component deleted") |> load_components()} {:error, _changeset} -> {:noreply, put_flash(socket, :error, "Failed to delete component")} end end def handle_event("show_add_form", _params, socket) do changeset = Inventory.change_component(%Component{}) form = to_form(changeset) {:noreply, socket |> assign(:show_add_form, true) |> assign(:form, form)} end def handle_event("hide_add_form", _params, socket) do {:noreply, socket |> assign(:show_add_form, false) |> assign(:form, nil)} end def handle_event("save_component", %{"component" => component_params}, socket) do case Inventory.create_component(component_params) do {:ok, _component} -> {:noreply, socket |> put_flash(:info, "Component created successfully") |> assign(:show_add_form, false) |> 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) filters = [ search: socket.assigns.search, sort_criteria: socket.assigns.sort_criteria, limit: @items_per_page, offset: socket.assigns.offset ] %{components: new_components, has_more: has_more} = Inventory.paginate_components(filters) components = if append do socket.assigns.components ++ new_components else new_components end socket |> assign(:components, components) |> assign(:has_more, has_more) end defp build_query_params(socket, overrides) do params = %{ search: Map.get(overrides, :search, socket.assigns.search), criteria: Map.get(overrides, :criteria, socket.assigns.sort_criteria) } params |> Enum.reject(fn {_k, v} -> is_nil(v) or v == "" end) |> URI.encode_query() end defp category_options(categories) do [{"Select a category", nil}] ++ Enum.map(categories, fn category -> {category.name, category.id} end) end @impl true def render(assigns) do ~H"""
<%= if component.datasheet_url do %> <%= component.name %> <.icon name="hero-arrow-top-right-on-square" class="w-4 h-4 inline ml-1" /> <% else %> <%= component.name %> <% end %>
<%= component.category.name %>
<%= if component.description do %> <%= component.description %> <% end %>
Position: <%= component.position %>
<% end %>Count: <%= component.count %>
<%= if @sort_criteria == "all" or @sort_criteria == "id" do %>ID: <%= component.id %>
<% end %>Keywords: <%= component.keywords %>
<%= if @search != "" do %> Try adjusting your search terms. <% else %> Get started by adding your first component. <% end %>