diff --git a/odoo_whatsapp_hub/static/src/js/chat_widget.js b/odoo_whatsapp_hub/static/src/js/chat_widget.js new file mode 100644 index 0000000..75160d6 --- /dev/null +++ b/odoo_whatsapp_hub/static/src/js/chat_widget.js @@ -0,0 +1,120 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { Component, useState, onWillStart, onMounted } from "@odoo/owl"; + +export class WhatsAppChatWidget extends Component { + static template = "odoo_whatsapp_hub.ChatWidget"; + static props = { + conversationId: { type: Number, optional: true }, + partnerId: { type: Number, optional: true }, + }; + + setup() { + this.orm = useService("orm"); + this.state = useState({ + conversation: null, + messages: [], + newMessage: "", + loading: true, + }); + + onWillStart(async () => { + await this.loadConversation(); + }); + + onMounted(() => { + this.scrollToBottom(); + }); + } + + async loadConversation() { + this.state.loading = true; + + try { + if (this.props.conversationId) { + const conversations = await this.orm.searchRead( + "whatsapp.conversation", + [["id", "=", this.props.conversationId]], + ["id", "display_name", "phone_number", "status"] + ); + if (conversations.length) { + this.state.conversation = conversations[0]; + await this.loadMessages(); + } + } + } finally { + this.state.loading = false; + } + } + + async loadMessages() { + if (!this.state.conversation) return; + + const messages = await this.orm.searchRead( + "whatsapp.message", + [["conversation_id", "=", this.state.conversation.id]], + ["id", "direction", "content", "message_type", "status", "create_date"], + { order: "create_date asc" } + ); + this.state.messages = messages; + + const unreadIds = messages + .filter(m => m.direction === "inbound" && !m.is_read) + .map(m => m.id); + if (unreadIds.length) { + await this.orm.write("whatsapp.message", unreadIds, { is_read: true }); + } + + this.scrollToBottom(); + } + + async sendMessage() { + if (!this.state.newMessage.trim() || !this.state.conversation) return; + + const content = this.state.newMessage; + this.state.newMessage = ""; + + await this.orm.call( + "whatsapp.message", + "send_message", + [this.state.conversation.id, content] + ); + + await this.loadMessages(); + } + + scrollToBottom() { + const container = document.querySelector(".o_whatsapp_messages"); + if (container) { + container.scrollTop = container.scrollHeight; + } + } + + formatTime(dateStr) { + if (!dateStr) return ""; + const date = new Date(dateStr); + return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); + } + + getStatusIcon(status) { + const icons = { + pending: "fa-clock-o", + sent: "fa-check", + delivered: "fa-check-double text-muted", + read: "fa-check-double text-primary", + failed: "fa-exclamation-circle text-danger", + }; + return icons[status] || ""; + } + + onKeyPress(ev) { + if (ev.key === "Enter" && !ev.shiftKey) { + ev.preventDefault(); + this.sendMessage(); + } + } +} + +registry.category("public_components").add("WhatsAppChatWidget", WhatsAppChatWidget); diff --git a/odoo_whatsapp_hub/static/src/xml/chat_widget.xml b/odoo_whatsapp_hub/static/src/xml/chat_widget.xml new file mode 100644 index 0000000..f4518e2 --- /dev/null +++ b/odoo_whatsapp_hub/static/src/xml/chat_widget.xml @@ -0,0 +1,57 @@ + + + +
+ +
+ +
+
+ + +
+
+ +
+
+
+
+
+
+ + +
+ +
+
+
+ + + + +
+
+ +
+ + +
+ + +
+
+ +
+ Selecciona una conversación +
+
+
+ +