@ozdao/martyrs 0.2.428 → 0.2.429
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/martyrs/src/components/Block/Block.vue.cjs +1 -1
- package/dist/martyrs/src/components/Block/Block.vue.js +1 -1
- package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.cjs → Tooltip.vue.cjs} +2 -2
- package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js.map → Tooltip.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js → Tooltip.vue.js} +2 -2
- package/dist/martyrs/src/components/Tooltip/Tooltip.vue.js.map +1 -0
- package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.cjs +13 -3
- package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.js +14 -4
- package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.js.map +1 -1
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.cjs +24 -6
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.js +25 -7
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.js.map +1 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.cjs +7 -8
- package/dist/martyrs/src/modules/chats/store/chat.store.cjs.map +1 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.js +7 -8
- package/dist/martyrs/src/modules/chats/store/chat.store.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs +6 -8
- package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js +6 -8
- package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.cjs +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.cjs +7 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +7 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.cjs +2 -2
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +200 -92
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +213 -105
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +8 -11
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +9 -12
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +99 -99
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +102 -102
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.cjs +14 -8
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +15 -9
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/store/orders.cjs +51 -0
- package/dist/martyrs/src/modules/orders/store/orders.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/store/orders.js +51 -0
- package/dist/martyrs/src/modules/orders/store/orders.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +1 -1
- package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs +15 -12
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js +15 -12
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/store/spots.cjs +11 -4
- package/dist/martyrs/src/modules/spots/store/spots.cjs.map +1 -1
- package/dist/martyrs/src/modules/spots/store/spots.js +11 -4
- package/dist/martyrs/src/modules/spots/store/spots.js.map +1 -1
- package/dist/orders.server.js +6 -0
- package/dist/orders.server.mjs +6 -0
- package/dist/spots.server.js +44 -3
- package/dist/spots.server.mjs +44 -3
- package/dist/style.css +17 -17
- package/package.json +1 -1
- package/src/modules/chats/components/pages/ChatPage.vue +18 -23
- package/src/modules/chats/components/sections/ChatWindow.vue +55 -38
- package/src/modules/chats/store/chat.store.js +20 -21
- package/src/modules/globals/views/classes/globals.websocket.js +10 -11
- package/src/modules/marketplace/views/components/sections/SectionMenu.vue +1 -1
- package/src/modules/notifications/components/elements/NotificationBadge.vue +7 -0
- package/src/modules/orders/components/blocks/CardOrderItem.vue +2 -2
- package/src/modules/orders/components/pages/OrderBackoffice.vue +146 -77
- package/src/modules/orders/components/pages/OrderCreate.vue +5 -10
- package/src/modules/orders/components/sections/FormDelivery.vue +35 -43
- package/src/modules/orders/components/sections/FormPayment.vue +17 -7
- package/src/modules/orders/controllers/orders.controller.js +10 -0
- package/src/modules/orders/store/orders.js +65 -0
- package/src/modules/spots/components/blocks/CardSpot.vue +8 -7
- package/src/modules/spots/controllers/spots.controller.js +49 -2
- package/src/modules/spots/routes/spots.routes.js +3 -1
- package/src/modules/spots/store/spots.js +12 -4
- package/dist/martyrs/src/components/Tooltip/Tooltip.vue2.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
3
|
const vue = require("vue");
|
|
4
|
-
const Tooltip = require("../Tooltip/Tooltip.
|
|
4
|
+
const Tooltip = require("../Tooltip/Tooltip.vue.cjs");
|
|
5
5
|
const _hoisted_1 = { class: "bg-light pd-medium radius-medium" };
|
|
6
6
|
const _hoisted_2 = {
|
|
7
7
|
key: 0,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSlots, createElementBlock, openBlock, createCommentVNode, renderSlot, createBlock, toDisplayString, Fragment, renderList, normalizeClass, withCtx, createElementVNode, Comment } from "vue";
|
|
2
|
-
import _sfc_main$1 from "../Tooltip/Tooltip.
|
|
2
|
+
import _sfc_main$1 from "../Tooltip/Tooltip.vue.js";
|
|
3
3
|
const _hoisted_1 = { class: "bg-light pd-medium radius-medium" };
|
|
4
4
|
const _hoisted_2 = {
|
|
5
5
|
key: 0,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
3
|
const vue = require("vue");
|
|
4
|
-
;/* empty css
|
|
4
|
+
;/* empty css */
|
|
5
5
|
const _sfc_main = {
|
|
6
6
|
__name: "Tooltip",
|
|
7
7
|
props: {
|
|
@@ -49,4 +49,4 @@ const _sfc_main = {
|
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
exports.default = _sfc_main;
|
|
52
|
-
//# sourceMappingURL=Tooltip.
|
|
52
|
+
//# sourceMappingURL=Tooltip.vue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.
|
|
1
|
+
{"version":3,"file":"Tooltip.vue.cjs","sources":["../../../../../src/components/Tooltip/Tooltip.vue"],"sourcesContent":["<template>\n <div class=\"cursor-pointer tooltip-container\" @mouseover=\"showTooltip\" @mouseleave=\"hideTooltip\">\n <slot></slot>\n <div class=\"tooltip-content\" :style=\"tooltipStyle\">\n {{ text }}\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, reactive } from 'vue';\n\nconst props = defineProps({\n text: {\n type: String,\n required: true\n }\n});\n\nconst visible = ref(false);\n\nconst tooltipStyle = reactive({\n position: 'absolute',\n width: 'max-content',\n zIndex: 1000,\n background: '#333',\n color: '#fff',\n padding: '5px 10px',\n borderRadius: '3px',\n fontSize: '14px',\n display: 'none',\n});\n\nfunction showTooltip(event) {\n visible.value = true;\n tooltipStyle.left = `${(event.clientX / 100) + 10 }px`;\n tooltipStyle.top = `${(event.clientY / 100) + 10 }px`;\n tooltipStyle.display = 'block';\n}\n\nfunction hideTooltip() {\n visible.value = false;\n tooltipStyle.display = 'none';\n}\n</script>\n\n<style >\n.tooltip-container {\n position: relative;\n display: inline-block;\n}\n\n.tooltip-content {\n pointer-events: none;\n}\n</style>"],"names":["ref","reactive"],"mappings":";;;;;;;;;;;;;AAmBA,UAAM,UAAUA,IAAG,IAAC,KAAK;AAEzB,UAAM,eAAeC,IAAAA,SAAS;AAAA,MAC5B,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,cAAc;AAAA,MACd,UAAU;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAED,aAAS,YAAY,OAAO;AAC1B,cAAQ,QAAQ;AAChB,mBAAa,OAAO,GAAI,MAAM,UAAU,MAAO,EAAE;AACjD,mBAAa,MAAM,GAAI,MAAM,UAAU,MAAO,EAAE;AAChD,mBAAa,UAAU;AAAA,IACzB;AAEA,aAAS,cAAc;AACrB,cAAQ,QAAQ;AAChB,mBAAa,UAAU;AAAA,IACzB;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, reactive, createElementBlock, openBlock, renderSlot, createElementVNode, normalizeStyle, toDisplayString } from "vue";
|
|
2
|
-
/* empty css
|
|
2
|
+
/* empty css */
|
|
3
3
|
const _sfc_main = {
|
|
4
4
|
__name: "Tooltip",
|
|
5
5
|
props: {
|
|
@@ -49,4 +49,4 @@ const _sfc_main = {
|
|
|
49
49
|
export {
|
|
50
50
|
_sfc_main as default
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=Tooltip.
|
|
52
|
+
//# sourceMappingURL=Tooltip.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.vue.js","sources":["../../../../../src/components/Tooltip/Tooltip.vue"],"sourcesContent":["<template>\n <div class=\"cursor-pointer tooltip-container\" @mouseover=\"showTooltip\" @mouseleave=\"hideTooltip\">\n <slot></slot>\n <div class=\"tooltip-content\" :style=\"tooltipStyle\">\n {{ text }}\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, reactive } from 'vue';\n\nconst props = defineProps({\n text: {\n type: String,\n required: true\n }\n});\n\nconst visible = ref(false);\n\nconst tooltipStyle = reactive({\n position: 'absolute',\n width: 'max-content',\n zIndex: 1000,\n background: '#333',\n color: '#fff',\n padding: '5px 10px',\n borderRadius: '3px',\n fontSize: '14px',\n display: 'none',\n});\n\nfunction showTooltip(event) {\n visible.value = true;\n tooltipStyle.left = `${(event.clientX / 100) + 10 }px`;\n tooltipStyle.top = `${(event.clientY / 100) + 10 }px`;\n tooltipStyle.display = 'block';\n}\n\nfunction hideTooltip() {\n visible.value = false;\n tooltipStyle.display = 'none';\n}\n</script>\n\n<style >\n.tooltip-container {\n position: relative;\n display: inline-block;\n}\n\n.tooltip-content {\n pointer-events: none;\n}\n</style>"],"names":[],"mappings":";;;;;;;;;;;AAmBA,UAAM,UAAU,IAAI,KAAK;AAEzB,UAAM,eAAe,SAAS;AAAA,MAC5B,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,cAAc;AAAA,MACd,UAAU;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAED,aAAS,YAAY,OAAO;AAC1B,cAAQ,QAAQ;AAChB,mBAAa,OAAO,GAAI,MAAM,UAAU,MAAO,EAAE;AACjD,mBAAa,MAAM,GAAI,MAAM,UAAU,MAAO,EAAE;AAChD,mBAAa,UAAU;AAAA,IACzB;AAEA,aAAS,cAAc;AACrB,cAAQ,QAAQ;AAChB,mBAAa,UAAU;AAAA,IACzB;;;;;;;;;;;;;;;;"}
|
|
@@ -4,6 +4,7 @@ const vue = require("vue");
|
|
|
4
4
|
const ChatWindow = require("../sections/ChatWindow.vue.cjs");
|
|
5
5
|
const chat_store = require("../../store/chat.store.cjs");
|
|
6
6
|
;/* empty css */
|
|
7
|
+
const _hoisted_1 = { class: "chat-main" };
|
|
7
8
|
const _sfc_main = {
|
|
8
9
|
__name: "ChatPage",
|
|
9
10
|
props: {
|
|
@@ -11,6 +12,10 @@ const _sfc_main = {
|
|
|
11
12
|
type: String,
|
|
12
13
|
required: true
|
|
13
14
|
},
|
|
15
|
+
user: {
|
|
16
|
+
type: String,
|
|
17
|
+
required: true
|
|
18
|
+
},
|
|
14
19
|
chatID: {
|
|
15
20
|
type: String,
|
|
16
21
|
required: true
|
|
@@ -20,11 +25,16 @@ const _sfc_main = {
|
|
|
20
25
|
const props = __props;
|
|
21
26
|
vue.onMounted(async () => {
|
|
22
27
|
chat_store.default.methods.setUsername(props.username || "user");
|
|
23
|
-
await chat_store.default.methods.connectWebSocket();
|
|
24
|
-
chat_store.default.methods.setCurrentChat(props.chatID);
|
|
28
|
+
await chat_store.default.methods.connectWebSocket(props.user);
|
|
29
|
+
await chat_store.default.methods.setCurrentChat(props.chatID);
|
|
30
|
+
});
|
|
31
|
+
vue.onUnmounted(() => {
|
|
32
|
+
chat_store.default.methods.disconnectChat();
|
|
25
33
|
});
|
|
26
34
|
return (_ctx, _cache) => {
|
|
27
|
-
return vue.openBlock(), vue.
|
|
35
|
+
return vue.openBlock(), vue.createElementBlock("main", _hoisted_1, [
|
|
36
|
+
vue.createVNode(ChatWindow.default)
|
|
37
|
+
]);
|
|
28
38
|
};
|
|
29
39
|
}
|
|
30
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPage.vue.cjs","sources":["../../../../../../../src/modules/chats/components/pages/ChatPage.vue"],"sourcesContent":["<template>\n
|
|
1
|
+
{"version":3,"file":"ChatPage.vue.cjs","sources":["../../../../../../../src/modules/chats/components/pages/ChatPage.vue"],"sourcesContent":["<template>\n <main class=\"chat-main\">\n <ChatWindow />\n </main>\n</template>\n\n<script setup>\nimport { ref, onMounted, onUnmounted } from 'vue';\nimport ChatWindow from '../sections/ChatWindow.vue';\nimport chatStore from '../../store/chat.store.js';\n\nconst props = defineProps({\n username: {\n type: String,\n required: true\n },\n user: {\n type: String,\n required: true\n },\n chatID: {\n type: String,\n required: true\n },\n});\n\nconst selectChat = (chatId) => {\n chatStore.methods.setCurrentChat(chatId);\n};\n\nonMounted(async () => {\n chatStore.methods.setUsername(props.username || 'user'); // Установка имени пользователя\n await chatStore.methods.connectWebSocket(props.user); // Подключение к WebSocket\n await chatStore.methods.setCurrentChat(props.chatID);\n});\n\nonUnmounted(() => {\n // Clean up when the component is unmounted (e.g., navigating away)\n chatStore.methods.disconnectChat();\n});\n</script>\n\n<style>\n/* Стили остаются без изменений */\n</style>"],"names":["onMounted","chatStore","onUnmounted"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAWA,UAAM,QAAQ;AAmBdA,QAAAA,UAAU,YAAY;AACpBC,iBAAS,QAAC,QAAQ,YAAY,MAAM,YAAY,MAAM;AACtD,YAAMA,WAAS,QAAC,QAAQ,iBAAiB,MAAM,IAAI;AACnD,YAAMA,WAAS,QAAC,QAAQ,eAAe,MAAM,MAAM;AAAA,IACrD,CAAC;AAEDC,QAAAA,YAAY,MAAM;AAEhBD,iBAAS,QAAC,QAAQ,eAAgB;AAAA,IACpC,CAAC;;;;;;;;;"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { onMounted,
|
|
1
|
+
import { onMounted, onUnmounted, createElementBlock, openBlock, createVNode } from "vue";
|
|
2
2
|
import _sfc_main$1 from "../sections/ChatWindow.vue.js";
|
|
3
3
|
import chatStore from "../../store/chat.store.js";
|
|
4
4
|
/* empty css */
|
|
5
|
+
const _hoisted_1 = { class: "chat-main" };
|
|
5
6
|
const _sfc_main = {
|
|
6
7
|
__name: "ChatPage",
|
|
7
8
|
props: {
|
|
@@ -9,6 +10,10 @@ const _sfc_main = {
|
|
|
9
10
|
type: String,
|
|
10
11
|
required: true
|
|
11
12
|
},
|
|
13
|
+
user: {
|
|
14
|
+
type: String,
|
|
15
|
+
required: true
|
|
16
|
+
},
|
|
12
17
|
chatID: {
|
|
13
18
|
type: String,
|
|
14
19
|
required: true
|
|
@@ -18,11 +23,16 @@ const _sfc_main = {
|
|
|
18
23
|
const props = __props;
|
|
19
24
|
onMounted(async () => {
|
|
20
25
|
chatStore.methods.setUsername(props.username || "user");
|
|
21
|
-
await chatStore.methods.connectWebSocket();
|
|
22
|
-
chatStore.methods.setCurrentChat(props.chatID);
|
|
26
|
+
await chatStore.methods.connectWebSocket(props.user);
|
|
27
|
+
await chatStore.methods.setCurrentChat(props.chatID);
|
|
28
|
+
});
|
|
29
|
+
onUnmounted(() => {
|
|
30
|
+
chatStore.methods.disconnectChat();
|
|
23
31
|
});
|
|
24
32
|
return (_ctx, _cache) => {
|
|
25
|
-
return openBlock(),
|
|
33
|
+
return openBlock(), createElementBlock("main", _hoisted_1, [
|
|
34
|
+
createVNode(_sfc_main$1)
|
|
35
|
+
]);
|
|
26
36
|
};
|
|
27
37
|
}
|
|
28
38
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPage.vue.js","sources":["../../../../../../../src/modules/chats/components/pages/ChatPage.vue"],"sourcesContent":["<template>\n
|
|
1
|
+
{"version":3,"file":"ChatPage.vue.js","sources":["../../../../../../../src/modules/chats/components/pages/ChatPage.vue"],"sourcesContent":["<template>\n <main class=\"chat-main\">\n <ChatWindow />\n </main>\n</template>\n\n<script setup>\nimport { ref, onMounted, onUnmounted } from 'vue';\nimport ChatWindow from '../sections/ChatWindow.vue';\nimport chatStore from '../../store/chat.store.js';\n\nconst props = defineProps({\n username: {\n type: String,\n required: true\n },\n user: {\n type: String,\n required: true\n },\n chatID: {\n type: String,\n required: true\n },\n});\n\nconst selectChat = (chatId) => {\n chatStore.methods.setCurrentChat(chatId);\n};\n\nonMounted(async () => {\n chatStore.methods.setUsername(props.username || 'user'); // Установка имени пользователя\n await chatStore.methods.connectWebSocket(props.user); // Подключение к WebSocket\n await chatStore.methods.setCurrentChat(props.chatID);\n});\n\nonUnmounted(() => {\n // Clean up when the component is unmounted (e.g., navigating away)\n chatStore.methods.disconnectChat();\n});\n</script>\n\n<style>\n/* Стили остаются без изменений */\n</style>"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAWA,UAAM,QAAQ;AAmBd,cAAU,YAAY;AACpB,gBAAU,QAAQ,YAAY,MAAM,YAAY,MAAM;AACtD,YAAM,UAAU,QAAQ,iBAAiB,MAAM,IAAI;AACnD,YAAM,UAAU,QAAQ,eAAe,MAAM,MAAM;AAAA,IACrD,CAAC;AAED,gBAAY,MAAM;AAEhB,gBAAU,QAAQ,eAAgB;AAAA,IACpC,CAAC;;;;;;;;"}
|
|
@@ -19,7 +19,12 @@ const _sfc_main = {
|
|
|
19
19
|
const newMessage = vue.ref("");
|
|
20
20
|
const allMessages = vue.ref(null);
|
|
21
21
|
const messages = vue.computed(() => chat_store.default.state.messages);
|
|
22
|
-
const
|
|
22
|
+
const scrollToBottom = () => {
|
|
23
|
+
if (allMessages.value) {
|
|
24
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const sendMessage = async () => {
|
|
23
28
|
if (newMessage.value) {
|
|
24
29
|
const message = {
|
|
25
30
|
text: newMessage.value,
|
|
@@ -27,13 +32,25 @@ const _sfc_main = {
|
|
|
27
32
|
chatId: chat_store.default.state.currentChatId
|
|
28
33
|
};
|
|
29
34
|
chat_store.default.methods.addMessage(message);
|
|
30
|
-
console.log(allMessages.value.lastElementChild.offsetHeight);
|
|
31
|
-
allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight;
|
|
32
35
|
newMessage.value = "";
|
|
36
|
+
await vue.nextTick();
|
|
37
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
38
|
+
scrollToBottom();
|
|
33
39
|
}
|
|
34
40
|
};
|
|
35
|
-
vue.
|
|
36
|
-
|
|
41
|
+
vue.onMounted(() => {
|
|
42
|
+
vue.nextTick(() => {
|
|
43
|
+
if (allMessages.value) {
|
|
44
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
vue.watch(messages, () => {
|
|
49
|
+
vue.nextTick(() => {
|
|
50
|
+
if (allMessages.value) {
|
|
51
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
37
54
|
}, { deep: true });
|
|
38
55
|
return (_ctx, _cache) => {
|
|
39
56
|
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
|
|
@@ -56,7 +73,8 @@ const _sfc_main = {
|
|
|
56
73
|
key: 1,
|
|
57
74
|
name: "list",
|
|
58
75
|
tag: "ul",
|
|
59
|
-
class: "w-100 o-hidden"
|
|
76
|
+
class: "w-100 o-hidden",
|
|
77
|
+
onAfterEnter: scrollToBottom
|
|
60
78
|
}, {
|
|
61
79
|
default: vue.withCtx(() => [
|
|
62
80
|
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(messages.value, (message) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWindow.vue.cjs","sources":["../../../../../../../src/modules/chats/components/sections/ChatWindow.vue"],"sourcesContent":["<template>\n <div class=\"bg-white radius-semi bg-white o-hidden pos-relative\">\n
|
|
1
|
+
{"version":3,"file":"ChatWindow.vue.cjs","sources":["../../../../../../../src/modules/chats/components/sections/ChatWindow.vue"],"sourcesContent":["<template>\n <div class=\"bg-white radius-semi bg-white o-hidden pos-relative\">\n <div ref=\"allMessages\" class=\"chat-messages o-scroll h-max-20r\">\n <div class=\"pos-relative h-min-20r flex-justify-end flex flex-column br-b br-solid br-black-transp-10\">\n <transition name=\"scaleIn\" mode=\"out-in\">\n <div v-if=\"messages.length < 1\" class=\"flex-center pd-small t-center w-100 h-100 flex-column flex pos-absolute\">\n <PlaceholderChat class=\"radius-100 mn-b-thin\"/>\n <h4 class='mn-b-thin'>Here you can view your chat history</h4>\n <p>Feel free to ask if you have any questions.</p>\n </div>\n\n <TransitionGroup v-else name=\"list\" tag=\"ul\" class=\"w-100 o-hidden\" @after-enter=\"scrollToBottom\">\n <ChatMessage\n v-for=\"message in messages\"\n :key=\"message._id\"\n :message=\"message\"\n />\n </TransitionGroup>\n </transition>\n </div>\n </div>\n\n <div class=\"flex-nowrap flex-v-center flex bg-white w-100 radius-big pd-small\">\n <IconAdd class=\"mn-r-thin t-transp i-regular\" />\n <input class=\"\" placeholder=\"Enter your message\" type=\"text\" v-model=\"newMessage\" @keyup.enter=\"sendMessage\" />\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, watch, onMounted, nextTick } from 'vue';\n\nimport IconAdd from '@martyrs/src/modules/icons/navigation/IconAdd.vue'\nimport PlaceholderChat from '@martyrs/src/modules/icons/placeholders/PlaceholderChat.vue'\n\nimport ChatMessage from '../blocks/ChatMessage.vue';\nimport chatStore from '../../store/chat.store.js';\n\nconst newMessage = ref('');\nconst allMessages = ref(null);\n\n// Вычисляемые свойства\nconst messages = computed(() => chatStore.state.messages);\n\n// Функция прокрутки вниз\nconst scrollToBottom = () => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n};\n\n// Функция для отправки сообщения\nconst sendMessage = async () => {\n if (newMessage.value) {\n const message = {\n text: newMessage.value,\n username: chatStore.state.username,\n chatId: chatStore.state.currentChatId\n };\n\n chatStore.methods.addMessage(message);\n newMessage.value = '';\n\n // Ждем, пока все анимации и рендеринг завершатся\n await nextTick();\n await new Promise(resolve => setTimeout(resolve, 100)); // Небольшая задержка для анимаций\n scrollToBottom();\n }\n};\n\n// Прокрутка вниз при монтировании\nonMounted(() => {\n nextTick(() => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n });\n});\n\n// Прокрутка вниз при изменении сообщений\nwatch(messages, () => {\n nextTick(() => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n });\n}, { deep: true });\n\n// Обработчик после завершения анимации входа нового элемента\n</script>\n\n<style>\n.list-enter-active,\n.list-leave-active {\n transition: all 0.5s ease;\n}\n.list-enter-from,\n.list-leave-to {\n opacity: 0;\n transform: translateX(30px);\n}\n</style>"],"names":["ref","computed","chatStore","nextTick","onMounted","watch"],"mappings":";;;;;;;;;;;;;;;;;;AAsCA,UAAM,aAAaA,IAAG,IAAC,EAAE;AACzB,UAAM,cAAcA,IAAG,IAAC,IAAI;AAG5B,UAAM,WAAWC,IAAAA,SAAS,MAAMC,mBAAU,MAAM,QAAQ;AAGxD,UAAM,iBAAiB,MAAM;AAC3B,UAAI,YAAY,OAAO;AACrB,oBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,MACpD;AAAA,IACA;AAGA,UAAM,cAAc,YAAY;AAC9B,UAAI,WAAW,OAAO;AACpB,cAAM,UAAU;AAAA,UACd,MAAM,WAAW;AAAA,UACjB,UAAUA,WAAAA,QAAU,MAAM;AAAA,UAC1B,QAAQA,WAAS,QAAC,MAAM;AAAA,QACzB;AAEDA,2BAAU,QAAQ,WAAW,OAAO;AACpC,mBAAW,QAAQ;AAGnB,cAAMC,aAAU;AAChB,cAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAG,CAAC;AACrD,uBAAgB;AAAA,MACpB;AAAA,IACA;AAGAC,QAAAA,UAAU,MAAM;AACdD,UAAAA,SAAS,MAAM;AACb,YAAI,YAAY,OAAO;AACrB,sBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,QACtD;AAAA,MACA,CAAG;AAAA,IACH,CAAC;AAGDE,QAAK,MAAC,UAAU,MAAM;AACpBF,UAAAA,SAAS,MAAM;AACb,YAAI,YAAY,OAAO;AACrB,sBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,QACtD;AAAA,MACA,CAAG;AAAA,IACH,GAAG,EAAE,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, computed, watch, createElementBlock, openBlock, createElementVNode, createVNode, Transition, withCtx, createBlock, TransitionGroup, Fragment, renderList, withDirectives, withKeys, vModelText } from "vue";
|
|
1
|
+
import { ref, computed, onMounted, nextTick, watch, createElementBlock, openBlock, createElementVNode, createVNode, Transition, withCtx, createBlock, TransitionGroup, Fragment, renderList, withDirectives, withKeys, vModelText } from "vue";
|
|
2
2
|
import _sfc_main$1 from "../../../icons/navigation/IconAdd.vue.js";
|
|
3
3
|
import PlaceholderChat from "../../../icons/placeholders/PlaceholderChat.vue.js";
|
|
4
4
|
import ChatMessage from "../blocks/ChatMessage.vue.js";
|
|
@@ -17,7 +17,12 @@ const _sfc_main = {
|
|
|
17
17
|
const newMessage = ref("");
|
|
18
18
|
const allMessages = ref(null);
|
|
19
19
|
const messages = computed(() => chatStore.state.messages);
|
|
20
|
-
const
|
|
20
|
+
const scrollToBottom = () => {
|
|
21
|
+
if (allMessages.value) {
|
|
22
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const sendMessage = async () => {
|
|
21
26
|
if (newMessage.value) {
|
|
22
27
|
const message = {
|
|
23
28
|
text: newMessage.value,
|
|
@@ -25,13 +30,25 @@ const _sfc_main = {
|
|
|
25
30
|
chatId: chatStore.state.currentChatId
|
|
26
31
|
};
|
|
27
32
|
chatStore.methods.addMessage(message);
|
|
28
|
-
console.log(allMessages.value.lastElementChild.offsetHeight);
|
|
29
|
-
allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight;
|
|
30
33
|
newMessage.value = "";
|
|
34
|
+
await nextTick();
|
|
35
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
36
|
+
scrollToBottom();
|
|
31
37
|
}
|
|
32
38
|
};
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
onMounted(() => {
|
|
40
|
+
nextTick(() => {
|
|
41
|
+
if (allMessages.value) {
|
|
42
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
watch(messages, () => {
|
|
47
|
+
nextTick(() => {
|
|
48
|
+
if (allMessages.value) {
|
|
49
|
+
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
35
52
|
}, { deep: true });
|
|
36
53
|
return (_ctx, _cache) => {
|
|
37
54
|
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
@@ -54,7 +71,8 @@ const _sfc_main = {
|
|
|
54
71
|
key: 1,
|
|
55
72
|
name: "list",
|
|
56
73
|
tag: "ul",
|
|
57
|
-
class: "w-100 o-hidden"
|
|
74
|
+
class: "w-100 o-hidden",
|
|
75
|
+
onAfterEnter: scrollToBottom
|
|
58
76
|
}, {
|
|
59
77
|
default: withCtx(() => [
|
|
60
78
|
(openBlock(true), createElementBlock(Fragment, null, renderList(messages.value, (message) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWindow.vue.js","sources":["../../../../../../../src/modules/chats/components/sections/ChatWindow.vue"],"sourcesContent":["<template>\n <div class=\"bg-white radius-semi bg-white o-hidden pos-relative\">\n
|
|
1
|
+
{"version":3,"file":"ChatWindow.vue.js","sources":["../../../../../../../src/modules/chats/components/sections/ChatWindow.vue"],"sourcesContent":["<template>\n <div class=\"bg-white radius-semi bg-white o-hidden pos-relative\">\n <div ref=\"allMessages\" class=\"chat-messages o-scroll h-max-20r\">\n <div class=\"pos-relative h-min-20r flex-justify-end flex flex-column br-b br-solid br-black-transp-10\">\n <transition name=\"scaleIn\" mode=\"out-in\">\n <div v-if=\"messages.length < 1\" class=\"flex-center pd-small t-center w-100 h-100 flex-column flex pos-absolute\">\n <PlaceholderChat class=\"radius-100 mn-b-thin\"/>\n <h4 class='mn-b-thin'>Here you can view your chat history</h4>\n <p>Feel free to ask if you have any questions.</p>\n </div>\n\n <TransitionGroup v-else name=\"list\" tag=\"ul\" class=\"w-100 o-hidden\" @after-enter=\"scrollToBottom\">\n <ChatMessage\n v-for=\"message in messages\"\n :key=\"message._id\"\n :message=\"message\"\n />\n </TransitionGroup>\n </transition>\n </div>\n </div>\n\n <div class=\"flex-nowrap flex-v-center flex bg-white w-100 radius-big pd-small\">\n <IconAdd class=\"mn-r-thin t-transp i-regular\" />\n <input class=\"\" placeholder=\"Enter your message\" type=\"text\" v-model=\"newMessage\" @keyup.enter=\"sendMessage\" />\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, watch, onMounted, nextTick } from 'vue';\n\nimport IconAdd from '@martyrs/src/modules/icons/navigation/IconAdd.vue'\nimport PlaceholderChat from '@martyrs/src/modules/icons/placeholders/PlaceholderChat.vue'\n\nimport ChatMessage from '../blocks/ChatMessage.vue';\nimport chatStore from '../../store/chat.store.js';\n\nconst newMessage = ref('');\nconst allMessages = ref(null);\n\n// Вычисляемые свойства\nconst messages = computed(() => chatStore.state.messages);\n\n// Функция прокрутки вниз\nconst scrollToBottom = () => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n};\n\n// Функция для отправки сообщения\nconst sendMessage = async () => {\n if (newMessage.value) {\n const message = {\n text: newMessage.value,\n username: chatStore.state.username,\n chatId: chatStore.state.currentChatId\n };\n\n chatStore.methods.addMessage(message);\n newMessage.value = '';\n\n // Ждем, пока все анимации и рендеринг завершатся\n await nextTick();\n await new Promise(resolve => setTimeout(resolve, 100)); // Небольшая задержка для анимаций\n scrollToBottom();\n }\n};\n\n// Прокрутка вниз при монтировании\nonMounted(() => {\n nextTick(() => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n });\n});\n\n// Прокрутка вниз при изменении сообщений\nwatch(messages, () => {\n nextTick(() => {\n if (allMessages.value) {\n allMessages.value.scrollTop = allMessages.value.scrollHeight;\n }\n });\n}, { deep: true });\n\n// Обработчик после завершения анимации входа нового элемента\n</script>\n\n<style>\n.list-enter-active,\n.list-leave-active {\n transition: all 0.5s ease;\n}\n.list-enter-from,\n.list-leave-to {\n opacity: 0;\n transform: translateX(30px);\n}\n</style>"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAsCA,UAAM,aAAa,IAAI,EAAE;AACzB,UAAM,cAAc,IAAI,IAAI;AAG5B,UAAM,WAAW,SAAS,MAAM,UAAU,MAAM,QAAQ;AAGxD,UAAM,iBAAiB,MAAM;AAC3B,UAAI,YAAY,OAAO;AACrB,oBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,MACpD;AAAA,IACA;AAGA,UAAM,cAAc,YAAY;AAC9B,UAAI,WAAW,OAAO;AACpB,cAAM,UAAU;AAAA,UACd,MAAM,WAAW;AAAA,UACjB,UAAU,UAAU,MAAM;AAAA,UAC1B,QAAQ,UAAU,MAAM;AAAA,QACzB;AAED,kBAAU,QAAQ,WAAW,OAAO;AACpC,mBAAW,QAAQ;AAGnB,cAAM,SAAU;AAChB,cAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAG,CAAC;AACrD,uBAAgB;AAAA,MACpB;AAAA,IACA;AAGA,cAAU,MAAM;AACd,eAAS,MAAM;AACb,YAAI,YAAY,OAAO;AACrB,sBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,QACtD;AAAA,MACA,CAAG;AAAA,IACH,CAAC;AAGD,UAAM,UAAU,MAAM;AACpB,eAAS,MAAM;AACb,YAAI,YAAY,OAAO;AACrB,sBAAY,MAAM,YAAY,YAAY,MAAM;AAAA,QACtD;AAAA,MACA,CAAG;AAAA,IACH,GAAG,EAAE,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -8,13 +8,12 @@ const state = vue.reactive({
|
|
|
8
8
|
username: null
|
|
9
9
|
});
|
|
10
10
|
const methods = {
|
|
11
|
-
async connectWebSocket() {
|
|
12
|
-
console.log("process env");
|
|
13
|
-
console.log(process.env.WSS_URL);
|
|
11
|
+
async connectWebSocket(user) {
|
|
14
12
|
try {
|
|
15
|
-
|
|
16
|
-
await globals_websocket.default.connect(
|
|
17
|
-
globals_websocket.default.
|
|
13
|
+
console.log("connect", user);
|
|
14
|
+
await globals_websocket.default.connect(user);
|
|
15
|
+
globals_websocket.default.removeModuleListeners("chat");
|
|
16
|
+
const listenerId = globals_websocket.default.addEventListener("message", (data) => {
|
|
18
17
|
if (data.chatId === state.currentChatId) {
|
|
19
18
|
state.messages.push(data);
|
|
20
19
|
}
|
|
@@ -29,8 +28,8 @@ const methods = {
|
|
|
29
28
|
console.log(process.env.API_URL);
|
|
30
29
|
state.messages = messages;
|
|
31
30
|
},
|
|
32
|
-
addMessage(message) {
|
|
33
|
-
globals_websocket.default.send(message);
|
|
31
|
+
async addMessage(message) {
|
|
32
|
+
await globals_websocket.default.send(message);
|
|
34
33
|
},
|
|
35
34
|
async setCurrentChat(chatId) {
|
|
36
35
|
state.currentChatId = chatId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.store.cjs","sources":["../../../../../../src/modules/chats/store/chat.store.js"],"sourcesContent":["import { reactive, readonly } from 'vue';\nimport globalWebSocket from '@martyrs/src/modules/globals/views/classes/globals.websocket.js';\n\nconst state = reactive({\n messages: [],\n currentChatId: null,\n username: null\n});\n\nconst methods = {\n async connectWebSocket() {\n
|
|
1
|
+
{"version":3,"file":"chat.store.cjs","sources":["../../../../../../src/modules/chats/store/chat.store.js"],"sourcesContent":["import { reactive, readonly } from 'vue';\nimport globalWebSocket from '@martyrs/src/modules/globals/views/classes/globals.websocket.js';\n\nconst state = reactive({\n messages: [],\n currentChatId: null,\n username: null\n});\n\nconst methods = {\n async connectWebSocket(user) {\n // Use the global WebSocket instance\n try {\n console.log('connect', user);\n await globalWebSocket.connect(user);\n\n // Remove any existing 'message' listeners for the 'chat' module to avoid duplicates\n globalWebSocket.removeModuleListeners('chat');\n\n // Register chat message event listener\n const listenerId = globalWebSocket.addEventListener('message', (data) => {\n if (data.chatId === state.currentChatId) {\n state.messages.push(data);\n }\n }, { module: 'chat' });\n\n return globalWebSocket;\n } catch (error) {\n console.error('Failed to connect to WebSocket:', error);\n throw error;\n }\n },\n\n setMessages(messages) {\n console.log(process.env.API_URL);\n state.messages = messages;\n },\n\n async addMessage(message) {\n await globalWebSocket.send(message);\n },\n\n async setCurrentChat(chatId) {\n state.currentChatId = chatId;\n state.messages = []; // Clear current messages when changing chat\n\n // Send join chat message through the WebSocket\n globalWebSocket.send({ type: 'joinChat', chatId });\n\n // Fetch chat history\n const response = await fetch(`/messages/${chatId}`);\n const messages = await response.json();\n\n methods.setMessages(messages);\n },\n\n setUsername(username) {\n state.username = username;\n },\n\n disconnectChat() {\n // Remove all chat-specific listeners when leaving chat page\n globalWebSocket.removeModuleListeners('chat');\n // Optionally disconnect the WebSocket if no longer needed\n // globalWebSocket.disconnect(); // Uncomment if you want to fully disconnect\n }\n};\n\nexport default {\n state: readonly(state),\n methods\n};"],"names":["reactive","globalWebSocket","readonly"],"mappings":";;;;AAGA,MAAM,QAAQA,IAAAA,SAAS;AAAA,EACrB,UAAU,CAAE;AAAA,EACZ,eAAe;AAAA,EACf,UAAU;AACZ,CAAC;AAED,MAAM,UAAU;AAAA,EACd,MAAM,iBAAiB,MAAM;AAE3B,QAAI;AACF,cAAQ,IAAI,WAAW,IAAI;AAC3B,YAAMC,kBAAe,QAAC,QAAQ,IAAI;AAGlCA,wBAAe,QAAC,sBAAsB,MAAM;AAG5C,YAAM,aAAaA,kBAAe,QAAC,iBAAiB,WAAW,CAAC,SAAS;AACvE,YAAI,KAAK,WAAW,MAAM,eAAe;AACvC,gBAAM,SAAS,KAAK,IAAI;AAAA,QAClC;AAAA,MACA,GAAS,EAAE,QAAQ,QAAQ;AAErB,aAAOA,kBAAe;AAAA,IACvB,SAAQ,OAAO;AACd,cAAQ,MAAM,mCAAmC,KAAK;AACtD,YAAM;AAAA,IACZ;AAAA,EACG;AAAA,EAED,YAAY,UAAU;AACpB,YAAQ,IAAI,QAAQ,IAAI,OAAO;AAC/B,UAAM,WAAW;AAAA,EAClB;AAAA,EAED,MAAM,WAAW,SAAS;AACxB,UAAMA,kBAAe,QAAC,KAAK,OAAO;AAAA,EACnC;AAAA,EAED,MAAM,eAAe,QAAQ;AAC3B,UAAM,gBAAgB;AACtB,UAAM,WAAW;AAGjBA,sBAAAA,QAAgB,KAAK,EAAE,MAAM,YAAY,OAAM,CAAE;AAGjD,UAAM,WAAW,MAAM,MAAM,aAAa,MAAM,EAAE;AAClD,UAAM,WAAW,MAAM,SAAS,KAAM;AAEtC,YAAQ,YAAY,QAAQ;AAAA,EAC7B;AAAA,EAED,YAAY,UAAU;AACpB,UAAM,WAAW;AAAA,EAClB;AAAA,EAED,iBAAiB;AAEfA,sBAAe,QAAC,sBAAsB,MAAM;AAAA,EAGhD;AACA;AAEA,MAAe,YAAA;AAAA,EACb,OAAOC,IAAQ,SAAC,KAAK;AAAA,EACrB;AACF;;"}
|
|
@@ -6,13 +6,12 @@ const state = reactive({
|
|
|
6
6
|
username: null
|
|
7
7
|
});
|
|
8
8
|
const methods = {
|
|
9
|
-
async connectWebSocket() {
|
|
10
|
-
console.log("process env");
|
|
11
|
-
console.log(process.env.WSS_URL);
|
|
9
|
+
async connectWebSocket(user) {
|
|
12
10
|
try {
|
|
13
|
-
|
|
14
|
-
await globalWebSocket.connect(
|
|
15
|
-
globalWebSocket.
|
|
11
|
+
console.log("connect", user);
|
|
12
|
+
await globalWebSocket.connect(user);
|
|
13
|
+
globalWebSocket.removeModuleListeners("chat");
|
|
14
|
+
const listenerId = globalWebSocket.addEventListener("message", (data) => {
|
|
16
15
|
if (data.chatId === state.currentChatId) {
|
|
17
16
|
state.messages.push(data);
|
|
18
17
|
}
|
|
@@ -27,8 +26,8 @@ const methods = {
|
|
|
27
26
|
console.log(process.env.API_URL);
|
|
28
27
|
state.messages = messages;
|
|
29
28
|
},
|
|
30
|
-
addMessage(message) {
|
|
31
|
-
globalWebSocket.send(message);
|
|
29
|
+
async addMessage(message) {
|
|
30
|
+
await globalWebSocket.send(message);
|
|
32
31
|
},
|
|
33
32
|
async setCurrentChat(chatId) {
|
|
34
33
|
state.currentChatId = chatId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.store.js","sources":["../../../../../../src/modules/chats/store/chat.store.js"],"sourcesContent":["import { reactive, readonly } from 'vue';\nimport globalWebSocket from '@martyrs/src/modules/globals/views/classes/globals.websocket.js';\n\nconst state = reactive({\n messages: [],\n currentChatId: null,\n username: null\n});\n\nconst methods = {\n async connectWebSocket() {\n
|
|
1
|
+
{"version":3,"file":"chat.store.js","sources":["../../../../../../src/modules/chats/store/chat.store.js"],"sourcesContent":["import { reactive, readonly } from 'vue';\nimport globalWebSocket from '@martyrs/src/modules/globals/views/classes/globals.websocket.js';\n\nconst state = reactive({\n messages: [],\n currentChatId: null,\n username: null\n});\n\nconst methods = {\n async connectWebSocket(user) {\n // Use the global WebSocket instance\n try {\n console.log('connect', user);\n await globalWebSocket.connect(user);\n\n // Remove any existing 'message' listeners for the 'chat' module to avoid duplicates\n globalWebSocket.removeModuleListeners('chat');\n\n // Register chat message event listener\n const listenerId = globalWebSocket.addEventListener('message', (data) => {\n if (data.chatId === state.currentChatId) {\n state.messages.push(data);\n }\n }, { module: 'chat' });\n\n return globalWebSocket;\n } catch (error) {\n console.error('Failed to connect to WebSocket:', error);\n throw error;\n }\n },\n\n setMessages(messages) {\n console.log(process.env.API_URL);\n state.messages = messages;\n },\n\n async addMessage(message) {\n await globalWebSocket.send(message);\n },\n\n async setCurrentChat(chatId) {\n state.currentChatId = chatId;\n state.messages = []; // Clear current messages when changing chat\n\n // Send join chat message through the WebSocket\n globalWebSocket.send({ type: 'joinChat', chatId });\n\n // Fetch chat history\n const response = await fetch(`/messages/${chatId}`);\n const messages = await response.json();\n\n methods.setMessages(messages);\n },\n\n setUsername(username) {\n state.username = username;\n },\n\n disconnectChat() {\n // Remove all chat-specific listeners when leaving chat page\n globalWebSocket.removeModuleListeners('chat');\n // Optionally disconnect the WebSocket if no longer needed\n // globalWebSocket.disconnect(); // Uncomment if you want to fully disconnect\n }\n};\n\nexport default {\n state: readonly(state),\n methods\n};"],"names":[],"mappings":";;AAGA,MAAM,QAAQ,SAAS;AAAA,EACrB,UAAU,CAAE;AAAA,EACZ,eAAe;AAAA,EACf,UAAU;AACZ,CAAC;AAED,MAAM,UAAU;AAAA,EACd,MAAM,iBAAiB,MAAM;AAE3B,QAAI;AACF,cAAQ,IAAI,WAAW,IAAI;AAC3B,YAAM,gBAAgB,QAAQ,IAAI;AAGlC,sBAAgB,sBAAsB,MAAM;AAG5C,YAAM,aAAa,gBAAgB,iBAAiB,WAAW,CAAC,SAAS;AACvE,YAAI,KAAK,WAAW,MAAM,eAAe;AACvC,gBAAM,SAAS,KAAK,IAAI;AAAA,QAClC;AAAA,MACA,GAAS,EAAE,QAAQ,QAAQ;AAErB,aAAO;AAAA,IACR,SAAQ,OAAO;AACd,cAAQ,MAAM,mCAAmC,KAAK;AACtD,YAAM;AAAA,IACZ;AAAA,EACG;AAAA,EAED,YAAY,UAAU;AACpB,YAAQ,IAAI,QAAQ,IAAI,OAAO;AAC/B,UAAM,WAAW;AAAA,EAClB;AAAA,EAED,MAAM,WAAW,SAAS;AACxB,UAAM,gBAAgB,KAAK,OAAO;AAAA,EACnC;AAAA,EAED,MAAM,eAAe,QAAQ;AAC3B,UAAM,gBAAgB;AACtB,UAAM,WAAW;AAGjB,oBAAgB,KAAK,EAAE,MAAM,YAAY,OAAM,CAAE;AAGjD,UAAM,WAAW,MAAM,MAAM,aAAa,MAAM,EAAE;AAClD,UAAM,WAAW,MAAM,SAAS,KAAM;AAEtC,YAAQ,YAAY,QAAQ;AAAA,EAC7B;AAAA,EAED,YAAY,UAAU;AACpB,UAAM,WAAW;AAAA,EAClB;AAAA,EAED,iBAAiB;AAEf,oBAAgB,sBAAsB,MAAM;AAAA,EAGhD;AACA;AAEA,MAAe,YAAA;AAAA,EACb,OAAO,SAAS,KAAK;AAAA,EACrB;AACF;"}
|
|
@@ -45,16 +45,14 @@ class GlobalWebSocket {
|
|
|
45
45
|
if (typeof window === "undefined") {
|
|
46
46
|
return Promise.resolve(false);
|
|
47
47
|
}
|
|
48
|
-
if (this.isConnected && this.userId === userId && this.socket) {
|
|
49
|
-
return Promise.resolve(this.socket);
|
|
50
|
-
}
|
|
51
48
|
this.userId = userId;
|
|
52
|
-
if (this.
|
|
53
|
-
return this.
|
|
49
|
+
if (this.isConnected && this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
50
|
+
return Promise.resolve(this.socket);
|
|
54
51
|
}
|
|
52
|
+
this.connectPromise = null;
|
|
55
53
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
56
54
|
this.disconnect();
|
|
57
|
-
const wsUrl = userId ? `${this.baseUrl}?userId=${userId}` : this.baseUrl;
|
|
55
|
+
const wsUrl = userId ? `${this.baseUrl}?userId=${encodeURIComponent(userId)}` : this.baseUrl;
|
|
58
56
|
this.socket = new WebSocket(wsUrl);
|
|
59
57
|
this.socket.onopen = () => {
|
|
60
58
|
this._handleOpen();
|
|
@@ -105,14 +103,14 @@ class GlobalWebSocket {
|
|
|
105
103
|
* @param {Object|String} data - Data to send
|
|
106
104
|
* @returns {Boolean} Success status
|
|
107
105
|
*/
|
|
108
|
-
send(data) {
|
|
106
|
+
async send(data) {
|
|
109
107
|
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
|
110
108
|
console.error("Cannot send message: WebSocket is not connected");
|
|
111
109
|
return false;
|
|
112
110
|
}
|
|
113
111
|
try {
|
|
114
112
|
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
115
|
-
this.socket.send(message);
|
|
113
|
+
await this.socket.send(message);
|
|
116
114
|
return true;
|
|
117
115
|
} catch (error) {
|
|
118
116
|
console.error("Error sending WebSocket message:", error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globals.websocket.cjs","sources":["../../../../../../../src/modules/globals/views/classes/globals.websocket.js"],"sourcesContent":["/**\n * Global WebSocket handler for centralized WebSocket connections\n * @martyrs/src/modules/globals/views/classes/globals.websocket.js\n */\nclass GlobalWebSocket {\n constructor() {\n this.socket = null;\n this.isConnected = false;\n this.reconnectAttempts = 0;\n this.maxReconnectAttempts = 5;\n this.reconnectDelay = 3000;\n this.baseUrl = null;\n this.pingInterval = null;\n this.pingIntervalTime = 30000; // 30 seconds\n this.listeners = {};\n this.userId = null;\n this.connectPromise = null;\n }\n\n /**\n * Initialize WebSocket with configuration options\n * @param {Object} options - Configuration options\n */\n initialize(options = {}) {\n this.maxReconnectAttempts = options.maxReconnectAttempts || this.maxReconnectAttempts;\n this.reconnectDelay = options.reconnectDelay || this.reconnectDelay;\n this.baseUrl = options.wsUrl || this._getDefaultWsUrl();\n this.pingIntervalTime = options.pingInterval || this.pingIntervalTime;\n }\n\n /**\n * Get default WebSocket URL based on current HTTP URL\n * @returns {String} WebSocket URL\n */\n _getDefaultWsUrl() {\n // Check if window exists (for SSR compatibility)\n if (typeof window === 'undefined') {\n return '/api/ws'; // Default fallback for SSR\n }\n \n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const host = window.location.host;\n return `${protocol}//${host}/api/ws`;\n }\n\n /**\n * Connect to WebSocket server\n * @param {String} userId - User ID for authentication\n * @returns {Promise} Promise that resolves when connection is established\n */\n connect(userId) {\n // Skip if running in SSR\n if (typeof window === 'undefined') {\n return Promise.resolve(false);\n }\n\n // If already connected with the same user, just return the existing connection\n if (this.isConnected && this.userId === userId && this.socket) {\n return Promise.resolve(this.socket);\n }\n\n this.userId = userId;\n\n // If there's already a connection attempt in progress, return that promise\n if (this.connectPromise) {\n return this.connectPromise;\n }\n\n // Create new connection promise\n this.connectPromise = new Promise((resolve, reject) => {\n // Close existing connection if any\n this.disconnect();\n\n // Create new WebSocket connection with user ID\n const wsUrl = userId ? `${this.baseUrl}?userId=${userId}` : this.baseUrl;\n this.socket = new WebSocket(wsUrl);\n\n // Setup event handlers\n this.socket.onopen = () => {\n this._handleOpen();\n resolve(this.socket);\n };\n \n this.socket.onmessage = this._handleMessage.bind(this);\n this.socket.onerror = (error) => {\n this._handleError(error);\n reject(error);\n };\n \n this.socket.onclose = this._handleClose.bind(this);\n\n // Timeout for connection\n setTimeout(() => {\n if (!this.isConnected) {\n reject(new Error('WebSocket connection timeout'));\n }\n }, 10000);\n }).finally(() => {\n this.connectPromise = null;\n });\n\n return this.connectPromise;\n }\n\n /**\n * Disconnect from WebSocket server\n */\n disconnect() {\n // Skip if running in SSR\n if (typeof window === 'undefined') {\n return;\n }\n\n if (this.socket) {\n // Remove event listeners\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onerror = null;\n this.socket.onclose = null;\n \n // Close connection\n if (this.socket.readyState === WebSocket.OPEN || \n this.socket.readyState === WebSocket.CONNECTING) {\n this.socket.close();\n }\n \n this.socket = null;\n }\n\n // Clear ping interval\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n\n this.isConnected = false;\n this.userId = null;\n }\n\n /**\n * Send data through WebSocket\n * @param {Object|String} data - Data to send\n * @returns {Boolean} Success status\n */\n send(data) {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n console.error('Cannot send message: WebSocket is not connected');\n return false;\n }\n\n try {\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n this.socket.send(message);\n return true;\n } catch (error) {\n console.error('Error sending WebSocket message:', error);\n return false;\n }\n }\n\n /**\n * Register an event listener\n * @param {String} eventType - Event type to listen for\n * @param {Function} callback - Callback function\n * @param {Object} options - Additional options like module name for namespacing\n * @returns {String} Listener ID for unregistering\n */\n addEventListener(eventType, callback, options = {}) {\n const listenerId = `${options.module || 'global'}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n \n if (!this.listeners[eventType]) {\n this.listeners[eventType] = {};\n }\n \n this.listeners[eventType][listenerId] = callback;\n return listenerId;\n }\n\n /**\n * Remove an event listener\n * @param {String} eventType - Event type\n * @param {String} listenerId - Listener ID returned from addEventListener\n */\n removeEventListener(eventType, listenerId) {\n if (this.listeners[eventType] && this.listeners[eventType][listenerId]) {\n delete this.listeners[eventType][listenerId];\n }\n }\n\n /**\n * Remove all listeners for a module\n * @param {String} moduleName - Module name to remove listeners for\n */\n removeModuleListeners(moduleName) {\n if (!moduleName) return;\n \n Object.keys(this.listeners).forEach(eventType => {\n Object.keys(this.listeners[eventType]).forEach(listenerId => {\n if (listenerId.startsWith(`${moduleName}_`)) {\n delete this.listeners[eventType][listenerId];\n }\n });\n });\n }\n\n /**\n * Handle WebSocket open event\n */\n _handleOpen() {\n this.isConnected = true;\n this.reconnectAttempts = 0;\n \n // Setup ping interval to keep connection alive\n this.pingInterval = setInterval(() => {\n if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n this.socket.send(JSON.stringify({ type: 'ping' }));\n }\n }, this.pingIntervalTime);\n\n // Notify listeners\n this._notifyListeners('open', { isConnected: true });\n }\n\n /**\n * Handle WebSocket message event\n * @param {Event} event - WebSocket message event\n */\n _handleMessage(event) {\n try {\n const data = JSON.parse(event.data);\n \n // Generic event notifications\n this._notifyListeners('message', data);\n \n // Specific event type notifications\n if (data.type) {\n this._notifyListeners(data.type, data);\n }\n \n } catch (error) {\n console.error('Error processing WebSocket message:', error);\n }\n }\n\n /**\n * Handle WebSocket error\n * @param {Error} error - WebSocket error\n */\n _handleError(error) {\n console.error('WebSocket error:', error);\n this._notifyListeners('error', { error });\n }\n\n /**\n * Handle WebSocket close event\n * @param {Event} event - WebSocket close event\n */\n _handleClose(event) {\n this.isConnected = false;\n \n // Clear ping interval\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n \n this._notifyListeners('close', { code: event.code, reason: event.reason });\n \n // Attempt to reconnect if not a normal closure and we have a userId\n if (event.code !== 1000 && this.userId && this.reconnectAttempts < this.maxReconnectAttempts) {\n this.reconnectAttempts++;\n const delay = this.reconnectDelay * this.reconnectAttempts;\n \n setTimeout(() => {\n if (this.userId) {\n this.connect(this.userId).catch(error => {\n console.error('Reconnection failed:', error);\n });\n }\n }, delay);\n }\n }\n\n /**\n * Notify event listeners\n * @param {String} eventType - Event type\n * @param {Object} data - Event data\n */\n _notifyListeners(eventType, data) {\n if (!this.listeners[eventType]) return;\n \n Object.values(this.listeners[eventType]).forEach(callback => {\n try {\n callback(data);\n } catch (error) {\n console.error(`Error in WebSocket ${eventType} listener:`, error);\n }\n });\n }\n\n /**\n * Get connection status\n * @returns {Boolean} Connection status\n */\n isSocketConnected() {\n return this.isConnected && this.socket?.readyState === WebSocket.OPEN;\n }\n}\n\n// Create singleton instance\nconst globalWebSocket = new GlobalWebSocket();\n\nexport default globalWebSocket;"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"globals.websocket.cjs","sources":["../../../../../../../src/modules/globals/views/classes/globals.websocket.js"],"sourcesContent":["/**\n * Global WebSocket handler for centralized WebSocket connections\n * @martyrs/src/modules/globals/views/classes/globals.websocket.js\n */\nclass GlobalWebSocket {\n constructor() {\n this.socket = null;\n this.isConnected = false;\n this.reconnectAttempts = 0;\n this.maxReconnectAttempts = 5;\n this.reconnectDelay = 3000;\n this.baseUrl = null;\n this.pingInterval = null;\n this.pingIntervalTime = 30000; // 30 seconds\n this.listeners = {};\n this.userId = null;\n this.connectPromise = null;\n }\n\n /**\n * Initialize WebSocket with configuration options\n * @param {Object} options - Configuration options\n */\n initialize(options = {}) {\n this.maxReconnectAttempts = options.maxReconnectAttempts || this.maxReconnectAttempts;\n this.reconnectDelay = options.reconnectDelay || this.reconnectDelay;\n this.baseUrl = options.wsUrl || this._getDefaultWsUrl();\n this.pingIntervalTime = options.pingInterval || this.pingIntervalTime;\n }\n\n /**\n * Get default WebSocket URL based on current HTTP URL\n * @returns {String} WebSocket URL\n */\n _getDefaultWsUrl() {\n // Check if window exists (for SSR compatibility)\n if (typeof window === 'undefined') {\n return '/api/ws'; // Default fallback for SSR\n }\n \n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const host = window.location.host;\n return `${protocol}//${host}/api/ws`;\n }\n\n /**\n * Connect to WebSocket server\n * @param {String} userId - User ID for authentication\n * @returns {Promise} Promise that resolves when connection is established\n */\n connect(userId) {\n // Skip if running in SSR\n if (typeof window === 'undefined') {\n return Promise.resolve(false);\n }\n\n // Always update userId before any connection logic\n this.userId = userId;\n\n // If already connected with the same user and socket is valid, return the existing connection\n if (this.isConnected && this.socket && this.socket.readyState === WebSocket.OPEN) {\n return Promise.resolve(this.socket);\n }\n\n // Clear any existing connection promise to avoid conflicts\n this.connectPromise = null;\n\n // Create new connection promise\n this.connectPromise = new Promise((resolve, reject) => {\n // Close existing connection if any\n this.disconnect();\n\n // Create new WebSocket connection with user ID\n const wsUrl = userId ? `${this.baseUrl}?userId=${encodeURIComponent(userId)}` : this.baseUrl;\n this.socket = new WebSocket(wsUrl);\n\n // Setup event handlers\n this.socket.onopen = () => {\n this._handleOpen();\n resolve(this.socket);\n };\n \n this.socket.onmessage = this._handleMessage.bind(this);\n this.socket.onerror = (error) => {\n this._handleError(error);\n reject(error);\n };\n \n this.socket.onclose = this._handleClose.bind(this);\n\n // Timeout for connection\n setTimeout(() => {\n if (!this.isConnected) {\n reject(new Error('WebSocket connection timeout'));\n }\n }, 10000);\n }).finally(() => {\n this.connectPromise = null;\n });\n\n return this.connectPromise;\n }\n\n /**\n * Disconnect from WebSocket server\n */\n disconnect() {\n // Skip if running in SSR\n if (typeof window === 'undefined') {\n return;\n }\n\n if (this.socket) {\n // Remove event listeners\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onerror = null;\n this.socket.onclose = null;\n \n // Close connection\n if (this.socket.readyState === WebSocket.OPEN || \n this.socket.readyState === WebSocket.CONNECTING) {\n this.socket.close();\n }\n \n this.socket = null;\n }\n\n // Clear ping interval\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n\n this.isConnected = false;\n this.userId = null;\n }\n\n /**\n * Send data through WebSocket\n * @param {Object|String} data - Data to send\n * @returns {Boolean} Success status\n */\n async send(data) {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n console.error('Cannot send message: WebSocket is not connected');\n return false;\n }\n\n try {\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n await this.socket.send(message);\n return true;\n } catch (error) {\n console.error('Error sending WebSocket message:', error);\n return false;\n }\n }\n\n /**\n * Register an event listener\n * @param {String} eventType - Event type to listen for\n * @param {Function} callback - Callback function\n * @param {Object} options - Additional options like module name for namespacing\n * @returns {String} Listener ID for unregistering\n */\n addEventListener(eventType, callback, options = {}) {\n const listenerId = `${options.module || 'global'}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n \n if (!this.listeners[eventType]) {\n this.listeners[eventType] = {};\n }\n \n this.listeners[eventType][listenerId] = callback;\n return listenerId;\n }\n\n /**\n * Remove an event listener\n * @param {String} eventType - Event type\n * @param {String} listenerId - Listener ID returned from addEventListener\n */\n removeEventListener(eventType, listenerId) {\n if (this.listeners[eventType] && this.listeners[eventType][listenerId]) {\n delete this.listeners[eventType][listenerId];\n }\n }\n\n /**\n * Remove all listeners for a module\n * @param {String} moduleName - Module name to remove listeners for\n */\n removeModuleListeners(moduleName) {\n if (!moduleName) return;\n \n Object.keys(this.listeners).forEach(eventType => {\n Object.keys(this.listeners[eventType]).forEach(listenerId => {\n if (listenerId.startsWith(`${moduleName}_`)) {\n delete this.listeners[eventType][listenerId];\n }\n });\n });\n }\n\n /**\n * Handle WebSocket open event\n */\n _handleOpen() {\n this.isConnected = true;\n this.reconnectAttempts = 0;\n \n // Setup ping interval to keep connection alive\n this.pingInterval = setInterval(() => {\n if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n this.socket.send(JSON.stringify({ type: 'ping' }));\n }\n }, this.pingIntervalTime);\n\n // Notify listeners\n this._notifyListeners('open', { isConnected: true });\n }\n\n /**\n * Handle WebSocket message event\n * @param {Event} event - WebSocket message event\n */\n _handleMessage(event) {\n try {\n const data = JSON.parse(event.data);\n \n // Generic event notifications\n this._notifyListeners('message', data);\n \n // Specific event type notifications\n if (data.type) {\n this._notifyListeners(data.type, data);\n }\n \n } catch (error) {\n console.error('Error processing WebSocket message:', error);\n }\n }\n\n /**\n * Handle WebSocket error\n * @param {Error} error - WebSocket error\n */\n _handleError(error) {\n console.error('WebSocket error:', error);\n this._notifyListeners('error', { error });\n }\n\n /**\n * Handle WebSocket close event\n * @param {Event} event - WebSocket close event\n */\n _handleClose(event) {\n this.isConnected = false;\n \n // Clear ping interval\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n \n this._notifyListeners('close', { code: event.code, reason: event.reason });\n \n // Attempt to reconnect if not a normal closure and we have a userId\n if (event.code !== 1000 && this.userId && this.reconnectAttempts < this.maxReconnectAttempts) {\n this.reconnectAttempts++;\n const delay = this.reconnectDelay * this.reconnectAttempts;\n \n setTimeout(() => {\n if (this.userId) {\n this.connect(this.userId).catch(error => {\n console.error('Reconnection failed:', error);\n });\n }\n }, delay);\n }\n }\n\n /**\n * Notify event listeners\n * @param {String} eventType - Event type\n * @param {Object} data - Event data\n */\n _notifyListeners(eventType, data) {\n if (!this.listeners[eventType]) return;\n \n Object.values(this.listeners[eventType]).forEach(callback => {\n try {\n callback(data);\n } catch (error) {\n console.error(`Error in WebSocket ${eventType} listener:`, error);\n }\n });\n }\n\n /**\n * Get connection status\n * @returns {Boolean} Connection status\n */\n isSocketConnected() {\n return this.isConnected && this.socket?.readyState === WebSocket.OPEN;\n }\n}\n\n// Create singleton instance\nconst globalWebSocket = new GlobalWebSocket();\n\nexport default globalWebSocket;"],"names":[],"mappings":"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"}
|
|
@@ -43,16 +43,14 @@ class GlobalWebSocket {
|
|
|
43
43
|
if (typeof window === "undefined") {
|
|
44
44
|
return Promise.resolve(false);
|
|
45
45
|
}
|
|
46
|
-
if (this.isConnected && this.userId === userId && this.socket) {
|
|
47
|
-
return Promise.resolve(this.socket);
|
|
48
|
-
}
|
|
49
46
|
this.userId = userId;
|
|
50
|
-
if (this.
|
|
51
|
-
return this.
|
|
47
|
+
if (this.isConnected && this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
48
|
+
return Promise.resolve(this.socket);
|
|
52
49
|
}
|
|
50
|
+
this.connectPromise = null;
|
|
53
51
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
54
52
|
this.disconnect();
|
|
55
|
-
const wsUrl = userId ? `${this.baseUrl}?userId=${userId}` : this.baseUrl;
|
|
53
|
+
const wsUrl = userId ? `${this.baseUrl}?userId=${encodeURIComponent(userId)}` : this.baseUrl;
|
|
56
54
|
this.socket = new WebSocket(wsUrl);
|
|
57
55
|
this.socket.onopen = () => {
|
|
58
56
|
this._handleOpen();
|
|
@@ -103,14 +101,14 @@ class GlobalWebSocket {
|
|
|
103
101
|
* @param {Object|String} data - Data to send
|
|
104
102
|
* @returns {Boolean} Success status
|
|
105
103
|
*/
|
|
106
|
-
send(data) {
|
|
104
|
+
async send(data) {
|
|
107
105
|
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
|
108
106
|
console.error("Cannot send message: WebSocket is not connected");
|
|
109
107
|
return false;
|
|
110
108
|
}
|
|
111
109
|
try {
|
|
112
110
|
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
113
|
-
this.socket.send(message);
|
|
111
|
+
await this.socket.send(message);
|
|
114
112
|
return true;
|
|
115
113
|
} catch (error) {
|
|
116
114
|
console.error("Error sending WebSocket message:", error);
|