vue-wiguet-chatweb 0.1.15 → 0.1.16
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|