From c1b2fbb8aa079b7b8948c50447baf673df86f776 Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Thu, 21 Mar 2024 12:32:02 -0400 Subject: [PATCH 01/42] only show pending approval message for public notes --- .../delivery/student/lesson/annotations.ex | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index 3e6e0b479a4..371ed7d49ad 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -327,16 +327,18 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :post, Oli.Resources.Collaboration.Post, required: true defp maybe_status(assigns) do - if assigns.post.status == :submitted do - ~H""" -
- Submitted and pending approval -
- """ - else - ~H""" + case assigns.post do + %Oli.Resources.Collaboration.Post{visibility: :public, status: :submitted} -> + ~H""" +
+ Submitted and pending approval +
+ """ + + _ -> + ~H""" - """ + """ end end From 5f3d929d8306dc289a8c0a24e4eb35f2d1a74074 Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Thu, 21 Mar 2024 16:11:04 -0400 Subject: [PATCH 02/42] only show notes if collab spaces are enabled refactor assigns handling --- .../delivery/student/lesson/annotations.ex | 10 +- .../live/delivery/student/lesson_live.ex | 221 ++++++++++-------- 2 files changed, 126 insertions(+), 105 deletions(-) diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index 371ed7d49ad..df029dceb74 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -7,7 +7,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :create_new_annotation, :boolean, default: false attr :annotations, :any, required: true attr :current_user, Oli.Accounts.User, required: true - attr :selected_annotations_tab, :atom, default: :my_notes + attr :active_tab, :atom, default: :my_notes def panel(assigns) do ~H""" @@ -19,10 +19,10 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do
<.tab_group class="py-3"> - <.tab name={:my_notes} selected={@selected_annotations_tab == :my_notes}> + <.tab name={:my_notes} selected={@active_tab == :my_notes}> <.user_icon class="mr-2" /> My Notes - <.tab name={:all_notes} selected={@selected_annotations_tab == :all_notes}> + <.tab name={:all_notes} selected={@active_tab == :all_notes}> <.users_icon class="mr-2" /> Class Notes @@ -32,9 +32,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do <.add_new_annotation_input class="my-2" active={@create_new_annotation} - disable_anonymous_option={ - @selected_annotations_tab == :my_notes || is_guest(@current_user) - } + disable_anonymous_option={@active_tab == :my_notes || is_guest(@current_user)} /> <%= case @annotations do %> diff --git a/lib/oli_web/live/delivery/student/lesson_live.ex b/lib/oli_web/live/delivery/student/lesson_live.ex index e1fa5e294c8..a49700734ec 100644 --- a/lib/oli_web/live/delivery/student/lesson_live.ex +++ b/lib/oli_web/live/delivery/student/lesson_live.ex @@ -11,6 +11,7 @@ defmodule OliWeb.Delivery.Student.LessonLive do alias Oli.Delivery.Page.PageContext alias Oli.Delivery.{Sections, Settings} alias Oli.Resources.Collaboration + alias Oli.Resources.Collaboration.CollabSpaceConfig alias OliWeb.Common.FormatDateTime alias OliWeb.Components.Delivery.Layouts alias OliWeb.Components.Modal @@ -23,14 +24,20 @@ defmodule OliWeb.Delivery.Student.LessonLive do on_mount {OliWeb.LiveSessionPlugs.InitPage, :previous_next_index} def mount(_params, _session, %{assigns: %{view: :practice_page}} = socket) do + course_collab_space_config = + Collaboration.get_course_collab_space_config( + socket.assigns.section.root_section_resource_id + ) + # when updating to Liveview 0.20 we should replace this with assign_async/3 # https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#assign_async/3 if connected?(socket) do async_load_annotations( self(), - socket.assigns.section.id, + socket.assigns.section, socket.assigns.page_context.page.resource_id, - socket.assigns[:current_user], + socket.assigns.current_user, + course_collab_space_config, :private, nil ) @@ -39,7 +46,8 @@ defmodule OliWeb.Delivery.Student.LessonLive do {:ok, socket |> assign_html_and_scripts() - |> assign_annotations()} + |> annotations_assigns(course_collab_space_config) + |> assign(course_collab_space_config: course_collab_space_config)} end def mount( @@ -181,15 +189,15 @@ defmodule OliWeb.Delivery.Student.LessonLive do def handle_event("update_point_markers", %{"point_markers" => point_markers}, socket) do markers = Enum.map(point_markers, fn pm -> %{id: pm["id"], top: pm["top"]} end) - {:noreply, assign(socket, point_markers: markers)} + {:noreply, assign_annotations(socket, point_markers: markers)} end def handle_event("toggle_sidebar", _params, socket) do - %{show_sidebar: show_sidebar, selected_point: selected_point} = socket.assigns + %{show_sidebar: show_sidebar, selected_point: selected_point} = socket.assigns.annotations {:noreply, socket - |> assign(show_sidebar: !show_sidebar) + |> assign_annotations(show_sidebar: !show_sidebar) |> push_event("request_point_markers", %{}) |> then(fn socket -> if show_sidebar do @@ -203,41 +211,43 @@ defmodule OliWeb.Delivery.Student.LessonLive do def handle_event("select_annotation_point", %{"point-marker-id" => point_marker_id}, socket) do async_load_annotations( self(), - socket.assigns.section.id, + socket.assigns.section, socket.assigns.page_context.page.resource_id, - socket.assigns[:current_user], - visibility_for_active_tab(socket.assigns.selected_annotations_tab), + socket.assigns.current_user, + socket.assigns.course_collab_space_config, + visibility_for_active_tab(socket.assigns.annotations.active_tab), point_marker_id ) {:noreply, socket - |> assign(selected_point: point_marker_id, annotations: nil) + |> assign_annotations(selected_point: point_marker_id, posts: nil) |> push_event("highlight_point_marker", %{id: point_marker_id})} end def handle_event("select_annotation_point", _params, socket) do async_load_annotations( self(), - socket.assigns.section.id, + socket.assigns.section, socket.assigns.page_context.page.resource_id, - socket.assigns[:current_user], - visibility_for_active_tab(socket.assigns.selected_annotations_tab), + socket.assigns.current_user, + socket.assigns.course_collab_space_config, + visibility_for_active_tab(socket.assigns.annotations.active_tab), nil ) {:noreply, socket - |> assign(selected_point: nil, annotations: nil) + |> assign_annotations(selected_point: nil, posts: nil) |> push_event("clear_highlighted_point_markers", %{})} end def handle_event("begin_create_annotation", _, socket) do - {:noreply, assign(socket, create_new_annotation: true)} + {:noreply, assign_annotations(socket, create_new_annotation: true)} end def handle_event("cancel_create_annotation", _, socket) do - {:noreply, assign(socket, create_new_annotation: false)} + {:noreply, assign_annotations(socket, create_new_annotation: false)} end def handle_event("create_annotation", %{"content" => ""}, socket) do @@ -249,13 +259,16 @@ defmodule OliWeb.Delivery.Student.LessonLive do current_user: current_user, section: section, page_context: page_context, - annotations: annotations, - selected_point: selected_point, - selected_annotations_tab: selected_annotations_tab + annotations: %{ + posts: posts, + selected_point: selected_point, + active_tab: active_tab, + auto_approve_annotations: auto_approve_annotations + } } = socket.assigns attrs = %{ - status: :submitted, + status: if(auto_approve_annotations, do: :approved, else: :submitted), user_id: current_user.id, section_id: section.id, resource_id: page_context.page.resource_id, @@ -263,7 +276,7 @@ defmodule OliWeb.Delivery.Student.LessonLive do annotated_block_id: selected_point, annotation_type: :point, anonymous: params["anonymous"] == "true", - visibility: visibility_for_active_tab(selected_annotations_tab), + visibility: visibility_for_active_tab(active_tab), content: %Collaboration.PostContent{message: value} } @@ -272,7 +285,7 @@ defmodule OliWeb.Delivery.Student.LessonLive do {:noreply, socket |> put_flash(:info, "Note created successfully") - |> assign(create_new_annotation: false, annotations: [post | annotations]) + |> assign_annotations(create_new_annotation: false, posts: [post | posts]) |> increment_post_count(selected_point)} {:error, _} -> @@ -290,27 +303,29 @@ defmodule OliWeb.Delivery.Student.LessonLive do async_load_annotations( self(), - socket.assigns.section.id, + socket.assigns.section, socket.assigns.page_context.page.resource_id, - socket.assigns[:current_user], + socket.assigns.current_user, + socket.assigns.course_collab_space_config, visibility_for_active_tab(tab), - socket.assigns.selected_point + socket.assigns.annotations.selected_point ) - {:noreply, assign(socket, selected_annotations_tab: tab, annotations: nil)} + {:noreply, assign_annotations(socket, active_tab: tab, posts: nil)} end + # handle assigns directly from other sub-tasks and processes def handle_info( - {:assign, key, annotations}, + {:assign_annotations, annotations}, socket ) do - {:noreply, assign(socket, [{key, annotations}])} + {:noreply, assign_annotations(socket, Enum.into(annotations, socket.assigns.annotations))} end - def render(%{view: :practice_page, annotations_enabled: true} = assigns) do + def render(%{view: :practice_page, annotations: %{}} = assigns) do # For practice page the activity scripts and activity_bridge script are needed as soon as the page loads. ~H""" - <.page_content_with_sidebar_layout show_sidebar={@show_sidebar}> + <.page_content_with_sidebar_layout show_sidebar={@annotations.show_sidebar}> <:header> <.page_header page_context={@page_context} @@ -330,17 +345,17 @@ defmodule OliWeb.Delivery.Student.LessonLive do <%= raw(@html) %>
- <:point_markers :if={@show_sidebar && @point_markers}> + <:point_markers :if={@annotations.show_sidebar && @annotations.point_markers}> @@ -352,10 +367,10 @@ defmodule OliWeb.Delivery.Student.LessonLive do <:sidebar> @@ -833,19 +848,6 @@ defmodule OliWeb.Delivery.Student.LessonLive do ) end - defp assign_annotations(socket) do - assign(socket, - annotations_enabled: true, - show_sidebar: false, - point_markers: nil, - selected_point: nil, - create_new_annotation: false, - annotations: nil, - post_counts: nil, - selected_annotations_tab: :my_notes - ) - end - defp get_max_attempts(%{effective_settings: %{max_attempts: 0}} = _page_context), do: "unlimited" @@ -876,58 +878,79 @@ defmodule OliWeb.Delivery.Student.LessonLive do }) end + defp annotations_assigns(socket, course_collab_space_config) do + case course_collab_space_config do + %CollabSpaceConfig{status: :enabled} -> + assign(socket, + annotations: %{ + show_sidebar: false, + point_markers: nil, + selected_point: nil, + post_counts: nil, + posts: nil, + active_tab: :my_notes, + create_new_annotation: false, + auto_approve_annotations: course_collab_space_config.auto_accept + } + ) + + _ -> + socket + end + end + defp async_load_annotations( - liveview_pid, - section_id, + caller, + section, resource_id, - %User{id: current_user_id}, + current_user, + course_collab_space_config, visibility, point_block_id ) do - # load annotations - Task.Supervisor.start_child(Oli.TaskSupervisor, fn -> - send( - liveview_pid, - {:assign, :annotations, - Collaboration.list_posts_for_user_in_point_block( - section_id, - resource_id, - current_user_id, - visibility, - point_block_id - )} - ) - end) - - # load post counts - Task.Supervisor.start_child(Oli.TaskSupervisor, fn -> - send( - liveview_pid, - {:assign, :post_counts, - Collaboration.list_post_counts_for_user_in_section( - section_id, - resource_id, - current_user_id, - visibility - )} - ) - end) + if current_user do + Task.Supervisor.start_child(Oli.TaskSupervisor, fn -> + case course_collab_space_config do + %CollabSpaceConfig{status: :enabled} -> + # load post counts + post_counts = + Collaboration.list_post_counts_for_user_in_section( + section.id, + resource_id, + current_user.id, + visibility + ) + + # load posts + posts = + Collaboration.list_posts_for_user_in_point_block( + section.id, + resource_id, + current_user.id, + visibility, + point_block_id + ) + + send( + caller, + {:assign_annotations, + %{ + post_counts: post_counts, + posts: posts, + auto_approve_annotations: course_collab_space_config.auto_accept + }} + ) + + _ -> + # do nothing + nil + end + end) + end end - defp async_load_annotations( - liveview_pid, - _section_id, - _resource_id, - _current_user, - _visibility, - _point_block_id - ) do - Task.Supervisor.start_child(Oli.TaskSupervisor, fn -> - send( - liveview_pid, - {:assign, :annotations, []} - ) - end) + defp assign_annotations(socket, annotations) do + assign(socket, annotations: Enum.into(annotations, socket.assigns.annotations)) end defp visibility_for_active_tab(:all_notes), do: :public @@ -935,12 +958,12 @@ defmodule OliWeb.Delivery.Student.LessonLive do defp visibility_for_active_tab(_), do: :private defp increment_post_count(socket, selected_point) do - case socket.assigns.post_counts do + case socket.assigns.annotations.post_counts do nil -> socket post_counts -> - assign(socket, + assign_annotations(socket, post_counts: Map.update(post_counts, selected_point, 1, &(&1 + 1)) ) end From 2e6e00f82a91b1dfb4d0b93c575625597b1e3e11 Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Mon, 25 Mar 2024 10:46:46 -0400 Subject: [PATCH 03/42] WIP --- .../delivery/student/lesson/annotations.ex | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index df029dceb74..af1b062b5fd 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -42,7 +42,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do
There are no posts yet
<% annotations -> %> <%= for annotation <- annotations do %> - <.note post={annotation} current_user={@current_user} /> + <.post post={annotation} current_user={@current_user} /> <% end %> <% end %> @@ -279,7 +279,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :post, Oli.Resources.Collaboration.Post, required: true attr :current_user, Oli.Accounts.User, required: true - defp note(assigns) do + defp post(assigns) do ~H"""
@@ -293,7 +293,19 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do

<%= @post.content.message %>

- <.maybe_status post={@post} /> + <.post_actions post={@post} /> +
+ """ + end + + attr :replies, :list, required: true + + defp post_replies(assigns) do + ~H""" +
+ <%= for reply <- @post.replies do %> + <.post post={reply} current_user={@current_user} /> + <% end %>
""" end @@ -324,7 +336,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :post, Oli.Resources.Collaboration.Post, required: true - defp maybe_status(assigns) do + defp post_actions(assigns) do case assigns.post do %Oli.Resources.Collaboration.Post{visibility: :public, status: :submitted} -> ~H""" @@ -333,6 +345,19 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do
""" + %Oli.Resources.Collaboration.Post{visibility: :public} -> + ~H""" +
+ +
+ """ + _ -> ~H""" @@ -405,4 +430,19 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do """ end + + def replies_bubble_icon(assigns) do + ~H""" + + + + + + """ + end end From 6699deb1cf08c463cf94d6105bfa06373b50ff01 Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Mon, 25 Mar 2024 12:25:24 -0400 Subject: [PATCH 04/42] change save to post --- lib/oli_web/live/delivery/student/lesson/annotations.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index af1b062b5fd..6350a257515 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -249,7 +249,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do <% end %>
- Save + Post Cancel From c72db744136355821b08b4e14abfc1bb92499b7a Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Mon, 25 Mar 2024 15:27:40 -0400 Subject: [PATCH 05/42] Update annotation form with dynamic save label and placeholder --- .../live/delivery/student/lesson/annotations.ex | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index 6350a257515..3941da2ca20 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -33,6 +33,10 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do class="my-2" active={@create_new_annotation} disable_anonymous_option={@active_tab == :my_notes || is_guest(@current_user)} + save_label={if(@active_tab == :my_notes, do: "Save", else: "Post")} + placeholder={ + if(@active_tab == :my_notes, do: "Add a new note...", else: "Post a new note...") + } /> <%= case @annotations do %> @@ -222,6 +226,8 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :active, :boolean, default: false attr :disable_anonymous_option, :boolean, default: false + attr :save_label, :string, default: "Save" + attr :placeholder, :string, default: "Add a new note..." attr :rest, :global, include: ~w(class) defp add_new_annotation_input(%{active: true} = assigns) do @@ -239,7 +245,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do phx-hook="AutoSelect" rows="4" class="w-full border border-gray-400 dark:border-gray-700 dark:bg-black rounded-lg p-3" - placeholder="Add a new note..." + placeholder={@placeholder} />
<%= unless @disable_anonymous_option do %> @@ -249,7 +255,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do <% end %>
- Post + <%= @save_label %> Cancel @@ -268,7 +274,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do
From 9a66fef667719c4dde018a9bfe81244e2c6d4a6b Mon Sep 17 00:00:00 2001 From: Eli Knebel Date: Tue, 26 Mar 2024 21:12:11 -0400 Subject: [PATCH 06/42] implement reply to post --- lib/oli/resources/collaboration.ex | 107 +++++++++----- .../delivery/student/lesson/annotations.ex | 131 +++++++++++++++--- .../live/delivery/student/lesson_live.ex | 83 ++++++++++- 3 files changed, 269 insertions(+), 52 deletions(-) diff --git a/lib/oli/resources/collaboration.ex b/lib/oli/resources/collaboration.ex index e00b02a3320..34cfe3ecd4d 100644 --- a/lib/oli/resources/collaboration.ex +++ b/lib/oli/resources/collaboration.ex @@ -491,6 +491,40 @@ defmodule Oli.Resources.Collaboration do ) end + # Define a subquery for root thread post replies count + defp replies_subquery() do + from(p in Post, + group_by: p.thread_root_id, + select: %{ + thread_root_id: p.thread_root_id, + count: count(p.id), + last_reply: max(p.updated_at) + } + ) + end + + # Define a subquery for root thread post read replies count + # (replies by the user are counted as read) + defp read_replies_subquery(user_id) do + from( + p in Post, + left_join: urp in UserReadPost, + on: urp.post_id == p.id, + where: + not is_nil(p.thread_root_id) and + (p.user_id == ^user_id or (urp.user_id == ^user_id and not is_nil(urp.post_id))), + group_by: p.thread_root_id, + select: %{ + thread_root_id: p.thread_root_id, + # Counting both user's posts and read posts + count: count(p.id) + } + ) + end + + @doc """ + Returns the list of root posts for a section. + """ def list_root_posts_for_section( user_id, section_id, @@ -500,35 +534,6 @@ defmodule Oli.Resources.Collaboration do sort_by, sort_order ) do - # Define a subquery for root thread post replies count - replies_subquery = - from(p in Post, - group_by: p.thread_root_id, - select: %{ - thread_root_id: p.thread_root_id, - count: count(p.id), - last_reply: max(p.updated_at) - } - ) - - # Define a subquery for root thread post read replies count - # (replies by the user are counted as read) - read_replies_subquery = - from( - p in Post, - left_join: urp in UserReadPost, - on: urp.post_id == p.id, - where: - not is_nil(p.thread_root_id) and - (p.user_id == ^user_id or (urp.user_id == ^user_id and not is_nil(urp.post_id))), - group_by: p.thread_root_id, - select: %{ - thread_root_id: p.thread_root_id, - # Counting both user's posts and read posts - count: count(p.id) - } - ) - order_clause = case {sort_by, sort_order} do {"popularity", :desc} -> @@ -566,9 +571,9 @@ defmodule Oli.Resources.Collaboration do on: rev.id == pr.revision_id, join: user in User, on: post.user_id == user.id, - left_join: replies in subquery(replies_subquery), + left_join: replies in subquery(replies_subquery()), on: replies.thread_root_id == post.id, - left_join: read_replies in subquery(read_replies_subquery), + left_join: read_replies in subquery(read_replies_subquery(user_id)), on: read_replies.thread_root_id == post.id, where: post.section_id == ^section_id and @@ -1122,15 +1127,24 @@ defmodule Oli.Resources.Collaboration do Repo.all( from( post in Post, + left_join: replies in subquery(replies_subquery()), + on: replies.thread_root_id == post.id, + left_join: read_replies in subquery(read_replies_subquery(user_id)), + on: read_replies.thread_root_id == post.id, where: post.section_id == ^section_id and post.resource_id == ^resource_id and + is_nil(post.parent_post_id) and is_nil(post.thread_root_id) and (post.status in [:approved, :archived] or (post.status == :submitted and post.user_id == ^user_id)), where: ^filter_by_point_block_id, where: post.visibility == ^visibility, - select: post, order_by: [desc: :inserted_at], - preload: [:user] + preload: [:user], + select: %{ + post + | replies_count: coalesce(replies.count, 0), + read_replies_count: coalesce(read_replies.count, 0) + } ) ) end @@ -1153,4 +1167,31 @@ defmodule Oli.Resources.Collaboration do |> Repo.all() |> Enum.into(%{}) end + + def list_replies_for_post_in_point_block(user_id, post_id) do + Repo.all( + from( + post in Post, + join: sr in SectionResource, + on: sr.resource_id == post.resource_id and sr.section_id == post.section_id, + join: spp in SectionsProjectsPublications, + on: spp.section_id == post.section_id and spp.project_id == sr.project_id, + join: pr in PublishedResource, + on: pr.publication_id == spp.publication_id and pr.resource_id == post.resource_id, + join: rev in Revision, + on: rev.id == pr.revision_id, + join: user in User, + on: post.user_id == user.id, + left_join: urp in UserReadPost, + on: urp.post_id == post.id and urp.user_id == ^user_id, + where: + post.parent_post_id == ^post_id and + (post.status in [:approved, :archived] or + (post.status == :submitted and post.user_id == ^user_id)), + select: post, + order_by: [asc: :updated_at] + ) + ) + |> build_metrics_for_reply_posts(user_id) + end end diff --git a/lib/oli_web/live/delivery/student/lesson/annotations.ex b/lib/oli_web/live/delivery/student/lesson/annotations.ex index 3941da2ca20..59384013364 100644 --- a/lib/oli_web/live/delivery/student/lesson/annotations.ex +++ b/lib/oli_web/live/delivery/student/lesson/annotations.ex @@ -8,6 +8,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :annotations, :any, required: true attr :current_user, Oli.Accounts.User, required: true attr :active_tab, :atom, default: :my_notes + attr :post_replies, :list, default: nil def panel(assigns) do ~H""" @@ -43,10 +44,15 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do <% nil -> %> <% [] -> %> -
There are no posts yet
+
<%= empty_label(@active_tab) %>
<% annotations -> %> <%= for annotation <- annotations do %> - <.post post={annotation} current_user={@current_user} /> + <.post + post={annotation} + current_user={@current_user} + post_replies={@post_replies} + disable_anonymous_option={@active_tab == :my_notes || is_guest(@current_user)} + /> <% end %> <% end %> @@ -58,6 +64,9 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do defp is_guest(%User{guest: guest}), do: guest defp is_guest(_), do: false + defp empty_label(:my_notes), do: "There are no notes yet" + defp empty_label(_), do: "There are no posts yet" + slot :inner_block, required: true def toggle_notes_button(assigns) do @@ -284,6 +293,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do attr :post, Oli.Resources.Collaboration.Post, required: true attr :current_user, Oli.Accounts.User, required: true + attr :post_replies, :any, required: true defp post(assigns) do ~H""" @@ -300,18 +310,7 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do <%= @post.content.message %>

<.post_actions post={@post} /> - - """ - end - - attr :replies, :list, required: true - - defp post_replies(assigns) do - ~H""" -
- <%= for reply <- @post.replies do %> - <.post post={reply} current_user={@current_user} /> - <% end %> + <.post_replies post={@post} replies={@post_replies} current_user={@current_user} />
""" end @@ -346,20 +345,23 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do case assigns.post do %Oli.Resources.Collaboration.Post{visibility: :public, status: :submitted} -> ~H""" -
+
Submitted and pending approval
""" %Oli.Resources.Collaboration.Post{visibility: :public} -> ~H""" -
+
""" @@ -371,6 +373,101 @@ defmodule OliWeb.Delivery.Student.Lesson.Annotations do end end + attr :post, Oli.Resources.Collaboration.Post, required: true + attr :current_user, Oli.Accounts.User, required: true + attr :replies, :any, required: true + attr :disable_anonymous_option, :boolean, default: false + + defp post_replies(assigns) do + id = assigns.post.id + + ~H""" + <%= case @replies do %> + <% {^id, :loading} -> %> + + <% {^id, []} -> %> + <.add_new_reply_input parent_post_id={@post.id} /> + <% {^id, replies} -> %> +
+ <%= for reply <- replies do %> + <.reply post={reply} current_user={@current_user} /> + <% end %> +
+ <.add_new_reply_input + parent_post_id={@post.id} + disable_anonymous_option={@disable_anonymous_option} + /> + <% _ -> %> + <% end %> + """ + end + + attr :parent_post_id, :integer, required: true + attr :disable_anonymous_option, :boolean, default: false + + defp add_new_reply_input(assigns) do + ~H""" +
+
+
+