Initial commit
This commit is contained in:
37
fusion_ringcentral/static/src/js/rc_click_to_dial.js
Normal file
37
fusion_ringcentral/static/src/js/rc_click_to_dial.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { PhoneField } from "@web/views/fields/phone/phone_field";
|
||||
import { rpcBus } from "@web/core/network/rpc";
|
||||
|
||||
patch(PhoneField.prototype, {
|
||||
onClickCall(ev) {
|
||||
if (window.RCAdapter) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const phoneNumber = this.props.record.data[this.props.name];
|
||||
if (phoneNumber) {
|
||||
window.RCAdapter.clickToCall(phoneNumber, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return super.onClickCall(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
rpcBus.addEventListener("RPC:RESPONSE", (ev) => {
|
||||
const { result } = ev.detail;
|
||||
if (!result || typeof result !== "object" || !window.RCAdapter) {
|
||||
return;
|
||||
}
|
||||
const infos = result.infos;
|
||||
if (!infos || !infos.rc_action || !infos.rc_phone_number) {
|
||||
return;
|
||||
}
|
||||
const { rc_action, rc_phone_number } = infos;
|
||||
if (rc_action === "call") {
|
||||
window.RCAdapter.clickToCall(rc_phone_number, true);
|
||||
} else if (rc_action === "sms") {
|
||||
window.RCAdapter.clickToSMS(rc_phone_number);
|
||||
}
|
||||
});
|
||||
86
fusion_ringcentral/static/src/js/rc_phone_widget.js
Normal file
86
fusion_ringcentral/static/src/js/rc_phone_widget.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { session } from "@web/session";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
|
||||
const RC_ADAPTER_URL = "https://apps.ringcentral.com/integration/ringcentral-embeddable/latest/adapter.js";
|
||||
|
||||
let rcWidgetLoaded = false;
|
||||
|
||||
async function loadRcWidget() {
|
||||
if (rcWidgetLoaded) return;
|
||||
|
||||
let config;
|
||||
try {
|
||||
config = await rpc("/ringcentral/widget-config", {});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!config || !config.enabled || !config.client_id) return;
|
||||
|
||||
rcWidgetLoaded = true;
|
||||
|
||||
const script = document.createElement("script");
|
||||
const params = new URLSearchParams({
|
||||
clientId: config.client_id,
|
||||
appServer: config.app_server || "https://platform.ringcentral.com",
|
||||
disableInactiveTabCallEvent: "1",
|
||||
});
|
||||
script.src = `${RC_ADAPTER_URL}?${params.toString()}`;
|
||||
document.head.appendChild(script);
|
||||
|
||||
window.addEventListener("message", (e) => {
|
||||
if (!e.data) return;
|
||||
|
||||
switch (e.data.type) {
|
||||
case "rc-login-status-notify":
|
||||
window.__rcLoggedIn = e.data.loggedIn;
|
||||
break;
|
||||
case "rc-active-call-notify":
|
||||
window.__rcActiveCall = e.data.call;
|
||||
break;
|
||||
case "rc-call-end-notify":
|
||||
_logCallToOdoo(e.data.call);
|
||||
break;
|
||||
case "rc-adapter-syncPresence":
|
||||
window.__rcPresence = {
|
||||
dndStatus: e.data.dndStatus,
|
||||
userStatus: e.data.userStatus,
|
||||
telephonyStatus: e.data.telephonyStatus,
|
||||
};
|
||||
window.dispatchEvent(new CustomEvent("rc-presence-changed", {
|
||||
detail: window.__rcPresence,
|
||||
}));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function _logCallToOdoo(call) {
|
||||
if (!call) return;
|
||||
try {
|
||||
await rpc("/web/dataset/call_kw", {
|
||||
model: "rc.call.history",
|
||||
method: "create",
|
||||
args: [{
|
||||
rc_session_id: String(call.sessionId || ""),
|
||||
direction: (call.direction || "").toLowerCase() === "inbound" ? "inbound" : "outbound",
|
||||
from_number: call.from || "",
|
||||
to_number: call.to || "",
|
||||
duration: call.duration || 0,
|
||||
status: call.duration > 0 ? "answered" : "missed",
|
||||
}],
|
||||
kwargs: {},
|
||||
});
|
||||
} catch {
|
||||
// Silently fail -- cron will catch it
|
||||
}
|
||||
}
|
||||
|
||||
registry.category("services").add("rc_phone_widget", {
|
||||
start() {
|
||||
loadRcWidget();
|
||||
},
|
||||
});
|
||||
89
fusion_ringcentral/static/src/js/rc_systray.js
Normal file
89
fusion_ringcentral/static/src/js/rc_systray.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onMounted } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
class RcSystrayItem extends Component {
|
||||
static template = "fusion_ringcentral.SystrayItem";
|
||||
static props = {};
|
||||
|
||||
setup() {
|
||||
this.state = useState({
|
||||
status: "offline",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
this._checkWidgetReady();
|
||||
window.addEventListener("rc-presence-changed", (ev) => {
|
||||
this._updatePresence(ev.detail);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_checkWidgetReady() {
|
||||
const interval = setInterval(() => {
|
||||
if (window.RCAdapter) {
|
||||
this.state.visible = true;
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 2000);
|
||||
setTimeout(() => clearInterval(interval), 30000);
|
||||
}
|
||||
|
||||
_updatePresence(presence) {
|
||||
if (!presence) return;
|
||||
this.state.visible = true;
|
||||
const userStatus = (presence.userStatus || "").toLowerCase();
|
||||
const dndStatus = (presence.dndStatus || "").toLowerCase();
|
||||
|
||||
if (dndStatus === "donotacceptanycalls") {
|
||||
this.state.status = "dnd";
|
||||
} else if (userStatus === "busy" || presence.telephonyStatus === "Ringing") {
|
||||
this.state.status = "busy";
|
||||
} else if (userStatus === "available") {
|
||||
this.state.status = "available";
|
||||
} else {
|
||||
this.state.status = "offline";
|
||||
}
|
||||
}
|
||||
|
||||
get statusColor() {
|
||||
const colors = {
|
||||
available: "text-success",
|
||||
busy: "text-danger",
|
||||
dnd: "text-warning",
|
||||
offline: "text-muted",
|
||||
};
|
||||
return colors[this.state.status] || "text-muted";
|
||||
}
|
||||
|
||||
get statusTitle() {
|
||||
const titles = {
|
||||
available: "Available",
|
||||
busy: "Busy",
|
||||
dnd: "Do Not Disturb",
|
||||
offline: "Offline",
|
||||
};
|
||||
return titles[this.state.status] || "RingCentral";
|
||||
}
|
||||
|
||||
onClick() {
|
||||
if (window.RCAdapter) {
|
||||
const frame = document.querySelector("#rc-widget-adapter-frame");
|
||||
if (frame) {
|
||||
const isMinimized = frame.style.display === "none" ||
|
||||
frame.closest("[style*='display: none']");
|
||||
if (isMinimized) {
|
||||
window.RCAdapter.setMinimized(false);
|
||||
} else {
|
||||
window.RCAdapter.setMinimized(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registry.category("systray").add("fusion_ringcentral.SystrayItem", {
|
||||
Component: RcSystrayItem,
|
||||
}, { sequence: 5 });
|
||||
11
fusion_ringcentral/static/src/xml/rc_systray.xml
Normal file
11
fusion_ringcentral/static/src/xml/rc_systray.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="fusion_ringcentral.SystrayItem">
|
||||
<div class="o_nav_entry" t-if="state.visible" t-on-click="onClick"
|
||||
t-att-title="statusTitle" role="button" style="cursor: pointer;">
|
||||
<i class="fa fa-phone fa-fw" t-att-class="statusColor"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
Reference in New Issue
Block a user