diff --git a/lib/ares_web/live/app/profile.ex b/lib/ares_web/live/app/profile.ex index 19380d5e..90d376b3 100644 --- a/lib/ares_web/live/app/profile.ex +++ b/lib/ares_web/live/app/profile.ex @@ -1,7 +1,10 @@ defmodule AresWeb.AppLive.Profile do use AresWeb, :live_view + alias Ares.Accounts + alias Ares.Accounts.User alias Ares.Teams + alias AresWeb.Components.CVUploader @impl true def render(assigns) do @@ -35,7 +38,7 @@ defmodule AresWeb.AppLive.Profile do <% end %> <%= if @user.team do %> -
+

Member of

@@ -120,6 +123,51 @@ defmodule AresWeb.AppLive.Profile do
<% end %> + +
+

Upload your CV

+ <%= if @user.cv do %> +
+

Current: {@user.cv.file_name}

+ +
+ <% end %> + + <.form + for={@form} + id="profile_info_form" + phx-submit="save" + phx-change="validate" + class="font-inter mt-8" + > + <.live_component + module={CVUploader} + id="cv-uploader" + uploaders={@uploads} + /> + + <.button + phx-disable-with="Saving..." + class="btn btn-primary w-full mt-6" + disabled={@cv_uploading || @cv_upload_error} + > + Save + + + <%= if @cv_upload_error do %> +

+ There was a problem with the uploaded CV. Please remove and re-upload or try a different file. +

+ <% end %> + +
""" @@ -135,6 +183,114 @@ defmodule AresWeb.AppLive.Profile do nil end - {:ok, assign(socket, user: Map.put(user, :team, team))} + changeset = Accounts.change_user(%User{}, %{}, validate_unique: false) + + {:ok, + socket + |> assign(user: Map.put(user, :team, team)) + |> assign_form(changeset) + |> assign(:cv_uploading, false) + |> assign(:cv_upload_error, nil) + |> allow_upload(:cv, + accept: ~w(.pdf .doc .docx .txt .md .rtf), + max_entries: 1, + max_file_size: 5_000_000, + auto_upload: true, + progress: &handle_progress/3 + )} + end + + def handle_event("remove-cv", _params, socket) do + user = socket.assigns.user + + case Accounts.update_user_cv(user, %{"cv" => nil}) do + {:ok, %Accounts.User{} = updated_user} -> + {:noreply, + socket + |> assign(user: updated_user) + |> put_flash(:info, "CV removed.")} + + {:error, _reason} -> + {:noreply, put_flash(socket, :error, "Could not remove CV.")} + end + end + + @impl true + def handle_event("cancel-upload", %{"ref" => ref} = _params, socket) do + {:noreply, socket |> cancel_upload(:cv, ref) |> assign(:cv_upload_error, nil)} + end + + @impl true + def handle_event("validate", %{"_target" => _} = _params, socket) do + upload_errors = upload_errors(socket.assigns.uploads.cv) || [] + {:noreply, socket |> assign(:cv_upload_error, upload_errors)} + end + + def handle_event("save", _params, socket) do + user = socket.assigns.user + + if socket.assigns.cv_uploading do + {:noreply, socket |> put_flash(:error, "CV upload still in progress. Please wait.")} + else + case consume_pdf_data(socket, {:ok, user}) do + {:ok, %Accounts.User{} = updated_user} -> + {:noreply, + socket + |> assign(user: updated_user) + |> put_flash(:info, "CV uploaded successfully.")} + + {:ok, _} -> + {:noreply, put_flash(socket, :info, "Nothing to upload.")} + + {:error, reason} -> + {:noreply, put_flash(socket, :error, "CV upload failed: #{inspect(reason)}")} + end + end + end + + defp consume_pdf_data(socket, {:ok, user}) do + result = + consume_uploaded_entries(socket, :cv, fn %{path: path}, entry -> + Accounts.update_user_cv(user, %{ + "cv" => %Plug.Upload{ + content_type: entry.client_type, + filename: entry.client_name, + path: path + } + }) + end) + + case result do + [] -> + {:ok, user} + + [error: reason] -> + {:error, reason} + + [updated_user] -> + {:ok, updated_user} + + _ -> + {:ok, socket} + end + end + + defp consume_pdf_data(_socket, result) do + result + end + + def handle_progress(:cv, entry, socket) do + uploading = entry.progress < 100 + errors = upload_errors(socket.assigns.uploads.cv) || [] + + {:noreply, + socket + |> assign(:cv_uploading, uploading) + |> assign(:cv_upload_error, if(errors == [], do: nil, else: errors))} + end + + defp assign_form(socket, %Ecto.Changeset{} = changeset) do + form = to_form(changeset, as: "user") + assign(socket, form: form) end end diff --git a/mix.lock b/mix.lock index e51a70d3..7660bf75 100644 --- a/mix.lock +++ b/mix.lock @@ -23,7 +23,7 @@ "gen_smtp": {:hex, :gen_smtp, "1.3.0", "62c3d91f0dcf6ce9db71bcb6881d7ad0d1d834c7f38c13fa8e952f4104a8442e", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "0b73fbf069864ecbce02fe653b16d3f35fd889d0fdd4e14527675565c39d84e6"}, "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"}, - "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized"]}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},