Oleada UX 7: Chat (presencia, busqueda en historial) y WACRM (metricas para gerencia, notas internas y etiquetas que sobreviven al sync) + fixes de concurrencia
This commit is contained in:
@@ -626,6 +626,43 @@ export interface WacrmConversation {
|
||||
last_message_at: string | null;
|
||||
unread_count: number;
|
||||
created_at: string | null;
|
||||
tags?: { id: number; name: string; color: string }[];
|
||||
}
|
||||
|
||||
export interface WacrmTag {
|
||||
id: number;
|
||||
name: string;
|
||||
color: string;
|
||||
sequence: number;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface WacrmNote {
|
||||
id: number;
|
||||
body: string;
|
||||
author: string;
|
||||
date: string | null;
|
||||
resolved: boolean;
|
||||
resolved_at: string | null;
|
||||
resolved_by: string;
|
||||
}
|
||||
|
||||
export interface WacrmMetrics {
|
||||
status: string;
|
||||
generado: string;
|
||||
periodo: { desde: string; hasta: string };
|
||||
sin_respuesta_horas: number;
|
||||
conversaciones: { hoy: number; semana: number; mes: number; total: number };
|
||||
mensajes: {
|
||||
hoy: { entrantes: number; salientes: number };
|
||||
semana: { entrantes: number; salientes: number };
|
||||
mes: { entrantes: number; salientes: number };
|
||||
};
|
||||
primera_respuesta: { muestras: number; promedio_min: number | null; mediana_min: number | null };
|
||||
sin_responder: { total: number; horas_minimas: number; detalle: { conversation_id: string; horas: number; ultimo_mensaje: string }[] };
|
||||
leads: { ganados: number; perdidos: number; abiertos: number; valor_ganado: number };
|
||||
criterios: Record<string, string>;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface WacrmMessage {
|
||||
@@ -713,6 +750,8 @@ export interface ChatUser {
|
||||
last_message: string | null;
|
||||
last_date: string | null;
|
||||
last_mine: boolean | null;
|
||||
online: boolean;
|
||||
last_seen: string | null;
|
||||
}
|
||||
|
||||
export interface ChatMessage {
|
||||
@@ -1180,8 +1219,24 @@ export const odooApi = {
|
||||
return data;
|
||||
},
|
||||
|
||||
async getChatMessages(userId: number, sinceId?: number): Promise<{ status: string; messages: ChatMessage[] }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/chat/messages`, { user_id: userId, since_id: sinceId || undefined });
|
||||
async getChatMessages(userId: number, sinceId?: number, aroundId?: number): Promise<{ status: string; messages: ChatMessage[]; around_id?: number | null }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/chat/messages`, {
|
||||
user_id: userId,
|
||||
since_id: sinceId || undefined,
|
||||
around_id: aroundId || undefined,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/** Búsqueda en el historial con otro usuario (servidor). */
|
||||
async searchChatMessages(userId: number, q: string, limit = 50): Promise<{ status: string; query: string; count: number; results: ChatMessage[] }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/chat/search`, { user_id: userId, q, limit });
|
||||
return data;
|
||||
},
|
||||
|
||||
/** Latido de presencia (se manda cada ~30 s con la app abierta). */
|
||||
async chatHeartbeat(): Promise<{ status: string; online_count: number; online_window_seconds: number }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/chat/heartbeat`);
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -1860,6 +1915,59 @@ export const odooApi = {
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Notas internas ----
|
||||
async getWacrmNotes(conversationId: string): Promise<{ status: string; notes: WacrmNote[]; pendientes: number }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/wacrm/conversations/${conversationId}/notes`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async createWacrmNote(conversationId: string, body: string): Promise<{ status: string; note: WacrmNote }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/wacrm/conversations/${conversationId}/notes`, { body });
|
||||
return data;
|
||||
},
|
||||
|
||||
async updateWacrmNote(noteId: number, payload: { body?: string; resolved?: boolean }): Promise<{ status: string; note: WacrmNote }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/wacrm/notes/${noteId}`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteWacrmNote(noteId: number): Promise<{ status: string; message: string }> {
|
||||
const { data } = await axios.delete(`${ODOO_BASE}/skeen/frontend/v1/wacrm/notes/${noteId}`);
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Etiquetas ----
|
||||
async getWacrmTags(): Promise<{ status: string; tags: WacrmTag[] }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/wacrm/tags`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async createWacrmTag(payload: { name: string; color?: string; sequence?: number }): Promise<{ status: string; tag: WacrmTag }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/wacrm/tags`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async updateWacrmTag(tagId: number, payload: Partial<WacrmTag>): Promise<{ status: string; tag: WacrmTag }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/wacrm/tags/${tagId}`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteWacrmTag(tagId: number): Promise<{ status: string; message: string }> {
|
||||
const { data } = await axios.delete(`${ODOO_BASE}/skeen/frontend/v1/wacrm/tags/${tagId}`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async assignWacrmTag(conversationId: string, tagId: number, action: 'add' | 'remove' = 'add'): Promise<{ status: string; tags: { id: number; name: string; color: string }[] }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/wacrm/conversations/${conversationId}/tags`, { tag_id: tagId, action });
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Métricas para gerencia ----
|
||||
async getWacrmMetrics(params?: { sin_respuesta_horas?: number }): Promise<WacrmMetrics> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/wacrm/metrics`, { params });
|
||||
return data;
|
||||
},
|
||||
|
||||
async sendWacrmMessage(payload: { conversation_id: string; text: string; assigned_agent_id: string }): Promise<{ status: string; message: string }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/wacrm/messages`, payload);
|
||||
return data;
|
||||
|
||||
Reference in New Issue
Block a user