turbo_chat 0.2.0 → 0.3.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -1
  3. data/README.md +178 -190
  4. data/app/assets/config/turbo_chat_manifest.js +3 -0
  5. data/app/assets/javascripts/turbo_chat/application.js +3 -0
  6. data/app/assets/javascripts/turbo_chat/invite_picker.js +19 -392
  7. data/app/assets/javascripts/turbo_chat/member_sync.js +426 -0
  8. data/app/assets/javascripts/turbo_chat/mentions.js +366 -0
  9. data/app/assets/javascripts/turbo_chat/messages.js +18 -370
  10. data/app/assets/javascripts/turbo_chat/realtime.js +3 -10
  11. data/app/assets/javascripts/turbo_chat/scroll_proxy.js +379 -0
  12. data/app/assets/javascripts/turbo_chat/shared.js +7 -383
  13. data/app/assets/stylesheets/turbo_chat/application.css +9 -1646
  14. data/app/assets/stylesheets/turbo_chat/base.css +84 -0
  15. data/app/assets/stylesheets/turbo_chat/components.css +193 -0
  16. data/app/assets/stylesheets/turbo_chat/composer.css +241 -0
  17. data/app/assets/stylesheets/turbo_chat/layout.css +307 -0
  18. data/app/assets/stylesheets/turbo_chat/members.css +264 -0
  19. data/app/assets/stylesheets/turbo_chat/menus.css +172 -0
  20. data/app/assets/stylesheets/turbo_chat/messages.css +430 -0
  21. data/app/controllers/turbo_chat/application_controller.rb +3 -7
  22. data/app/controllers/turbo_chat/chat_memberships_controller.rb +35 -1
  23. data/app/controllers/turbo_chat/chat_messages_controller.rb +4 -8
  24. data/app/controllers/turbo_chat/chats_controller.rb +10 -12
  25. data/app/helpers/turbo_chat/application_helper/config_support.rb +42 -32
  26. data/app/helpers/turbo_chat/application_helper/mention_support.rb +3 -3
  27. data/app/helpers/turbo_chat/application_helper/message_rendering.rb +24 -13
  28. data/app/models/turbo_chat/chat.rb +43 -20
  29. data/app/models/turbo_chat/chat_membership.rb +1 -1
  30. data/app/models/turbo_chat/chat_message/blocked_words_moderation.rb +9 -25
  31. data/app/models/turbo_chat/chat_message/body_length_validation.rb +1 -1
  32. data/app/models/turbo_chat/chat_message/broadcasting.rb +2 -6
  33. data/app/models/turbo_chat/chat_message/formatting.rb +3 -7
  34. data/app/models/turbo_chat/chat_message/mention_validation.rb +1 -1
  35. data/app/models/turbo_chat/chat_message/signals.rb +1 -1
  36. data/app/models/turbo_chat/chat_message.rb +3 -8
  37. data/app/views/turbo_chat/chat_messages/_form.html.erb +9 -9
  38. data/app/views/turbo_chat/chat_messages/_message.html.erb +2 -2
  39. data/app/views/turbo_chat/chat_messages/_signals.html.erb +11 -13
  40. data/app/views/turbo_chat/chat_messages/_system.html.erb +1 -1
  41. data/app/views/turbo_chat/chats/_invite_form.html.erb +1 -1
  42. data/app/views/turbo_chat/chats/_member_entries.html.erb +15 -1
  43. data/app/views/turbo_chat/chats/index.html.erb +1 -1
  44. data/app/views/turbo_chat/chats/new.html.erb +4 -7
  45. data/app/views/turbo_chat/chats/show.html.erb +29 -27
  46. data/config/routes.rb +6 -1
  47. data/db/migrate/20260325000016_add_chat_mode_to_turbo_chat_chats.rb +6 -0
  48. data/lib/generators/turbo_chat/install/templates/turbo_chat.rb +8 -0
  49. data/lib/turbo_chat/configuration/defaults.rb +21 -0
  50. data/lib/turbo_chat/configuration.rb +105 -0
  51. data/lib/turbo_chat/moderation/chat_actions.rb +2 -2
  52. data/lib/turbo_chat/moderation/member_actions.rb +2 -1
  53. data/lib/turbo_chat/moderation/support.rb +5 -9
  54. data/lib/turbo_chat/permission/support.rb +6 -2
  55. data/lib/turbo_chat/permission.rb +1 -5
  56. data/lib/turbo_chat/signals.rb +1 -1
  57. data/lib/turbo_chat/version.rb +1 -1
  58. metadata +13 -2
@@ -0,0 +1,430 @@
1
+ .chat-messages {
2
+ position: relative;
3
+ z-index: 2;
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 12px;
7
+ min-height: 220px;
8
+ max-height: min(58vh, 540px);
9
+ overflow-y: auto;
10
+ padding: 6px 2px calc(4px + var(--chat-signal-offset));
11
+ box-sizing: border-box;
12
+ transition: padding-bottom 180ms ease;
13
+ }
14
+
15
+ .chat-bubble {
16
+ min-width: 0;
17
+ max-width: min(78%, 680px);
18
+ background: var(--chat-bubble-bg, #ffffff);
19
+ border-radius: 16px 16px 16px 8px;
20
+ padding: 12px 14px 10px;
21
+ border: 1px solid var(--chat-bubble-border, #d4deea);
22
+ box-shadow: 0 8px 18px rgba(18, 38, 63, 0.08);
23
+ }
24
+
25
+ .chat-bubble--own {
26
+ margin-left: auto;
27
+ background: var(--chat-bubble-bg, #e4f1ff);
28
+ border-color: var(--chat-bubble-border, #9bc9ff);
29
+ border-radius: 16px 16px 8px 16px;
30
+ }
31
+
32
+ .chat-system-message {
33
+ align-self: center;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ gap: 8px;
37
+ max-width: min(92%, 720px);
38
+ padding: 4px 10px;
39
+ border-radius: 999px;
40
+ border: 1px solid #d6e0ec;
41
+ background: rgba(244, 248, 253, 0.9);
42
+ color: #60758d;
43
+ font-size: 12px;
44
+ line-height: 1.3;
45
+ }
46
+
47
+ .chat-system-message__body {
48
+ margin: 0;
49
+ }
50
+
51
+ .chat-system-message__timestamp {
52
+ font-variant-numeric: tabular-nums;
53
+ white-space: nowrap;
54
+ }
55
+
56
+ .chat-meta {
57
+ display: flex;
58
+ align-items: center;
59
+ gap: 8px;
60
+ flex-wrap: wrap;
61
+ font-size: 12px;
62
+ color: var(--chat-muted);
63
+ margin-bottom: 6px;
64
+ min-width: 0;
65
+ }
66
+
67
+ .chat-meta__author {
68
+ color: #1b324f;
69
+ font-weight: 700;
70
+ letter-spacing: 0.01em;
71
+ min-width: 0;
72
+ overflow-wrap: anywhere;
73
+ }
74
+
75
+ .chat-meta__role {
76
+ display: inline-flex;
77
+ align-items: center;
78
+ border: 1px solid #a8bad0;
79
+ border-radius: 999px;
80
+ padding: 1px 7px;
81
+ font-size: 10px;
82
+ letter-spacing: 0.05em;
83
+ text-transform: uppercase;
84
+ background: #f4f8fd;
85
+ }
86
+
87
+ .chat-meta__source {
88
+ display: inline-flex;
89
+ align-items: center;
90
+ border: 1px solid #c6d5e7;
91
+ border-radius: 999px;
92
+ padding: 1px 7px;
93
+ font-size: 10px;
94
+ font-weight: 700;
95
+ letter-spacing: 0.05em;
96
+ text-transform: uppercase;
97
+ background: #edf3fb;
98
+ color: #35506f;
99
+ }
100
+
101
+ .chat-meta__timestamp {
102
+ margin-left: auto;
103
+ font-variant-numeric: tabular-nums;
104
+ white-space: nowrap;
105
+ }
106
+
107
+ .chat-meta__edited {
108
+ display: inline-flex;
109
+ align-items: center;
110
+ padding: 1px 6px;
111
+ border-radius: 999px;
112
+ border: 1px solid #d6e0ec;
113
+ background: #f4f8fd;
114
+ color: #60758d;
115
+ font-size: 11px;
116
+ text-transform: lowercase;
117
+ }
118
+
119
+ .chat-body {
120
+ margin: 0;
121
+ font-size: 16px;
122
+ line-height: 1.45;
123
+ color: #12263f;
124
+ word-break: break-word;
125
+ overflow-wrap: anywhere;
126
+ }
127
+
128
+ .chat-body p {
129
+ margin: 0 0 8px;
130
+ }
131
+
132
+ .chat-body p:last-child {
133
+ margin-bottom: 0;
134
+ }
135
+
136
+ .chat-body pre {
137
+ max-width: 100%;
138
+ overflow-x: auto;
139
+ }
140
+
141
+ .chat-body img,
142
+ .chat-body video,
143
+ .chat-body table {
144
+ max-width: 100%;
145
+ height: auto;
146
+ }
147
+
148
+ .chat-body table {
149
+ display: block;
150
+ width: 100%;
151
+ overflow-x: auto;
152
+ }
153
+
154
+ .chat-mention {
155
+ color: var(--chat-primary);
156
+ font-weight: 700;
157
+ }
158
+
159
+ .chat-mention--targeted {
160
+ background: var(--chat-mention-mark-background);
161
+ border-radius: 4px;
162
+ padding: 0 3px;
163
+ box-decoration-break: clone;
164
+ -webkit-box-decoration-break: clone;
165
+ }
166
+
167
+ .chat-message-actions {
168
+ margin-top: 8px;
169
+ display: flex;
170
+ justify-content: flex-end;
171
+ opacity: 0;
172
+ transform: translateY(2px);
173
+ transition: opacity 150ms ease, transform 150ms ease;
174
+ pointer-events: none;
175
+ }
176
+
177
+ .chat-bubble:hover .chat-message-actions,
178
+ .chat-bubble:focus-within .chat-message-actions,
179
+ .chat-bubble--editing .chat-message-actions {
180
+ opacity: 1;
181
+ transform: translateY(0);
182
+ pointer-events: auto;
183
+ }
184
+
185
+ .chat-message-action {
186
+ font-size: 11px;
187
+ line-height: 1.2;
188
+ border: 1px solid #c9d6e6;
189
+ background: #f5f9ff;
190
+ border-radius: 999px;
191
+ padding: 3px 9px;
192
+ margin: 0;
193
+ color: var(--chat-primary-dark);
194
+ text-decoration: none;
195
+ cursor: pointer;
196
+ }
197
+
198
+ .chat-message-action:hover {
199
+ background: #e6f0ff;
200
+ }
201
+
202
+ .chat-message-edit {
203
+ margin-top: 10px;
204
+ padding-top: 10px;
205
+ border-top: 1px dashed #c5d3e3;
206
+ }
207
+
208
+ .chat-inline-edit-form {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 8px;
212
+ }
213
+
214
+ .chat-inline-edit-field {
215
+ position: relative;
216
+ }
217
+
218
+ .chat-inline-edit-form textarea {
219
+ width: 100%;
220
+ min-height: 96px;
221
+ resize: vertical;
222
+ }
223
+
224
+ .chat-inline-edit-actions {
225
+ display: flex;
226
+ justify-content: flex-end;
227
+ gap: 8px;
228
+ }
229
+
230
+ .chat-inline-edit-error {
231
+ margin: 0 0 8px;
232
+ color: var(--chat-danger);
233
+ font-size: 12px;
234
+ }
235
+
236
+ .chat-signal-entry {
237
+ font-size: 12px;
238
+ color: var(--chat-muted);
239
+ }
240
+
241
+ .chat-signals {
242
+ flex: 0 0 auto;
243
+ min-height: 0;
244
+ max-height: 0;
245
+ opacity: 0;
246
+ overflow: hidden;
247
+ transition: max-height 200ms ease, opacity 200ms ease;
248
+ }
249
+
250
+ .chat-signals--active {
251
+ max-height: 120px;
252
+ opacity: 1;
253
+ overflow: visible;
254
+ }
255
+
256
+ .chat-typing-indicator {
257
+ display: inline-flex;
258
+ align-items: center;
259
+ gap: 9px;
260
+ font-size: 12px;
261
+ color: var(--chat-muted);
262
+ background: #edf3fb;
263
+ border: 1px solid #d2deed;
264
+ border-radius: 999px;
265
+ padding: 6px 12px;
266
+ overflow: hidden;
267
+ max-height: 34px;
268
+ opacity: 1;
269
+ transform: translateY(0);
270
+ transition: max-height 180ms ease, opacity 180ms ease, transform 180ms ease, padding 180ms ease;
271
+ animation: chat-signal-enter 200ms ease;
272
+ }
273
+
274
+ @keyframes chat-signal-enter {
275
+ from {
276
+ opacity: 0;
277
+ max-height: 0;
278
+ transform: translateY(8px);
279
+ }
280
+ to {
281
+ opacity: 1;
282
+ max-height: 34px;
283
+ transform: translateY(0);
284
+ }
285
+ }
286
+
287
+ .chat-typing-indicator--leaving {
288
+ max-height: 0;
289
+ opacity: 0;
290
+ padding: 0;
291
+ transform: translateY(-4px);
292
+ }
293
+
294
+ .chat-dots {
295
+ display: inline-flex;
296
+ gap: 3px;
297
+ }
298
+
299
+ .chat-signal-text {
300
+ display: inline-block;
301
+ max-width: 320px;
302
+ overflow: hidden;
303
+ text-overflow: ellipsis;
304
+ white-space: nowrap;
305
+ }
306
+
307
+ .chat-signal-text--pulse {
308
+ animation: chat-signal-pulse 2s ease-in-out infinite;
309
+ }
310
+
311
+ @keyframes chat-signal-pulse {
312
+ 0%, 100% { opacity: 1; }
313
+ 50% { opacity: 0.4; }
314
+ }
315
+
316
+ .chat-signal-text--sheen {
317
+ display: inline-flex;
318
+ align-items: center;
319
+ min-width: 0;
320
+ color: #4b6683;
321
+ font-weight: 600;
322
+ }
323
+
324
+ .chat-signal-text--sheen::before,
325
+ .chat-signal-text--sheen::after {
326
+ color: #5f738a;
327
+ font-weight: 600;
328
+ }
329
+
330
+ .chat-signal-text--sheen::before {
331
+ content: "[";
332
+ }
333
+
334
+ .chat-signal-text--sheen::after {
335
+ content: "]";
336
+ }
337
+
338
+ .chat-signal-text-sheen {
339
+ display: inline-block;
340
+ max-width: 100%;
341
+ padding: 1px 2px;
342
+ border-radius: 4px;
343
+ background: linear-gradient(
344
+ 100deg,
345
+ rgba(181, 204, 230, 0.28) 0%,
346
+ rgba(232, 243, 255, 0.75) 45%,
347
+ rgba(181, 204, 230, 0.28) 100%
348
+ );
349
+ background-size: 220% 100%;
350
+ animation: chat-signal-sheen 2.4s linear infinite;
351
+ }
352
+
353
+ @keyframes chat-signal-sheen {
354
+ 0% {
355
+ background-position: 210% 0;
356
+ }
357
+ 100% {
358
+ background-position: -10% 0;
359
+ }
360
+ }
361
+
362
+ .chat-dots i {
363
+ width: 6px;
364
+ height: 6px;
365
+ border-radius: 999px;
366
+ background: var(--chat-muted);
367
+ animation: chat-bounce 1.1s infinite ease-in-out;
368
+ }
369
+
370
+ .chat-dots i:nth-child(2) {
371
+ animation-delay: 0.15s;
372
+ }
373
+
374
+ .chat-dots i:nth-child(3) {
375
+ animation-delay: 0.3s;
376
+ }
377
+
378
+ @keyframes chat-bounce {
379
+ 0%,
380
+ 80%,
381
+ 100% {
382
+ transform: translateY(0);
383
+ opacity: 0.45;
384
+ }
385
+ 40% {
386
+ transform: translateY(-4px);
387
+ opacity: 1;
388
+ }
389
+ }
390
+
391
+ @media (prefers-reduced-motion: reduce) {
392
+ .chat-signal-text--pulse {
393
+ animation: none;
394
+ }
395
+ .chat-signal-text-sheen {
396
+ animation: none;
397
+ }
398
+ .chat-typing-indicator {
399
+ animation: none;
400
+ }
401
+ }
402
+
403
+ @media (max-width: 900px) {
404
+ .chat-messages {
405
+ min-height: 190px;
406
+ }
407
+
408
+ .chat-bubble {
409
+ max-width: 90%;
410
+ }
411
+ }
412
+
413
+ @media (max-width: 640px) {
414
+ .chat-bubble {
415
+ max-width: 100%;
416
+ }
417
+
418
+ .chat-meta__timestamp {
419
+ margin-left: 0;
420
+ width: 100%;
421
+ }
422
+
423
+ .chat-inline-edit-actions {
424
+ justify-content: stretch;
425
+ }
426
+
427
+ .chat-inline-edit-actions .chat-btn {
428
+ flex: 1 1 0;
429
+ }
430
+ }
@@ -58,18 +58,14 @@ module TurboChat
58
58
  end
59
59
 
60
60
  def authorize_post_message!(chat)
61
- return head(:forbidden) if chat_input_disabled?
61
+ return head(:forbidden) if chat_input_disabled?(chat)
62
62
  return if permission_for(chat).can_post_message?
63
63
 
64
64
  head :forbidden
65
65
  end
66
66
 
67
- def chat_input_disabled?
68
- configuration = TurboChat.configuration
69
- value = configuration.respond_to?(:disable_input) ? configuration.disable_input : false
70
- ActiveModel::Type::Boolean.new.cast(value)
71
- rescue NoMethodError, TypeError
72
- false
67
+ def chat_input_disabled?(chat = nil)
68
+ TurboChat::Configuration.config_boolean(:disable_input, default: false, chat: chat)
73
69
  end
74
70
  end
75
71
  end
@@ -4,13 +4,20 @@ module TurboChat
4
4
 
5
5
  before_action :set_chat
6
6
  before_action -> { authorize_view_chat!(@chat) }
7
- before_action :set_chat_membership, only: :update
7
+ before_action :set_chat_membership, only: %i[update mute ban]
8
8
  before_action :authorize_invite_member!, only: :create
9
9
  before_action :authorize_grant_member_permissions!, only: :update
10
+ before_action :authorize_mute_member!, only: :mute
11
+ before_action :authorize_ban_member!, only: :ban
10
12
 
11
13
  def create
12
14
  participant = invite_participant
13
15
  membership = @chat.chat_memberships.find_or_initialize_by(participant: participant)
16
+ if membership.persisted?
17
+ return redirect_to(chat_path(@chat), alert: "Participant is already in this chat") if membership.active?
18
+ return redirect_to(chat_path(@chat), alert: "Invitation already pending") if membership.pending?
19
+ end
20
+
14
21
  membership.assign_attributes(invitation_membership_attributes(membership))
15
22
 
16
23
  membership.save!
@@ -43,6 +50,25 @@ module TurboChat
43
50
  redirect_to chat_path(@chat), alert: error.record.errors.full_messages.to_sentence
44
51
  end
45
52
 
53
+ def mute
54
+ if @chat_membership.muted?
55
+ TurboChat::Moderation.unmute_member!(actor: current_chat_participant, membership: @chat_membership)
56
+ redirect_to chat_path(@chat), notice: "Member unmuted"
57
+ else
58
+ TurboChat::Moderation.mute_member!(actor: current_chat_participant, membership: @chat_membership)
59
+ redirect_to chat_path(@chat), notice: "Member muted"
60
+ end
61
+ rescue TurboChat::Moderation::AuthorizationError
62
+ head :forbidden
63
+ end
64
+
65
+ def ban
66
+ TurboChat::Moderation.ban_member!(actor: current_chat_participant, membership: @chat_membership)
67
+ redirect_to chat_path(@chat), notice: "Member removed"
68
+ rescue TurboChat::Moderation::AuthorizationError
69
+ head :forbidden
70
+ end
71
+
46
72
  private
47
73
 
48
74
  def set_chat
@@ -61,6 +87,14 @@ module TurboChat
61
87
  authorize_permission!(:can_grant_member_permissions?, @chat_membership)
62
88
  end
63
89
 
90
+ def authorize_mute_member!
91
+ authorize_permission!(:can_mute_member?, @chat_membership)
92
+ end
93
+
94
+ def authorize_ban_member!
95
+ authorize_permission!(:can_ban_member?, @chat_membership)
96
+ end
97
+
64
98
  def invite_params
65
99
  params.require(:chat_membership).permit(:participant_type, :participant_id)
66
100
  end
@@ -82,8 +82,8 @@ module TurboChat
82
82
  def respond_to_chat_message_create_failure
83
83
  @chat_messages = @chat.visible_messages
84
84
  @chat_permission = permission_for(@chat)
85
- @can_post_message = @chat_permission.can_post_message? && !chat_input_disabled?
86
- @show_members = chat_config_boolean(:show_members, default: true)
85
+ @can_post_message = @chat_permission.can_post_message? && !chat_input_disabled?(@chat)
86
+ @show_members = chat_config_boolean(:show_members, default: true, chat: @chat)
87
87
  respond_to do |format|
88
88
  format.turbo_stream { render "turbo_chat/chats/show", status: :unprocessable_entity }
89
89
  format.html { render "turbo_chat/chats/show", status: :unprocessable_entity }
@@ -145,12 +145,8 @@ module TurboChat
145
145
 
146
146
  def normalize_submittable_message_kind(kind) = kind.to_s == "signal" ? "signal" : "message"
147
147
 
148
- def chat_config_boolean(method_name, default:)
149
- configuration = TurboChat.configuration
150
- value = configuration.respond_to?(method_name) ? configuration.public_send(method_name) : default
151
- ActiveModel::Type::Boolean.new.cast(value)
152
- rescue NoMethodError, TypeError
153
- default
148
+ def chat_config_boolean(method_name, default:, chat: nil)
149
+ TurboChat::Configuration.config_boolean(method_name, default: default, chat: chat)
154
150
  end
155
151
  end
156
152
  end
@@ -9,8 +9,7 @@ module TurboChat
9
9
  def index
10
10
  participant = current_chat_participant
11
11
  @chats = TurboChat::Chat.for_participant(participant).order(created_at: :desc, id: :desc)
12
- @show_members = show_members_enabled?
13
- @chat_member_counts = if @show_members
12
+ @chat_member_counts = if @chats.exists?
14
13
  chat_ids = @chats.except(:order).select(:id)
15
14
  TurboChat::ChatMembership.active.where(chat_id: chat_ids).group(:chat_id).count
16
15
  else
@@ -61,10 +60,13 @@ module TurboChat
61
60
  @chat_lifecycle_event = chat_lifecycle_event_payload
62
61
  @chat_permission = permission_for(@chat)
63
62
  @chat_messages = @chat.visible_messages
64
- @can_post_message = @chat_permission.can_post_message? && !chat_input_disabled?
65
- @show_members = show_members_enabled?
63
+ @can_post_message = @chat_permission.can_post_message? && !chat_input_disabled?(@chat)
64
+ @show_members = show_members_enabled?(@chat)
66
65
  @can_invite_member = permission_allows?(@chat_permission, :can_invite_member?)
67
- @can_manage_member_permissions = permission_allows?(@chat_permission, :can_grant_member_permissions?)
66
+ @can_grant_member_permissions = permission_allows?(@chat_permission, :can_grant_member_permissions?)
67
+ @can_mute_member = permission_allows?(@chat_permission, :can_mute_member?)
68
+ @can_ban_member = permission_allows?(@chat_permission, :can_ban_member?)
69
+ @can_manage_member_permissions = @can_grant_member_permissions || @can_mute_member || @can_ban_member
68
70
  @can_close_chat = @chat_permission.can_close_chat?
69
71
  @can_reopen_chat = @chat_permission.can_reopen_chat?
70
72
  @can_edit_own_messages = permission_allows?(@chat_permission, :can_edit_message?, fallback: @can_post_message)
@@ -95,14 +97,10 @@ module TurboChat
95
97
  @chat = TurboChat::Chat.find(params[:id])
96
98
  end
97
99
 
98
- def chat_params = params.require(:chat).permit(:title)
100
+ def chat_params = params.require(:chat).permit(:title, :chat_mode)
99
101
 
100
- def show_members_enabled?
101
- configuration = TurboChat.configuration
102
- value = configuration.respond_to?(:show_members) ? configuration.show_members : true
103
- ActiveModel::Type::Boolean.new.cast(value)
104
- rescue NoMethodError, TypeError
105
- true
102
+ def show_members_enabled?(chat = nil)
103
+ TurboChat::Configuration.config_boolean(:show_members, default: true, chat: chat)
106
104
  end
107
105
 
108
106
  def pending_invitation_membership_for(participant, action:)