|
@ -2,6 +2,8 @@ |
|
|
import { rpc } from "@web/core/network/rpc"; |
|
|
import { rpc } from "@web/core/network/rpc"; |
|
|
const { mount, xml, onMounted, useState, useRef } = owl; |
|
|
const { mount, xml, onMounted, useState, useRef } = owl; |
|
|
import { ChatMsgView } from "./pos_chat_view"; |
|
|
import { ChatMsgView } from "./pos_chat_view"; |
|
|
|
|
|
import { useService } from "@web/core/utils/hooks"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class PosMsgView extends owl.Component { |
|
|
export class PosMsgView extends owl.Component { |
|
|
setup() { |
|
|
setup() { |
|
@ -11,6 +13,11 @@ export class PosMsgView extends owl.Component { |
|
|
this.MsgWindow = new ChatMsgView(); |
|
|
this.MsgWindow = new ChatMsgView(); |
|
|
this.state = useState({ |
|
|
this.state = useState({ |
|
|
data: [], |
|
|
data: [], |
|
|
|
|
|
counts: { |
|
|
|
|
|
all: 0, |
|
|
|
|
|
chat: 0, |
|
|
|
|
|
channels: 0 |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -20,15 +27,32 @@ export class PosMsgView extends owl.Component { |
|
|
const message_list = data.map((message) => { |
|
|
const message_list = data.map((message) => { |
|
|
const parser = new DOMParser(); |
|
|
const parser = new DOMParser(); |
|
|
const parsedHtml = parser.parseFromString(message.message_body, "text/html"); |
|
|
const parsedHtml = parser.parseFromString(message.message_body, "text/html"); |
|
|
const plainText = parsedHtml.documentElement.textContent; |
|
|
let plainText = parsedHtml.documentElement.textContent; |
|
|
|
|
|
|
|
|
|
|
|
// Format SMS failure messages
|
|
|
|
|
|
if (message.type === 'sms_failure') { |
|
|
|
|
|
plainText = `SMS Failure: Contact\nAn error occurred when sending an SMS\nAug 18`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
id: message.id, |
|
|
id: message.id, |
|
|
type: message.type, |
|
|
type: message.type, |
|
|
name: message.name, |
|
|
name: message.name, |
|
|
message_body: plainText, |
|
|
message_body: plainText, |
|
|
|
|
|
count: message.count || 0, |
|
|
}; |
|
|
}; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Calculate counts for each category
|
|
|
|
|
|
const counts = { |
|
|
|
|
|
chat: message_list.filter(m => m.type === 'chat').reduce((sum, msg) => sum + msg.count, 0), |
|
|
|
|
|
all: message_list.filter(m => m.type === 'channel').reduce((sum, msg) => sum + msg.count, 0), |
|
|
|
|
|
channels : message_list.reduce((sum, msg) => sum + msg.count, 0), |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
this.state.data = message_list; |
|
|
this.state.data = message_list; |
|
|
|
|
|
this.state.counts = counts; |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -56,14 +80,33 @@ export class PosMsgView extends owl.Component { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** Open chat view */ |
|
|
/** Open chat view */ |
|
|
_onClickToMessage(ev) { |
|
|
async _onClickToMessage(ev) { |
|
|
const channel_id = ev.currentTarget.getAttribute("value"); |
|
|
const channel_id = ev.currentTarget.getAttribute("value"); |
|
|
this.__owl__.remove(); |
|
|
if (!channel_id || isNaN(parseInt(channel_id))) { |
|
|
|
|
|
console.error("Invalid channel_id:", channel_id); |
|
|
|
|
|
alert("Cannot open chat: Invalid message ID"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
console.log("Channel ID:", channel_id); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const result = await rpc("/web/dataset/call_kw/mail.message/compute_read_message", { |
|
|
|
|
|
model: "mail.message", |
|
|
|
|
|
method: "compute_read_message", |
|
|
|
|
|
args: [channel_id], |
|
|
|
|
|
kwargs:{} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
if (!document.querySelector("#pos_chat_view")) { |
|
|
this.__owl__.remove(); |
|
|
this.schedule_dropdown = mount(ChatMsgView, document.body, { props: { channel_id } }); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.schedule_dropdown = mount(ChatMsgView, document.body, { props: { channel_id } }); |
|
|
this.schedule_dropdown = mount(ChatMsgView, document.body, { props: { channel_id } }); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("RPC Error Details:", { |
|
|
|
|
|
message: error.message, |
|
|
|
|
|
data: error.data, |
|
|
|
|
|
type: error.type, |
|
|
|
|
|
stack: error.stack |
|
|
|
|
|
}); |
|
|
|
|
|
alert("Failed to load chat. Please try again."); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -72,46 +115,75 @@ PosMsgView.template = xml` |
|
|
<div class="pos_systray_template" t-ref="root" |
|
|
<div class="pos_systray_template" t-ref="root" |
|
|
style="height:auto;width:350px;background-color:#f3f3f3;position:fixed;right:5px;top:49px;padding:10px;margin: 7px 14px;"> |
|
|
style="height:auto;width:350px;background-color:#f3f3f3;position:fixed;right:5px;top:49px;padding:10px;margin: 7px 14px;"> |
|
|
|
|
|
|
|
|
<div style="display:flex;height: 27px;"> |
|
|
<div style="display:flex;height: 27px;position:relative;"> |
|
|
<p style="margin-left:10px;cursor: pointer;" id="all_message_button" |
|
|
<div style="display:flex;"> |
|
|
t-on-click="_onClickAllMessage">All</p> |
|
|
<p style="margin-left:10px;cursor: pointer;" id="all_message_button" |
|
|
<p style="margin-left:10px;cursor: pointer;color:#9c9a97;" id="all_chat_button" |
|
|
t-on-click="_onClickAllMessage">All</p> |
|
|
t-on-click="_onClickAllChat">Chat</p> |
|
|
<p style="margin-left:10px;cursor: pointer;color:#9c9a97;" id="all_chat_button" |
|
|
<p style="margin-left:10px;cursor: pointer;color:#9c9a97;" id="all_channels_button" |
|
|
t-on-click="_onClickAllChat">Chat</p> |
|
|
t-on-click="_onClickAllChannels">Channels</p> |
|
|
<p style="margin-left:10px;cursor: pointer;color:#9c9a97;" id="all_channels_button" |
|
|
|
|
|
t-on-click="_onClickAllChannels">Channels</p> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- Count badges with exact positioning from image --> |
|
|
|
|
|
<span t-if="state.counts.all > 0" |
|
|
|
|
|
style="position:absolute;right:220px;top:-18px;background:#2196F3;color:white;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center;line-height:18px;" |
|
|
|
|
|
t-esc="state.counts.all"/> |
|
|
|
|
|
|
|
|
|
|
|
<span t-if="state.counts.chat > 0" |
|
|
|
|
|
style="position:absolute;right:267px;top:-19px;background:#04AA6D;color:white;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center;line-height:18px;" |
|
|
|
|
|
t-esc="state.counts.chat"/> |
|
|
|
|
|
|
|
|
|
|
|
<span t-if="state.counts.channels > 0" |
|
|
|
|
|
style="position:absolute;right:302px;top:-19px;background:#ffeb3b;color:black;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center;line-height:18px;" |
|
|
|
|
|
t-esc="state.counts.channels"/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<hr/> |
|
|
<hr/> |
|
|
|
|
|
|
|
|
|
|
|
<!-- All Messages --> |
|
|
<div id="all_message"> |
|
|
<div id="all_message"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<div style="background-color: #e7f3fe;border-left: 6px solid #2196F3; |
|
|
<div style="background-color: #e7f3fe;border-left: 6px solid #2196F3; |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;" t-att-value="data.id" |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;position:relative;" t-att-value="data.id" |
|
|
t-on-click="_onClickToMessage"> |
|
|
t-on-click="_onClickToMessage"> |
|
|
|
|
|
|
|
|
<div style="width:30px"> |
|
|
<div style="width:30px"> |
|
|
<t t-if="data.type == 'channel'"> |
|
|
<t t-if="data.type == 'channel'"> |
|
|
<i style="margin:40%" class="fa fa-users"/> |
|
|
<i style="margin:40%" class="fa fa-users"/> |
|
|
</t> |
|
|
</t> |
|
|
|
|
|
<t t-elif="data.type == 'sms_failure'"> |
|
|
|
|
|
<i style="margin:40%" class="fa fa-exclamation-triangle"/> |
|
|
|
|
|
</t> |
|
|
<t t-else=""> |
|
|
<t t-else=""> |
|
|
<i style="margin:40%" class="fa fa-user"/> |
|
|
<i style="margin:40%" class="fa fa-user"/> |
|
|
</t> |
|
|
</t> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<span t-esc="data.name"/> |
|
|
<div style="display:flex;justify-content:space-between;"> |
|
|
<br/> |
|
|
<span t-esc="data.name"/> |
|
|
<small style="color:#9c9a97;" t-raw="data.message_body"/> |
|
|
<t t-if="data.count > 0"> |
|
|
|
|
|
<span style="background-color:#2196F3;color:white;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center; |
|
|
|
|
|
line-height:18px;" t-esc="data.count"/> |
|
|
|
|
|
</t> |
|
|
|
|
|
</div> |
|
|
|
|
|
<small style="color:#9c9a97; white-space: pre-line;" t-raw="data.message_body"/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</t> |
|
|
</t> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- Chat Messages --> |
|
|
<div id="all_chat" style="display:none"> |
|
|
<div id="all_chat" style="display:none"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<t t-if="data.type == 'chat'"> |
|
|
<t t-if="data.type == 'chat'"> |
|
|
<div style="background-color: #ddffdd; border-left: 6px solid #04AA6D; |
|
|
<div style="background-color: #ddffdd;border-left: 6px solid #04AA6D; |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;" t-att-value="data.id" |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;position:relative;" t-att-value="data.id" |
|
|
t-on-click="_onClickToMessage"> |
|
|
t-on-click="_onClickToMessage"> |
|
|
|
|
|
|
|
|
<div style="width:30px"> |
|
|
<div style="width:30px"> |
|
@ -119,20 +191,27 @@ PosMsgView.template = xml` |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<span t-esc="data.name"/> |
|
|
<div style="display:flex;justify-content:space-between;"> |
|
|
<br/> |
|
|
<span t-esc="data.name"/> |
|
|
<small style="color:#9c9a97;" t-raw="data.message_body"/> |
|
|
<t t-if="data.count > 0"> |
|
|
|
|
|
<span style="background-color:#04AA6D;color:white;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center; |
|
|
|
|
|
line-height:18px;" t-esc="data.count"/> |
|
|
|
|
|
</t> |
|
|
|
|
|
</div> |
|
|
|
|
|
<small style="color:#9c9a97; white-space: pre-line;" t-raw="data.message_body"/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</t> |
|
|
</t> |
|
|
</t> |
|
|
</t> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- Channel Messages --> |
|
|
<div id="all_channels" style="display:none"> |
|
|
<div id="all_channels" style="display:none"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<t t-foreach="state.data" t-as="data" t-key="data.id"> |
|
|
<t t-if="data.type == 'channel'"> |
|
|
<t t-if="data.type == 'channel'"> |
|
|
<div style="background-color: #ffffcc;border-left: 6px solid #ffeb3b; |
|
|
<div style="background-color: #ffffcc;border-left: 6px solid #ffeb3b; |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;" t-att-value="data.id" |
|
|
margin-bottom: 15px;padding: 4px 12px;display:flex;cursor:pointer;position:relative;" t-att-value="data.id" |
|
|
t-on-click="_onClickToMessage"> |
|
|
t-on-click="_onClickToMessage"> |
|
|
|
|
|
|
|
|
<div style="width:30px"> |
|
|
<div style="width:30px"> |
|
@ -140,9 +219,15 @@ PosMsgView.template = xml` |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<div style="margin-left: 20px;width: 250px"> |
|
|
<span t-esc="data.name"/> |
|
|
<div style="display:flex;justify-content:space-between;"> |
|
|
<br/> |
|
|
<span t-esc="data.name"/> |
|
|
<small style="color:#9c9a97;" t-raw="data.message_body"/> |
|
|
<t t-if="data.count > 0"> |
|
|
|
|
|
<span style="background-color:#ffeb3b;color:black;border-radius:50%; |
|
|
|
|
|
width:18px;height:18px;font-size:10px;text-align:center; |
|
|
|
|
|
line-height:18px;" t-esc="data.count"/> |
|
|
|
|
|
</t> |
|
|
|
|
|
</div> |
|
|
|
|
|
<small style="color:#9c9a97; white-space: pre-line;" t-raw="data.message_body"/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</t> |
|
|
</t> |
|
|