defmodule BerrypodWeb.Admin.Providers.Index do use BerrypodWeb, :live_view alias Berrypod.Products alias Berrypod.Products.ProviderConnection alias Berrypod.Providers.Provider @impl true def mount(_params, _session, socket) do connections = Products.list_provider_connections() {:ok, socket |> assign(:page_title, "Provider connections") |> assign(:available_providers, Provider.available()) |> stream(:connections, connections)} end @impl true def handle_event("delete", %{"id" => id}, socket) do connection = Products.get_provider_connection!(id) {:ok, _} = Products.delete_provider_connection(connection) {:noreply, socket |> stream_delete(:connections, connection) |> put_flash(:info, "Provider connection deleted")} end @impl true def handle_event("sync", %{"id" => id}, socket) do connection = Products.get_provider_connection!(id) case Products.enqueue_sync(connection) do {:ok, _job} -> # Update the connection status in the stream updated = %{connection | sync_status: "syncing"} {:noreply, socket |> stream_insert(:connections, updated) |> put_flash(:info, "Sync started for #{connection.name}")} {:error, _reason} -> {:noreply, put_flash(socket, :error, "Failed to start sync")} end end # Function components for the template attr :status, :string, required: true attr :enabled, :boolean, required: true defp status_indicator(assigns) do ~H""" "bg-base-content/30" @status == "syncing" -> "bg-warning animate-pulse" @status == "completed" -> "bg-success" @status == "failed" -> "bg-error" true -> "bg-base-content/30" end ]} /> """ end attr :connection, ProviderConnection, required: true defp connection_info(assigns) do product_count = Products.count_products_for_connection(assigns.connection.id) assigns = assign(assigns, :product_count, product_count) ~H""" <.icon name="hero-cube" class="size-4 inline" /> {@product_count} {if @product_count == 1, do: "product", else: "products"} <.icon name="hero-clock" class="size-4 inline" /> Last synced {format_relative_time(@connection.last_synced_at)} <.icon name="hero-exclamation-triangle" class="size-4 inline" /> Never synced """ end defp provider_name(type) do case Provider.get(type) do %{name: name} -> name nil -> String.capitalize(type) end end defp format_relative_time(datetime) do diff = DateTime.diff(DateTime.utc_now(), datetime, :second) cond do diff < 60 -> "just now" diff < 3600 -> "#{div(diff, 60)} min ago" diff < 86400 -> "#{div(diff, 3600)} hours ago" true -> "#{div(diff, 86400)} days ago" end end end