|
|
@@ -1,5 +1,5 @@
|
|
|
//--- Imports ---
|
|
|
-import { sendMessage as serviceSendMessage } from './service/chat.js';
|
|
|
+import { getUserList } from './service/chat.js';
|
|
|
import { getProducts, sendOrder } from './service/product.js';
|
|
|
import { login } from './service/auth.js';
|
|
|
import { createGlobalLoader, showGlobalLoader, hideGlobalLoader } from './utils/loader.js';
|
|
|
@@ -191,6 +191,7 @@ function initializeWebSocket() {
|
|
|
}
|
|
|
chatWebsocket.onmessage = (event) => {
|
|
|
const data = JSON.parse(event.data);
|
|
|
+ console.log("Event:", data);
|
|
|
if (data.type === "message") {
|
|
|
displayChatMessage(data.username, data.message);
|
|
|
}
|
|
|
@@ -200,6 +201,10 @@ function initializeWebSocket() {
|
|
|
else if (data.type === "leave") {
|
|
|
userLeftChat(data.username);
|
|
|
}
|
|
|
+ else if (data.type === "mentioned") {
|
|
|
+ if (data.username && data.username !== chatUserName) return; // not for me
|
|
|
+ showMentioned();
|
|
|
+ }
|
|
|
else if (data.type === "ping") {
|
|
|
chatWebsocket.send(JSON.stringify({
|
|
|
type: "pong"
|
|
|
@@ -209,8 +214,42 @@ function initializeWebSocket() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+async function sendMessage(message) {
|
|
|
+ if (chatWebsocket) {
|
|
|
+ if (chatWebsocket.readyState !== WebSocket.OPEN) {
|
|
|
+ console.error("WebSocket is not open, reopening...");
|
|
|
+ chatWebsocket = null;
|
|
|
+ initializeWebSocket();
|
|
|
+ }
|
|
|
+ await chatWebsocket.send(JSON.stringify({
|
|
|
+ type: "message",
|
|
|
+ username: chatUserName,
|
|
|
+ message: message
|
|
|
+ }));
|
|
|
+ await setTimeout(() => {
|
|
|
+ const mentionRegex = /@([a-zA-Z0-9_]+_mesa\d+|IAKlein)/g;
|
|
|
+ const mentions = message.match(mentionRegex);
|
|
|
+ if (mentions) {
|
|
|
+ mentions.forEach(mention => {
|
|
|
+ const username = mention.slice(1);
|
|
|
+ if (username === "IAKlein"){
|
|
|
+ sendMessageToAI(message);
|
|
|
+ }else {
|
|
|
+ userMentioned(username);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, 1000); // small delay to ensure message order
|
|
|
+ // regex text_mesa111 or IAKlein
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+function userMentioned(username) {
|
|
|
+ chatWebsocket.send(JSON.stringify({
|
|
|
+ type: "mention",
|
|
|
+ username: username
|
|
|
+ }));
|
|
|
+}
|
|
|
/**
|
|
|
* Initialize chat functionality
|
|
|
*/
|
|
|
@@ -221,21 +260,35 @@ function initializeChat() {
|
|
|
if (chatInputElement.value.trim() === "") return;
|
|
|
|
|
|
// sendMessageToAI();
|
|
|
- if (chatWebsocket) {
|
|
|
- chatWebsocket.send(JSON.stringify({
|
|
|
- type: "message",
|
|
|
- username: chatUserName,
|
|
|
- message: chatInputElement.value
|
|
|
- }));
|
|
|
- chatInputElement.value = "";
|
|
|
- }
|
|
|
- // displayChatMessage(chatUserName, chatInputElement.value)
|
|
|
+ sendMessage(chatInputElement.value.trim());
|
|
|
+ chatInputElement.value = "";
|
|
|
});
|
|
|
- chatInputElement.addEventListener("input", () => {
|
|
|
+ chatInputElement.addEventListener("input", async () => {
|
|
|
const lastWord = chatInputElement.value.split(" ").at(-1)
|
|
|
if (lastWord.trim().startsWith("@")) {
|
|
|
+ console.log("Detectado @ en el input, buscando usuarios...");
|
|
|
userList.classList.remove("hidden")
|
|
|
-
|
|
|
+ console.log("Buscando usuarios para:", lastWord.trim().substring(1));
|
|
|
+ let users = await getUserList(lastWord.trim().substring(1), userToken)
|
|
|
+ users = users.filter(u => u !== chatUserName)
|
|
|
+ users.push("IAKlein")
|
|
|
+ userList.innerHTML = ""
|
|
|
+ users.forEach(user => {
|
|
|
+ const userItem = document.createElement("button");
|
|
|
+ userItem.type = "button"
|
|
|
+ userItem.onclick = () => {
|
|
|
+ chatInputElement.value = chatInputElement.value.replace(lastWord, `@${user}`);
|
|
|
+ userList.classList.add("hidden");
|
|
|
+ };
|
|
|
+ console.log(user);
|
|
|
+ const color = getUserColor(user);
|
|
|
+ userItem.classList.add("list-user-name");
|
|
|
+ userItem.classList.add("cursor-pointer");
|
|
|
+ userItem.classList.add(color);
|
|
|
+
|
|
|
+ userItem.textContent = user;
|
|
|
+ userList.appendChild(userItem);
|
|
|
+ });
|
|
|
}else{
|
|
|
userList.classList.add("hidden")
|
|
|
}
|
|
|
@@ -750,14 +803,46 @@ async function processOrder() {
|
|
|
* Display chat message with proper styling
|
|
|
*/
|
|
|
|
|
|
+function showMentioned(){
|
|
|
+ const chatButton = document.querySelector("#chatIcon span");
|
|
|
+
|
|
|
+ if (chatButton) {
|
|
|
+ //get after element
|
|
|
+ console.log("Mostrando mención en el botón de chat");
|
|
|
+ chatButton.classList.remove("hidden");
|
|
|
+ chatButton.animate(
|
|
|
+ [
|
|
|
+ { transform: 'scale(1)' },
|
|
|
+ { transform: 'scale(1.5)' },
|
|
|
+ { transform: 'scale(1)' }
|
|
|
+ ],
|
|
|
+ {
|
|
|
+ duration: 300,
|
|
|
+ iterations: 3,
|
|
|
+ easing: 'ease-in-out'
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+window.hideMentioned = function(){
|
|
|
+ const chatButton = document.querySelector("#chatIcon span");
|
|
|
+ if (chatButton) {
|
|
|
+ chatButton.classList.add("hidden");
|
|
|
+ }
|
|
|
+}
|
|
|
function getUserColor(username) {
|
|
|
const hash = [...username].reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
|
- return userColors[hash % userColors.length];
|
|
|
+ console.log(userColors.length)
|
|
|
+ const color = userColors[hash % userColors.length];
|
|
|
+ console.log(`User: ${username}, Hash: ${hash}, Color: ${color}`);
|
|
|
+
|
|
|
+ return color;
|
|
|
}
|
|
|
|
|
|
function displayChatMessage(sender, message, time = undefined) {
|
|
|
console.log(`[${sender.toUpperCase()}] ${message}`);
|
|
|
- let realtime = `[${time ? time : new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}] `;
|
|
|
+ let realtime = `[${time ? time : new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })}] `;
|
|
|
let messageTemplate = chatMessagesElement.querySelector("#chatMessageTemplate");
|
|
|
if (!messageTemplate) return;
|
|
|
|
|
|
@@ -774,8 +859,11 @@ function newUserInChat(userName) {
|
|
|
let userTemplate = chatMessagesElement.querySelector("#systemMessageTemplate");
|
|
|
if (!userTemplate) return;
|
|
|
|
|
|
+ const realtime = `[${new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })}] `;
|
|
|
+
|
|
|
let userClone = userTemplate.content.cloneNode(true).firstElementChild;
|
|
|
userClone.classList.add("text-green-600");
|
|
|
+ userClone.querySelector(".chat-message-time").innerHTML = realtime;
|
|
|
userClone.querySelector(".chat-message-text").innerHTML = `*** ${userName} se ha unido al chat`;
|
|
|
chatMessagesElement.appendChild(userClone);
|
|
|
}
|
|
|
@@ -784,54 +872,33 @@ function userLeftChat(userName) {
|
|
|
let userTemplate = chatMessagesElement.querySelector("#systemMessageTemplate");
|
|
|
if (!userTemplate) return;
|
|
|
|
|
|
+ const realtime = `[${new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })}] `;
|
|
|
+
|
|
|
let userClone = userTemplate.content.cloneNode(true).firstElementChild;
|
|
|
userClone.classList.add("text-red-600");
|
|
|
+ userClone.querySelector(".chat-message-time").innerHTML = realtime;
|
|
|
userClone.querySelector(".chat-message-text").innerHTML = `*** ${userName} se ha ido del chat`;
|
|
|
chatMessagesElement.appendChild(userClone);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Send message to AI service
|
|
|
- */
|
|
|
-async function sendMessageToAI() {
|
|
|
- if (!chatInputElement || !aiLoadingIndicator) return;
|
|
|
-
|
|
|
- const userInput = chatInputElement.value.trim();
|
|
|
- if (!userInput) return;
|
|
|
+function sendMessageToAI() {
|
|
|
+ const userMessage = chatInputElement.value.trim();
|
|
|
+ if (userMessage === "") return;
|
|
|
+ const messages = Array.from(chatMessagesElement.querySelectorAll(".chat-message")).slice(-10);
|
|
|
+ let formattedMessages = messages.map(msg => {
|
|
|
+ const sender = msg.querySelector(".chat-message-user").textContent;
|
|
|
+ const content = msg.querySelector(".chat-message-text").innerHTML;
|
|
|
+ return { user: sender, content: content };
|
|
|
+ });
|
|
|
|
|
|
- displayChatMessage("user", userInput);
|
|
|
- chatSuggestionsElement.classList.add("hidden");
|
|
|
- chatInputElement.value = '';
|
|
|
- aiLoadingIndicator.classList.remove("hidden");
|
|
|
|
|
|
- try {
|
|
|
- const response = await serviceSendMessage(userInput, chatHistory, userName, userToken);
|
|
|
-
|
|
|
- if (!response) {
|
|
|
- displayChatMessage("ai", "Hubo un problema al conectar con el Chef IA.");
|
|
|
- } else if (response === "not_init") {
|
|
|
- if (await initializeService()) {
|
|
|
- const retryResponse = await serviceSendMessage(userInput, chatHistory, userName, userToken);
|
|
|
- if (retryResponse) {
|
|
|
- chatHistory = retryResponse.messageList;
|
|
|
- displayChatMessage("ai", retryResponse.assistantResponse);
|
|
|
- } else {
|
|
|
- displayChatMessage("ai", "Hubo un problema al enviar el mensaje.");
|
|
|
- }
|
|
|
- } else {
|
|
|
- displayChatMessage("ai", "Fallo la reconexión. Por favor, refresca la página.");
|
|
|
- }
|
|
|
- } else if (response.assistantResponse) {
|
|
|
- chatHistory = response.messageList;
|
|
|
- displayChatMessage("ai", response.assistantResponse);
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error("Error enviando mensaje a IA:", error);
|
|
|
- displayChatMessage("ai", `Error: ${error.message || "No se pudo conectar con el Chef IA."}`);
|
|
|
- } finally {
|
|
|
- aiLoadingIndicator.classList.add("hidden");
|
|
|
- if (chatInputElement) chatInputElement.focus();
|
|
|
- }
|
|
|
+ chatWebsocket.send(JSON.stringify({
|
|
|
+ type: "ai_message",
|
|
|
+ username: chatUserName,
|
|
|
+ messages: formattedMessages
|
|
|
+ }));
|
|
|
+ chatInputElement.value = "";
|
|
|
+
|
|
|
}
|
|
|
//--- Sistema de Recompensas ---
|
|
|
|
|
|
@@ -916,31 +983,7 @@ function closeModal() {
|
|
|
claimRewardBtn.classList.add('opacity-50', 'cursor-not-allowed');
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Show reward success notification
|
|
|
- */
|
|
|
-function showRewardSuccess(code) {
|
|
|
- const successToast = document.createElement('div');
|
|
|
- successToast.className = `
|
|
|
- fixed top-4 left-1/2 transform -translate-x-1/2
|
|
|
- bg-green-500 text-white text-sm rounded-lg px-6 py-4
|
|
|
- shadow-lg z-50 max-w-sm text-center
|
|
|
- `;
|
|
|
- successToast.innerHTML = `
|
|
|
- <div class="font-bold mb-1">🎉 ¡Premio Reclamado!</div>
|
|
|
- <div class="text-xs opacity-90">Tu código: <strong>${code}</strong></div>
|
|
|
- <div class="text-xs mt-1 opacity-80">Muéstralo al mesero</div>
|
|
|
- `;
|
|
|
-
|
|
|
- document.body.appendChild(successToast);
|
|
|
-
|
|
|
- // Remove after 5 seconds
|
|
|
- setTimeout(() => {
|
|
|
- if (successToast.parentNode) {
|
|
|
- successToast.remove();
|
|
|
- }
|
|
|
- }, 5000);
|
|
|
-}
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* Reset reward progress to 0%
|
|
|
@@ -972,7 +1015,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
createGlobalLoader();
|
|
|
// Uncomment these lines when ready to initialize the full app:
|
|
|
initializeLoginModal();
|
|
|
- hideGUI();
|
|
|
+ // hideGUI();
|
|
|
// initializeApp();
|
|
|
});
|
|
|
|