simple_chat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +178 -0
- data/Rakefile +6 -0
- data/app/assets/stylesheets/simple_chat/application.css +726 -0
- data/app/assets/stylesheets/simple_chat/application.tailwind.css +1 -0
- data/app/controllers/simple_chat/application_controller.rb +16 -0
- data/app/controllers/simple_chat/chat_members_controller.rb +27 -0
- data/app/controllers/simple_chat/chat_rooms_controller.rb +74 -0
- data/app/controllers/simple_chat/messages_controller.rb +77 -0
- data/app/helpers/simple_chat/application_helper.rb +4 -0
- data/app/helpers/simple_chat/chat_rooms_helper.rb +4 -0
- data/app/helpers/simple_chat/messages_helper.rb +4 -0
- data/app/jobs/simple_chat/application_job.rb +4 -0
- data/app/mailers/simple_chat/application_mailer.rb +6 -0
- data/app/models/simple_chat/application_record.rb +5 -0
- data/app/models/simple_chat/chat_member.rb +6 -0
- data/app/models/simple_chat/chat_room.rb +22 -0
- data/app/models/simple_chat/message.rb +8 -0
- data/app/views/layouts/simple_chat/application.html.erb +24 -0
- data/app/views/simple_chat/chat_rooms/_chat_room.html.erb +7 -0
- data/app/views/simple_chat/chat_rooms/_form.html.erb +22 -0
- data/app/views/simple_chat/chat_rooms/edit.html.erb +12 -0
- data/app/views/simple_chat/chat_rooms/index.html.erb +14 -0
- data/app/views/simple_chat/chat_rooms/new.html.erb +11 -0
- data/app/views/simple_chat/chat_rooms/show.html.erb +80 -0
- data/app/views/simple_chat/messages/_form.html.erb +28 -0
- data/app/views/simple_chat/messages/_message.html.erb +28 -0
- data/app/views/simple_chat/messages/create.turbo_stream.erb +10 -0
- data/app/views/simple_chat/messages/edit.html.erb +12 -0
- data/app/views/simple_chat/messages/index.html.erb +14 -0
- data/app/views/simple_chat/messages/new.html.erb +11 -0
- data/app/views/simple_chat/messages/show.html.erb +8 -0
- data/config/routes.rb +7 -0
- data/config/tailwind.config.js +15 -0
- data/db/migrate/20260406070146_create_simple_chat_chat_rooms.rb +9 -0
- data/db/migrate/20260406080846_create_simple_chat_chat_members.rb +11 -0
- data/db/migrate/20260406081003_create_simple_chat_messages.rb +12 -0
- data/db/migrate/20260503095220_add_channel_hash_to_solid_cable_messages.rb +6 -0
- data/lib/generators/simple_chat/install_generator.rb +21 -0
- data/lib/simple_chat/configuration.rb +16 -0
- data/lib/simple_chat/engine.rb +13 -0
- data/lib/simple_chat/version.rb +3 -0
- data/lib/simple_chat.rb +42 -0
- data/lib/tasks/simple_chat_tasks.rake +40 -0
- metadata +146 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class ApplicationController < ::ApplicationController
|
|
3
|
+
helper_method :simple_chat_current_user
|
|
4
|
+
|
|
5
|
+
def simple_chat_current_user
|
|
6
|
+
method = SimpleChat.configuration.current_user_method
|
|
7
|
+
if respond_to?(method, true)
|
|
8
|
+
send(method)
|
|
9
|
+
elsif defined?(Current) && Current.respond_to?(:user)
|
|
10
|
+
Current.user
|
|
11
|
+
else
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class ChatMembersController < ApplicationController
|
|
3
|
+
before_action :set_chat_room
|
|
4
|
+
|
|
5
|
+
def create
|
|
6
|
+
@chat_member = @chat_room.chat_members.find_or_initialize_by(user: simple_chat_current_user)
|
|
7
|
+
|
|
8
|
+
if @chat_member.save
|
|
9
|
+
redirect_to @chat_room, notice: "You are now a member of this chat room."
|
|
10
|
+
else
|
|
11
|
+
redirect_to @chat_room, alert: "Unable to join chat room."
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def destroy
|
|
16
|
+
@chat_member = @chat_room.chat_members.find_by(user: simple_chat_current_user)
|
|
17
|
+
@chat_member&.destroy
|
|
18
|
+
redirect_to chat_rooms_path, notice: "You have left the chat room."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def set_chat_room
|
|
24
|
+
@chat_room = ChatRoom.find(params[:chat_room_id])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class ChatRoomsController < ApplicationController
|
|
3
|
+
before_action :set_chat_room, only: %i[ show edit update destroy ]
|
|
4
|
+
before_action :ensure_member, only: %i[ show edit update destroy ]
|
|
5
|
+
|
|
6
|
+
# GET /chat_rooms
|
|
7
|
+
def index
|
|
8
|
+
if simple_chat_current_user
|
|
9
|
+
@chat_rooms = ChatRoom.for_user(simple_chat_current_user)
|
|
10
|
+
else
|
|
11
|
+
@chat_rooms = ChatRoom.none
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /chat_rooms/1
|
|
16
|
+
def show
|
|
17
|
+
@messages = @chat_room.messages.select(&:persisted?)
|
|
18
|
+
@message = @chat_room.messages.build
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# GET /chat_rooms/new
|
|
22
|
+
def new
|
|
23
|
+
@chat_room = ChatRoom.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# GET /chat_rooms/1/edit
|
|
27
|
+
def edit
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# POST /chat_rooms
|
|
31
|
+
def create
|
|
32
|
+
@chat_room = ChatRoom.new(chat_room_params)
|
|
33
|
+
|
|
34
|
+
if @chat_room.save
|
|
35
|
+
@chat_room.chat_members.create(user: simple_chat_current_user) if simple_chat_current_user
|
|
36
|
+
redirect_to @chat_room, notice: "Chat room was successfully created and you have been added as a member."
|
|
37
|
+
else
|
|
38
|
+
render :new, status: :unprocessable_content
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# PATCH/PUT /chat_rooms/1
|
|
43
|
+
def update
|
|
44
|
+
if @chat_room.update(chat_room_params)
|
|
45
|
+
redirect_to @chat_room, notice: "Chat room was successfully updated.", status: :see_other
|
|
46
|
+
else
|
|
47
|
+
render :edit, status: :unprocessable_content
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# DELETE /chat_rooms/1
|
|
52
|
+
def destroy
|
|
53
|
+
@chat_room.destroy!
|
|
54
|
+
redirect_to chat_rooms_path, notice: "Chat room was successfully destroyed.", status: :see_other
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
59
|
+
def set_chat_room
|
|
60
|
+
@chat_room = ChatRoom.find(params.expect(:id))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Only allow a list of trusted parameters through.
|
|
64
|
+
def chat_room_params
|
|
65
|
+
params.expect(chat_room: [ :title ])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def ensure_member
|
|
69
|
+
unless @chat_room.is_member?(simple_chat_current_user)
|
|
70
|
+
redirect_to chat_rooms_path, alert: "You are not a member of this chat room."
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class MessagesController < ApplicationController
|
|
3
|
+
before_action :set_message, only: %i[ show edit update destroy ]
|
|
4
|
+
|
|
5
|
+
# GET /messages
|
|
6
|
+
def index
|
|
7
|
+
if params[:chat_room_id]
|
|
8
|
+
@chat_room = ChatRoom.find(params[:chat_room_id])
|
|
9
|
+
@messages = @chat_room.messages
|
|
10
|
+
else
|
|
11
|
+
@messages = Message.all
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /messages/1
|
|
16
|
+
def show
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# GET /messages/new
|
|
20
|
+
def new
|
|
21
|
+
@message = Message.new(chat_room_id: params[:chat_room_id])
|
|
22
|
+
@chat_room = @message.chat_room
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# GET /messages/1/edit
|
|
26
|
+
def edit
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# POST /messages
|
|
30
|
+
def create
|
|
31
|
+
@message = Message.new(message_params)
|
|
32
|
+
@message.user = simple_chat_current_user
|
|
33
|
+
@chat_room = @message.chat_room
|
|
34
|
+
|
|
35
|
+
if @chat_room && !@chat_room.is_member?(simple_chat_current_user)
|
|
36
|
+
redirect_to @chat_room, alert: "You must be a member of this chat room to post messages."
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if @message.save
|
|
41
|
+
respond_to do |format|
|
|
42
|
+
format.html { redirect_to @chat_room || @message, notice: "Message was successfully created." }
|
|
43
|
+
format.turbo_stream
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
render :new, status: :unprocessable_content
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# PATCH/PUT /messages/1
|
|
51
|
+
def update
|
|
52
|
+
if @message.update(message_params)
|
|
53
|
+
redirect_to @message, notice: "Message was successfully updated.", status: :see_other
|
|
54
|
+
else
|
|
55
|
+
render :edit, status: :unprocessable_content
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# DELETE /messages/1
|
|
60
|
+
def destroy
|
|
61
|
+
chat_room = @message.chat_room
|
|
62
|
+
@message.destroy!
|
|
63
|
+
redirect_to messages_path(chat_room_id: chat_room&.id), notice: "Message was successfully destroyed.", status: :see_other
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
def set_message
|
|
68
|
+
@message = Message.find(params[:id])
|
|
69
|
+
@chat_room = @message.chat_room
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Only allow a list of trusted parameters through.
|
|
73
|
+
def message_params
|
|
74
|
+
params.expect(message: [ :content, :chat_room_id ])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class ChatRoom < ApplicationRecord
|
|
3
|
+
has_many :messages, dependent: :destroy
|
|
4
|
+
has_many :chat_members, dependent: :destroy
|
|
5
|
+
validates :title, uniqueness: true
|
|
6
|
+
|
|
7
|
+
scope :for_user, ->(user) { joins(:chat_members).where(simple_chat_chat_members: { user_id: user.id }) }
|
|
8
|
+
|
|
9
|
+
def is_member?(user)
|
|
10
|
+
chat_members.exists?(user: user)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
def is_group_chat
|
|
15
|
+
chat_members.count > 2
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def last_message_id
|
|
19
|
+
messages.last.id
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module SimpleChat
|
|
2
|
+
class Message < ApplicationRecord
|
|
3
|
+
belongs_to :chat_room
|
|
4
|
+
belongs_to :user, class_name: SimpleChat.configuration.chat_user_model
|
|
5
|
+
|
|
6
|
+
after_create_commit -> { broadcast_append_later_to "simple_chat", chat_room, target: "messages_list", partial: "simple_chat/messages/message", locals: { message: self } }
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Simple chat</title>
|
|
5
|
+
<%= csrf_meta_tags %>
|
|
6
|
+
<%= csp_meta_tag %>
|
|
7
|
+
|
|
8
|
+
<%= yield :head %>
|
|
9
|
+
|
|
10
|
+
<%= stylesheet_link_tag "simple_chat/application", "data-turbo-track": "reload" %>
|
|
11
|
+
<%= javascript_importmap_tags %>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<% if notice %>
|
|
15
|
+
<p style="color: green"><%= notice %></p>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% if alert %>
|
|
18
|
+
<p style="color: red"><%= alert %></p>
|
|
19
|
+
<% end %>
|
|
20
|
+
|
|
21
|
+
<%= yield %>
|
|
22
|
+
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%= form_with(model: chat_room) do |form| %>
|
|
2
|
+
<% if chat_room.errors.any? %>
|
|
3
|
+
<div style="color: red">
|
|
4
|
+
<h2><%= pluralize(chat_room.errors.count, "error") %> prohibited this chat_room from being saved:</h2>
|
|
5
|
+
|
|
6
|
+
<ul>
|
|
7
|
+
<% chat_room.errors.each do |error| %>
|
|
8
|
+
<li><%= error.full_message %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<div>
|
|
15
|
+
<%= form.label :title, style: "display: block" %>
|
|
16
|
+
<%= form.text_field :title %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div>
|
|
20
|
+
<%= form.submit %>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% content_for :title, "Editing chat room" %>
|
|
2
|
+
|
|
3
|
+
<h1>Editing chat room</h1>
|
|
4
|
+
|
|
5
|
+
<%= render "form", chat_room: @chat_room %>
|
|
6
|
+
|
|
7
|
+
<br>
|
|
8
|
+
|
|
9
|
+
<div>
|
|
10
|
+
<%= link_to "Show this chat room", @chat_room %> |
|
|
11
|
+
<%= link_to "Back to chat rooms", chat_rooms_path %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<% content_for :title, "Chat rooms" %>
|
|
2
|
+
|
|
3
|
+
<h1>Chat rooms</h1>
|
|
4
|
+
|
|
5
|
+
<div id="chat_rooms">
|
|
6
|
+
<% @chat_rooms.each do |chat_room| %>
|
|
7
|
+
<%= render chat_room %>
|
|
8
|
+
<p>
|
|
9
|
+
<%= link_to "Show this chat room", chat_room %>
|
|
10
|
+
</p>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<%= link_to "New chat room", new_chat_room_path %>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<div class="mx-auto max-w-4xl px-4 py-8">
|
|
2
|
+
<div class="flex justify-between items-center mb-6 border-b pb-4">
|
|
3
|
+
<h1 class="text-2xl font-bold text-gray-900">
|
|
4
|
+
<%= @chat_room.title %>
|
|
5
|
+
</h1>
|
|
6
|
+
<div class="flex gap-2">
|
|
7
|
+
<%= link_to "Edit", edit_chat_room_path(@chat_room), class: "text-sm text-blue-600 hover:text-blue-800" %>
|
|
8
|
+
<%= link_to "Back", chat_rooms_path, class: "text-sm text-gray-600 hover:text-gray-800" %>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<%= turbo_stream_from "simple_chat", @chat_room %>
|
|
13
|
+
|
|
14
|
+
<div class="bg-white shadow sm:rounded-lg overflow-hidden flex flex-col h-[600px] border border-gray-200">
|
|
15
|
+
<div id="messages_list_container" class="flex-grow overflow-y-auto p-6 bg-gray-50">
|
|
16
|
+
<ul id="messages_list" role="list" class="space-y-6">
|
|
17
|
+
<%= render @messages %>
|
|
18
|
+
</ul>
|
|
19
|
+
</div>
|
|
20
|
+
<script>
|
|
21
|
+
(function() {
|
|
22
|
+
const scrollToBottom = () => {
|
|
23
|
+
const container = document.getElementById('messages_list_container');
|
|
24
|
+
if (container) {
|
|
25
|
+
// Smooth scroll to bottom
|
|
26
|
+
container.scrollTo({
|
|
27
|
+
top: container.scrollHeight,
|
|
28
|
+
behavior: 'smooth'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const setupScroll = () => {
|
|
34
|
+
const container = document.getElementById('messages_list_container');
|
|
35
|
+
const list = document.getElementById('messages_list');
|
|
36
|
+
|
|
37
|
+
if (container && list) {
|
|
38
|
+
// Initial scroll
|
|
39
|
+
container.scrollTop = container.scrollHeight;
|
|
40
|
+
|
|
41
|
+
// Scroll when new messages are added via MutationObserver
|
|
42
|
+
const observer = new MutationObserver((mutations) => {
|
|
43
|
+
scrollToBottom();
|
|
44
|
+
});
|
|
45
|
+
observer.observe(list, { childList: true });
|
|
46
|
+
|
|
47
|
+
// Cleanup previous observer if any (though this script runs once per page load)
|
|
48
|
+
window._chatScrollObserver?.disconnect();
|
|
49
|
+
window._chatScrollObserver = observer;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Run on initial load
|
|
54
|
+
if (document.readyState === 'loading') {
|
|
55
|
+
document.addEventListener('DOMContentLoaded', setupScroll);
|
|
56
|
+
} else {
|
|
57
|
+
setupScroll();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Also handle Turbo navigation
|
|
61
|
+
document.addEventListener("turbo:load", setupScroll);
|
|
62
|
+
document.addEventListener("turbo:render", setupScroll);
|
|
63
|
+
})();
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div id="new-message" class="border-t border-gray-200 p-4 bg-gray-50">
|
|
67
|
+
<div class="flex gap-x-3">
|
|
68
|
+
<div class="size-6 flex-none rounded-full bg-gray-200 flex items-center justify-center ring-1 ring-gray-300">
|
|
69
|
+
<span class="text-[10px] font-bold text-gray-500">?</span>
|
|
70
|
+
</div>
|
|
71
|
+
<%= render "simple_chat/messages/form", message: @message %>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div class="mt-6 flex justify-between items-center">
|
|
77
|
+
<%= button_to "Leave Chat Room", chat_room_chat_member_path(@chat_room, "current"), method: :delete, data: { confirm: "Are you sure?" }, class: "text-sm text-red-600 hover:text-red-800 font-medium" %>
|
|
78
|
+
<%= button_to "Destroy Room", @chat_room, method: :delete, data: { confirm: "Permanent delete. Are you sure?" }, class: "text-xs text-gray-400 hover:text-red-400" %>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<%= form_with(model: message, class: "relative flex-auto") do |form| %>
|
|
2
|
+
<% if message.errors.any? %>
|
|
3
|
+
<div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mb-4 w-full text-xs">
|
|
4
|
+
<ul>
|
|
5
|
+
<% message.errors.each do |error| %>
|
|
6
|
+
<li><%= error.full_message %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<% if message.chat_room_id.present? %>
|
|
13
|
+
<%= form.hidden_field :chat_room_id %>
|
|
14
|
+
<% else %>
|
|
15
|
+
<div class="mb-2">
|
|
16
|
+
<%= form.collection_select :chat_room_id, SimpleChat::ChatRoom.all, :id, :title, { prompt: "Select Chat Room" }, class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" %>
|
|
17
|
+
</div>
|
|
18
|
+
<% end %>
|
|
19
|
+
|
|
20
|
+
<div class="overflow-hidden rounded-lg pb-12 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600 bg-white">
|
|
21
|
+
<label for="message_content" class="sr-only">Add your message</label>
|
|
22
|
+
<%= form.text_area :content, id: "message_content", rows: 2, placeholder: "Add your message...", class: "block w-full resize-none bg-transparent px-3 py-1.5 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6" %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="absolute inset-x-0 bottom-0 flex justify-end py-2 pr-2 pl-3">
|
|
26
|
+
<%= form.submit "Send Message", class: "rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 cursor-pointer" %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<%# Using local variable message instead of calling helper to avoid issues in background jobs %>
|
|
2
|
+
<% current_user = local_assigns[:current_user] || (respond_to?(:simple_chat_current_user) ? simple_chat_current_user : nil) %>
|
|
3
|
+
<li id="<%= dom_id message %>" class="relative flex gap-x-4">
|
|
4
|
+
<div class="absolute top-0 -bottom-6 left-0 flex w-6 justify-center">
|
|
5
|
+
<div class="w-px bg-gray-200"></div>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div class="relative mt-3 size-6 flex-none rounded-full bg-gray-50 flex items-center justify-center ring-1 ring-gray-200">
|
|
9
|
+
<span class="text-[10px] font-bold text-gray-500"><%= message.user.respond_to?(:name) ? message.user.name[0].upcase : message.user_id %></span>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="flex-auto rounded-md p-3 ring-1 ring-gray-200 ring-inset <%= message.user == current_user ? 'bg-blue-50/50 ring-blue-100' : 'bg-white' %>">
|
|
13
|
+
<div class="flex justify-between gap-x-4">
|
|
14
|
+
<div class="py-0.5 text-xs/5 text-gray-500">
|
|
15
|
+
<span class="font-medium text-gray-900"><%= message.user.respond_to?(:name) ? message.user.name : "User ##{message.user_id}" %></span>
|
|
16
|
+
<% if message.user == current_user %>
|
|
17
|
+
<span class="ml-1 text-[10px] text-blue-500 font-semibold">(You)</span>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
<time datetime="<%= message.created_at.iso8601 %>" class="flex-none py-0.5 text-xs/5 text-gray-400">
|
|
21
|
+
<%= time_ago_in_words(message.created_at) %> ago
|
|
22
|
+
</time>
|
|
23
|
+
</div>
|
|
24
|
+
<p class="text-sm/6 text-gray-600">
|
|
25
|
+
<%= message.content %>
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
</li>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= turbo_stream.replace "new-message" do %>
|
|
2
|
+
<div id="new-message" class="border-t border-gray-200 p-4 bg-gray-50">
|
|
3
|
+
<div class="flex gap-x-3">
|
|
4
|
+
<div class="size-6 flex-none rounded-full bg-gray-200 flex items-center justify-center ring-1 ring-gray-300">
|
|
5
|
+
<span class="text-[10px] font-bold text-gray-500">?</span>
|
|
6
|
+
</div>
|
|
7
|
+
<%= render "simple_chat/messages/form", message: @chat_room.messages.build %>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% content_for :title, "Editing message" %>
|
|
2
|
+
|
|
3
|
+
<h1>Editing message</h1>
|
|
4
|
+
|
|
5
|
+
<%= render "form", message: @message %>
|
|
6
|
+
|
|
7
|
+
<br>
|
|
8
|
+
|
|
9
|
+
<div>
|
|
10
|
+
<%= link_to "Show this message", @message %> |
|
|
11
|
+
<%= link_to "Back to messages", messages_path(chat_room_id: @chat_room&.id) %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<% content_for :title, "Messages" %>
|
|
2
|
+
|
|
3
|
+
<h1>Messages<%= " for #{@chat_room.title}" if @chat_room %></h1>
|
|
4
|
+
|
|
5
|
+
<% @messages.each do |message| %>
|
|
6
|
+
<%= render message %>
|
|
7
|
+
<p>
|
|
8
|
+
<%= link_to "Show this message", message %>
|
|
9
|
+
</p>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<%= link_to "New message", new_message_path(chat_room_id: @chat_room&.id) %>
|
|
13
|
+
| <%= link_to "Back to chat room", @chat_room if @chat_room %>
|
|
14
|
+
<%= "| #{link_to 'Back to chat rooms', chat_rooms_path}" if @chat_room.nil? %>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
content: [
|
|
3
|
+
'./app/views/**/*.html.erb',
|
|
4
|
+
'./app/helpers/**/*.rb',
|
|
5
|
+
'./app/javascript/**/*.js',
|
|
6
|
+
'./test/dummy/app/views/**/*.html.erb',
|
|
7
|
+
'./test/dummy/app/javascript/**/*.js',
|
|
8
|
+
],
|
|
9
|
+
theme: {
|
|
10
|
+
extend: {},
|
|
11
|
+
},
|
|
12
|
+
plugins: [
|
|
13
|
+
require('@tailwindcss/forms'),
|
|
14
|
+
],
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CreateSimpleChatChatMembers < ActiveRecord::Migration[8.1]
|
|
2
|
+
def change
|
|
3
|
+
create_table :simple_chat_chat_members do |t|
|
|
4
|
+
t.references :chat_room, null: false, foreign_key: { to_table: :simple_chat_chat_rooms }
|
|
5
|
+
t.integer :user_id, null: false
|
|
6
|
+
|
|
7
|
+
t.timestamps
|
|
8
|
+
end
|
|
9
|
+
add_index :simple_chat_chat_members, :user_id
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class CreateSimpleChatMessages < ActiveRecord::Migration[8.1]
|
|
2
|
+
def change
|
|
3
|
+
create_table :simple_chat_messages do |t|
|
|
4
|
+
t.references :chat_room, null: false, foreign_key: { to_table: :simple_chat_chat_rooms }
|
|
5
|
+
t.integer :user_id, null: false
|
|
6
|
+
t.text :content
|
|
7
|
+
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
add_index :simple_chat_messages, :user_id
|
|
11
|
+
end
|
|
12
|
+
end
|