chat 0.2.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -8
  3. data/Rakefile +2 -0
  4. data/app/assets/javascripts/chat/channels/message.coffee +33 -43
  5. data/app/assets/javascripts/chat/channels/status.coffee +2 -2
  6. data/app/assets/javascripts/chat/messages.coffee +12 -11
  7. data/app/assets/stylesheets/chat/avatar_grid.sass +40 -0
  8. data/app/assets/stylesheets/chat/chat.sass +9 -4
  9. data/app/assets/stylesheets/chat/checkbox.sass +3 -3
  10. data/app/assets/stylesheets/chat/emojionearea.min.css +1 -1
  11. data/app/assets/stylesheets/chat/header.sass +25 -8
  12. data/app/assets/stylesheets/chat/launch.sass +39 -3
  13. data/app/assets/stylesheets/chat/list.sass +56 -23
  14. data/app/assets/stylesheets/chat/message_form.sass +7 -4
  15. data/app/assets/stylesheets/chat/new.sass +27 -22
  16. data/app/assets/stylesheets/chat/transcript.sass +60 -64
  17. data/app/channels/chat/messages_channel.rb +3 -2
  18. data/app/channels/chat/notification_channel.rb +2 -0
  19. data/app/channels/chat/status_channel.rb +12 -10
  20. data/app/controllers/chat/application_controller.rb +5 -1
  21. data/app/controllers/chat/conversations_controller.rb +24 -2
  22. data/app/controllers/chat/messages_controller.rb +8 -2
  23. data/app/helpers/chat/application_helper.rb +35 -24
  24. data/app/jobs/chat/application_job.rb +9 -1
  25. data/app/jobs/chat/message_relay_job.rb +5 -13
  26. data/app/jobs/chat/notification_relay_job.rb +10 -4
  27. data/app/jobs/chat/status_relay_job.rb +3 -3
  28. data/app/mailers/chat/application_mailer.rb +2 -0
  29. data/app/models/chat/application_record.rb +2 -0
  30. data/app/models/chat/conversation.rb +12 -0
  31. data/app/models/chat/dot_command.rb +2 -0
  32. data/app/models/chat/dot_command/gif.rb +2 -0
  33. data/app/models/chat/dot_command/shrug.rb +3 -1
  34. data/app/models/chat/dot_command/validator.rb +3 -1
  35. data/app/models/chat/message.rb +10 -2
  36. data/app/models/chat/session.rb +3 -3
  37. data/app/views/chat/_chat.html.haml +10 -6
  38. data/app/views/chat/conversations/_conversation.html.haml +23 -0
  39. data/app/views/chat/conversations/_index.html.haml +1 -6
  40. data/app/views/chat/conversations/_new.html.haml +2 -4
  41. data/app/views/chat/conversations/_show.html.haml +8 -7
  42. data/app/views/chat/conversations/create.js.erb +14 -10
  43. data/app/views/chat/conversations/show.js.erb +8 -5
  44. data/app/views/chat/messages/_message.haml +9 -12
  45. data/config/routes.rb +4 -2
  46. data/lib/chat.rb +5 -1
  47. data/lib/chat/engine.rb +2 -0
  48. data/lib/chat/user.rb +7 -12
  49. data/lib/chat/version.rb +3 -1
  50. data/lib/generators/chat/install/install_generator.rb +2 -0
  51. data/lib/generators/chat/install/templates/add_chat_to_users.rb +3 -1
  52. data/lib/generators/chat/install/templates/chat.rb +2 -0
  53. data/lib/generators/chat/install/templates/create_chat.rb +19 -7
  54. data/lib/tasks/chat_tasks.rake +1 -0
  55. metadata +15 -48
  56. data/app/models/chat/dot_command/leave.rb +0 -16
@@ -1,7 +1,7 @@
1
- @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300,400,700,900"
2
2
 
3
3
  #chat .new_message
4
- margin: 0px 40px 36px 40px
4
+ margin: 0px 20px 25px 20px
5
5
  flex-direction: column
6
6
  display: flex
7
7
  position: relative
@@ -15,7 +15,7 @@
15
15
  cursor: pointer
16
16
  font-size: 22px
17
17
  &:hover
18
- color: #212121
18
+ color: #fff
19
19
  input[type='text'], textarea
20
20
  font-size: 17px
21
21
  font-family: "Lato" !important
@@ -35,7 +35,7 @@
35
35
  width: 0
36
36
  bottom: 0px
37
37
  position: absolute
38
- background: #3f51b5
38
+ background: #fff
39
39
  transition: 0.2s ease all
40
40
  -moz-transition: 0.2s ease all
41
41
  -webkit-transition: 0.2s ease all
@@ -48,3 +48,6 @@
48
48
  width: 50%
49
49
  input[type='file']
50
50
  display: none !important
51
+ .emojionearea .emojionearea-editor
52
+ border-bottom: 1px solid #bdbdbd !important
53
+ color: #fff !important
@@ -1,52 +1,57 @@
1
- @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300,400,700,900"
2
2
 
3
3
  #chat .new_conversation
4
- height: calc(100% - 48px)
5
- display: none
4
+ height: calc(100% - 50px)
5
+ overflow-y: scroll
6
+ position: absolute
7
+ right: 100%
8
+ transition: 0.5s
9
+ width: 100%
10
+ z-index: 13
11
+ display: flex
6
12
  flex-direction: column
7
- .chat__user-check-boxes
8
- margin: 10px 20px 0px 20px
9
- display: flex
10
- flex-direction: column
11
- height: calc(100% - 48px)
12
- overflow-y: auto
13
- &::-webkit-scrollbar
14
- display: none
13
+ &::-webkit-scrollbar
14
+ visibility: hidden
15
15
  label
16
16
  position: relative
17
17
  margin: 1rem
18
- line-height: 135%
19
18
  cursor: pointer
20
- font-size: 18px
21
19
  font-family: "Lato" !important
22
20
  letter-spacing: 1.5px !important
23
21
  padding-left: 40px
22
+ color: #fff
23
+ width: calc(100% - 40px - 1rem)
24
24
  .chat__status
25
25
  &:after
26
26
  content: "\2022"
27
27
  &.offline
28
28
  &:after
29
- color: #EF5350
29
+ color: hsl(355, 65%, 65%)
30
30
  &.online
31
31
  &:after
32
32
  color: #AED581
33
33
 
34
+ .chat__submit-container
35
+ margin: 1rem
36
+ padding: 10px 0
37
+ width: calc(100% - 1rem)
38
+ display: flex
39
+ flex-direction: column
40
+ justify-content: center
41
+ align-items: center
42
+
34
43
  input[type='submit']
35
- border-top: 1px solid #BDBDBD
36
- border-left: none
37
- border-bottom: none
38
- border-right: none
44
+ border: none
39
45
  font-family: "Lato" !important
40
46
  letter-spacing: 1.5px !important
41
47
  font-size: 17px
42
48
  background: transparent
43
- width: 100%
44
- padding: 10px 0 10px 0
49
+ padding: 0
45
50
  cursor: pointer
46
51
  transition: all 0.3s ease
47
52
  z-index: 10
48
- &:hover
49
- background: #BDBDBD
53
+ color: #fff
54
+ margin: 0px
50
55
 
51
56
  #chat .chat__errors
52
57
  text-align: center
@@ -1,76 +1,72 @@
1
1
  #chat .current_chat
2
- height: calc(100% - 48px)
2
+ display: flex
3
3
  flex-direction: column
4
+ overflow-y: scroll
5
+ position: absolute
6
+ width: 100%
7
+ height: calc(100% - 50px)
8
+ left: 100%
9
+ opacity: 1
10
+ transition: 0.5s
11
+ z-index: 13
12
+ &::-webkit-scrollbar
13
+ visibility: hidden
4
14
  img.chat__user-avatar
5
15
  width: 50px
6
16
  height: 50px
7
17
  object-fit: cover
8
18
  border-radius: 50%
19
+ .transcript_placeholder_avatar
20
+ width: 50px
21
+ height: 50px
9
22
  i.chat__user-avatar
10
23
  font-size: 50px
11
24
  .chat__transcript
12
- max-height: calc(100% - 78px)
13
- overflow-y: auto
14
- &::-webkit-scrollbar
15
- display: none
16
- .chat__image-message
17
- width: 100%
18
- padding-top: 10px
19
- padding-bottom: 10px
20
- img
21
- width: 100%
22
- border-bottom: 4px solid #C8E6C9
23
- &.current img
24
- border-bottom: 4px solid #B2EBF2
25
- .chat__message
26
- padding: 10px
27
- display: flex
28
- flex-direction: row
29
- img
30
- font-size: inherit
31
- height: 2ex
32
- width: 2.1ex
33
- min-height: 20px
34
- min-width: 20px
35
- display: inline-block
36
- margin: -.2ex .15em .2ex
37
- line-height: normal
38
- vertical-align: middle
39
- max-width: 100%
40
- top: 0
41
- .text
42
- padding: 5px
43
- flex: 1
44
- position: relative
25
+ margin-left: 25px
26
+ margin-right: 25px
27
+ .message-container
28
+ display: flex
29
+ flex-direction: row
45
30
  &.right
46
- margin-right: 10px
47
- border-radius: 5px 0px 5px 5px
48
- background: #B2EBF2
49
- border: none
50
- &:after
51
- content: ""
52
- position: absolute
53
- border-style: solid
54
- border-width: 0px 0 13px 15px
55
- border-color: transparent #B2EBF2
56
- display: block
57
- width: 0
58
- z-index: 1
59
- right: -15px
60
- top: 0px
61
- &.left
62
- margin-left: 10px
63
- border-radius: 0px 5px 5px 5px
64
- background: #C8E6C9
65
- border: none
66
- &:after
67
- content: ""
68
- position: absolute
69
- border-style: solid
70
- border-width: 0px 15px 13px 0px
71
- border-color: transparent #C8E6C9
31
+ text-align: right
32
+ flex-direction: row-reverse
33
+ .message
34
+ flex-direction: row-reverse
35
+ .content
36
+ border-top-right-radius: 0 !important
37
+ border-top-left-radius: 10px !important
38
+ &.image img
39
+ border-top-right-radius: 0 !important
40
+ border-top-left-radius: 10px !important
41
+ .message
42
+ min-height: 50px
43
+ display: flex
44
+ margin: 0 10px 5px 10px
45
+ flex: 1
46
+ flex-direction: row
47
+ max-width: 100%
48
+ &.image
72
49
  display: block
73
- width: 0
74
- z-index: 1
75
- left: -15px
76
- top: 0px
50
+ img
51
+ max-width: 100%
52
+ border-radius: 10px
53
+ border-top-left-radius: 0
54
+ .content
55
+ background: #fff
56
+ padding: 10px
57
+ border-radius: 10px
58
+ color: #212121
59
+ border-top-left-radius: 0
60
+ word-break: break-all
61
+ img
62
+ font-size: inherit
63
+ height: 2ex
64
+ width: 2.1ex
65
+ min-height: 20px
66
+ min-width: 20px
67
+ display: inline-block
68
+ margin: -.2ex .15em .2ex
69
+ line-height: normal
70
+ vertical-align: middle
71
+ max-width: 100%
72
+ top: 0
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Chat::MessagesChannel < ApplicationCable::Channel
2
4
  def follow(data)
3
5
  stop_all_streams
4
6
  stream_from "chats::#{data['chat_id']}::messages"
5
7
  end
6
8
 
7
- def unfollow
9
+ def unsubscribed
8
10
  stop_all_streams
9
11
  end
10
- alias unsubscribed unfollow
11
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Chat::NotificationChannel < ApplicationCable::Channel
2
4
  def follow(data)
3
5
  stop_all_streams
@@ -1,12 +1,14 @@
1
- class Chat::StatusChannel < ApplicationCable::Channel
2
- def online
3
- stop_all_streams
4
- stream_from "chat::status"
5
- current_user.online
6
- end
1
+ # frozen_string_literal: true
7
2
 
8
- def unsubscribed
9
- current_user.offline
10
- stop_all_streams
11
- end
3
+ class Chat::StatusChannel < ApplicationCable::Channel
4
+ def online
5
+ stop_all_streams
6
+ stream_from "chat::status"
7
+ current_user.online
12
8
  end
9
+
10
+ def unsubscribed
11
+ current_user.offline
12
+ stop_all_streams
13
+ end
14
+ end
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chat
2
- class ApplicationController < ActionController::Base
4
+ class ApplicationController < ::ApplicationController
3
5
  protect_from_forgery with: :exception
6
+
7
+ before_action Chat.logged_in_check
4
8
  end
5
9
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chat
2
4
  class ConversationsController < ApplicationController
3
- before_action Chat.logged_in_check
4
5
  before_action :set_conversation, only: :show
5
6
 
6
7
  def show
@@ -8,6 +9,14 @@ module Chat
8
9
 
9
10
  def create
10
11
  @conversation = Chat::Conversation.create(conversation_params)
12
+
13
+ if @conversation.persisted? ||
14
+ @conversation.errors.messages[:sessions].present?
15
+ render template: :create
16
+ else
17
+ @conversation = find_existing_conversation
18
+ render template: "chat/conversations/show"
19
+ end
11
20
  end
12
21
 
13
22
  private
@@ -20,11 +29,24 @@ module Chat
20
29
 
21
30
  def conversation_params
22
31
  chat_params = params.require(:conversation).permit(user_ids: [])
23
- if chat_params[:user_ids].reject(&:blank?).present?
32
+ if chat_params[:user_ids].reject!(&:blank?).present?
24
33
  chat_params[:user_ids] << current_user.id
34
+ chat_params[:user_ids].map!(&:to_i)
25
35
  end
26
36
 
27
37
  chat_params
28
38
  end
39
+
40
+ def find_existing_conversation
41
+ Chat::Conversation.includes(
42
+ :users, messages: :user
43
+ ).find(
44
+ Chat::Conversation.joins(:users).having(
45
+ "COUNT(DISTINCT users.id) = ?", conversation_params[:user_ids].count
46
+ ).group(:id).find_by(
47
+ users: { id: conversation_params[:user_ids] }
48
+ ).id
49
+ )
50
+ end
29
51
  end
30
52
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chat
2
4
  class MessagesController < ApplicationController
3
- before_action Chat.logged_in_check
4
5
  before_action :set_conversation
6
+ before_action :set_session
5
7
 
6
8
  def create
7
9
  @conversation.messages.create(message_params)
@@ -19,9 +21,13 @@ module Chat
19
21
  @conversation = Chat::Conversation.find(params[:conversation_id])
20
22
  end
21
23
 
24
+ def set_session
25
+ @session = @conversation.sessions.find_by(user: current_user)
26
+ end
27
+
22
28
  def message_params
23
29
  params.require(:message).permit(:text, :image).merge(
24
- user_id: current_user.id
30
+ user_id: current_user.id, session_id: @session.id
25
31
  )
26
32
  end
27
33
  end
@@ -1,18 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Chat
2
4
  module ApplicationHelper
3
- def render_chat(background = nil, color = nil)
5
+ def render_chat
4
6
  return unless send Chat.signed_in
5
7
 
6
- render "chat/chat", background: background, color: color
8
+ render "chat/chat"
7
9
  end
8
10
 
9
- def launch_chat_fab(background = "#4CAF50", color = "light")
11
+ def launch_chat_fab
10
12
  attrs = {
11
- class: "chat__launch", style: "background: #{background}",
12
- data: { "current-user" => current_user.id }
13
+ class: "chat__launch", data: { "current-user" => current_user.id }
13
14
  }
14
15
  button_tag(attrs) do
15
- material_icon.forum.css_class("md-#{color}").to_s.html_safe
16
+ material_icon.forum.css_class("md-dark").to_s.html_safe
16
17
  end
17
18
  end
18
19
 
@@ -32,31 +33,41 @@ module Chat
32
33
  end
33
34
 
34
35
  def chat_avatar(user)
35
- if user.send(Chat.user_avatar.to_s + "?")
36
- image_tag(user.send(Chat.user_avatar), class: "chat__user-avatar")
36
+ if user.chat_avatar?
37
+ image_tag(user.chat_avatar, class: "chat__user-avatar")
37
38
  else
38
39
  MaterialIcon.new.css_class("chat__user-avatar").person
39
40
  end
40
41
  end
41
42
 
42
43
  def chat_list
43
- @chat_list ||=
44
- Chat::Conversation.joins(:users)
45
- .group("chat_sessions.conversation_id")
46
- .select(:id, group_concat)
47
- .merge(current_user.conversations)
48
- .order(created_at: :desc)
49
- end
50
-
51
- private
52
-
53
- def group_concat
54
- if ActiveRecord::Base.connection.adapter_name == "SQLite"
55
- "GROUP_CONCAT(users.#{::User.first_name} || ' ' || users.#{::User.last_name}, ', ') as names"
56
- elsif ActiveRecord::Base.connection.adapter_name == "MySQL"
57
- "GROUP_CONCAT(CONCAT(\"users.#{User.first_name}\",\" \", \"users.#{User.last_name}\") "\
58
- "SEPARATOR ', ') as names"
44
+ @chat_list ||= current_user.conversations.includes(:users).order(
45
+ "chat_conversations.created_at desc"
46
+ )
47
+ end
48
+
49
+ def chat_avatars(conversation)
50
+ (conversation.users - [current_user]).first(2).map do |u|
51
+ chat_avatar(u)
59
52
  end
60
53
  end
54
+
55
+ def chat_avatar_count(conversation)
56
+ if (count = conversation_user_count(conversation)) <= 2
57
+ "count_#{count}"
58
+ else
59
+ "count_default"
60
+ end
61
+ end
62
+
63
+ def conversation_user_count(conversation)
64
+ conversation.users.to_a.size - 1
65
+ end
66
+
67
+ def message_classes(message)
68
+ css_class = message.user == current_user ? "right" : "left"
69
+ css_class += message.image? ? " image" : ""
70
+ css_class
71
+ end
61
72
  end
62
73
  end