Skip to content
Snippets Groups Projects
Commit f23f57cc authored by Aaron Bohy's avatar Aaron Bohy
Browse files

[FIX] im_livechat: livechat restored after refactoring of mail

Refactoring of the livechat itself and integration in the new architecture of
mail since its large refactoring.

Joint work with ged
parent 8019c89e
No related branches found
No related tags found
No related merge requests found
odoo.define('im_livechat.im_livechat', function (require) { odoo.define('im_livechat.im_livechat', function (require) {
"use strict"; "use strict";
var bus = require('bus.bus'); var bus = require('bus.bus').bus;
var core = require('web.core'); var core = require('web.core');
var user_session = require('web.session'); var session = require('web.session');
var time = require('web.time'); var time = require('web.time');
var utils = require('web.utils'); var utils = require('web.utils');
var Widget = require('web.Widget'); var Widget = require('web.Widget');
// var mail_chat_common = require('mail.chat_common');
var ChatWindow = require('mail.ChatWindow');
var _t = core._t; var _t = core._t;
var QWeb = core.qweb; var QWeb = core.qweb;
return {
LivechatButton: Widget,
};
/*
* Conversation Patch
*
* The state of anonymous session is hold by the client and not the
* server. Override the method managing the state of normal conversation.
*/
mail_chat_common.Conversation.include({
init: function(parent, session, options){
this._super.apply(this, arguments);
this.shown = true;
this.feedback = false;
this.options.default_username = session.anonymous_name || this.options.default_username;
},
show: function(){
this._super.apply(this, arguments);
this.shown = true;
},
hide: function(){
this._super.apply(this, arguments);
this.shown = false;
},
session_fold: function(state){
// set manually the new state
if(state === 'closed'){
this.destroy();
utils.set_cookie('im_livechat_session', "", -1);
}else{
if(state === 'open'){
this.show();
}else{
if(this.shown){
state = 'fold';
this.hide();
}else{
state = 'open';
this.show();
}
}
this._super(state);
// session and cookie update
utils.set_cookie('im_livechat_session', JSON.stringify(this.get('session')), 60*60);
}
},
on_click_close: function(event) {
var self = this;
event.stopPropagation();
if(!this.feedback && (this.get('messages').length > 1)){
this.feedback = new Feedback(this);
this.$(".o_mail_chat_im_window_content").empty();
this.$(".o_mail_chat_im_window_input").prop('disabled', true);
this.feedback.appendTo(this.$(".o_mail_chat_im_window_content"));
// bind event to close conversation
var args = arguments;
var _super = this._super;
this.feedback.on("feedback_sent", this, function(){
_super.apply(self, args);
});
}else{
this._super.apply(this, arguments);
}
},
});
/*
* Livechat Conversation Manager
*
* To avoid exeption when the anonymous has close his conversation and when operator send
* him a message. Extending ConversationManager is better than monkey-patching it.
*/
var LivechatConversationManager = mail_chat_common.ConversationManager.extend({
message_receive: function(message) {
try{
this._super(message);
}catch(e){}
}
});
/**
* Livechat Button
*
* This widget is the Button to start a conversation with an operator on the livechat channel
* (defined in options.channel_id). This will auto-popup if the rule say so, create the conversation
* window if a session is saved in a cookie, ...
*/
var LivechatButton = Widget.extend({ var LivechatButton = Widget.extend({
template: 'im_livechat.LivechatButton', className:"openerp o_livechat_button hidden-print",
events: { events: {
"click": "on_click" "click": "open_chat"
}, },
init: function(parent, server_url, options, rule) {
this._super.apply(this, arguments); init: function (parent, server_url, options) {
this.server_url = server_url; this._super(parent);
this.options = _.defaults(options || {}, { this.options = _.defaults(options || {}, {
placeholder: _t('Ask something ...'), placeholder: _t('Ask something ...'),
default_username: _t("Visitor"), default_username: _t("Visitor"),
button_text: _t("Chat with one of our collaborators"), button_text: _t("Chat with one of our collaborators"),
default_message: _t("How may I help you?"), default_message: _t("How may I help you?"),
}); });
this.rule = rule || false; this.channel = null;
this.mail_channel = false; this.chat_window = null;
this.messages = [];
}, },
willStart: function(){
return $.when(this.load_qweb_template(), this._super()); willStart: function () {
return this.load_qweb_template();
}, },
start: function(){
var self = this; start: function () {
return this._super.apply(this, arguments).then(function(){ this.$el.text(this.options.button_text);
// set up the manager bus.on('notification', this, function (notification) {
self.manager = new LivechatConversationManager(self, self.options); this.add_message(notification[1]);
self.manager.set("bottom_offset", self.$el.outerHeight()); this.render_messages();
// check if a session already exists in a cookie
var cookie = utils.get_cookie('im_livechat_session');
if(cookie){
self.set_conversation(JSON.parse(cookie), false);
}else{ // if not session, apply the rule
var auto_popup_cookie = utils.get_cookie('im_livechat_auto_popup') ? JSON.parse(utils.get_cookie('im_livechat_auto_popup')) : true;
self.auto_popup_cookie = auto_popup_cookie;
if (self.rule.action === 'auto_popup' && auto_popup_cookie){
setTimeout(function() {
self.on_click();
}, self.rule.auto_popup_timer*1000);
}
}
}); });
return this._super();
}, },
load_qweb_template: function(){
var self = this; load_qweb_template: function () {
var defs = []; var xml_files = ['/mail/static/src/xml/chat_window.xml',
var templates = ['/mail/static/src/xml/mail_chat_common.xml', '/im_livechat/static/src/xml/im_livechat.xml']; '/mail/static/src/xml/thread.xml',
_.each(templates, function(tmpl){ '/im_livechat/static/src/xml/im_livechat.xml'];
defs.push(user_session.rpc('/web/proxy/load', {path: tmpl}).then(function(xml) { var defs = _.map(xml_files, function (tmpl) {
return session.rpc('/web/proxy/load', {path: tmpl}).then(function (xml) {
QWeb.add_template(xml); QWeb.add_template(xml);
})); });
}); });
return $.when.apply($, defs); return $.when.apply($, defs);
}, },
load_mail_channel: function(display_warning){
open_chat: function () {
var self = this; var self = this;
return user_session.rpc('/im_livechat/get_session', { var cookie = utils.get_cookie('im_livechat_session');
"channel_id" : this.options.channel_id, var def;
"anonymous_name" : this.options.default_username, if (cookie) {
}, {shadow: true}).then(function(channel){ def = $.when(JSON.parse(cookie));
if(channel){ } else {
self.set_conversation(channel, true); this.messages = []; // re-initialize messages cache
}else{ def = session.rpc('/im_livechat/get_session', {
if(display_warning){ channel_id : this.options.channel_id,
self.alert_available_message(); anonymous_name : this.options.default_username,
} }, {shadow: true});
}
def.then(function (channel) {
if (!channel || !channel.operator_pid) {
alert(_t("None of our collaborators seems to be available, please try again later."));
} else {
self.channel = channel;
self.open_chat_window(channel);
self.send_welcome_message();
self.render_messages();
bus.add_channel(channel.uuid);
bus.restart_poll();
utils.set_cookie('im_livechat_session', JSON.stringify(channel), 60*60);
} }
}); });
}, },
on_click: function(event){
var self = this; open_chat_window: function (channel) {
if(!this.mail_channel){
this.load_mail_channel(event !== undefined);
}
},
set_conversation: function(mail_channel, welcome_message){
var self = this; var self = this;
// set the mail_channel and create the Conversation Window var options = {
this.mail_channel = mail_channel; display_stars: false,
// force open conversation window };
if(mail_channel['state'] == 'closed'){ this.chat_window = new ChatWindow(this, channel.id, channel.name, false, options);
mail_channel['state'] = 'open'; this.chat_window.appendTo($('body')).then(function () {
} self.chat_window.$el.css({right: 0, bottom: 0});
self.$el.hide();
});
this.chat_window.on("close_chat_session", this, function () {
if (this.messages.length > 1) {
this.ask_feedback();
} else {
this.close_chat();
}
});
this.chat_window.on("post_message", this, function (message) {
self.send_message(message).fail(function (error, e) {
e.preventDefault();
return self.send_message(message); // try again just in case
});
this.conv = this.manager.session_apply(mail_channel, {
'load_history': !welcome_message,
'focus': welcome_message
}); });
this.conv.on("destroyed", this, function() { },
bus.bus.stop_polling();
delete self.conv; close_chat: function () {
delete self.mail_channel; this.chat_window.destroy();
this.$el.show();
utils.set_cookie('im_livechat_session', "", -1); // remove cookie
},
send_message: function (message) {
return session.rpc("/mail/chat_post", {uuid: this.channel.uuid, message_content: message.content});
},
add_message: function (data) {
this.messages.push({
id: data.id,
attachment_ids: data.attachment_ids,
author_id: data.author_id,
body: data.body,
date: data.date,
is_needaction: false,
is_note: data.is_note,
}); });
// setup complet when the conversation window is appended
this.manager._session_defs[mail_channel.id].then(function(){
// start the polling
bus.bus.add_channel(mail_channel.uuid);
bus.bus.start_polling();
// add the automatic welcome message
if(welcome_message){
self.send_welcome_message();
}
// create the cookies
utils.set_cookie('im_livechat_auto_popup', JSON.stringify(false), 60*60);
utils.set_cookie('im_livechat_session', JSON.stringify(mail_channel), 60*60);
})
}, },
send_welcome_message: function(){
var self = this; render_messages: function () {
if(this.mail_channel.operator_pid && this.options.default_message) { this.chat_window.render(this.messages);
setTimeout(function(){ this.chat_window.scrollBottom();
self.conv.message_receive({
id : 1,
message_type: "comment",
model: 'mail.channel',
body: self.options.default_message,
date: time.datetime_to_str(new Date()),
author_id: self.mail_channel.operator_pid,
channel_ids: [self.mail_channel.id],
tracking_value_ids: [],
attachment_ids: [],
});
}, 1000);
}
}, },
alert_available_message: function(){
alert(_t("None of our collaborators seems to be available, please try again later.")); send_welcome_message: function () {
this.add_message({
id: 1,
attachment_ids: [],
author_id: this.channel.operator_pid,
body: this.options.default_message,
channel_ids: [this.channel.id],
date: time.datetime_to_str(new Date()),
tracking_value_ids: [],
});
}, },
})
ask_feedback: function () {
this.chat_window.$(".o_chat_content").empty();
this.chat_window.$(".o_chat_input input").prop('disabled', true);
var feedback = new Feedback(this, this.channel.uuid);
feedback.appendTo(this.chat_window.$(".o_chat_content"));
feedback.on("send_message", this, this.send_message);
feedback.on("feedback_sent", this, this.close_chat);
}
});
/* /*
* Rating for Livechat * Rating for Livechat
* *
* This widget display the 3 rating smileys, and a textarea to add a reason (only for red * This widget displays the 3 rating smileys, and a textarea to add a reason
* smileys), and sent the user feedback to the server. * (only for red smiley), and sends the user feedback to the server.
*/ */
var Feedback = Widget.extend({ var Feedback = Widget.extend({
template : "im_livechat.feedback", template: "im_livechat.FeedBack",
init: function(parent){
this._super(parent); events: {
this.conversation = parent; 'click .o_livechat_rating_choices img': 'on_click_smiley',
this.reason = false; 'click .o_rating_submit_button': 'on_click_send',
this.rating = false;
this.server_origin = user_session.origin;
}, },
start: function(){
this._super.apply(this.arguments); init: function (parent, channel_uuid) {
// bind events this._super(parent);
this.$('.o_livechat_rating_choices img').on('click', _.bind(this.click_smiley, this)); this.channel_uuid = channel_uuid;
this.$('#rating_submit').on('click', _.bind(this.click_send, this)); this.server_origin = session.origin;
this.rating = undefined;
}, },
click_smiley: function(ev){
var self = this; on_click_smiley: function (ev) {
this.rating = parseInt($(ev.currentTarget).data('value')); this.rating = parseInt($(ev.currentTarget).data('value'));
this.$('.o_livechat_rating_choices img').removeClass('selected'); this.$('.o_livechat_rating_choices img').removeClass('selected');
this.$('.o_livechat_rating_choices img[data-value="'+this.rating+'"]').addClass('selected'); this.$('.o_livechat_rating_choices img[data-value="'+this.rating+'"]').addClass('selected');
// only display textearea if bad smiley selected // only display textearea if bad smiley selected
var close_conv = false; var close_chat = false;
if(this.rating === 0){ if (this.rating === 0) {
this.$('.o_livechat_rating_reason').show(); this.$('.o_livechat_rating_reason').show();
}else{ } else {
this.$('.o_livechat_rating_reason').hide(); this.$('.o_livechat_rating_reason').hide();
close_conv = true; close_chat = true;
} }
this._send_feedback(close_conv).then(function(){ this._send_feedback({close: close_chat});
self.$('textarea').val(''); // empty the reason each time a click on a smiley is done
});
}, },
click_send: function(ev){
this.reason = this.$('textarea').val(); on_click_send: function () {
if(_.contains([0,5,10], this.rating)){ // need to use contains, since the rating can 0, evaluate to false if (_.isNumber(this.rating)) {
this._send_feedback(true); this._send_feedback({ reason: this.$('textarea').val(), close: true });
} }
}, },
_send_feedback: function(close){
_send_feedback: function (options) {
var self = this; var self = this;
var uuid = this.conversation.get('session').uuid; var args = {
return user_session.rpc('/im_livechat/feedback', {uuid: uuid, rate: this.rating, reason : this.reason}).then(function(res) { uuid: this.channel_uuid,
if(close){ rate: this.rating,
self.trigger("feedback_sent"); // will close the conversation reason : options.reason
self.conversation.message_send(_.str.sprintf(_t("I rated you with :rating_%d"), self.rating), "message"); };
return session.rpc('/im_livechat/feedback', args).then(function () {
if (options.close) {
var content = _.str.sprintf(_t("I rated you with :rating_%d"), self.rating);
if (options.reason) {
content += _.str.sprintf(_t(" for the following reason: %s"), options.reason);
}
self.trigger("send_message", {content: content});
self.trigger("feedback_sent"); // will close the chat
} }
}); });
} }
}); });
return { return {
Feedback: Feedback,
LivechatButton: LivechatButton, LivechatButton: LivechatButton,
Feedback: Feedback,
}; };
}); });
odoo.define('im_livechat.chat_backend', function (require) {
"use strict";
// var mail_chat_backend = require('mail.chat_backend');
return;
/**
* Patch for the client action to integrate Livechat Mail Channel in a particular slot
*/
mail_chat_backend.ChatMailThread.include({
init: function(parent, action){
this._super.apply(this, arguments);
this.set('channel_livechat', []);
},
start: function(){
var self = this;
this.on("change:channel_livechat", this, function(){
self.channel_render('channel_livechat');
});
self.$el.on('click', '.o_mail_chat_channel_unpin', _.bind(self.on_click_channel_unpin, self));
return this._super.apply(this, arguments).then(function(){
});
},
on_click_channel_unpin: function(event){
var self = this;
var channel_id = this.$(event.currentTarget).data('channel-id');
var channel = this.channels[channel_id];
return this.channel_pin(channel.uuid, false).then(function(){
self.channel_remove(channel_id);
// if unpin current channel, switch to inbox
if(self.get('current_channel_id') === channel_id){
self.set('current_channel_id', 'channel_inbox');
}
});
},
channel_change: function(){
// update the default username
var current_channel = this.channels[this.get('current_channel_id')];
if(current_channel){
this.options.default_username = current_channel.anonymous_name || this.options.default_username
}
return this._super.apply(this, arguments);
},
// utils function
get_channel_slot: function(channel){
if(channel.channel_type === 'livechat'){
return 'channel_livechat';
}
return this._super.apply(this, arguments);
},
});
});
.openerp { /* base style of openerp */
font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
color: #4c4c4c;
font-size: 13px;
}
.o_mail_chat_im_window * {
box-sizing: border-box;
}
.o_livechat_button { .o_livechat_button {
width: 230px;
position: fixed; position: fixed;
bottom: 0px; bottom: 0px;
right: 6px; right: 6px;
display: inline-block;
white-space: nowrap;
min-width: 100px; min-width: 100px;
cursor: pointer;
white-space: nowrap;
background-color: rgba(60, 60, 60, 0.6); background-color: rgba(60, 60, 60, 0.6);
font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Verdana, sans-serif; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Verdana, sans-serif;
font-size: 14px; font-size: 14px;
...@@ -29,48 +16,44 @@ ...@@ -29,48 +16,44 @@
border-bottom: 0px; border-bottom: 0px;
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-top-right-radius: 5px; border-top-right-radius: 5px;
cursor: pointer;
z-index:500;
} }
/* Livechat Rating : feedback smiley */ /* Livechat Rating : feedback smiley */
.o_mail_chat_im_window_content .o_livechat_rating{ .o_chat_window .o_chat_content .o_livechat_rating {
padding: 15px; padding: 15px;
vertical-align: middle;
}
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_feedback_text {
vertical-align: middle;
font-size: 14px;
}
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices{
height:40px;
text-align: center;
margin: 10px 0 30px 0;
}
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img{
width: 50px;
opacity: 0.60;
cursor: pointer;
margin: 5px;
}
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img:hover{
opacity:1;
}
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img.selected{
opacity: 1;
}
/* feedback reason */ .o_livechat_rating_feedback_text {
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason { text-align: justify;
margin: 10px 0; }
display: none; /* hidden by default */
} .o_livechat_rating_choices {
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason textarea { margin: 10px 0;
width: 100%; text-align: center;
height: 70px;
resize: none; > img {
} width: 50px;
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason_button input{ opacity: 0.60;
float: right; cursor: pointer;
margin-left : 10px; margin: 5px;
&:hover, &.selected {
opacity: 1;
}
}
}
/* feedback reason */
.o_livechat_rating_reason {
margin: 10px 0;
display: none; /* hidden by default */
> textarea {
width: 100%;
height: 70px;
resize: none;
}
}
.o_livechat_rating_reason_button > input {
float: right;
}
} }
...@@ -2,13 +2,7 @@ ...@@ -2,13 +2,7 @@
<templates xml:space="preserve"> <templates xml:space="preserve">
<t t-name="im_livechat.LivechatButton"> <t t-name="im_livechat.FeedBack">
<div class="openerp o_livechat_button hidden-print" t-att-data-livechat-channel-id="widget.options.channel_id">
<t t-esc="widget.options.button_text"/>
</div>
</t>
<t t-name="im_livechat.feedback">
<div class="o_livechat_rating"> <div class="o_livechat_rating">
<div class="o_livechat_rating_feedback_text"> <div class="o_livechat_rating_feedback_text">
Did we correctly answer your question ? Did we correctly answer your question ?
...@@ -21,7 +15,7 @@ ...@@ -21,7 +15,7 @@
<div class="o_livechat_rating_reason"> <div class="o_livechat_rating_reason">
<textarea id="reason" placeholder="Explain your note"></textarea> <textarea id="reason" placeholder="Explain your note"></textarea>
<div class="o_livechat_rating_reason_button"> <div class="o_livechat_rating_reason_button">
<input type="button" id="rating_submit" value="Send" /> <input type="button" class="o_rating_submit_button" value="Send" />
</div> </div>
</div> </div>
</div> </div>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<template> <template>
<!-- <t t-extend="mail.chat.ChatMailThread.channels"> <t t-extend="mail.chat.Sidebar">
<t t-jquery="li > a" t-operation="append">
<t t-if="channel.channel_type === 'livechat'">
<span class="fa fa-times pull-right o_mail_chat_channel_unpin" t-att-title="_t('Close')" t-att-data-channel-id="channel.id"/>
</t>
</t>
</t>
<t t-extend="mail.chat.ChatMailThread">
<t t-jquery=".o_mail_chat_sidebar" t-operation="append"> <t t-jquery=".o_mail_chat_sidebar" t-operation="append">
<h4 class="o_mail_chat_sidebar_title"><t t-esc="_t('Livechat')"/></h4> <t t-set="channel_type">livechat</t>
<t t-call="mail.chat.ChatMailThread.channels"> <t t-call="mail.chat.SidebarTitle">
<t t-set="channel_slot" t-value="'channel_livechat'"/> <t t-set="channel_title">Livechat</t>
<t t-set="disable_add_channel">true</t>
</t>
<t t-call="mail.chat.SidebarItems">
<t t-set="display_close_button">true</t>
</t> </t>
</t> </t>
</t> --> </t>
</template> </template>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment