Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improve announcements pages #530

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e9f3a43
refactor: announcement forms
JoaoCoelho2003 Sep 9, 2024
750bedf
fix: upload images annoucments
FilipeR13 Sep 10, 2024
8f56c58
feat: completed announcement feed page
JoaoCoelho2003 Sep 10, 2024
55b65af
feat: show announcement page
JoaoCoelho2003 Sep 10, 2024
f61df59
fix: textarea size in create an announcement page
JoaoCoelho2003 Sep 11, 2024
a010415
fix: create announcement elems positioning
JoaoCoelho2003 Sep 11, 2024
88d0b12
fix: padding
JoaoCoelho2003 Sep 11, 2024
1c8defc
feat: completed create announcement page
JoaoCoelho2003 Sep 11, 2024
57d689d
fix: show announcement page padding
JoaoCoelho2003 Sep 11, 2024
3802137
fix: format
JoaoCoelho2003 Sep 12, 2024
0d17920
fix: text overflow
JoaoCoelho2003 Sep 17, 2024
23558c6
Merge branch 'develop' into jc/improve-announcements
JoaoCoelho2003 Sep 19, 2024
f1800bc
fix: conflits
JoaoCoelho2003 Sep 23, 2024
6b0f7ec
fix: new icons
JoaoCoelho2003 Sep 23, 2024
678c82d
fix: fix test
JoaoCoelho2003 Sep 23, 2024
fac57ec
fix: test
JoaoCoelho2003 Sep 23, 2024
424175a
fix: main page nil announcement bug
JoaoCoelho2003 Sep 24, 2024
040ee69
fix: delete announcement test
JoaoCoelho2003 Sep 24, 2024
5812fae
fix: format
JoaoCoelho2003 Sep 24, 2024
a7a468b
feat: created an announcement card component
JoaoCoelho2003 Sep 24, 2024
8735240
fix: format
JoaoCoelho2003 Sep 24, 2024
7f1935f
fix: icon and removed hover effect
JoaoCoelho2003 Sep 24, 2024
8f248e5
refacotr: announcement card
JoaoCoelho2003 Sep 25, 2024
3d16dca
fix: padding
JoaoCoelho2003 Oct 3, 2024
4384942
Merge branch 'develop' into jc/improve-announcements
JoaoCoelho2003 Nov 7, 2024
4a36fa3
fix: errors after merge
JoaoCoelho2003 Nov 7, 2024
a80c0fa
refactor: announcements is not part of the admin pages
JoaoCoelho2003 Nov 7, 2024
1af4b79
refactor: finished updating the routes
JoaoCoelho2003 Nov 7, 2024
abe715e
feat: announcements page only shows posts by the organization logged in
JoaoCoelho2003 Nov 7, 2024
01dfeb0
fix: format
JoaoCoelho2003 Nov 7, 2024
66bda3f
fix: function documentation
JoaoCoelho2003 Nov 7, 2024
e8c16b7
fix: format
JoaoCoelho2003 Nov 7, 2024
458970f
fix: delete functionality
JoaoCoelho2003 Nov 20, 2024
8628165
feat: truncate text in the announcements feed page
JoaoCoelho2003 Nov 20, 2024
799482b
fix: border down in the page component
JoaoCoelho2003 Nov 21, 2024
0c07740
refactor: show announcement page
JoaoCoelho2003 Nov 29, 2024
6fb1608
feat: final tweaks to the show announcement page
JoaoCoelho2003 Dec 2, 2024
fc2552c
Merge branch 'develop' into jc/improve-announcements
JoaoCoelho2003 Dec 2, 2024
3907760
fix: avatar component and overflowing text after merge
JoaoCoelho2003 Dec 2, 2024
8f50450
fix: format, once again I HATE YOU
JoaoCoelho2003 Dec 2, 2024
df47eb3
fix: maximum image height, permission issues
JoaoCoelho2003 Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions lib/atomic/organizations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -495,19 +495,24 @@ defmodule Atomic.Organizations do
end

@doc """
Returns the list of announcements belonging to an organization.
Returns the list of announcements belonging to an organization, filtered and validated by the given parameters.

## Examples

iex> list_announcements_by_organization_id("99d7c9e5-4212-4f59-a097-28aaa33c2621")
[%Announcement{}, ...]
iex> list_announcements_by_organization_id("99d7c9e5-4212-4f59-a097-28aaa33c2621", %{})
{:ok, [%Announcement{}, ...]}

iex> list_announcements_by_organization_id("99d7c9e5-4212-4f59-a097-28aaa33c2621", %{},
...> some_option: true
...> )
{:ok, [%Announcement{}, ...]}

"""
def list_announcements_by_organization_id(id, opts \\ []) do
def list_announcements_by_organization_id(id, %{} = flop, opts \\ []) when is_list(opts) do
Announcement
|> where(organization_id: ^id)
|> apply_filters(opts)
|> Repo.all()
|> Flop.validate_and_run(flop, for: Announcement)
end

@doc """
Expand Down Expand Up @@ -564,7 +569,7 @@ defmodule Atomic.Organizations do
{:error, %Ecto.Changeset{}}

"""
def create_announcement_with_post(attrs \\ %{}) do
def create_announcement_with_post(attrs \\ %{}, after_save \\ &{:ok, &1}) do
Multi.new()
|> Multi.insert(:post, fn _ ->
%Post{}
Expand All @@ -580,7 +585,7 @@ defmodule Atomic.Organizations do
|> Repo.transaction()
|> case do
{:ok, %{announcement: announcement, post: _post}} ->
{:ok, announcement}
after_save.(announcement)

{:error, _reason, changeset, _actions} ->
{:error, changeset}
Expand All @@ -605,10 +610,11 @@ defmodule Atomic.Organizations do
{:error, %Ecto.Changeset{}}

"""
def update_announcement(%Announcement{} = announcement, attrs, _after_save \\ &{:ok, &1}) do
def update_announcement(%Announcement{} = announcement, attrs, after_save \\ &{:ok, &1}) do
announcement
|> Announcement.changeset(attrs)
|> Repo.update()
|> after_save(after_save)
end

@doc """
Expand All @@ -624,7 +630,14 @@ defmodule Atomic.Organizations do

"""
def delete_announcement(%Announcement{} = announcement) do
Repo.delete(announcement)
Ecto.Multi.new()
|> Ecto.Multi.delete(:announcement, announcement)
|> Ecto.Multi.delete(:post, Repo.get!(Post, announcement.post_id))
|> Repo.transaction()
|> case do
{:ok, _changes} -> {:ok, announcement}
{:error, _step, reason, _changes} -> {:error, reason}
end
end

@doc """
Expand All @@ -639,4 +652,22 @@ defmodule Atomic.Organizations do
def change_announcement(%Announcement{} = announcement, attrs \\ %{}) do
Announcement.changeset(announcement, attrs)
end

@doc """
Updates an announcement image.

## Examples

iex> update_announcement_image(announcement, %{field: new_value})
{:ok, %Announcement{}}

iex> update_announcement_image(announcement, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_announcement_image(%Announcement{} = announcement, attrs) do
announcement
|> Announcement.image_changeset(attrs)
|> Repo.update()
end
end
4 changes: 2 additions & 2 deletions lib/atomic_web/components/page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ defmodule AtomicWeb.Components.Page do
def page(assigns) do
~H"""
<div class="flex min-h-full flex-col items-stretch justify-between lg:flex-row">
<div class={"#{if @bottom_border, do: 'border-b', else: ''} min-h-[100vh] flex w-full flex-col bg-white lg:flex-row lg:border-r"}>
<div class="min-h-[100vh] flex w-full flex-col bg-white lg:flex-row lg:border-r">
<main class="relative z-0 mb-10 flex-1 overflow-y-auto focus:outline-none xl:order-last">
<div class="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
<div class={["mx-auto max-w-5xl px-4 sm:px-6 lg:px-8", @bottom_border && "border-b"]}>
<div class="my-6 flex min-w-0 flex-row items-center justify-between">
<h1 class="flex-1 select-none truncate text-2xl font-bold text-zinc-900">
<%= @title %>
Expand Down
14 changes: 7 additions & 7 deletions lib/atomic_web/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ defmodule AtomicWeb.Config do
url: ~p"/organizations/#{current_organization}/departments",
tabs: []
},
%{
key: :announcements,
title: "Announcements",
icon: "hero-newspaper",
url: ~p"/organizations/#{current_organization}/announcements",
tabs: []
},
%{
key: :partners,
title: "Partners",
Expand Down Expand Up @@ -83,13 +90,6 @@ defmodule AtomicWeb.Config do
url: ~p"/activities",
tabs: []
},
%{
key: :announcements,
title: "Announcements",
icon: "hero-newspaper",
url: ~p"/announcements",
tabs: []
},
%{
key: :organizations,
title: "Organizations",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule AtomicWeb.AnnouncementLive.Components.AnnouncementCard do
@moduledoc false

import AtomicWeb.Components.Avatar

use AtomicWeb, :component

def announcement_card(assigns) do
JoaoCoelho2003 marked this conversation as resolved.
Show resolved Hide resolved
~H"""
<div class="mt-4 flex flex-col justify-center rounded-lg bg-white md:mt-2 lg:p-4">
<.link navigate={~p"/organizations/#{@organization}/announcements/#{@announcement}"} class="block">
<div class="flex items-center space-x-2 px-4 py-1">
<div class="flex-shrink-0">
<.avatar name={@announcement.organization.name} color={:light_zinc} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@announcement.organization.logo, @announcement.organization}, :original)} />
</div>
<div>
<p class="text-sm font-medium text-zinc-700"><%= @announcement.organization.name %></p>
<p class="text-xs text-gray-500">
<span class="sr-only">Published on</span>
<time><%= relative_datetime(@announcement.inserted_at) %></time>
</p>
</div>
</div>
<div class="px-4 py-2">
<p class="text-lg font-semibold text-zinc-900" title={@announcement.title}>
JoaoCoelho2003 marked this conversation as resolved.
Show resolved Hide resolved
<%= @announcement.title %>
</p>
<p class="overflow-wrap mt-2 overflow-hidden break-all text-sm leading-relaxed text-zinc-700">
<%= maybe_slice_string(@announcement.description, 300) %>
</p>
</div>
<%= if @announcement.image do %>
<div class="h-auto w-full overflow-hidden">
<img class="max-h-[32rem] max-w-screen object-cover sm:max-w-xl md:rounded-xl" src={Uploaders.Post.url({@announcement.image, @announcement}, :original)} alt="Announcement Image" />
</div>
<% end %>
</.link>
</div>
"""
end
end
4 changes: 3 additions & 1 deletion lib/atomic_web/live/announcement_live/edit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ defmodule AtomicWeb.AnnouncementLive.Edit do
{:noreply,
socket
|> put_flash(:info, gettext("Announcement deleted successfully"))
|> push_navigate(to: ~p"/announcements")}
|> push_navigate(
to: ~p"/organizations/#{socket.assigns.current_organization.id}/announcements"
)}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/atomic_web/live/announcement_live/edit.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
</.button>
</:actions>
<div class="pt-4 px-4">
<.live_component module={AtomicWeb.AnnouncementLive.FormComponent} id={@announcement.id} organization={@current_organization} title={@page_title} action={@live_action} announcement={@announcement} return_to={~p"/announcements/#{@announcement}"} />
<.live_component module={AtomicWeb.AnnouncementLive.FormComponent} id={@announcement.id} organization={@current_organization} title={@page_title} action={@live_action} announcement={@announcement} return_to={~p"/organizations/#{@current_organization}/announcements"} />
</div>
</.page>
36 changes: 33 additions & 3 deletions lib/atomic_web/live/announcement_live/form_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
use AtomicWeb, :live_component

alias Atomic.Organizations
alias AtomicWeb.Components.ImageUploader

import AtomicWeb.Components.Forms

Expand All @@ -17,7 +18,8 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
|> assign(:changeset, changeset)
|> allow_upload(:image, accept: Uploaders.Post.extension_whitelist(), max_entries: 1)}
end

@impl true
Expand All @@ -35,10 +37,16 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
save_announcement(socket, socket.assigns.action, announcement_params)
end

@impl true
def handle_event("cancel-image", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :image, ref)}
end

defp save_announcement(socket, :edit, announcement_params) do
case Organizations.update_announcement(
socket.assigns.announcement,
announcement_params
announcement_params,
&consume_image_data(socket, &1)
) do
{:ok, _announcement} ->
{:noreply,
Expand All @@ -55,7 +63,10 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
announcement_params =
Map.put(announcement_params, "organization_id", socket.assigns.organization.id)

case Organizations.create_announcement_with_post(announcement_params) do
case Organizations.create_announcement_with_post(
announcement_params,
&consume_image_data(socket, &1)
) do
{:ok, _announcement} ->
{:noreply,
socket
Expand All @@ -66,4 +77,23 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
{:noreply, assign(socket, :changeset, changeset)}
end
end

defp consume_image_data(socket, announcement) do
consume_uploaded_entries(socket, :image, fn %{path: path}, entry ->
Organizations.update_announcement_image(announcement, %{
"image" => %Plug.Upload{
content_type: entry.client_type,
filename: entry.client_name,
path: path
}
})
end)
|> case do
[{:ok, announcement}] ->
{:ok, announcement}

_errors ->
{:ok, announcement}
end
end
end
21 changes: 15 additions & 6 deletions lib/atomic_web/live/announcement_live/form_component.html.heex
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
<div>
<.form :let={f} for={@changeset} id="announcement-form" phx-target={@myself} phx-change="validate" phx-submit="save">
<.field field={f[:title]} help_text={gettext("The title of the announcement")} type="text" placeholder="Title" required />
<div class="relative">
<.form :let={f} for={@changeset} id="announcement-form" phx-target={@myself} phx-change="validate" phx-submit="save" class="space-y-6">
<div class="relative pb-16">
<div class="grid gap-4 xl:grid-cols-2">
<div class="flex flex-col">
<.field field={f[:title]} type="text" placeholder="Title" required class="w-full" />

<.field field={f[:description]} help_text={gettext("Announcement description")} type="text" placeholder="Description" required />
<.field field={f[:description]} type="textarea" placeholder="Description" required class="w-full overflow-auto resize-none h-44 xl:h-64" />
</div>
<div class="space-y-4">
<.live_component module={ImageUploader} id="uploader" uploads={@uploads} target={@myself} class="object-cover" />

<div class="mt-8 flex w-full justify-end">
<.button size={:md} color={:white} icon="hero-cube" type="submit"><%= gettext("Save Changes") %></.button>
<div class="flex justify-end">
<.button size={:md} color={:white} icon="hero-cube" type="submit"><%= gettext("Save Changes") %></.button>
</div>
</div>
</div>
</div>
</.form>
</div>
40 changes: 9 additions & 31 deletions lib/atomic_web/live/announcement_live/index.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
defmodule AtomicWeb.AnnouncementLive.Index do
use AtomicWeb, :live_view

import AtomicWeb.Components.{Button, Empty, Pagination, Tabs}
import AtomicWeb.Components.{Button, Empty, Pagination}
import AtomicWeb.AnnouncementLive.Components.AnnouncementCard

alias Atomic.Accounts
alias Atomic.Organizations
Expand All @@ -12,44 +13,24 @@ defmodule AtomicWeb.AnnouncementLive.Index do
end

@impl true
def handle_params(params, _, socket) do
def handle_params(%{"organization_id" => organization_id} = params, _, socket) do
organization = Organizations.get_organization!(organization_id)

{:noreply,
socket
|> assign(:page_title, gettext("Announcements"))
|> assign(:current_page, :announcements)
|> assign(:current_tab, current_tab(socket, params))
|> assign(:organization, organization)
|> assign(:params, params)
|> assign(:has_permissions?, has_permissions?(socket))
|> assign(list_announcements(socket, params))
|> assign(list_announcements_by_organization(socket, params, organization_id))
|> then(fn complete_socket ->
assign(complete_socket, :empty?, Enum.empty?(complete_socket.assigns.announcements))
end)}
end

defp list_announcements(socket, params) do
params = Map.put(params, "page_size", 6)

case current_tab(socket, params) do
"all" -> list_all_announcements(socket, params)
"following" -> list_following_announcements(socket, params)
end
end

defp list_all_announcements(_socket, params) do
case Organizations.list_announcements(params, preloads: [:organization]) do
{:ok, {announcements, meta}} ->
%{announcements: announcements, meta: meta}

{:error, flop} ->
%{announcements: [], meta: flop}
end
end

defp list_following_announcements(socket, params) do
organizations =
Organizations.list_organizations_followed_by_user(socket.assigns.current_user.id)

case Organizations.list_organizations_announcements(organizations, params,
defp list_announcements_by_organization(_socket, params, organization_id) do
case Organizations.list_announcements_by_organization_id(organization_id, params,
preloads: [:organization]
) do
{:ok, {announcements, meta}} ->
Expand All @@ -60,9 +41,6 @@ defmodule AtomicWeb.AnnouncementLive.Index do
end
end

defp current_tab(_socket, params) when is_map_key(params, "tab"), do: params["tab"]
defp current_tab(_socket, _params), do: "all"

defp has_permissions?(socket) when not socket.assigns.is_authenticated?, do: false

defp has_permissions?(socket) do
Expand Down
Loading
Loading