feat: Use display_name instead of name of the agent (#1097)
* feat: Use display_name instead of name of the agent
This commit is contained in:
parent
f30c8943d9
commit
2b1d445003
21 changed files with 80 additions and 41 deletions
|
@ -16,6 +16,14 @@ class Api::V1::ProfilesController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def profile_params
|
def profile_params
|
||||||
params.require(:profile).permit(:email, :name, :password, :password_confirmation, :avatar, :availability)
|
params.require(:profile).permit(
|
||||||
|
:email,
|
||||||
|
:name,
|
||||||
|
:display_name,
|
||||||
|
:password,
|
||||||
|
:password_confirmation,
|
||||||
|
:avatar,
|
||||||
|
:availability
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -118,7 +118,12 @@ export default {
|
||||||
return axios.post(urlData.url, { email });
|
return axios.post(urlData.url, { email });
|
||||||
},
|
},
|
||||||
|
|
||||||
profileUpdate({ password, password_confirmation, ...profileAttributes }) {
|
profileUpdate({
|
||||||
|
password,
|
||||||
|
password_confirmation,
|
||||||
|
displayName,
|
||||||
|
...profileAttributes
|
||||||
|
}) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
Object.keys(profileAttributes).forEach(key => {
|
Object.keys(profileAttributes).forEach(key => {
|
||||||
const value = profileAttributes[key];
|
const value = profileAttributes[key];
|
||||||
|
@ -126,6 +131,7 @@ export default {
|
||||||
formData.append(`profile[${key}]`, value);
|
formData.append(`profile[${key}]`, value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
formData.append('profile[display_name]', displayName || '');
|
||||||
if (password && password_confirmation) {
|
if (password && password_confirmation) {
|
||||||
formData.append('profile[password]', password);
|
formData.append('profile[password]', password);
|
||||||
formData.append('profile[password_confirmation]', password_confirmation);
|
formData.append('profile[password_confirmation]', password_confirmation);
|
||||||
|
|
|
@ -58,12 +58,12 @@
|
||||||
<div class="current-user" @click.prevent="showOptions()">
|
<div class="current-user" @click.prevent="showOptions()">
|
||||||
<thumbnail
|
<thumbnail
|
||||||
:src="currentUser.avatar_url"
|
:src="currentUser.avatar_url"
|
||||||
:username="currentUser.name"
|
:username="currentUserAvailableName"
|
||||||
:status="currentUser.availability_status"
|
:status="currentUser.availability_status"
|
||||||
/>
|
/>
|
||||||
<div class="current-user--data">
|
<div class="current-user--data">
|
||||||
<h3 class="current-user--name">
|
<h3 class="current-user--name">
|
||||||
{{ currentUser.name }}
|
{{ currentUserAvailableName }}
|
||||||
</h3>
|
</h3>
|
||||||
<h5 class="current-user--role">
|
<h5 class="current-user--role">
|
||||||
{{ currentRole }}
|
{{ currentRole }}
|
||||||
|
@ -202,6 +202,10 @@ export default {
|
||||||
uiFlags: 'agents/getUIFlags',
|
uiFlags: 'agents/getUIFlags',
|
||||||
accountLabels: 'labels/getLabelsOnSidebar',
|
accountLabels: 'labels/getLabelsOnSidebar',
|
||||||
}),
|
}),
|
||||||
|
currentUserAvailableName() {
|
||||||
|
const { available_name: availableName } = this.currentUser;
|
||||||
|
return availableName;
|
||||||
|
},
|
||||||
showChangeAccountOption() {
|
showChangeAccountOption() {
|
||||||
if (this.globalConfig.createNewAccountFromDashboard) {
|
if (this.globalConfig.createNewAccountFromDashboard) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<multiselect
|
<multiselect
|
||||||
v-model="currentChat.meta.assignee"
|
v-model="currentChat.meta.assignee"
|
||||||
:options="agentList"
|
:options="agentList"
|
||||||
label="name"
|
label="available_name"
|
||||||
:allow-empty="true"
|
:allow-empty="true"
|
||||||
deselect-label="Remove"
|
deselect-label="Remove"
|
||||||
placeholder="Select Agent"
|
placeholder="Select Agent"
|
||||||
|
@ -95,7 +95,7 @@ export default {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
confirmed: true,
|
confirmed: true,
|
||||||
name: 'None',
|
available_name: 'None',
|
||||||
id: 0,
|
id: 0,
|
||||||
role: 'agent',
|
role: 'agent',
|
||||||
account_id: 0,
|
account_id: 0,
|
||||||
|
|
|
@ -95,10 +95,13 @@ export default {
|
||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
sentByMessage() {
|
sentByMessage() {
|
||||||
return this.data.message_type === 1 &&
|
const { sender } = this.data;
|
||||||
!this.isHovered &&
|
|
||||||
this.data.sender !== undefined
|
return this.data.message_type === 1 && !this.isHovered && sender
|
||||||
? { content: `Sent by: ${this.data.sender.name}`, classes: 'top' }
|
? {
|
||||||
|
content: `Sent by: ${sender.available_name || sender.name}`,
|
||||||
|
classes: 'top',
|
||||||
|
}
|
||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
wrapClass() {
|
wrapClass() {
|
||||||
|
|
|
@ -44,9 +44,14 @@
|
||||||
"LABEL": "Profile Image"
|
"LABEL": "Profile Image"
|
||||||
},
|
},
|
||||||
"NAME": {
|
"NAME": {
|
||||||
"LABEL": "Your name",
|
"LABEL": "Your full name",
|
||||||
"ERROR": "Please enter a valid name",
|
"ERROR": "Please enter a valid full name",
|
||||||
"PLACEHOLDER": "Please enter your name, this would be displayed in conversations"
|
"PLACEHOLDER": "Please enter your full name"
|
||||||
|
},
|
||||||
|
"DISPLAY_NAME": {
|
||||||
|
"LABEL": "Display name",
|
||||||
|
"ERROR": "Please enter a valid display name",
|
||||||
|
"PLACEHOLDER": "Please enter a display name, this would be displayed in conversations"
|
||||||
},
|
},
|
||||||
"AVAILABILITY": {
|
"AVAILABILITY": {
|
||||||
"LABEL": "Availability",
|
"LABEL": "Availability",
|
||||||
|
|
|
@ -291,16 +291,9 @@ export default {
|
||||||
inboxId: this.currentInboxId,
|
inboxId: this.currentInboxId,
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
data: { payload },
|
data: { payload: inboxMembers },
|
||||||
} = response;
|
} = response;
|
||||||
payload.forEach(el => {
|
this.selectedAgents = inboxMembers;
|
||||||
const [item] = this.agentList.filter(
|
|
||||||
agent => agent.id === el.user_id
|
|
||||||
);
|
|
||||||
if (item) {
|
|
||||||
this.selectedAgents.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,17 @@
|
||||||
{{ $t('PROFILE_SETTINGS.FORM.NAME.ERROR') }}
|
{{ $t('PROFILE_SETTINGS.FORM.NAME.ERROR') }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label :class="{ error: $v.displayName.$error }">
|
||||||
|
{{ $t('PROFILE_SETTINGS.FORM.DISPLAY_NAME.LABEL') }}
|
||||||
|
<input
|
||||||
|
v-model="displayName"
|
||||||
|
type="text"
|
||||||
|
:placeholder="
|
||||||
|
$t('PROFILE_SETTINGS.FORM.DISPLAY_NAME.PLACEHOLDER')
|
||||||
|
"
|
||||||
|
@input="$v.displayName.$touch"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
<label :class="{ error: $v.email.$error }">
|
<label :class="{ error: $v.email.$error }">
|
||||||
{{ $t('PROFILE_SETTINGS.FORM.EMAIL.LABEL') }}
|
{{ $t('PROFILE_SETTINGS.FORM.EMAIL.LABEL') }}
|
||||||
<input
|
<input
|
||||||
|
@ -130,6 +141,7 @@ export default {
|
||||||
avatarFile: '',
|
avatarFile: '',
|
||||||
avatarUrl: '',
|
avatarUrl: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
displayName: '',
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
passwordConfirmation: '',
|
passwordConfirmation: '',
|
||||||
|
@ -141,6 +153,7 @@ export default {
|
||||||
name: {
|
name: {
|
||||||
required,
|
required,
|
||||||
},
|
},
|
||||||
|
displayName: {},
|
||||||
email: {
|
email: {
|
||||||
required,
|
required,
|
||||||
email,
|
email,
|
||||||
|
@ -188,6 +201,7 @@ export default {
|
||||||
this.email = this.currentUser.email;
|
this.email = this.currentUser.email;
|
||||||
this.avatarUrl = this.currentUser.avatar_url;
|
this.avatarUrl = this.currentUser.avatar_url;
|
||||||
this.availability = this.currentUser.availability_status;
|
this.availability = this.currentUser.availability_status;
|
||||||
|
this.displayName = this.currentUser.display_name;
|
||||||
},
|
},
|
||||||
async updateUser() {
|
async updateUser() {
|
||||||
this.$v.$touch();
|
this.$v.$touch();
|
||||||
|
@ -203,6 +217,7 @@ export default {
|
||||||
email: this.email,
|
email: this.email,
|
||||||
avatar: this.avatarFile,
|
avatar: this.avatarFile,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
|
displayName: this.displayName,
|
||||||
availability: this.availability,
|
availability: this.availability,
|
||||||
password_confirmation: this.passwordConfirmation,
|
password_confirmation: this.passwordConfirmation,
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,7 +21,7 @@ const getters = {
|
||||||
getMineChats(_state) {
|
getMineChats(_state) {
|
||||||
const currentUserID = authAPI.getCurrentUser().id;
|
const currentUserID = authAPI.getCurrentUser().id;
|
||||||
return _state.allConversations.filter(chat =>
|
return _state.allConversations.filter(chat =>
|
||||||
chat.meta.assignee === null
|
!chat.meta.assignee
|
||||||
? false
|
? false
|
||||||
: chat.status === _state.chatStatusFilter &&
|
: chat.status === _state.chatStatusFilter &&
|
||||||
chat.meta.assignee.id === currentUserID
|
chat.meta.assignee.id === currentUserID
|
||||||
|
@ -29,8 +29,7 @@ const getters = {
|
||||||
},
|
},
|
||||||
getUnAssignedChats(_state) {
|
getUnAssignedChats(_state) {
|
||||||
return _state.allConversations.filter(
|
return _state.allConversations.filter(
|
||||||
chat =>
|
chat => !chat.meta.assignee && chat.status === _state.chatStatusFilter
|
||||||
chat.meta.assignee === null && chat.status === _state.chatStatusFilter
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
getAllStatusChats(_state) {
|
getAllStatusChats(_state) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ class ConversationReplyMailer < ApplicationMailer
|
||||||
|
|
||||||
def reply_email
|
def reply_email
|
||||||
if inbound_email_enabled?
|
if inbound_email_enabled?
|
||||||
"#{@agent.name} <reply+#{@conversation.uuid}@#{current_domain}>"
|
"#{@agent.available_name} <reply+#{@conversation.uuid}@#{current_domain}>"
|
||||||
else
|
else
|
||||||
@agent&.email
|
@agent&.email
|
||||||
end
|
end
|
||||||
|
@ -64,9 +64,9 @@ class ConversationReplyMailer < ApplicationMailer
|
||||||
|
|
||||||
def from_email
|
def from_email
|
||||||
if inbound_email_enabled?
|
if inbound_email_enabled?
|
||||||
"#{@agent.name} <#{account_support_email}>"
|
"#{@agent.available_name} <#{account_support_email}>"
|
||||||
else
|
else
|
||||||
"#{@agent.name} <#{ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com')}>"
|
"#{@agent.available_name} <#{ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com')}>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ class Conversation < ApplicationRecord
|
||||||
def create_activity
|
def create_activity
|
||||||
return unless Current.user
|
return unless Current.user
|
||||||
|
|
||||||
user_name = Current.user&.name
|
user_name = Current.user&.available_name
|
||||||
|
|
||||||
create_status_change_message(user_name) if saved_change_to_status?
|
create_status_change_message(user_name) if saved_change_to_status?
|
||||||
create_assignee_change(user_name) if saved_change_to_assignee_id?
|
create_assignee_change(user_name) if saved_change_to_assignee_id?
|
||||||
|
@ -208,7 +208,7 @@ class Conversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_assignee_change(user_name)
|
def create_assignee_change(user_name)
|
||||||
params = { assignee_name: assignee&.name, user_name: user_name }.compact
|
params = { assignee_name: assignee&.available_name, user_name: user_name }.compact
|
||||||
key = assignee_id ? 'assigned' : 'removed'
|
key = assignee_id ? 'assigned' : 'removed'
|
||||||
content = I18n.t("conversations.activity.assignee.#{key}", **params)
|
content = I18n.t("conversations.activity.assignee.#{key}", **params)
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ class User < ApplicationRecord
|
||||||
account_users.find_by(account_id: Current.account.id) if Current.account
|
account_users.find_by(account_id: Current.account.id) if Current.account
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_name
|
def available_name
|
||||||
self[:display_name].presence || name
|
self[:display_name].presence || name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ class User < ApplicationRecord
|
||||||
{
|
{
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
|
available_name: available_name,
|
||||||
avatar_url: avatar_url,
|
avatar_url: avatar_url,
|
||||||
type: 'user',
|
type: 'user',
|
||||||
availability_status: availability_status
|
availability_status: availability_status
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Conversations::EventDataPresenter < SimpleDelegator
|
||||||
end
|
end
|
||||||
|
|
||||||
def push_meta
|
def push_meta
|
||||||
{ sender: contact.push_event_data, assignee: assignee }
|
{ sender: contact.push_event_data, assignee: assignee&.push_event_data }
|
||||||
end
|
end
|
||||||
|
|
||||||
def push_timestamps
|
def push_timestamps
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
json.payload do
|
json.payload do
|
||||||
json.array! @agents do |agent|
|
json.array! @agents do |agent|
|
||||||
json.user_id agent.id
|
json.partial! 'api/v1/models/user.json.jbuilder', resource: agent
|
||||||
json.name agent.name
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,11 @@ json.meta do
|
||||||
json.partial! 'api/v1/models/contact.json.jbuilder', resource: conversation.contact
|
json.partial! 'api/v1/models/contact.json.jbuilder', resource: conversation.contact
|
||||||
end
|
end
|
||||||
json.channel conversation.inbox.try(:channel_type)
|
json.channel conversation.inbox.try(:channel_type)
|
||||||
json.assignee conversation.assignee
|
if conversation.assignee
|
||||||
|
json.assignee do
|
||||||
|
json.partial! 'api/v1/models/user.json.jbuilder', resource: conversation.assignee
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
json.id conversation.display_id
|
json.id conversation.display_id
|
||||||
|
|
|
@ -2,6 +2,7 @@ json.account_id resource.account.id
|
||||||
json.availability_status resource.availability_status
|
json.availability_status resource.availability_status
|
||||||
json.confirmed resource.confirmed?
|
json.confirmed resource.confirmed?
|
||||||
json.email resource.email
|
json.email resource.email
|
||||||
|
json.available_name resource.available_name
|
||||||
json.id resource.id
|
json.id resource.id
|
||||||
json.name resource.name
|
json.name resource.name
|
||||||
json.role resource.role
|
json.role resource.role
|
||||||
|
|
|
@ -3,6 +3,7 @@ json.provider resource.provider
|
||||||
json.uid resource.uid
|
json.uid resource.uid
|
||||||
json.name resource.name
|
json.name resource.name
|
||||||
json.display_name resource.display_name
|
json.display_name resource.display_name
|
||||||
|
json.available_name resource.available_name
|
||||||
json.email resource.email
|
json.email resource.email
|
||||||
json.account_id resource.active_account_user&.account_id
|
json.account_id resource.active_account_user&.account_id
|
||||||
json.pubsub_token resource.pubsub_token
|
json.pubsub_token resource.pubsub_token
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
json.payload do
|
json.payload do
|
||||||
json.array! @inbox_members do |inbox_member|
|
json.array! @inbox_members do |inbox_member|
|
||||||
json.id inbox_member.user.id
|
json.id inbox_member.user.id
|
||||||
json.name inbox_member.user.name
|
json.name inbox_member.user.available_name
|
||||||
json.avatar_url inbox_member.user.avatar_url
|
json.avatar_url inbox_member.user.avatar_url
|
||||||
json.availability_status inbox_member.user.availability_status
|
json.availability_status inbox_member.user.availability_status
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<% @messages.each do |message| %>
|
<% @messages.each do |message| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<b><%= message.incoming? ? 'You' : message.sender.name %></b>
|
<b><%= message.incoming? ? 'You' : message.sender.available_name %></b>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -108,13 +108,13 @@ RSpec.describe ConversationReplyMailer, type: :mailer do
|
||||||
|
|
||||||
it 'sets reply to email to be based on the domain' do
|
it 'sets reply to email to be based on the domain' do
|
||||||
reply_to_email = "reply+#{message.conversation.uuid}@#{conversation.account.domain}"
|
reply_to_email = "reply+#{message.conversation.uuid}@#{conversation.account.domain}"
|
||||||
reply_to = "#{agent.name} <#{reply_to_email}>"
|
reply_to = "#{agent.available_name} <#{reply_to_email}>"
|
||||||
expect(mail['REPLY-TO'].value).to eq(reply_to)
|
expect(mail['REPLY-TO'].value).to eq(reply_to)
|
||||||
expect(mail.reply_to).to eq([reply_to_email])
|
expect(mail.reply_to).to eq([reply_to_email])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sets the from email to be the support email' do
|
it 'sets the from email to be the support email' do
|
||||||
expect(mail['FROM'].value).to eq("#{agent.name} <#{conversation.account.support_email}>")
|
expect(mail['FROM'].value).to eq("#{agent.available_name} <#{conversation.account.support_email}>")
|
||||||
expect(mail.from).to eq([conversation.account.support_email])
|
expect(mail.from).to eq([conversation.account.support_email])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,8 @@ RSpec.describe Conversation, type: :model do
|
||||||
|
|
||||||
it 'creates conversation activities' do
|
it 'creates conversation activities' do
|
||||||
# create_activity
|
# create_activity
|
||||||
expect(conversation.messages.pluck(:content)).to include("Conversation was marked resolved by #{old_assignee.name}")
|
expect(conversation.messages.pluck(:content)).to include("Conversation was marked resolved by #{old_assignee.available_name}")
|
||||||
expect(conversation.messages.pluck(:content)).to include("Assigned to #{new_assignee.name} by #{old_assignee.name}")
|
expect(conversation.messages.pluck(:content)).to include("Assigned to #{new_assignee.available_name} by #{old_assignee.available_name}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue