defmodule DaProductAppWeb.DeviceConfigLive.Index do use DaProductAppWeb, :live_view require Logger alias DaProductApp.TerminalManagement alias DaProductApp.TerminalManagement.DeviceConfiguration @impl true def mount(_params, _session, socket) do if connected?(socket), do: Phoenix.PubSub.subscribe(DaProductApp.PubSub, "device_configs") filters = %{"status" => "all", "device_type" => "", "name" => ""} configurations = TerminalManagement.list_device_configurations_with_filters(filters) terminals = TerminalManagement.list_terminals_full() {:ok, assign(socket, configurations: configurations, terminals: terminals, current_page: "device_configs", filters: filters, selected_config: nil, show_new_config: false, show_config_form: false, new_config_form: %{}, config_form: %{}, config_errors: %{}, page: 1, per_page: 10, total: length(configurations) )} end @impl true def handle_params(_params, _uri, %{assigns: %{live_action: :new}} = socket) do new_config_form = %{ "name" => "", "description" => "", "device_type" => "", "configuration_data" => Jason.encode!(DeviceConfiguration.default_configuration("SR600 Mini"), pretty: true), "status" => "draft", "terminal_id" => "", "created_by" => get_current_user_email(socket), "updated_by" => get_current_user_email(socket) } {:noreply, assign(socket, show_new_config: true, new_config_form: new_config_form, config_errors: %{} )} end @impl true def handle_params(_params, _uri, socket) do {:noreply, assign(socket, show_new_config: false, selected_config: nil)} end @impl true def handle_event("filter", params, socket) do filters = Map.merge(socket.assigns.filters, params) configurations = TerminalManagement.list_device_configurations_with_filters(filters) {:noreply, assign(socket, configurations: configurations, filters: filters, page: 1, total: length(configurations) )} end @impl true def handle_event("set_status_tab", %{"status" => status}, socket) do filters = Map.put(socket.assigns.filters, "status", status) configurations = TerminalManagement.list_device_configurations_with_filters(filters) {:noreply, assign(socket, configurations: configurations, filters: filters, page: 1, total: length(configurations) )} end @impl true def handle_event("close_new_config", _params, socket) do {:noreply, push_patch(socket, to: "/admin/device-configs")} end @impl true def handle_event("show_config_details", %{"id" => id}, socket) do config = TerminalManagement.get_device_configuration!(id) config_form = %{ "name" => config.name, "description" => config.description || "", "device_type" => config.device_type, "configuration_data" => Jason.encode!(config.configuration_data, pretty: true), "status" => config.status, "terminal_id" => to_string(config.terminal_id || ""), "updated_by" => get_current_user_email(socket) } {:noreply, assign(socket, selected_config: config, config_form: config_form, show_config_form: false )} end @impl true def handle_event("close_config_details", _params, socket) do {:noreply, assign(socket, selected_config: nil, show_config_form: false)} end @impl true def handle_event("toggle_edit_mode", _params, socket) do {:noreply, assign(socket, show_config_form: !socket.assigns.show_config_form)} end @impl true def handle_event("update_new_config_form", %{"new_config_form" => form_params}, socket) do # Handle device type change to update default configuration new_form = if form_params["device_type"] != socket.assigns.new_config_form["device_type"] do default_config = DeviceConfiguration.default_configuration(form_params["device_type"]) Map.put(form_params, "configuration_data", Jason.encode!(default_config, pretty: true)) else form_params end new_config_form = Map.merge(socket.assigns.new_config_form, new_form) {:noreply, assign(socket, new_config_form: new_config_form, config_errors: %{})} end @impl true def handle_event("update_config_form", %{"config_form" => form_params}, socket) do config_form = Map.merge(socket.assigns.config_form, form_params) {:noreply, assign(socket, config_form: config_form)} end @impl true def handle_event("create_config", _params, socket) do config_attrs = prepare_config_attrs(socket.assigns.new_config_form) Logger.debug("Creating config with attrs: #{inspect(config_attrs)}") case TerminalManagement.create_device_configuration(config_attrs) do {:ok, config} -> Logger.debug("Config created successfully: #{inspect(config)}") configurations = TerminalManagement.list_device_configurations_with_filters(socket.assigns.filters) {:noreply, socket |> put_flash(:info, "Device configuration created successfully") |> assign(:configurations, configurations) |> push_patch(to: "/admin/device-configs")} {:error, changeset} -> Logger.error("Failed to create config: #{inspect(changeset.errors)}") errors = extract_errors(changeset) {:noreply, assign(socket, config_errors: errors)} end end @impl true def handle_event("update_config", _params, socket) do config_attrs = prepare_config_attrs(socket.assigns.config_form) case TerminalManagement.update_device_configuration(socket.assigns.selected_config, config_attrs) do {:ok, config} -> configurations = TerminalManagement.list_device_configurations_with_filters(%{}) {:noreply, socket |> put_flash(:info, "Configuration updated successfully") |> assign(:configurations, configurations) |> assign(:selected_config, config) |> assign(:show_config_form, false)} {:error, changeset} -> errors = extract_changeset_errors(changeset) {:noreply, assign(socket, :config_errors, errors)} end end @impl true def handle_event("delete_config", %{"id" => id}, socket) do config = TerminalManagement.get_device_configuration!(id) case TerminalManagement.delete_device_configuration(config) do {:ok, _} -> configurations = TerminalManagement.list_device_configurations_with_filters(socket.assigns.filters) {:noreply, socket |> put_flash(:info, "Device configuration deleted successfully") |> assign(:configurations, configurations) |> assign(:selected_config, nil)} {:error, _changeset} -> {:noreply, put_flash(socket, :error, "Unable to delete configuration")} end end @impl true def handle_event("apply_to_terminal", %{"config_id" => config_id, "terminal_id" => terminal_id}, socket) do user = get_current_user_email(socket) case TerminalManagement.apply_configuration_to_terminal(config_id, terminal_id, user) do {:ok, _} -> {:noreply, put_flash(socket, :info, "Configuration applied to terminal successfully")} {:error, _reason} -> {:noreply, put_flash(socket, :error, "Failed to apply configuration to terminal")} end end @impl true def handle_event("close_slide_over", _params, socket) do {:noreply, socket |> assign(:selected_config, nil) |> assign(:show_new_config, false) |> assign(:show_config_form, false)} end # Utility functions defp prepare_config_attrs(form_data) do config_data = case Jason.decode(form_data["configuration_data"] || "{}") do {:ok, data} -> data {:error, _} -> %{} end form_data |> Map.put("configuration_data", config_data) |> Map.reject(fn {_k, v} -> is_nil(v) or v == "" end) |> Enum.into(%{}, fn {k, v} -> case k do "terminal_id" when v != "" -> case Integer.parse(v) do {int_val, ""} -> {String.to_atom(k), int_val} _ -> {String.to_atom(k), nil} end _ -> {String.to_atom(k), v} end end) end defp extract_errors(changeset) do changeset.errors |> Enum.into(%{}, fn {field, {message, _}} -> {to_string(field), message} end) end defp extract_changeset_errors(changeset) do changeset.errors |> Enum.into(%{}, fn {field, {message, _}} -> {to_string(field), message} end) end defp get_current_user_email(socket) do case socket.assigns[:current_user] do %{email: email} -> email _ -> "system@example.com" end end end