diff --git a/lib/algora/jobs/jobs.ex b/lib/algora/jobs/jobs.ex index 447c7f8a0..b80bdb756 100644 --- a/lib/algora/jobs/jobs.ex +++ b/lib/algora/jobs/jobs.ex @@ -213,6 +213,13 @@ defmodule Algora.Jobs do end end + def withdraw_application(job_id, user) do + case JobApplication |> where([a], a.job_id == ^job_id and a.user_id == ^user.id) |> Repo.one() do + nil -> {:error, :not_found} + application -> Repo.delete(application) + end + end + def list_user_applications(user) do JobApplication |> where([a], a.user_id == ^user.id) diff --git a/lib/algora_web/live/org/jobs_live.ex b/lib/algora_web/live/org/jobs_live.ex index 01e3548c6..96d472ab2 100644 --- a/lib/algora_web/live/org/jobs_live.ex +++ b/lib/algora_web/live/org/jobs_live.ex @@ -178,9 +178,19 @@ defmodule AlgoraWeb.Org.JobsLive do <% end %> - <.button phx-click="apply_job" phx-value-job-id={job.id}> - I'm interested - + <%= if MapSet.member?(@user_applications, job.id) do %> + <.button + variant="secondary" + phx-click="withdraw_application" + phx-value-job-id={job.id} + > + Withdraw + + <% else %> + <.button phx-click="apply_job" phx-value-job-id={job.id}> + I'm interested + + <% end %> <% end %> @@ -254,6 +264,27 @@ defmodule AlgoraWeb.Org.JobsLive do end end + @impl true + def handle_event("withdraw_application", %{"job-id" => job_id}, socket) do + current_user = socket.assigns[:current_user] + org = socket.assigns.current_org + + if current_user do + case Jobs.withdraw_application(job_id, current_user) do + {:ok, _application} -> + {:noreply, assign_user_applications(socket)} + + {:error, :not_found} -> + {:noreply, put_flash(socket, :error, "Application not found.")} + + {:error, _changeset} -> + {:noreply, put_flash(socket, :error, "Failed to withdraw application. Please try again.")} + end + else + {:noreply, push_navigate(socket, to: "/#{org.handle}/job/#{job_id}/apply")} + end + end + @impl true def handle_event(_event, _params, socket) do {:noreply, socket} diff --git a/test/algora/jobs_test.exs b/test/algora/jobs_test.exs new file mode 100644 index 000000000..eb5af1471 --- /dev/null +++ b/test/algora/jobs_test.exs @@ -0,0 +1,34 @@ +defmodule Algora.JobsTest do + use Algora.DataCase + + import Algora.Factory + + alias Algora.Jobs + alias Algora.Jobs.JobApplication + alias Algora.Repo + + describe "withdraw_application/2" do + test "deletes the current user's application" do + user = insert!(:user) + job = insert!(:job_posting, user: insert!(:user)) + + assert {:ok, application} = Jobs.create_application(job.id, user) + assert MapSet.member?(Jobs.list_user_applications(user), job.id) + + assert {:ok, deleted_application} = Jobs.withdraw_application(job.id, user) + assert deleted_application.id == application.id + refute MapSet.member?(Jobs.list_user_applications(user), job.id) + refute Repo.get(JobApplication, application.id) + end + + test "does not delete another user's application" do + owner = insert!(:user) + other_user = insert!(:user) + job = insert!(:job_posting, user: insert!(:user)) + + assert {:ok, application} = Jobs.create_application(job.id, owner) + assert {:error, :not_found} = Jobs.withdraw_application(job.id, other_user) + assert Repo.get(JobApplication, application.id) + end + end +end diff --git a/test/algora_web/live/org/jobs_live_test.exs b/test/algora_web/live/org/jobs_live_test.exs new file mode 100644 index 000000000..4859c6cee --- /dev/null +++ b/test/algora_web/live/org/jobs_live_test.exs @@ -0,0 +1,38 @@ +defmodule AlgoraWeb.Org.JobsLiveTest do + use AlgoraWeb.ConnCase + + import Algora.Factory + import Phoenix.LiveViewTest + + alias Algora.Jobs + alias AlgoraWeb.UserAuth + + setup %{conn: conn} do + {:ok, conn: Phoenix.ConnTest.init_test_session(conn, %{})} + end + + test "lets a user withdraw an existing job application", %{conn: conn} do + user = insert!(:user) + org = insert!(:organization) + job = insert!(:job_posting, user: org) + + assert {:ok, _application} = Jobs.create_application(job.id, user) + + {:ok, view, html} = + conn + |> UserAuth.put_current_user(user) + |> live("/#{org.handle}/jobs") + + assert html =~ "Withdraw" + assert has_element?(view, "button[phx-click=withdraw_application]", "Withdraw") + refute has_element?(view, "button[phx-click=apply_job]", "I'm interested") + + view + |> element("button[phx-click=withdraw_application]") + |> render_click() + + assert has_element?(view, "button[phx-click=apply_job]", "I'm interested") + refute has_element?(view, "button[phx-click=withdraw_application]", "Withdraw") + assert {:error, :not_found} = Jobs.withdraw_application(job.id, user) + end +end