skailan-conversations
Version:
Servicio de conversaciones y mensajería para Skailan
240 lines • 8.39 kB
JavaScript
export class MessageDisplayService {
/**
* Convierte un mensaje de la base de datos a formato de visualización
*/
formatMessageForDisplay(message) {
const isOutgoing = message.senderType === "system" || message.senderType === "bot";
// Determinar el tipo de mensaje basado en el contenido y metadata
const messageType = this.determineMessageType(message);
// Obtener información del remitente
const senderInfo = this.getSenderInfo(message);
// Extraer metadata específica del canal
const metadata = this.extractChannelMetadata(message);
return {
id: message.id,
content: message.content || "",
type: messageType,
senderType: message.senderType,
senderId: message.senderId,
senderName: senderInfo.name,
senderAvatar: senderInfo.avatar,
timestamp: message.timestamp,
status: message.status,
isOutgoing,
channelType: this.determineChannelType(message),
metadata,
};
}
/**
* Convierte una conversación a formato de visualización
*/
formatConversationForDisplay(conversation, lastMessage, unreadCount = 0) {
const participants = this.getConversationParticipants(conversation);
return {
id: conversation.id,
title: `Conversación ${conversation.id.slice(0, 8)}`,
status: conversation.status,
lastMessage: lastMessage
? this.formatMessageForDisplay(lastMessage)
: undefined,
unreadCount,
participants,
channelType: this.determineChannelTypeFromConversation(conversation),
createdAt: conversation.createdAt,
updatedAt: conversation.updatedAt,
};
}
/**
* Determina el tipo de mensaje basado en el contenido
*/
determineMessageType(message) {
// Si hay mediaUrl, determinar tipo por extensión
if (message.mediaUrl) {
const extension = message.mediaUrl.split(".").pop()?.toLowerCase();
if (["jpg", "jpeg", "png", "gif", "webp"].includes(extension || "")) {
return "image";
}
if (["mp4", "avi", "mov", "wmv"].includes(extension || "")) {
return "video";
}
if (["mp3", "wav", "ogg", "m4a"].includes(extension || "")) {
return "audio";
}
return "document";
}
// Si el contenido es JSON, podría ser un mensaje especial
try {
const parsed = JSON.parse(message.content || "");
if (parsed.type === "location")
return "location";
if (parsed.type === "contact")
return "contact";
}
catch {
// No es JSON, continuar
}
return "text";
}
/**
* Obtiene información del remitente
*/
getSenderInfo(message) {
switch (message.senderType) {
case "system":
return {
name: "Sistema",
avatar: "/avatars/system.png",
};
case "bot":
return {
name: "Bot de Telegram",
avatar: "/avatars/bot.png",
};
case "user":
return {
name: `Usuario ${message.senderId.slice(0, 8)}`,
avatar: `/avatars/user-${message.senderId.slice(0, 8)}.png`,
};
default:
return {
name: "Usuario",
avatar: "/avatars/default.png",
};
}
}
/**
* Extrae metadata específica del canal
*/
extractChannelMetadata(message) {
const metadata = {};
// Extraer Telegram Message ID si existe
if (message.externalMessageId) {
metadata.telegramMessageId = parseInt(message.externalMessageId);
}
// Si el contenido es JSON, extraer metadata adicional
try {
const parsed = JSON.parse(message.content || "");
if (parsed.replyToMessageId) {
metadata.replyToMessageId = parsed.replyToMessageId;
}
if (parsed.inlineKeyboard) {
metadata.inlineKeyboard = parsed.inlineKeyboard;
}
if (parsed.fileUrl) {
metadata.fileUrl = parsed.fileUrl;
}
if (parsed.fileName) {
metadata.fileName = parsed.fileName;
}
if (parsed.fileSize) {
metadata.fileSize = parsed.fileSize;
}
if (parsed.mimeType) {
metadata.mimeType = parsed.mimeType;
}
}
catch {
// No es JSON, continuar
}
return metadata;
}
/**
* Determina el tipo de canal basado en el mensaje
*/
determineChannelType(message) {
// Basado en el senderId o metadata
if (message.senderId.includes("telegram") ||
message.senderId.includes("bot")) {
return "telegram";
}
if (message.senderId.includes("whatsapp")) {
return "whatsapp";
}
if (message.senderId.includes("email")) {
return "email";
}
return "web";
}
/**
* Determina el tipo de canal basado en la conversación
*/
determineChannelTypeFromConversation(conversation) {
// Basado en el channelId o metadata de la conversación
if (conversation.channelId?.includes("telegram")) {
return "telegram";
}
if (conversation.channelId?.includes("whatsapp")) {
return "whatsapp";
}
if (conversation.channelId?.includes("email")) {
return "email";
}
return "web";
}
/**
* Obtiene los participantes de una conversación
*/
getConversationParticipants(conversation) {
const participants = [];
// Agregar usuario asignado si existe
if (conversation.assignedToUserId) {
participants.push({
id: conversation.assignedToUserId,
name: `Agente ${conversation.assignedToUserId.slice(0, 8)}`,
avatar: `/avatars/agent-${conversation.assignedToUserId.slice(0, 8)}.png`,
type: "user",
});
}
// Agregar bot del canal
participants.push({
id: "bot",
name: "Bot de Telegram",
avatar: "/avatars/bot.png",
type: "bot",
});
return participants;
}
/**
* Formatea timestamp para visualización
*/
formatTimestamp(timestamp) {
const now = new Date();
const diff = now.getTime() - timestamp.getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1)
return "Ahora";
if (minutes < 60)
return `Hace ${minutes} min`;
if (hours < 24)
return `Hace ${hours} h`;
if (days < 7)
return `Hace ${days} días`;
return timestamp.toLocaleDateString("es-ES", {
day: "2-digit",
month: "2-digit",
year: "2-digit",
});
}
/**
* Obtiene el estado visual del mensaje
*/
getMessageStatusDisplay(status) {
switch (status) {
case "sent":
return { text: "Enviado", icon: "✓", color: "text-gray-500" };
case "delivered":
return { text: "Entregado", icon: "✓✓", color: "text-blue-500" };
case "read":
return { text: "Leído", icon: "✓✓", color: "text-green-500" };
case "failed":
return { text: "Error", icon: "✗", color: "text-red-500" };
case "pending":
return { text: "Enviando...", icon: "⏳", color: "text-yellow-500" };
default:
return { text: "Desconocido", icon: "?", color: "text-gray-400" };
}
}
}
//# sourceMappingURL=MessageDisplayService.js.map