Class: Livechat::Conversation

Inherits:
ApplicationRecord show all
Defined in:
app/models/livechat/conversation.rb

Overview

One thread per visitor — like a phone line, not a ticket queue. A visitor writing into a resolved conversation reopens it; history stays in place. Visitor identity is loose (no foreign key to the host's user table): signed-in visitors are keyed by visitor_id, guests by a cookie token.

Constant Summary collapse

STATUSES =
%w[open resolved].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.claim!(visitor_token:, visitor_id:, visitor_label: nil) ⇒ Object

A guest who signs in keeps their conversation: threads started under the cookie token are adopted by the user, once, permanently.



38
39
40
41
42
43
# File 'app/models/livechat/conversation.rb', line 38

def self.claim!(visitor_token:, visitor_id:, visitor_label: nil)
  return if visitor_token.blank? || visitor_id.blank?

  where(visitor_token: visitor_token, visitor_id: nil)
    .update_all(visitor_id: visitor_id.to_s, visitor_label: visitor_label)
end

.for_visitor(visitor_id: nil, visitor_token: nil) ⇒ Object

The visitor's ongoing thread. Signed-in identity wins; guests are found by their cookie token (only unclaimed threads — a token that has been adopted by a user belongs to that user now).



28
29
30
31
32
33
34
# File 'app/models/livechat/conversation.rb', line 28

def self.for_visitor(visitor_id: nil, visitor_token: nil)
  if visitor_id.present?
    where(visitor_id: visitor_id.to_s).order(id: :desc).first
  elsif visitor_token.present?
    where(visitor_token: visitor_token, visitor_id: nil).order(id: :desc).first
  end
end

Instance Method Details

#display_nameObject



99
100
101
# File 'app/models/livechat/conversation.rb', line 99

def display_name
  visitor_label.presence || visitor_email.presence || "Visitor ##{id}"
end

#mark_read_for_agent!Object



91
92
93
# File 'app/models/livechat/conversation.rb', line 91

def mark_read_for_agent!
  messages.from_visitor.unread.update_all(read_at: Time.current)
end

#mark_read_for_visitor!Object



95
96
97
# File 'app/models/livechat/conversation.rb', line 95

def mark_read_for_visitor!
  messages.from_agent.unread.update_all(read_at: Time.current)
end

#post_agent_message!(body:, agent_id:, agent_label:, files: nil) ⇒ Object



55
56
57
58
59
60
61
# File 'app/models/livechat/conversation.rb', line 55

def post_agent_message!(body:, agent_id:, agent_label:, files: nil)
  message = messages.new(author_type: 'agent', body: body,
                         agent_id: agent_id.to_s, agent_label: agent_label)
  attach(message, files)
  message.save!
  message
end

#post_visitor_message!(body, files: nil) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'app/models/livechat/conversation.rb', line 45

def post_visitor_message!(body, files: nil)
  transaction do
    update!(status: 'open') if resolved?
    message = messages.new(author_type: 'visitor', body: body)
    attach(message, files)
    message.save!
    message
  end
end

#register_message(message) ⇒ Object

Denormalized inbox-list fields, refreshed on every message. Written with update_columns: cheap, no callbacks, no updated_at churn.



83
84
85
86
87
# File 'app/models/livechat/conversation.rb', line 83

def register_message(message)
  updates = { last_activity_at: message.created_at }
  updates[:last_message_preview] = message.preview unless message.system?
  update_columns(updates)
end

#reopen_by!(agent_label) ⇒ Object



72
73
74
75
76
77
78
79
# File 'app/models/livechat/conversation.rb', line 72

def reopen_by!(agent_label)
  return if open?

  transaction do
    update!(status: 'open')
    messages.create!(author_type: 'system', event: 'reopened', agent_label: agent_label)
  end
end

#resolve_by!(agent_label) ⇒ Object



63
64
65
66
67
68
69
70
# File 'app/models/livechat/conversation.rb', line 63

def resolve_by!(agent_label)
  return if resolved?

  transaction do
    update!(status: 'resolved')
    messages.create!(author_type: 'system', event: 'resolved', agent_label: agent_label)
  end
end

#unread_from_visitor_countObject



89
# File 'app/models/livechat/conversation.rb', line 89

def unread_from_visitor_count = messages.from_visitor.unread.count