Add GUI for customFields in Livechat

pull/15840/head
Anton Kazarinov 7 years ago
parent ddfd1b8b05
commit 5f051d2caa
  1. 23
      app/livechat/client/views/app/tabbar/visitorEdit.html
  2. 57
      app/livechat/client/views/app/tabbar/visitorEdit.js
  3. 65
      app/livechat/client/views/app/tabbar/visitorInfo.html
  4. 33
      app/livechat/client/views/app/tabbar/visitorInfo.js
  5. 7
      app/livechat/server/lib/Livechat.js
  6. 2
      app/livechat/server/methods/saveInfo.js
  7. 11
      app/models/server/models/LivechatRooms.js
  8. 9
      app/models/server/models/LivechatVisitors.js

@ -30,6 +30,17 @@
</div>
</label>
</div>
{{#each visitorCustomFields}}
<div class="rc-input rc-form-group rc-form-group--small">
<label class="rc-input__label">
<div class="rc-input__title">{{label}}</div>
<div class="rc-input__wrapper">
<input class="rc-input__element" type="text" name="{{name}}" autocomplete="off" data-visitorLivechatData="true" value="{{value}}">
</div>
</label>
</div>
{{/each}}
{{/with}}
{{#with room}}
@ -77,7 +88,19 @@
{{/each}}
</ul>
</div>
{{#each roomCustomFields}}
<div class="rc-input rc-form-group rc-form-group--small">
<label class="rc-input__label">
<div class="rc-input__title">{{label}}</div>
<div class="rc-input__wrapper">
<input class="rc-input__element" type="text" name="{{name}}" autocomplete="off" data-roomLivechatData="true" value="{{value}}">
</div>
</label>
</div>
{{/each}}
{{/with}}
<div class="rc-user-info__flex rc-user-info__row">
<button class='rc-button cancel' type="button"><span>{{_ "Cancel"}}</span></button>
<button class='rc-button rc-button--primary save'><span>{{_ "Save"}}</span></button>

@ -7,16 +7,61 @@ import { t } from '../../../../../utils';
import { hasRole } from '../../../../../authorization';
import './visitorEdit.html';
import { APIClient } from '../../../../../utils/client';
import { LivechatCustomField } from '../../../collections/LivechatCustomField';
Template.visitorEdit.helpers({
visitor() {
return Template.instance().visitor.get();
},
visitorCustomFields() {
const fields = [];
const visitor = Template.instance().visitor.get();
const customFields = Template.instance().customFields.get();
if (!customFields) {
return fields;
}
customFields.forEach((field) => {
if (field.visibility !== 'hidden' && field.scope === 'visitor') {
const value = visitor.hasOwnProperty('livechatData') && visitor.livechatData.hasOwnProperty(field._id)
? visitor.livechatData[field._id]
: '';
fields.push({ name: field._id, label: field.label, value });
}
});
return fields;
},
room() {
return Template.instance().room.get();
},
roomCustomFields() {
const fields = [];
const room = Template.instance().room.get();
const customFields = Template.instance().customFields.get();
if (!customFields) {
return fields;
}
customFields.forEach((field) => {
if (field.visibility !== 'hidden' && field.scope === 'room') {
const value = room.hasOwnProperty('livechatData') && room.livechatData.hasOwnProperty(field._id)
? room.livechatData[field._id]
: '';
fields.push({ name: field._id, label: field.label, value });
}
});
return fields;
},
email() {
const visitor = Template.instance().visitor.get();
if (visitor.visitorEmails && visitor.visitorEmails.length > 0) {
@ -61,6 +106,7 @@ Template.visitorEdit.onCreated(async function() {
this.availableTags = new ReactiveVar([]);
this.agentDepartments = new ReactiveVar([]);
this.availableUserTags = new ReactiveVar([]);
this.customFields = new ReactiveVar([]);
this.autorun(async () => {
const { visitorId } = Template.currentData();
@ -72,10 +118,13 @@ Template.visitorEdit.onCreated(async function() {
const rid = Template.currentData().roomId;
this.subscribe('livechat:customFields');
this.autorun(async () => {
const { room } = await APIClient.v1.get(`rooms.info?roomId=${ rid }`);
const customFields = LivechatCustomField.find().fetch();
this.room.set(room);
this.tags.set((room && room.tags) || []);
this.customFields.set(customFields || []);
});
const uid = Meteor.userId();
@ -106,9 +155,17 @@ Template.visitorEdit.events({
userData.name = event.currentTarget.elements.name.value;
userData.email = event.currentTarget.elements.email.value;
userData.phone = event.currentTarget.elements.phone.value;
userData.livechatData = {};
$('[data-visitorLivechatData=true]').each(function() {
userData.livechatData[this.name] = $(this).val() || '';
});
roomData.topic = event.currentTarget.elements.topic.value;
roomData.tags = instance.tags.get();
roomData.livechatData = {};
$('[data-roomLivechatData=true]').each(function() {
roomData.livechatData[this.name] = $(this).val() || '';
});
if (sms) {
delete userData.phone;

@ -10,42 +10,45 @@
{{#with user}}
<div class="info">
{{#if name}}
<h3 title="{{name}}"><i class="status-{{status}}"></i> {{name}}</h3>
<h3 title="{{name}}">{{name}} <i class="status-{{status}}"></i></h3>
<p class="secondary-font-color">{{username}}</p>
{{else}}
<h3 title="{{username}}"><i class="status-{{status}}"></i> {{username}}</h3>
<h3 title="{{username}}">{{username}} <i class="status-{{status}}"></i></h3>
{{/if}}
<ul>
{{#if utc}}<li><i class="icon-clock"></i>{{userTime}} (UTC {{utc}})</li>{{/if}}
{{#each visitorEmails}} <li><i class="icon-mail"></i> {{address}}{{#if verified}}&nbsp;<i class="icon-ok success-color"></i>{{/if}}</li> {{/each}}
{{#each phone}} <li><i class="icon-phone"></i> {{phoneNumber}}</li> {{/each}}
{{#if lastLogin}} <li><i class="icon-calendar"></i> {{_ "Created_at"}}: {{createdAt}}</li> {{/if}}
{{#if lastLogin}} <li><i class="icon-calendar"></i> {{_ "Last_login"}}: {{lastLogin}}</li> {{/if}}
{{#each visitorEmails}}<li><i class="icon-mail"></i> {{address}}{{#if verified}}&nbsp;<i class="icon-ok success-color"></i>{{/if}}</li> {{/each}}
{{#each phone}}<li><i class="icon-phone"></i> {{phoneNumber}}</li> {{/each}}
{{#if lastLogin}}<li><i class="icon-calendar"></i> {{_ "Created_at"}}: {{createdAt}}</li> {{/if}}
{{#if lastLogin}}<li><i class="icon-calendar"></i> {{_ "Last_login"}}: {{lastLogin}}</li> {{/if}}
{{#if ip}}<li><i class="icon-laptop"></i><span>{{ip}}</span></li>{{/if}}
{{#if os}}<li><i class="{{osIcon}}"></i><span>{{os}}</span></li>{{/if}}
{{#if browser}}<li><i class="{{browserIcon}}"></i><span>{{browser}}</span></li>{{/if}}
{{#if customVisitorFields}}
{{#each customVisitorFields}}<li><strong>{{label}}</strong>: {{value}}</li>{{/each}}
{{/if}}
</ul>
</div>
{{/with}}
{{#with room}}
<div class="info">
<ul>
{{#if facebook}} <li><i class="icon-facebook"></i>{{_ "Facebook_Page"}}: {{facebook.page.name}}</li> {{/if}}
{{#if sms}} <li><i class="icon-mobile"></i>{{_ "SMS_Enabled"}}</li> {{/if}}
{{#if topic}} <li><strong>{{_ "Topic"}}</strong>: {{{RocketChatMarkdown topic}}}</li> {{/if}}
{{#if tags}} <li><strong>{{_ "Tags"}}</strong>: {{joinTags}}</li> {{/if}}
</ul>
</div>
{{/with}}
{{#with department}}
<div class="info">
<ul>
{{#if name}} <li>{{_ "Department"}}: {{name}}</li> {{/if}}
</ul>
</div>
{{/with}}
<div class="info">
<h3>{{_ "Conversation"}}</h3>
<ul>
{{#with room}}
<li><strong>{{_ "Agent"}}</strong>: {{servedBy.username}}</li>
{{#if facebook}}<li><i class="icon-facebook"></i>{{_ "Facebook_Page"}}: {{facebook.page.name}}</li>{{/if}}
{{#if sms}}<li><i class="i con-mobile"></i>{{_ "SMS_Enabled"}}</li>{{/if}}
{{#if topic}}<li><strong>{{_ "Topic"}}</strong>: {{{RocketChatMarkdown topic}}}</li>{{/if}}
{{#if tags}}<li><strong>{{_ "Tags"}}</strong>: {{joinTags}}</li>{{/if}}
{{/with}}
{{#with department}}
{{#if name}}<li>{{_ "Department"}}: {{name}}</li>{{/if}}
{{/with}}
{{#if customRoomFields}}
{{#each customRoomFields}}<li><strong>{{label}}</strong>: {{value}}</li>{{/each}}
{{/if}}
</ul>
</div>
</div>
{{#if canSeeButtons}}
@ -68,20 +71,6 @@
</nav>
{{/if}}
{{#if customFields}}
<div class="visitor-custom-fields">
<h4>{{_ "Custom_Fields"}}</h4>
<div class="visitor-scroll">
<ul>
{{#each customFields}}
<li>{{label}}: {{value}}</li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
{{> visitorNavigation .}}
</div>
</template>

@ -62,14 +62,9 @@ Template.visitorInfo.helpers({
return tags && tags.join(', ');
},
customFields() {
customRoomFields() {
const fields = [];
let livechatData = {};
const user = Template.instance().user.get();
if (user) {
livechatData = _.extend(livechatData, user.livechatData);
}
const data = Template.currentData();
if (data && data.rid) {
const room = Template.instance().room.get();
@ -84,7 +79,31 @@ Template.visitorInfo.helpers({
const customFields = Template.instance().customFields.get();
if (customFields) {
const field = _.findWhere(customFields, { _id });
if (field && field.visibility !== 'hidden') {
if (field && field.visibility !== 'hidden' && field.scope === 'room') {
fields.push({ label: field.label, value: livechatData[_id] });
}
}
}
}
return fields;
}
},
customVisitorFields() {
const fields = [];
let livechatData = {};
const user = Template.instance().user.get();
if (user) {
livechatData = _.extend(livechatData, user.livechatData);
}
if (!_.isEmpty(livechatData)) {
for (const _id in livechatData) {
if (livechatData.hasOwnProperty(_id)) {
const customFields = Template.instance().customFields.get();
if (customFields) {
const field = _.findWhere(customFields, { _id });
if (field && field.visibility !== 'hidden' && field.scope === 'visitor') {
fields.push({ label: field.label, value: livechatData[_id] });
}
}

@ -276,7 +276,7 @@ export const Livechat = {
return false;
},
saveGuest({ _id, name, email, phone }) {
saveGuest({ _id, name, email, phone, livechatData }) {
const updateData = {};
if (name) {
@ -288,6 +288,9 @@ export const Livechat = {
if (phone) {
updateData.phone = phone;
}
if (livechatData) {
updateData.livechatData = livechatData;
}
const ret = LivechatVisitors.saveGuestById(_id, updateData);
Meteor.defer(() => {
@ -414,7 +417,7 @@ export const Livechat = {
},
saveRoomInfo(roomData, guestData) {
if ((roomData.topic != null || roomData.tags != null) && !LivechatRooms.setTopicAndTagsById(roomData._id, roomData.topic, roomData.tags)) {
if (!LivechatRooms.saveRoomById(roomData)) {
return false;
}

@ -17,12 +17,14 @@ Meteor.methods({
name: Match.Optional(String),
email: Match.Optional(String),
phone: Match.Optional(String),
livechatData: Match.Optional(Object),
}));
check(roomData, Match.ObjectIncluding({
_id: String,
topic: Match.Optional(String),
tags: Match.Optional([String]),
livechatData: Match.Optional(Object),
}));
const room = LivechatRooms.findOneById(roomData._id, { t: 1, servedBy: 1 });

@ -68,7 +68,7 @@ export class LivechatRooms extends Base {
return this.update(query, update);
}
setTopicAndTagsById(_id, topic, tags) {
saveRoomById({ _id, topic, tags, livechatData }) {
const setData = {};
const unsetData = {};
@ -86,6 +86,15 @@ export class LivechatRooms extends Base {
unsetData.tags = 1;
}
if (livechatData) {
setData.livechatData = {};
for (const field in livechatData) {
if (livechatData.hasOwnProperty(field) && !_.isEmpty(s.trim(livechatData[field]))) {
setData.livechatData[field] = s.trim(livechatData[field]);
}
}
}
const update = {};
if (!_.isEmpty(setData)) {

@ -160,6 +160,15 @@ export class LivechatVisitors extends Base {
}
}
if (data.livechatData) {
setData.livechatData = {};
for (const field in data.livechatData) {
if (data.livechatData.hasOwnProperty(field) && !_.isEmpty(s.trim(data.livechatData[field]))) {
setData.livechatData[field] = s.trim(data.livechatData[field]);
}
}
}
const update = {};
if (!_.isEmpty(setData)) {

Loading…
Cancel
Save