From 763ea5331b1977dd949c776215f2c7719f81ee9a Mon Sep 17 00:00:00 2001 From: Logan Hunt Date: Wed, 20 Apr 2022 16:03:17 -0600 Subject: [PATCH] Initial chat box; man phoenix does not have the best docs --- assets/css/app.css | 100 ++++++++++++++++++ assets/js/chat.js | 43 +------- lib/aggiedit/rooms.ex | 8 +- lib/aggiedit/rooms/comment.ex | 4 + lib/aggiedit_web/channels/post_channel.ex | 20 +++- lib/aggiedit_web/live/post_live/show.ex | 6 +- .../live/post_live/show.html.heex | 92 ++++++++++++---- 7 files changed, 207 insertions(+), 66 deletions(-) diff --git a/assets/css/app.css b/assets/css/app.css index 882a0bb..907783d 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -120,4 +120,104 @@ .thumbnail { max-width: 100px; max-height: 100px; +} + +.post-body { + white-space: pre-line; +} + + +/* Chat css from: https://www.bootdey.com/snippets/view/card-chat-list#html */ +.chat-list { + padding: 0; + font-size: .8rem; +} + +.chat-list li { + margin-bottom: 10px; + overflow: auto; + color: #ffffff; +} + +.chat-list .chat-message { + -webkit-border-radius: 50px; + -moz-border-radius: 50px; + border-radius: 50px; + background: #5a99ee; + display: inline-block; + padding: 10px 20px; + position: relative; +} + +.chat-list .chat-message:before { + content: ""; + position: absolute; + top: 15px; + width: 0; + height: 0; +} + +.chat-list .chat-message h5 { + margin: 0 0 5px 0; + font-weight: 600; + line-height: 100%; + font-size: .9rem; +} + +.chat-list .chat-message p { + line-height: 18px; + margin: 0; + padding: 0; +} + +.chat-list .chat-card-body { + margin-left: 20px; + float: left; + width: 70%; +} + +.chat-list .in .chat-message:before { + left: -12px; + border-bottom: 20px solid transparent; + border-right: 20px solid #5a99ee; +} + +.chat-list .out .chat-img { + float: right; +} + +.chat-list .out .chat-body { + float: right; + margin-right: 20px; + text-align: right; +} + +.chat-list .out .chat-message { + background: #fc6d4c; +} + +.chat-list .out .chat-message:before { + right: -12px; + border-bottom: 20px solid transparent; + border-left: 20px solid #fc6d4c; +} + +.chat-card { + overflow-y: scroll; + max-height: 300px; +} + +.chat-card .card-header:first-child { + -webkit-border-radius: 0.3rem 0.3rem 0 0; + -moz-border-radius: 0.3rem 0.3rem 0 0; + border-radius: 0.3rem 0.3rem 0 0; +} +.chat-card .card-header { + background: #17202b; + border: 0; + font-size: 1rem; + padding: .65rem 1rem; + position: relative; + font-weight: 600; + color: #ffffff; } \ No newline at end of file diff --git a/assets/js/chat.js b/assets/js/chat.js index aa32aba..4183531 100644 --- a/assets/js/chat.js +++ b/assets/js/chat.js @@ -1,46 +1,11 @@ let RoomChat = { - init(socket, postId) { - console.log(postId); - console.log(socket); + connect(socket, postId) { let channel = socket.channel(`post:${postId}`) channel.join() - .receive("ok", resp => { console.log("Joined successfully", resp) }) - .receive("error", resp => { console.log("Unable to join", resp) }) - this.listenForChats(channel) + .receive("ok", resp => { console.log("Joined successfully: ", resp) }) + .receive("error", resp => { console.log("Unable to join: ", resp) }) + return channel; }, - addMessage(user, message) { -// let body = `${user}: ${message}
` -// if (message.match(new RegExp(`@${window.userName}`, "ig"))) { -// $("#chat-box").append('

' + body + '

') -// } else { -// $("#chat-box").append('

' + body + '

') -// } - }, - scrollBottom() { -// $("#chat-box").animate({ scrollTop: $('#chat-box').prop("scrollHeight")}, 200) - }, - listenForChats(channel) { - channel.push('send', { body: "HELLO"}); -// $(() => { -// $("#chat-form").on("submit", function(ev) { -// ev.preventDefault() -// -// let userMsg = $('#user-msg').val() -// channel.push('send', {body: userMsg}) -// -// $("#user-msg").val("") -// }) - -// channel.on('shout', function(payload) { -// console.log(payload) -// RoomChat.addMessage(payload.name, payload.body) -// RoomChat.scrollBottom() -// }) - // }) - channel.on('shout', function(payload) { - console.log(payload) - }); - } } export default RoomChat; \ No newline at end of file diff --git a/lib/aggiedit/rooms.ex b/lib/aggiedit/rooms.ex index 41df588..239dd90 100644 --- a/lib/aggiedit/rooms.ex +++ b/lib/aggiedit/rooms.ex @@ -94,7 +94,7 @@ defmodule Aggiedit.Rooms do end def vote_count(post) do - votes = post + post |> Repo.preload(:votes) |> Map.get(:votes) |> Enum.map(fn vote -> if vote.is_up, do: 1, else: -1 end) @@ -105,11 +105,17 @@ defmodule Aggiedit.Rooms do is_up = direction == "upvote" vote = %Vote{is_up: is_up, user: user, post: post} |> Repo.insert(on_conflict: [set: [is_up: is_up]], conflict_target: [:user_id, :post_id]) + post = change_post(post, %{score: vote_count(post)}) |> Repo.update() + broadcast_post_over_room(post, :post_voted) end + def comment_post(%Post{} = post, %User{} = user, comment) do + Repo.insert(%Comment{comment: comment, user: user, post: post}) + end + defp broadcast_post_over_room({:error, _reason}=error, _event), do: error defp broadcast_post_over_room({:ok, post}, event) do PubSub.broadcast(Aggiedit.PubSub, "room:#{post.room_id}:posts", {event, post}) diff --git a/lib/aggiedit/rooms/comment.ex b/lib/aggiedit/rooms/comment.ex index 6747ba3..01f411a 100644 --- a/lib/aggiedit/rooms/comment.ex +++ b/lib/aggiedit/rooms/comment.ex @@ -17,4 +17,8 @@ defmodule Aggiedit.Post.Comment do |> cast(attrs, [:comment]) |> validate_required([:comment]) end + + def serialize(c) do + %{"body" => c.comment, "user" => c.user.username, "id" => c.id, "inserted_at" => c.inserted_at} + end end diff --git a/lib/aggiedit_web/channels/post_channel.ex b/lib/aggiedit_web/channels/post_channel.ex index 308c6de..ea79d76 100644 --- a/lib/aggiedit_web/channels/post_channel.ex +++ b/lib/aggiedit_web/channels/post_channel.ex @@ -2,21 +2,35 @@ defmodule AggieditWeb.PostChannel do use AggieditWeb, :channel alias Aggiedit.Roles + alias Aggiedit.Repo alias Aggiedit.Rooms @impl true def join("post:" <> post_id, _payload, socket) do post = Rooms.get_post!(post_id) if Roles.guard?(socket.assigns.current_user, :show, post) do - {:ok, socket} + send(self(), :after_join) + {:ok, assign(socket, %{:post => post})} else {:error, "You do not have permission to view this post."} end end @impl true - def handle_in("send", body, socket) do - broadcast!(socket, "shout", body) + def handle_info(:after_join, socket) do + comments = socket.assigns.post + |> Repo.preload(comments: [:user]) + |> Map.get(:comments) + |> Enum.map(fn c -> Aggiedit.Post.Comment.serialize(c) end) + push(socket, "initial-comments", %{:comments => comments}) + + {:noreply, socket} + end + + @impl true + def handle_in("send", %{"body" => comment}=body, socket) do + {:ok, comment} = Rooms.comment_post(socket.assigns.post, socket.assigns.current_user, comment) + broadcast!(socket, "shout", Aggiedit.Post.Comment.serialize(comment)) {:reply, :ok, socket} end end \ No newline at end of file diff --git a/lib/aggiedit_web/live/post_live/show.ex b/lib/aggiedit_web/live/post_live/show.ex index 9d8f86c..69cd6c5 100644 --- a/lib/aggiedit_web/live/post_live/show.ex +++ b/lib/aggiedit_web/live/post_live/show.ex @@ -15,10 +15,10 @@ defmodule AggieditWeb.PostLive.Show do post = Rooms.get_post!(id) |> Repo.preload(:upload) if Roles.guard?(socket.assigns.current_user, socket.assigns.live_action, post) do - {:noreply, - socket + socket = (if socket.assigns.live_action == :show, do: push_event(socket, "initial-post", %{:id => post.id}), else: socket) |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:post, post)} + |> assign(:post, post) + {:noreply, socket} else {:noreply, socket |> put_flash(:error, "You don't have permission to do that.") |> redirect(to: Routes.post_show_path(socket, :show, socket.assigns.room, post))} end diff --git a/lib/aggiedit_web/live/post_live/show.html.heex b/lib/aggiedit_web/live/post_live/show.html.heex index 107a3a6..8f91fda 100644 --- a/lib/aggiedit_web/live/post_live/show.html.heex +++ b/lib/aggiedit_web/live/post_live/show.html.heex @@ -1,4 +1,37 @@ -

Show Post

+ +
+
+
+

<%= @post.title %>

+
+
+ <%= if Ecto.assoc_loaded?(@post.upload) && !is_nil(@post.upload) do %> + + <% end %> +
+
+ <%= @post.body %> +
+ <%= if Aggiedit.Roles.guard?(@current_user, :edit, @post) do %> + <%= live_patch "Edit", to: Routes.post_show_path(@socket, :edit, @room, @post), class: "button" %> | + <% end %> + <%= live_redirect "Back", to: Routes.post_index_path(@socket, :index, @room) %> +
+
+ + +
+
+
+
+
+
    +
+
+
+
+
+
<%= if @live_action in [:edit] do %> <.modal return_to={Routes.post_show_path(@socket, :show, @room, @post)}> @@ -14,24 +47,43 @@ <% end %> - - -<%= live_patch "Edit", to: Routes.post_show_path(@socket, :edit, @room, @post), class: "button" %> | -<%= live_redirect "Back", to: Routes.post_index_path(@socket, :index, @room) %> -