summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLogan Hunt <loganhunt@simponic.xyz>2022-04-20 16:03:17 -0600
committerLogan Hunt <loganhunt@simponic.xyz>2022-04-20 16:03:17 -0600
commit763ea5331b1977dd949c776215f2c7719f81ee9a (patch)
treec457c73fbf0f73a6d1975ece6d1573f4dfc6a26a
parent3cf9f4a364ac91cca30799c8379a682139425e71 (diff)
downloadaggiedit-763ea5331b1977dd949c776215f2c7719f81ee9a.tar.gz
aggiedit-763ea5331b1977dd949c776215f2c7719f81ee9a.zip
Initial chat box; man phoenix does not have the best docs
-rw-r--r--assets/css/app.css100
-rw-r--r--assets/js/chat.js43
-rw-r--r--lib/aggiedit/rooms.ex8
-rw-r--r--lib/aggiedit/rooms/comment.ex4
-rw-r--r--lib/aggiedit_web/channels/post_channel.ex20
-rw-r--r--lib/aggiedit_web/live/post_live/show.ex6
-rw-r--r--lib/aggiedit_web/live/post_live/show.html.heex84
7 files changed, 203 insertions, 62 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 = `<span class="username"><b>${user}</b></span>: ${message}<br>`
-// if (message.match(new RegExp(`@${window.userName}`, "ig"))) {
-// $("#chat-box").append('<p class="chat-entry"><span class="mentioned">' + body + '</span></p>')
-// } else {
-// $("#chat-box").append('<p class="chat-entry">' + body + '</p>')
-// }
- },
- 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 @@
-<h1>Show Post</h1>
+
+<div class="d-flex justify-content-center">
+ <div class="container">
+ <div>
+ <h1><%= @post.title %></h1>
+ </div>
+ <div>
+ <%= if Ecto.assoc_loaded?(@post.upload) && !is_nil(@post.upload) do %>
+ <img src={Routes.static_path(@socket, "/uploads/#{@post.upload.file}")} class="img-fluid"/>
+ <% end %>
+ </div>
+ <div class="post-body">
+ <%= @post.body %>
+ </div>
+ <%= if Aggiedit.Roles.guard?(@current_user, :edit, @post) do %>
+ <span><%= live_patch "Edit", to: Routes.post_show_path(@socket, :edit, @room, @post), class: "button" %></span> |
+ <% end %>
+ <span><%= live_redirect "Back", to: Routes.post_index_path(@socket, :index, @room) %></span>
+ </div>
+</div>
+
+<!-- chat container from https://www.bootdey.com/snippets/view/card-chat-list#html -->
+<div class="container content mt-2">
+ <div class="row">
+ <div class="col-xl-6 col-lg-6 col-md-6 col-sm-12 col-12">
+ <div class="chat-card">
+ <div class="chat-card-body">
+ <ul class="chat-list" id="chat" phx-update="ignore">
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
<%= if @live_action in [:edit] do %>
<.modal return_to={Routes.post_show_path(@socket, :show, @room, @post)}>
@@ -14,24 +47,43 @@
</.modal>
<% end %>
-<ul>
+<script>
+ const scrollToBottom = (element) => {
+ element.scrollIntoView({ behavior: 'smooth', block: 'end' });
+ };
- <li>
- <strong>Title:</strong>
- <%= @post.title %>
- </li>
+ const appendComment = ({user, body, id, inserted_at}, element) => {
+ const messageElement = document.createElement("div");
+ messageElement.innerHTML = `
+ <li class="in" id=${id}>
+ <div class="chat-card-body">
+ <div class="chat-message">
+ <h5>${user}</h5>
+ <p>${body}</p>
+ </div>
+ </div>
+ </li>
+ `;
+ element.appendChild(messageElement);
+ scrollToBottom(element);
+ };
- <li>
- <strong>Body:</strong>
- <%= @post.body %>
- </li>
-</ul>
+ window.addEventListener('phx:initial-post', (e) => {
+ const chatWindow = document.getElementById("chat");
+ window.userSocket.connect();
+ let channel = window.RoomChat.connect(window.userSocket, e.detail.id);
-<span><%= live_patch "Edit", to: Routes.post_show_path(@socket, :edit, @room, @post), class: "button" %></span> |
-<span><%= live_redirect "Back", to: Routes.post_index_path(@socket, :index, @room) %></span>
+ channel.on('shout', (comment) => {
+ appendComment(comment, chatWindow);
+ });
-<script>
- window.userSocket.connect();
- window.RoomChat.init(window.userSocket, <%= @post.id %>)
+ channel.on('initial-comments', ({comments}) => {
+ comments.forEach((comment) => {
+ appendComment(comment, chatWindow);
+ });
+ scrollToBottom(chatWindow);
+ });
+ channel.push("send", {body: "Hello!"});
+ });
</script>