2026-02-18 21:23:15 +00:00
|
|
|
defmodule BerrypodWeb.Admin.Providers.Index do
|
|
|
|
|
use BerrypodWeb, :live_view
|
2026-01-31 22:08:34 +00:00
|
|
|
|
2026-02-18 21:23:15 +00:00
|
|
|
alias Berrypod.Products
|
|
|
|
|
alias Berrypod.Products.ProviderConnection
|
add setup onboarding page, dashboard launch checklist, provider registry
- new /setup page with three-section onboarding (account, provider, payments)
- dashboard launch checklist with progress bar, go-live, dismiss
- provider registry on Provider module (single source of truth for metadata)
- payments registry for Stripe
- setup context made provider-agnostic (provider_connected, theme_customised, etc.)
- admin provider pages now fully registry-driven (no hardcoded provider names)
- auth flow: fresh installs redirect to /setup, signed_in_path respects setup state
- removed old /admin/setup wizard
- 840 tests, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 00:34:06 +00:00
|
|
|
alias Berrypod.Providers.Provider
|
2026-01-31 22:08:34 +00:00
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
|
def mount(_params, _session, socket) do
|
|
|
|
|
connections = Products.list_provider_connections()
|
|
|
|
|
|
|
|
|
|
{:ok,
|
|
|
|
|
socket
|
|
|
|
|
|> assign(:page_title, "Provider connections")
|
add setup onboarding page, dashboard launch checklist, provider registry
- new /setup page with three-section onboarding (account, provider, payments)
- dashboard launch checklist with progress bar, go-live, dismiss
- provider registry on Provider module (single source of truth for metadata)
- payments registry for Stripe
- setup context made provider-agnostic (provider_connected, theme_customised, etc.)
- admin provider pages now fully registry-driven (no hardcoded provider names)
- auth flow: fresh installs redirect to /setup, signed_in_path respects setup state
- removed old /admin/setup wizard
- 840 tests, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 00:34:06 +00:00
|
|
|
|> assign(:available_providers, Provider.available())
|
2026-01-31 22:08:34 +00:00
|
|
|
|> 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"""
|
|
|
|
|
<span class={[
|
complete admin CSS refactor: delete utilities.css, add layout primitives
- Delete utilities.css (701 lines / 24 KB of Tailwind utility clones)
- Add layout.css with admin-stack, admin-row, admin-cluster, admin-grid
primitives and gap variants (sm, md, lg, xl)
- Add transitions.css import and layout.css import to admin.css entry point
- Replace all Tailwind utility classes across 26 admin templates with
semantic admin-*/theme-*/page-specific CSS classes
- Replace all non-dynamic inline styles with semantic classes
- Add ~100 new semantic classes to components.css (analytics, dashboard,
order detail, settings, theme editor, generic utilities)
- Fix stray text-error → admin-text-error in media.ex
- Add missing .truncate definition to admin CSS
- Only remaining inline styles are dynamic data values (progress bars,
chart dimensions) and one JS.toggle target
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:40:21 +00:00
|
|
|
"admin-provider-dot",
|
2026-01-31 22:08:34 +00:00
|
|
|
cond do
|
complete admin CSS refactor: delete utilities.css, add layout primitives
- Delete utilities.css (701 lines / 24 KB of Tailwind utility clones)
- Add layout.css with admin-stack, admin-row, admin-cluster, admin-grid
primitives and gap variants (sm, md, lg, xl)
- Add transitions.css import and layout.css import to admin.css entry point
- Replace all Tailwind utility classes across 26 admin templates with
semantic admin-*/theme-*/page-specific CSS classes
- Replace all non-dynamic inline styles with semantic classes
- Add ~100 new semantic classes to components.css (analytics, dashboard,
order detail, settings, theme editor, generic utilities)
- Fix stray text-error → admin-text-error in media.ex
- Add missing .truncate definition to admin CSS
- Only remaining inline styles are dynamic data values (progress bars,
chart dimensions) and one JS.toggle target
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:40:21 +00:00
|
|
|
not @enabled -> "admin-provider-dot-idle"
|
|
|
|
|
@status == "syncing" -> "admin-provider-dot-syncing"
|
|
|
|
|
@status == "completed" -> "admin-provider-dot-ok"
|
|
|
|
|
@status == "failed" -> "admin-provider-dot-error"
|
|
|
|
|
true -> "admin-provider-dot-idle"
|
2026-01-31 22:08:34 +00:00
|
|
|
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"""
|
|
|
|
|
<span>
|
|
|
|
|
<.icon name="hero-cube" class="size-4 inline" />
|
|
|
|
|
{@product_count} {if @product_count == 1, do: "product", else: "products"}
|
|
|
|
|
</span>
|
|
|
|
|
<span :if={@connection.last_synced_at}>
|
|
|
|
|
<.icon name="hero-clock" class="size-4 inline" />
|
|
|
|
|
Last synced {format_relative_time(@connection.last_synced_at)}
|
|
|
|
|
</span>
|
complete admin CSS refactor: delete utilities.css, add layout primitives
- Delete utilities.css (701 lines / 24 KB of Tailwind utility clones)
- Add layout.css with admin-stack, admin-row, admin-cluster, admin-grid
primitives and gap variants (sm, md, lg, xl)
- Add transitions.css import and layout.css import to admin.css entry point
- Replace all Tailwind utility classes across 26 admin templates with
semantic admin-*/theme-*/page-specific CSS classes
- Replace all non-dynamic inline styles with semantic classes
- Add ~100 new semantic classes to components.css (analytics, dashboard,
order detail, settings, theme editor, generic utilities)
- Fix stray text-error → admin-text-error in media.ex
- Add missing .truncate definition to admin CSS
- Only remaining inline styles are dynamic data values (progress bars,
chart dimensions) and one JS.toggle target
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:40:21 +00:00
|
|
|
<span :if={!@connection.last_synced_at} class="admin-text-warning">
|
2026-01-31 22:08:34 +00:00
|
|
|
<.icon name="hero-exclamation-triangle" class="size-4 inline" /> Never synced
|
|
|
|
|
</span>
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
add setup onboarding page, dashboard launch checklist, provider registry
- new /setup page with three-section onboarding (account, provider, payments)
- dashboard launch checklist with progress bar, go-live, dismiss
- provider registry on Provider module (single source of truth for metadata)
- payments registry for Stripe
- setup context made provider-agnostic (provider_connected, theme_customised, etc.)
- admin provider pages now fully registry-driven (no hardcoded provider names)
- auth flow: fresh installs redirect to /setup, signed_in_path respects setup state
- removed old /admin/setup wizard
- 840 tests, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 00:34:06 +00:00
|
|
|
defp provider_name(type) do
|
|
|
|
|
case Provider.get(type) do
|
|
|
|
|
%{name: name} -> name
|
|
|
|
|
nil -> String.capitalize(type)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2026-01-31 22:08:34 +00:00
|
|
|
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
|