Packages
phoenix_kit
1.7.44
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/shop/web/import_show.ex
defmodule PhoenixKit.Modules.Shop.Web.ImportShow do
@moduledoc """
LiveView for displaying import details.
Shows:
- Import metadata (filename, user, dates)
- Statistics summary (imported/updated/skipped/errors)
- List of imported products with links to edit
- Error details (if any)
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Shop
alias PhoenixKit.Modules.Shop.Translations
alias PhoenixKit.Utils.Routes
@impl true
def mount(%{"uuid" => uuid}, _session, socket) do
case Shop.get_import_log(uuid, preload: [:user]) do
nil ->
{:ok,
socket
|> put_flash(:error, "Import not found")
|> push_navigate(to: Routes.path("/admin/shop/imports"))}
import_log ->
products = load_products(import_log.product_ids || [])
socket =
socket
|> assign(:page_title, "Import: #{import_log.filename}")
|> assign(:import, import_log)
|> assign(:products, products)
{:ok, socket}
end
end
@impl true
def handle_params(_params, uri, socket) do
{:noreply, assign(socket, :url_path, URI.parse(uri).path)}
end
defp load_products([]), do: []
defp load_products(product_ids) do
Shop.list_products_by_ids(product_ids)
end
defp format_datetime(nil), do: "-"
defp format_datetime(datetime) do
Calendar.strftime(datetime, "%b %d, %Y %H:%M")
end
defp get_localized(nil), do: "-"
defp get_localized(value) when is_binary(value), do: value
defp get_localized(value) when is_map(value) do
lang = Translations.default_language()
Map.get(value, lang) || Map.get(value, "en") || Map.values(value) |> List.first() || "-"
end
defp format_price(nil), do: "-"
defp format_price(%Decimal{} = price), do: Decimal.to_string(price)
defp format_price(price) when is_number(price), do: to_string(price)
@impl true
def render(assigns) do
~H"""
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={@phoenix_kit_current_scope}
current_path={@url_path}
current_locale={@current_locale}
page_title={@page_title}
>
<div class="container mx-auto px-4 py-6 max-w-4xl">
<%!-- Header with back button --%>
<header class="mb-6 flex items-center gap-4">
<.link
navigate={Routes.path("/admin/shop/imports")}
class="btn btn-ghost btn-sm"
>
<.icon name="hero-arrow-left" class="w-4 h-4" />
</.link>
<h1 class="text-2xl font-bold flex-1">Import Details</h1>
<span class={[
"badge",
case @import.status do
"pending" -> "badge-warning"
"processing" -> "badge-info"
"completed" -> "badge-success"
"failed" -> "badge-error"
_ -> "badge-ghost"
end
]}>
{@import.status}
</span>
</header>
<%!-- Metadata card --%>
<div class="card bg-base-100 shadow mb-6">
<div class="card-body">
<h2 class="card-title text-lg mb-4">
<.icon name="hero-document-text" class="w-5 h-5" /> Import Information
</h2>
<dl class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<dt class="text-sm text-base-content/60">Filename</dt>
<dd class="font-medium">{@import.filename}</dd>
</div>
<div>
<dt class="text-sm text-base-content/60">User</dt>
<dd class="font-medium">{if @import.user, do: @import.user.email, else: "-"}</dd>
</div>
<div>
<dt class="text-sm text-base-content/60">Started At</dt>
<dd class="font-medium">{format_datetime(@import.started_at)}</dd>
</div>
<div>
<dt class="text-sm text-base-content/60">Completed At</dt>
<dd class="font-medium">{format_datetime(@import.completed_at)}</dd>
</div>
</dl>
</div>
</div>
<%!-- Statistics --%>
<div class="stats shadow w-full mb-6">
<div class="stat">
<div class="stat-figure text-success">
<.icon name="hero-plus-circle" class="w-8 h-8" />
</div>
<div class="stat-title">Imported</div>
<div class="stat-value text-success">{@import.imported_count}</div>
<div class="stat-desc">new products</div>
</div>
<div class="stat">
<div class="stat-figure text-info">
<.icon name="hero-arrow-path" class="w-8 h-8" />
</div>
<div class="stat-title">Updated</div>
<div class="stat-value text-info">{@import.updated_count}</div>
<div class="stat-desc">existing products</div>
</div>
<div class="stat">
<div class="stat-figure text-warning">
<.icon name="hero-minus-circle" class="w-8 h-8" />
</div>
<div class="stat-title">Skipped</div>
<div class="stat-value text-warning">{@import.skipped_count}</div>
<div class="stat-desc">filtered out</div>
</div>
<div class="stat">
<div class="stat-figure text-error">
<.icon name="hero-exclamation-circle" class="w-8 h-8" />
</div>
<div class="stat-title">Errors</div>
<div class="stat-value text-error">{@import.error_count}</div>
<div class="stat-desc">failed rows</div>
</div>
</div>
<%!-- Products list --%>
<%= if @products != [] do %>
<div class="card bg-base-100 shadow mb-6">
<div class="card-body">
<h2 class="card-title text-lg mb-4">
<.icon name="hero-cube" class="w-5 h-5" /> Imported Products
<span class="badge badge-ghost">{length(@products)}</span>
</h2>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th>Title</th>
<th>Slug</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<%= for product <- @products do %>
<tr class="hover">
<td class="font-medium max-w-[250px] truncate">
{get_localized(product.title)}
</td>
<td class="text-base-content/70 text-sm">
{get_localized(product.slug) || "-"}
</td>
<td>{format_price(product.price)}</td>
<td>
<div class="flex gap-1">
<.link
navigate={Routes.path("/admin/shop/products/#{product.uuid}")}
class="btn btn-xs btn-ghost"
title="View"
>
<.icon name="hero-eye" class="w-4 h-4" />
</.link>
<.link
navigate={Routes.path("/admin/shop/products/#{product.uuid}/edit")}
class="btn btn-xs btn-ghost"
title="Edit"
>
<.icon name="hero-pencil" class="w-4 h-4" />
</.link>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<% else %>
<div class="alert mb-6">
<.icon name="hero-information-circle" class="w-6 h-6" />
<span>
No products tracked for this import. Product tracking was added in a later version.
</span>
</div>
<% end %>
<%!-- Errors section (if any) --%>
<%= if @import.error_count > 0 and @import.error_details != [] do %>
<div class="card bg-base-100 shadow">
<div class="card-body">
<h2 class="card-title text-lg text-error mb-4">
<.icon name="hero-exclamation-triangle" class="w-5 h-5" /> Errors
<span class="badge badge-error">{@import.error_count}</span>
</h2>
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<tr>
<th>Handle</th>
<th>Error</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<%= for error <- Enum.take(@import.error_details, 50) do %>
<tr>
<td class="font-mono text-sm">{error["handle"]}</td>
<td class="text-error text-sm max-w-[300px] truncate">
{error["error"]}
</td>
<td class="text-xs text-base-content/60">
{error["timestamp"]}
</td>
</tr>
<% end %>
</tbody>
</table>
<%= if length(@import.error_details) > 50 do %>
<p class="text-sm text-base-content/60 mt-2">
Showing first 50 of {length(@import.error_details)} errors
</p>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>
"""
end
end