Skip to content

Commit

Permalink
feat: edit and delete activity from activity view
Browse files Browse the repository at this point in the history
- adjusted `activities_assessment_points_activity_id_fkey` constraint to prevent delete cascade assessment points when deleting activities
  • Loading branch information
endoooo committed Dec 1, 2023
1 parent 14eb7e0 commit 573526b
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 26 deletions.
17 changes: 13 additions & 4 deletions lib/lanttern/learning_context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,20 @@ defmodule Lanttern.LearningContext do
defp set_activity_position_attr(attrs) do
strand_id = attrs[:strand_id] || attrs["strand_id"]

position =
positions =
from(
a in Activity,
where: a.strand_id == ^strand_id,
select: count()
select: a.position,
order_by: [desc: a.position]
)
|> Repo.one()
|> Repo.all()

position =
case Enum.at(positions, 0) do
nil -> 0
pos -> pos + 1
end

cond do
not is_nil(attrs[:strand_id]) ->
Expand Down Expand Up @@ -282,7 +289,9 @@ defmodule Lanttern.LearningContext do
"""
def delete_activity(%Activity{} = activity) do
Repo.delete(activity)
activity
|> Activity.delete_changeset()
|> Repo.delete()
end

@doc """
Expand Down
10 changes: 10 additions & 0 deletions lib/lanttern/learning_context/activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,14 @@ defmodule Lanttern.LearningContext.Activity do
|> validate_required([:name, :description, :position, :strand_id])
|> put_subjects()
end

def delete_changeset(activity) do
activity
|> cast(%{}, [])
|> foreign_key_constraint(
:id,
name: :activities_assessment_points_activity_id_fkey,
message: "Activity has linked assessment points."
)
end
end
30 changes: 30 additions & 0 deletions lib/lanttern_web/live/strand_live/activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule LantternWeb.StrandLive.Activity do
alias Lanttern.LearningContext
alias LantternWeb.StrandLive.ActivityTabs

# live components
alias LantternWeb.StrandLive.ActivityFormComponent
alias LantternWeb.AssessmentPointLive.ActivityAssessmentPointFormComponent

@tabs %{
Expand All @@ -14,10 +16,12 @@ defmodule LantternWeb.StrandLive.Activity do

# lifecycle

@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :activity, nil), layout: {LantternWeb.Layouts, :app_logged_in_blank}}
end

@impl true
def handle_params(params, _url, socket) do
{:noreply,
socket
Expand Down Expand Up @@ -66,8 +70,34 @@ defmodule LantternWeb.StrandLive.Activity do

defp apply_action(socket, _live_action, _params), do: socket

# event handlers

@impl true
def handle_event("delete_activity", _params, socket) do
case LearningContext.delete_activity(socket.assigns.activity) do
{:ok, _activity} ->
{:noreply,
socket
|> put_flash(:info, "Activity deleted")
|> push_navigate(to: ~p"/strands/#{socket.assigns.activity.strand}?tab=activities")}

{:error, _changeset} ->
{:noreply,
socket
|> put_flash(
:error,
"Activity has linked assessments. Deleting it would cause some data loss."
)}
end
end

# info handlers

@impl true
def handle_info({ActivityFormComponent, {:saved, activity}}, socket) do
{:noreply, assign(socket, :activity, activity)}
end

def handle_info(
{ActivityTabs.AssessmentComponent, {:apply_class_filters, classes_ids}},
socket
Expand Down
90 changes: 69 additions & 21 deletions lib/lanttern_web/live/strand_live/activity.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,47 @@
</div>
</.cover>
<div class="sticky top-0 z-30 border-b border-ltrn-lighter bg-white">
<.nav_tabs class="container mx-auto lg:max-w-5xl" id="activity-nav-tabs">
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "details"}}"}
is_current={@current_tab == :details && "true"}
>
Details & Curriculum
</:tab>
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "assessment"}}"}
is_current={@current_tab == :assessment && "true"}
>
Assessment
</:tab>
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "notes"}}"}
is_current={@current_tab == :notes && "true"}
icon_name="hero-eye-slash"
>
My notes
</:tab>
</.nav_tabs>
<div class="flex items-center justify-between container lg:max-w-5xl mx-auto">
<.nav_tabs id="activity-nav-tabs">
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "details"}}"}
is_current={@current_tab == :details && "true"}
>
Details & Curriculum
</:tab>
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "assessment"}}"}
is_current={@current_tab == :assessment && "true"}
>
Assessment
</:tab>
<:tab
patch={~p"/strands/activity/#{@activity}?#{%{tab: "notes"}}"}
is_current={@current_tab == :notes && "true"}
icon_name="hero-eye-slash"
>
My notes
</:tab>
</.nav_tabs>
<.menu_button id={"activity-#{@activity.id}"}>
<:menu_items>
<.menu_button_item
id={"edit-activity-#{@activity.id}"}
phx-click={JS.patch(~p"/strands/activity/#{@activity}/edit")}
>
Edit activity
</.menu_button_item>
<.menu_button_item
id={"remove-activity-#{@activity.id}"}
class="text-red-500"
phx-click="delete_activity"
data-confirm="Are you sure?"
>
Delete
</.menu_button_item>
</:menu_items>
</.menu_button>
</div>
</div>
<div class="ltrn-bg-main-local">
<.live_component
Expand All @@ -71,3 +91,31 @@
current_user={@current_user}
/>
</div>
<.slide_over
:if={@live_action == :edit}
id="activity-form-overlay"
show={true}
on_cancel={JS.patch(~p"/strands/activity/#{@activity}")}
>
<:title>Edit activity</:title>
<.live_component
module={ActivityFormComponent}
id={@activity.id}
activity={@activity}
action={@live_action}
patch={~p"/strands/activity/#{@activity}"}
notify_parent
/>
<:actions>
<.button
type="button"
theme="ghost"
phx-click={JS.exec("data-cancel", to: "#activity-form-overlay")}
>
Cancel
</.button>
<.button type="submit" form="activity-form">
Save
</.button>
</:actions>
</.slide_over>
2 changes: 1 addition & 1 deletion lib/lanttern_web/live/strand_live/details.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
id={"edit-strand-#{@strand.id}"}
phx-click={JS.patch(~p"/strands/#{@strand}/edit")}
>
Edit
Edit strand
</.menu_button_item>
<.menu_button_item
id={"remove-strand-#{@strand.id}"}
Expand Down
1 change: 1 addition & 0 deletions lib/lanttern_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ defmodule LantternWeb.Router do
live "/strands/:id/edit", StrandLive.Details, :edit
live "/strands/:id/new_activity", StrandLive.Details, :new_activity
live "/strands/activity/:id", StrandLive.Activity, :show
live "/strands/activity/:id/edit", StrandLive.Activity, :edit

live "/strands/activity/:id/assessment_point/new",
StrandLive.Activity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Lanttern.Repo.Migrations.SetActivitiesAssessmentPointsActivityIdFkeyOnDeleteNothing do
use Ecto.Migration

def change do
execute """
ALTER TABLE activities_assessment_points
DROP CONSTRAINT activities_assessment_points_activity_id_fkey,
ADD CONSTRAINT activities_assessment_points_activity_id_fkey FOREIGN KEY (activity_id)
REFERENCES activities (id);
""",
"""
ALTER TABLE activities_assessment_points
DROP CONSTRAINT activities_assessment_points_activity_id_fkey,
ADD CONSTRAINT activities_assessment_points_activity_id_fkey FOREIGN KEY (activity_id)
REFERENCES activities (id) ON DELETE CASCADE;
"""
end
end
46 changes: 46 additions & 0 deletions test/lanttern_web/live/strand_live/activity_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,50 @@ defmodule LantternWeb.StrandLive.ActivityTest do
assert view |> has_element?("p", "activity description abc")
end
end

describe "Activity management" do
test "edit activity", %{conn: conn} do
subject = TaxonomyFixtures.subject_fixture(%{name: "subject abc"})
strand = LearningContextFixtures.strand_fixture(%{subjects_ids: [subject.id]})

activity =
LearningContextFixtures.activity_fixture(%{strand_id: strand.id, name: "activity abc"})

{:ok, view, _html} = live(conn, "#{@live_view_base_path}/#{activity.id}/edit")

assert view
|> has_element?("h2", "Edit activity")

# add subject
view
|> element("#activity-form #activity_subject_id")
|> render_change(%{"activity" => %{"subject_id" => subject.id}})

# submit form with valid field
view
|> element("#activity-form")
|> render_submit(%{
"activity" => %{
"name" => "activity name xyz"
}
})

assert_patch(view, "#{@live_view_base_path}/#{activity.id}")

assert view |> has_element?("h1", "activity name xyz")
assert view |> has_element?("span", subject.name)
end

test "delete activity", %{conn: conn} do
activity = LearningContextFixtures.activity_fixture()

{:ok, view, _html} = live(conn, "#{@live_view_base_path}/#{activity.id}")

view
|> element("button#remove-activity-#{activity.id}")
|> render_click()

assert_redirect(view, "/strands/#{activity.strand_id}?tab=activities")
end
end
end

0 comments on commit 573526b

Please sign in to comment.