postland/lib/postland_web/live/timeline_live.ex
2025-01-27 18:01:04 -06:00

201 lines
5.1 KiB
Elixir

defmodule PostlandWeb.TimelineLive do
use PostlandWeb, :live_view
alias Postland.Activities
alias Postland.Objects
def render(assigns) do
~H"""
<div id="timeline">
<.post_form draft={@draft} upload={@uploads.files} />
<div id="timeline-posts" phx-update="stream">
<div :for={{id, post} <- @streams.posts} id={id} class="mt-10">
<.post_card
post={post}
post_dom_id={id}
draft_reply={dbg(@draft_replies[post.id])}
upload={@uploads.files}
/>
</div>
</div>
</div>
"""
end
def mount(_params, _session, socket) do
socket =
socket
|> assign(:draft, %Postland.Draft{})
|> assign(:draft_replies, %{})
|> stream(:posts, Postland.Timeline.timeline())
|> allow_upload(:files,
accept: ["image/*"],
auto_upload: true,
progress: &handle_progress/3
)
{:ok, socket}
end
def handle_event("create_post", %{"draft_body" => draft_body}, socket) do
{:ok, results} =
Postland.Activities.record_markdown_post(
draft_body,
socket.assigns.draft.cw,
socket.assigns.draft.attachments
)
new_posts =
results
|> Enum.filter(fn {_key, value} ->
is_struct(value, Postland.Object)
end)
socket =
socket
|> assign(:draft, %Postland.Draft{})
|> then(fn socket ->
Enum.reduce(new_posts, socket, fn {_id, post}, socket ->
stream_insert(socket, :posts, post, at: 0)
end)
end)
{:noreply, socket}
end
def handle_event("delete_post", %{"post-id" => id, "post-dom-id" => dom_id}, socket) do
post = Objects.get_by_id(id)
case Activities.delete_post(post) do
{:ok, _} ->
{:noreply, socket |> stream_delete_by_dom_id(:posts, dom_id)}
_ ->
{:noreply, socket |> put_flash(:error, "An unexpected error has occurred.")}
end
end
def handle_event("like_post", %{"post-id" => id, "post-dom-id" => dom_id}, socket) do
post = Objects.get_by_id(id)
case Activities.like_post(post) do
{:ok, _} ->
post = Objects.get_by_id(id)
{:noreply, socket |> stream_insert(:posts, post)}
_ ->
{:noreply, socket |> put_flash(:error, "An unexpected error has occurred.")}
end
end
def handle_event("unlike_post", %{"post-id" => id}, socket) do
post = Objects.get_by_id(id)
case Activities.unlike_post(post) do
{:ok, _} ->
post = Objects.get_by_id(id)
{:noreply, socket |> stream_insert(:posts, post)}
_ ->
{:noreply, socket |> put_flash(:error, "An unexpected error has occurred.")}
end
end
def handle_event("show_reply_form", %{"post-id" => id}, socket) do
post = Objects.get_by_id(id)
draft_replies =
case Map.get(socket.assigns.draft_replies, id) do
nil ->
Map.put(socket.assigns.draft_replies, id, %Postland.Draft{})
_ ->
socket.assigns.draft_replies
end
{:noreply, socket |> assign(:draft_replies, draft_replies) |> stream_insert(:posts, post)}
end
def handle_event("change_post", %{"draft_body" => draft_body} = params, socket) do
cw = Map.get(params, "cw")
draft =
socket.assigns.draft
|> Map.put(:text, draft_body)
|> Map.put(:cw, cw)
{:noreply, socket |> assign(draft: draft)}
end
def handle_event("remove_attachment", %{"url" => url}, socket) do
attachments =
socket.assigns.draft.attachments
|> Enum.reject(fn %{"url" => attachment_url} -> attachment_url == url end)
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
end
def handle_event("change_alt_text", %{"alt" => value, "url" => url}, socket) do
attachments =
socket.assigns.draft.attachments
|> Enum.map(fn
%{"url" => ^url} = attachment ->
Map.put(attachment, "name", value)
other ->
other
end)
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
end
def handle_event("add_cw", _, socket) do
draft =
socket.assigns.draft
|> Map.put(:cw, "")
{:noreply, assign(socket, draft: draft)}
end
def handle_event("remove_cw", _, socket) do
draft =
socket.assigns.draft
|> Map.put(:cw, nil)
{:noreply, assign(socket, draft: draft)}
end
def handle_progress(:files, entry, socket) do
if entry.done? do
uploaded_file =
consume_uploaded_entry(socket, entry, fn meta ->
Postland.Uploads.handle_upload(entry, meta)
end)
attachment = %{
"type" => "Document",
"mediaType" => entry.client_type,
"url" => unverified_url(PostlandWeb.Endpoint, uploaded_file),
"name" => nil
}
attachments = socket.assigns.draft.attachments ++ [attachment]
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
else
{:noreply, socket}
end
end
end