Skip to content

Instantly share code, notes, and snippets.

@mplatts
Created September 24, 2020 02:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mplatts/1f985f5a72add3cca6aea13eb0b65e5b to your computer and use it in GitHub Desktop.
Save mplatts/1f985f5a72add3cca6aea13eb0b65e5b to your computer and use it in GitHub Desktop.
defmodule AppWeb.PageLive do
use AppWeb, :live_view
alias App.Posts
alias App.Posts.Post
alias App.Votes
@impl true
def mount(_params, session, socket) do
socket = maybe_assign_user(session, socket)
days = 5
votes = get_votes(socket)
if connected?(socket) do
AppWeb.Endpoint.subscribe("post")
end
{:ok,
assign(socket, %{
days: get_days(days),
votes: votes
})}
end
@impl true
def handle_info(
%{topic: "post", event: "upvoted", payload: %{post_id: post_id, day: day, month: month}},
socket
) do
post = find_post_in_socket(post_id, day, month, socket)
post = %Post{post | upvotes: post.upvotes + 1}
{:noreply,
assign(socket, %{
days: upvote_post_in_days(post, day, month, socket.assigns.days)
})}
end
@impl true
def handle_event("upvote", %{"id" => post_id, "day" => day, "month" => month}, socket) do
socket =
if(socket.assigns[:current_user]) do
day = String.to_integer(day)
month = String.to_integer(month)
post_id = String.to_integer(post_id)
post = find_post_in_socket(post_id, day, month, socket)
{:ok, post} =
Posts.update_post(post, %{
upvotes: post.upvotes + 1
})
{:ok, vote} =
Votes.create_vote(%{
user_id: socket.assigns.current_user.id,
post_id: post_id
})
AppWeb.Endpoint.broadcast("post", "upvoted", %{
day: day,
month: month,
post_id: post.id
})
assign(socket, %{
votes: socket.assigns.votes ++ [vote]
})
else
socket
end
{:noreply, socket}
end
defp get_votes(socket) do
if socket.assigns[:current_user] do
App.Repo.preload(socket.assigns.current_user, :votes).votes
else
[]
end
end
defp get_days(count) do
now = Timex.beginning_of_day(Timex.now())
Enum.map(0..(count - 1), fn i ->
date = Timex.shift(now, days: -i)
%{
date: date,
day: date.day,
month: date.month,
posts: Posts.most_popular_for_date(date)
}
end)
end
defp find_post_in_socket(post_id, day, month, socket) do
get_in(socket.assigns.days, [
Access.filter(&(&1.day == day && &1.month == month)),
:posts,
Access.filter(&(&1.id == post_id))
])
|> List.flatten()
|> List.first()
end
defp upvote_post_in_days(post, day, month, days) do
put_in(
days,
[
Access.filter(&(&1.day == day && &1.month == month)),
:posts,
Access.filter(&(&1.id == post.id)),
Access.key!(:upvotes)
],
post.upvotes
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment