Show upload progress and submission confirmation on /submit
Add a per-entry progress bar (with cancel) while a CSV streams in, and replace the small post-commit alert with a prominent "X contacts submitted" confirmation card.
This commit is contained in:
parent
912f161874
commit
f21277cf4f
2 changed files with 71 additions and 27 deletions
|
|
@ -109,6 +109,10 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_event("cancel_csv_upload", %{"ref" => ref}, socket) do
|
||||
{:noreply, cancel_upload(socket, :csv, ref)}
|
||||
end
|
||||
|
||||
def handle_event("confirm_csv", _params, socket) do
|
||||
case socket.assigns.csv_preview do
|
||||
%{valid: valid_rows} when valid_rows != [] ->
|
||||
|
|
@ -117,7 +121,7 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
{:noreply,
|
||||
socket
|
||||
|> assign(csv_preview: nil, csv_result: commit_result)
|
||||
|> put_flash(:info, "Imported #{length(commit_result.imported)} contacts.")}
|
||||
|> put_flash(:info, "#{length(commit_result.imported)} contacts submitted.")}
|
||||
|
||||
_ ->
|
||||
{:noreply, put_flash(socket, :error, "Nothing to import.")}
|
||||
|
|
@ -164,6 +168,11 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
end
|
||||
end
|
||||
|
||||
defp error_to_string(:too_large), do: "File is too large"
|
||||
defp error_to_string(:too_many_files), do: "Only one file allowed"
|
||||
defp error_to_string(:not_accepted), do: "Only .csv files are accepted"
|
||||
defp error_to_string(other), do: to_string(other)
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
|
|
@ -348,6 +357,37 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<div :for={entry <- @uploads.csv.entries} class="space-y-1">
|
||||
<div class="flex items-center justify-between text-xs tabular-nums">
|
||||
<span class="truncate pr-2">{entry.client_name}</span>
|
||||
<span class="flex items-center gap-2 shrink-0">
|
||||
<span>{entry.progress}%</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-xs"
|
||||
phx-click="cancel_csv_upload"
|
||||
phx-value-ref={entry.ref}
|
||||
aria-label="Cancel upload"
|
||||
>
|
||||
<.icon name="hero-x-mark" class="w-4 h-4" />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<progress
|
||||
class="progress progress-primary w-full"
|
||||
value={entry.progress}
|
||||
max="100"
|
||||
>
|
||||
</progress>
|
||||
<div :for={err <- upload_errors(@uploads.csv, entry)} class="text-xs text-error">
|
||||
{error_to_string(err)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :for={err <- upload_errors(@uploads.csv)} class="text-xs text-error">
|
||||
{error_to_string(err)}
|
||||
</div>
|
||||
|
||||
<%= if @current_user do %>
|
||||
<input type="hidden" name="submitter_email" value={@current_user.email} />
|
||||
<% else %>
|
||||
|
|
@ -559,24 +599,32 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
defp duplicate_source(_), do: "Duplicate"
|
||||
|
||||
defp csv_results(assigns) do
|
||||
~H"""
|
||||
<div class="space-y-4">
|
||||
<%= if length(@result.imported) > 0 do %>
|
||||
<div class="alert alert-success">
|
||||
<.icon name="hero-check-circle" class="w-5 h-5" />
|
||||
<span>
|
||||
{length(@result.imported)} {if length(@result.imported) == 1,
|
||||
do: "contact",
|
||||
else: "contacts"} imported successfully
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
assigns =
|
||||
assign(assigns,
|
||||
imported_count: length(assigns.result.imported),
|
||||
error_count: length(assigns.result.errors)
|
||||
)
|
||||
|
||||
<%= if length(@result.errors) > 0 do %>
|
||||
~H"""
|
||||
<div class="space-y-6">
|
||||
<div
|
||||
:if={@imported_count > 0}
|
||||
class="rounded-box border border-success/40 bg-success/10 p-8 text-center"
|
||||
>
|
||||
<.icon name="hero-check-circle" class="w-16 h-16 text-success mx-auto mb-3" />
|
||||
<div class="text-3xl font-bold tabular-nums">
|
||||
{@imported_count} {if @imported_count == 1, do: "contact", else: "contacts"} submitted
|
||||
</div>
|
||||
<p class="text-sm opacity-70 mt-2">
|
||||
Weather, terrain, and propagation data will be attached shortly.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div :if={@error_count > 0} class="space-y-2">
|
||||
<div class="alert alert-error">
|
||||
<.icon name="hero-exclamation-triangle" class="w-5 h-5" />
|
||||
<span>
|
||||
{length(@result.errors)} {if length(@result.errors) == 1, do: "row", else: "rows"} had errors at insert time
|
||||
{@error_count} {if @error_count == 1, do: "row", else: "rows"} had errors at insert time
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -589,20 +637,16 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= for {row_num, messages} <- @result.errors do %>
|
||||
<tr>
|
||||
<td class="font-mono">Row {row_num}</td>
|
||||
<td>
|
||||
<%= for msg <- messages do %>
|
||||
<div>{msg}</div>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr :for={{row_num, messages} <- @result.errors}>
|
||||
<td class="font-mono">Row {row_num}</td>
|
||||
<td>
|
||||
<div :for={msg <- messages}>{msg}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-outline" phx-click="reset_csv">
|
||||
Upload another
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ defmodule MicrowavepropWeb.SubmitLiveTest do
|
|||
|> element("button[phx-click=confirm_csv]")
|
||||
|> render_click()
|
||||
|
||||
assert confirm_html =~ "1 contact imported"
|
||||
assert confirm_html =~ "1 contact submitted"
|
||||
assert Repo.aggregate(Contact, :count) == 1
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue