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
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
@@ -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 """
@@ -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{}
@@ -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}
@@ -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 """
@@ -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 """
@@ -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
@@ -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 %>
14 changes: 7 additions & 7 deletions lib/atomic_web/config.ex
Original file line number Diff line number Diff line change
@@ -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",
@@ -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",
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
@@ -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
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
@@ -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
@@ -2,6 +2,7 @@ defmodule AtomicWeb.AnnouncementLive.FormComponent do
use AtomicWeb, :live_component

alias Atomic.Organizations
alias AtomicWeb.Components.ImageUploader

import AtomicWeb.Components.Forms

@@ -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
@@ -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,
@@ -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
@@ -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
@@ -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}} ->
@@ -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
35 changes: 5 additions & 30 deletions lib/atomic_web/live/announcement_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -1,47 +1,22 @@
<.page title="Announcements">
<.page title="Announcements" bottom_border={true}>
<:actions>
<%= if not @empty? and @has_permissions? do %>
<.button navigate={~p"/announcements/new"}>
<%= gettext("New") %>
<.button navigate={~p"/organizations/#{@current_organization}/announcements/new"} icon="hero-plus">
<%= gettext("New Announcement") %>
</.button>
<% end %>
</:actions>
<!-- Tabs -->
<.tabs class="max-w-5-xl mx-auto px-4 sm:px-6 lg:px-8">
<.link patch="?tab=all" replace={false}>
<.tab active={@current_tab == "all"}>
<%= gettext("All") %>
</.tab>
</.link>

<.link patch="?tab=following" replace={false}>
<.tab active={@current_tab == "following"}>
<%= gettext("Following") %>
</.tab>
</.link>
</.tabs>
<!-- Announcements index -->
<%= if @empty? and @has_permissions? do %>
<div class="mt-32">
<.empty_state url={~p"/announcements/new"} placeholder="announcement" />
<.empty_state url={~p"/organizations/#{@organization}/announcements/new"} placeholder="announcement" />
</div>
<% else %>
<div class="overflow-hidden bg-white">
<ul role="list" class="divide-y divide-zinc-200 overflow-auto">
<%= for announcement <- @announcements do %>
<li id={announcement.id}>
<.link navigate={~p"/announcements/#{announcement}"} class="block hover:bg-zinc-50">
<div class="px-4 py-4 lg:px-6">
<div class="flex items-center justify-between">
<p class="truncate text-sm font-medium text-zinc-900">
<%= announcement.title %>
</p>
</div>
<p class="mt-2 text-sm text-zinc-500">
<%= announcement.description %>
</p>
</div>
</.link>
<.announcement_card announcement={announcement} organization={@organization} />
</li>
<% end %>
</ul>
2 changes: 1 addition & 1 deletion lib/atomic_web/live/announcement_live/new.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<.page title={gettext("New Announcement")}>
<div class="pt-4 px-4">
<.live_component module={AtomicWeb.AnnouncementLive.FormComponent} id={:new} organization={@current_organization} title={@page_title} action={@live_action} announcement={@announcement} return_to={~p"/announcements"} />
<.live_component module={AtomicWeb.AnnouncementLive.FormComponent} id={:new} organization={@current_organization} title={@page_title} action={@live_action} announcement={@announcement} return_to={~p"/organizations/#{@current_organization}/announcements"} />
</div>
</.page>
6 changes: 4 additions & 2 deletions lib/atomic_web/live/announcement_live/show.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
defmodule AtomicWeb.AnnouncementLive.Show do
use AtomicWeb, :live_view

import AtomicWeb.Components.Avatar

alias Atomic.Accounts
alias Atomic.Organizations

@@ -18,7 +20,7 @@ defmodule AtomicWeb.AnnouncementLive.Show do
|> assign(:page_title, "#{announcement.title}")
|> assign(:current_page, :announcements)
|> assign(:announcement, announcement)
|> assign(:has_permissions?, has_permissions?(socket))}
|> assign(:has_permissions?, has_permissions?(socket |> assign(:announcement, announcement)))}
end

defp has_permissions?(socket) when not socket.assigns.is_authenticated?, do: false
@@ -33,7 +35,7 @@ defmodule AtomicWeb.AnnouncementLive.Show do
Accounts.has_master_permissions?(socket.assigns.current_user.id) ||
Accounts.has_permissions_inside_organization?(
socket.assigns.current_user.id,
socket.assigns.current_organization.id
socket.assigns.announcement.organization.id
)
end
end
54 changes: 36 additions & 18 deletions lib/atomic_web/live/announcement_live/show.html.heex
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
<div class="py-4 px-4 sm:px-0">
<div class="px-4 flex flex-col gap-2 mt-6 sm:flex-row sm:items-center">
<div>
<div class="flex justify-between items-center">
<h4 class="text-2xl font-bold text-zinc-800">
<.page title="Announcements" bottom_border={true}>
<:actions>
<%= if @has_permissions? do %>
<.button navigate={~p"/organizations/#{@announcement.organization}/announcements/#{@announcement}/edit"} icon="hero-pencil-solid"><%= gettext("Edit Announcement") %></.button>
Copy link
Contributor

@FilipeR13 FilipeR13 Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two previous issues that still need to be fixed:
The button should disappear when viewing as a user or another organization.

View as a user and not organization:
imagem

View as other organization:
imagem

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed, unless you are using a master account

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Exactly, supposedly it is already working (let's not comment about the image used as an example)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct in that sense.

However, when viewing as a master in user mode, the button appears—which may be fine—but attempting to edit raises this error:
imagem

The first strategy to address this should be fixing the error. If that's not possible, consider hiding the button.

<% end %>
</:actions>
<div id={@announcement.id} class="mx-auto max-w-5xl">
<div class="mt-4 md:mt-2 flex flex-col justify-center rounded-lg bg-white lg:p-4">
<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} size={:md} type={:organization} src={Uploaders.Logo.url({@announcement.organization.logo, @announcement.organization}, :original)} />
</div>
<div>
<p class="text-lg sm:text-xl font-bold text-zinc-700"><%= @announcement.organization.name %></p>
<p class="text-base md:text-md 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 mt-8">
<p class="text-xl md:text-2xl font-semibold text-zinc-900" title={@announcement.title}>
<%= @announcement.title %>
</h4>
</p>
<p class="mt-2 overflow-hidden break-words text-sm md:text-base leading-relaxed">
<span class="py-4 text-zinc-800">
<%= Enum.map(String.split(@announcement.description, "\n"), fn phrase -> %>
<%= phrase %>
<% end) %>
</span>
</p>
</div>
<p class="mt-1 text-zinc-500">
<%= @announcement.description %>
</p>
<%= if @announcement.image do %>
<div class="h-auto w-full overflow-hidden mt-4">
<img class="max-h-[32rem] sm:max-wxl object-cover max-w-screen md:rounded-xl" src={Uploaders.Post.url({@announcement.image, @announcement}, :original)} alt="Announcement Image" />
</div>
<% end %>
</div>
</div>
</div>

<%= if @has_permissions? do %>
<.link patch={~p"/organizations/#{@announcement.organization}/announcements/#{@announcement}/edit"} class="px-2 button">
<div type="button" class="inline-flex justify-center py-2 px-4 w-fit text-sm font-medium text-zinc-700 bg-white rounded-md border border-zinc-300 shadow-sm hover:bg-zinc-50" id="sort-menu-button" aria-expanded="false" aria-haspopup="true">
<.icon name="hero-pencil-solid" class="mr-3 w-5 h-5 text-zinc-400" /> Edit
</div>
</.link>
<% end %>
</.page>
6 changes: 6 additions & 0 deletions lib/atomic_web/router.ex
Original file line number Diff line number Diff line change
@@ -132,6 +132,12 @@ defmodule AtomicWeb.Router do
live "/", PartnerLive.Index, :index
live "/:id", PartnerLive.Show, :show
end

scope "/announcements" do
pipe_through :confirm_announcement_association
live "/", AnnouncementLive.Index, :index
live "/:id", AnnouncementLive.Show, :show
end
end

# Only masters can create organizations