vue-wiguet-chatweb 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +1 -1
- package/dist/vue-wiguet-chatweb.js +1789 -1758
- package/dist/vue-wiguet-chatweb.umd.cjs +6 -6
- package/package.json +1 -1
- package/src/components/Chat.vue +116 -57
- package/src/components/MessageList.vue +36 -8
package/package.json
CHANGED
package/src/components/Chat.vue
CHANGED
@@ -28,7 +28,11 @@
|
|
28
28
|
required
|
29
29
|
ref="textAreaRef"
|
30
30
|
@input="() => autoAdjustHeight()"
|
31
|
-
@keydown.enter
|
31
|
+
@keydown.enter="
|
32
|
+
(event) => {
|
33
|
+
!isMovil && event.preventDefault();
|
34
|
+
}
|
35
|
+
"
|
32
36
|
@keyup.enter="saltoDeLineaOEnviar"
|
33
37
|
/>
|
34
38
|
|
@@ -43,7 +47,15 @@
|
|
43
47
|
</template>
|
44
48
|
|
45
49
|
<script setup lang="ts">
|
46
|
-
import {
|
50
|
+
import {
|
51
|
+
ref,
|
52
|
+
onMounted,
|
53
|
+
nextTick,
|
54
|
+
PropType,
|
55
|
+
watch,
|
56
|
+
onUnmounted,
|
57
|
+
computed,
|
58
|
+
} from "vue";
|
47
59
|
import { v4 as uuidv4 } from "uuid";
|
48
60
|
|
49
61
|
import {
|
@@ -109,8 +121,8 @@ const messageContainerRef = ref<HTMLElement | null>(null);
|
|
109
121
|
watch(
|
110
122
|
() => props.visible,
|
111
123
|
async (current) => {
|
112
|
-
if(!current) return
|
113
|
-
|
124
|
+
if (!current) return;
|
125
|
+
|
114
126
|
emit("clear-new-messages");
|
115
127
|
scrollToBottom();
|
116
128
|
|
@@ -122,18 +134,23 @@ watch(
|
|
122
134
|
|
123
135
|
const resp = await getInformationApi(props.tokenAuth);
|
124
136
|
|
125
|
-
if(resp) {
|
137
|
+
if (resp) {
|
126
138
|
appChatId.value = resp.appChat.id;
|
127
139
|
}
|
128
140
|
}
|
129
141
|
);
|
130
142
|
|
131
143
|
function saltoDeLineaOEnviar(event: KeyboardEvent) {
|
144
|
+
if(isMovil.value) {
|
145
|
+
autoAdjustHeight();
|
146
|
+
return;
|
147
|
+
}
|
148
|
+
|
132
149
|
if (event.key === "Enter" && event.shiftKey) {
|
133
|
-
const val = (event.target as any)?.value ||
|
150
|
+
const val = (event.target as any)?.value || "";
|
134
151
|
(event.target as any).value = val + "\n";
|
135
|
-
autoAdjustHeight()
|
136
|
-
return
|
152
|
+
autoAdjustHeight();
|
153
|
+
return;
|
137
154
|
}
|
138
155
|
|
139
156
|
submitMessage(event);
|
@@ -149,7 +166,7 @@ const submitMessage = async (event: Event) => {
|
|
149
166
|
});
|
150
167
|
return;
|
151
168
|
}
|
152
|
-
|
169
|
+
|
153
170
|
if (!message.value.trim()) {
|
154
171
|
emit("show-toast", {
|
155
172
|
severity: "warn",
|
@@ -176,11 +193,11 @@ const submitMessage = async (event: Event) => {
|
|
176
193
|
msPersonaId: props.user.msPersonaId,
|
177
194
|
},
|
178
195
|
};
|
179
|
-
|
196
|
+
|
180
197
|
const idx = messagesData.value.data.push(newMessage) - 1;
|
181
|
-
|
182
|
-
sendApi(message.value, appChatId.value).then((newMsg)=>{
|
183
|
-
if(!newMsg) {
|
198
|
+
|
199
|
+
sendApi(message.value, appChatId.value).then((newMsg) => {
|
200
|
+
if (!newMsg) {
|
184
201
|
messagesData.value.data[idx].error = {
|
185
202
|
error: true,
|
186
203
|
id: newMessage.id,
|
@@ -194,13 +211,13 @@ const submitMessage = async (event: Event) => {
|
|
194
211
|
});
|
195
212
|
} else {
|
196
213
|
messagesData.value.data[idx] = newMsg;
|
197
|
-
|
198
|
-
const message = {...newMsg, chatId:newMessage.chatId }
|
214
|
+
|
215
|
+
const message = { ...newMsg, chatId: newMessage.chatId };
|
199
216
|
socketService.value?.emit(
|
200
|
-
|
217
|
+
"sendMessage",
|
201
218
|
{ roomId: information?.value?.appChat.id, message },
|
202
219
|
(response: any) => {
|
203
|
-
console.log(
|
220
|
+
console.log("🚀 ~ socketService.value.emit ~ response:", response);
|
204
221
|
}
|
205
222
|
);
|
206
223
|
}
|
@@ -208,7 +225,7 @@ const submitMessage = async (event: Event) => {
|
|
208
225
|
|
209
226
|
message.value = "";
|
210
227
|
scrollToBottom();
|
211
|
-
textAreaRef.value && (textAreaRef.value.style.height = "20px")
|
228
|
+
textAreaRef.value && (textAreaRef.value.style.height = "20px");
|
212
229
|
};
|
213
230
|
|
214
231
|
const sendApi = async (message: string, appChatId: string) => {
|
@@ -221,37 +238,35 @@ const sendApi = async (message: string, appChatId: string) => {
|
|
221
238
|
};
|
222
239
|
|
223
240
|
const getMessages = async () => {
|
224
|
-
|
225
241
|
const lastMessagesId = messagesData.value.data[0]?.id;
|
226
242
|
const body: ListMessageBody = {
|
227
243
|
lastMessagesId,
|
228
244
|
appChatId: appChatId.value,
|
229
|
-
limit: 10
|
245
|
+
limit: 10,
|
230
246
|
};
|
231
247
|
|
232
248
|
isLoading.value = true;
|
233
249
|
const resp = await getMessagesApi({ body, token: props.tokenAuth });
|
234
250
|
isLoading.value = false;
|
235
|
-
|
251
|
+
|
236
252
|
messagesData.value.data.unshift(
|
237
253
|
...resp.data.sort((a, b) => -b.createdAt.localeCompare(a.createdAt))
|
238
254
|
);
|
239
|
-
|
255
|
+
|
240
256
|
messagesData.value.canLoadMoreMessages =
|
241
257
|
resp.pagination.total > resp.pagination.size;
|
242
|
-
|
258
|
+
|
243
259
|
if (lastMessagesId && messageContainerRef.value?.scrollHeight) {
|
244
260
|
mantainElementsOnViewport(messageContainerRef.value?.scrollHeight);
|
245
261
|
}
|
246
|
-
|
262
|
+
|
247
263
|
if (!lastMessagesId) scrollToBottom();
|
248
264
|
};
|
249
265
|
|
250
266
|
const retryMessage = async (message: Message) => {
|
251
267
|
emit("show-confirm", async () => {
|
252
|
-
|
253
268
|
if (!message.error?.id) return;
|
254
|
-
|
269
|
+
|
255
270
|
const msg = await sendApi(message.message, appChatId.value);
|
256
271
|
|
257
272
|
if (!msg) {
|
@@ -267,13 +282,13 @@ const retryMessage = async (message: Message) => {
|
|
267
282
|
"id",
|
268
283
|
message.error.id
|
269
284
|
);
|
270
|
-
|
285
|
+
|
271
286
|
messagesData.value.data[idx] = { ...msg, error: undefined };
|
272
287
|
|
273
|
-
socketService.value?.emit(
|
274
|
-
|
275
|
-
|
276
|
-
);
|
288
|
+
socketService.value?.emit("sendMessage", {
|
289
|
+
roomId: information?.value?.appChat.id,
|
290
|
+
message,
|
291
|
+
});
|
277
292
|
}
|
278
293
|
|
279
294
|
scrollToBottom();
|
@@ -305,23 +320,28 @@ const fontSpace = 14;
|
|
305
320
|
function autoAdjustHeight() {
|
306
321
|
if (!textAreaRef.value) return;
|
307
322
|
|
308
|
-
textAreaRef.value.style.height =
|
323
|
+
textAreaRef.value.style.height =
|
324
|
+
textAreaRef.value.scrollHeight - fontSpace + "px";
|
325
|
+
|
326
|
+
if (textAreaRef.value.scrollHeight === textAreaRef.value.clientHeight)
|
327
|
+
return;
|
309
328
|
|
310
|
-
|
311
|
-
|
312
|
-
textAreaRef.value.style.height = textAreaRef.value.scrollHeight + "px"
|
329
|
+
textAreaRef.value.style.height = textAreaRef.value.scrollHeight + "px";
|
313
330
|
}
|
314
331
|
|
315
332
|
const socketService = ref<Socket>();
|
316
333
|
const information = ref<ChatInformation>();
|
317
334
|
|
318
|
-
function connectMsWebSocket
|
319
|
-
|
335
|
+
function connectMsWebSocket(
|
336
|
+
userChat: ChatInformation,
|
337
|
+
app: APP_TYPE = APP_TYPE.WEBCHAT
|
338
|
+
) {
|
339
|
+
if (!userChat) throw new Error("user chat is required");
|
320
340
|
|
321
341
|
socketService.value = io(window.VITE_SOCKET_URI, {
|
322
342
|
query: {
|
323
343
|
// TODO: confirmar si se quita o no
|
324
|
-
usuarioId: `${userChat?.chat?.persona?.funcionarioId}`,
|
344
|
+
usuarioId: `${userChat?.chat?.persona?.funcionarioId}`,
|
325
345
|
aplicacion: app,
|
326
346
|
},
|
327
347
|
extraHeaders: { Authorization: props.tokenAuth },
|
@@ -329,24 +349,24 @@ function connectMsWebSocket (userChat: ChatInformation ,app: APP_TYPE = APP_TYPE
|
|
329
349
|
|
330
350
|
socketService.value.removeAllListeners();
|
331
351
|
|
332
|
-
socketService.value.on(
|
333
|
-
console.log(
|
352
|
+
socketService.value.on("connect", () => {
|
353
|
+
console.log("Conectado al servidor de sockets");
|
334
354
|
|
335
|
-
socketService.value?.emit(
|
336
|
-
|
337
|
-
`${userChat?.appChat?.id}`
|
338
|
-
);
|
339
|
-
})
|
355
|
+
socketService.value?.emit("joinRoom", `${userChat?.appChat?.id}`);
|
356
|
+
});
|
340
357
|
|
341
|
-
socketService.value.on(
|
342
|
-
console.log(
|
358
|
+
socketService.value.on("disconnect", () => {
|
359
|
+
console.log("Desconectado del servidor de sockets");
|
343
360
|
});
|
344
361
|
|
345
|
-
socketService.value.on(
|
346
|
-
console.log(
|
347
|
-
|
348
|
-
if (
|
349
|
-
|
362
|
+
socketService.value.on("receiveMessage", (data: any) => {
|
363
|
+
console.log("Mensaje recibido:", data.message, userChat);
|
364
|
+
|
365
|
+
if (
|
366
|
+
data.message.sender.msPersonaId === userChat?.chat?.persona?.msPersonaId
|
367
|
+
)
|
368
|
+
return;
|
369
|
+
|
350
370
|
messagesData.value.data.push(data.message);
|
351
371
|
setVistoToTrueApi(data.message.appChatId, props.tokenAuth);
|
352
372
|
scrollToBottom();
|
@@ -354,17 +374,56 @@ function connectMsWebSocket (userChat: ChatInformation ,app: APP_TYPE = APP_TYPE
|
|
354
374
|
});
|
355
375
|
}
|
356
376
|
|
377
|
+
const isMovil = computed(() => {
|
378
|
+
return [OS.ANDROID, OS.IOS].includes(getOS() as OS);
|
379
|
+
});
|
380
|
+
|
381
|
+
const enum OS {
|
382
|
+
ANDROID = "Android",
|
383
|
+
IOS = "iPhone",
|
384
|
+
}
|
385
|
+
|
386
|
+
function getOS() {
|
387
|
+
const userAgent = window.navigator.userAgent;
|
388
|
+
const platform = (window.navigator as any)?.userAgentData?.platform || window.navigator.platform;
|
389
|
+
const macosPlatforms = [
|
390
|
+
"macOS",
|
391
|
+
"Macintosh",
|
392
|
+
"MacIntel",
|
393
|
+
"MacPPC",
|
394
|
+
"Mac68K",
|
395
|
+
];
|
396
|
+
const windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"];
|
397
|
+
const iosPlatforms = ["iPhone", "iPad", "iPod"];
|
398
|
+
|
399
|
+
let os = null;
|
400
|
+
|
401
|
+
if (macosPlatforms.indexOf(platform) !== -1) {
|
402
|
+
os = "Mac OS";
|
403
|
+
} else if (iosPlatforms.indexOf(platform) !== -1) {
|
404
|
+
os = OS.IOS;
|
405
|
+
} else if (windowsPlatforms.indexOf(platform) !== -1) {
|
406
|
+
os = "Windows";
|
407
|
+
} else if (/Android/.test(userAgent)) {
|
408
|
+
os = OS.ANDROID;
|
409
|
+
} else if (/Linux/.test(platform)) {
|
410
|
+
os = "Linux";
|
411
|
+
}
|
412
|
+
|
413
|
+
return os;
|
414
|
+
}
|
415
|
+
|
357
416
|
onMounted(async () => {
|
358
417
|
if (appChatId.value) return;
|
359
|
-
|
418
|
+
|
360
419
|
const resp = await getInformationApi(props.tokenAuth);
|
361
|
-
|
362
|
-
if(!resp) return;
|
363
|
-
|
420
|
+
|
421
|
+
if (!resp) return;
|
422
|
+
|
364
423
|
information.value = resp;
|
365
424
|
appChatId.value = resp.appChat.id;
|
366
425
|
notViewed.value = resp.appChat.totalNoVistosCliente;
|
367
|
-
connectMsWebSocket(resp)
|
426
|
+
connectMsWebSocket(resp);
|
368
427
|
getMessages();
|
369
428
|
emit("not-viewed-total", resp.appChat.totalNoVistosCliente);
|
370
429
|
});
|
@@ -26,7 +26,7 @@
|
|
26
26
|
<div class="chat-message">
|
27
27
|
<div class="bubble" :class="message.esCliente ? 'right' : 'left'">
|
28
28
|
<div :class="message.esCliente ? 'content-right' : 'content-left'">
|
29
|
-
<div class="message-text" style="white-space: pre-line" v-html="
|
29
|
+
<div class="message-text" style="white-space: pre-line" v-html="textToRichFormat(message.message)"></div>
|
30
30
|
<div class="detail-message flex justify-content-between">
|
31
31
|
<span class="mr-5" v-if="message.sender?.nombreCompleto">
|
32
32
|
{{
|
@@ -98,15 +98,43 @@ watch(
|
|
98
98
|
}
|
99
99
|
);
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
type RichTextType = {
|
102
|
+
regex: RegExp;
|
103
|
+
tag: string;
|
104
|
+
};
|
104
105
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
const richText: { [key in string]: RichTextType } = {
|
107
|
+
BOLD: { regex: /\*(.+?)\*(?!\*)/g, tag: '<strong--custom-tag>{val}</strong--custom-tag>' },
|
108
|
+
ITALIC: { regex: /_(.+?)_/, tag: '<i--custom-tag>{val}</i--custom-tag>' },
|
109
|
+
CROSSED_OUT: { regex: /~(.+?)~(?!~)/g, tag: '<del--custom-tag>{val}</del--custom-tag>' },
|
110
|
+
URL: {
|
111
|
+
regex: /(http?s?:\/\/[^\s]+)/g,
|
112
|
+
tag: '<a--custom-tag href="{val}" target="_blank">{val}</a--custom-tag>',
|
113
|
+
},
|
114
|
+
};
|
115
|
+
|
116
|
+
function textToRichFormat(text: string) {
|
117
|
+
const richTextValues = Object.values(richText);
|
118
|
+
|
119
|
+
if (!richTextValues || (Array.isArray(richTextValues) && richTextValues.length === 0))
|
120
|
+
return text;
|
121
|
+
|
122
|
+
const newMessage = () => {
|
123
|
+
|
124
|
+
return richTextValues.reduce((textPrev, rtv) => {
|
125
|
+
return textPrev.replace(rtv.regex, (middleValueAssert, middleValue) => {
|
126
|
+
const regexVerifyExistTag = /--custom-tag/;
|
127
|
+
|
128
|
+
if (regexVerifyExistTag.test(middleValueAssert)) return middleValueAssert;
|
129
|
+
|
130
|
+
return rtv.tag.replace(/{val}/g, middleValue);
|
131
|
+
});
|
132
|
+
}, text);
|
133
|
+
};
|
134
|
+
|
135
|
+
return newMessage().replace(/--custom-tag/g, '');
|
109
136
|
}
|
137
|
+
|
110
138
|
</script>
|
111
139
|
|
112
140
|
<style scoped>
|