@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.
Files changed (94) hide show
  1. package/dist/martyrs/src/components/Block/Block.vue.cjs +1 -1
  2. package/dist/martyrs/src/components/Block/Block.vue.js +1 -1
  3. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.cjs → Tooltip.vue.cjs} +2 -2
  4. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js.map → Tooltip.vue.cjs.map} +1 -1
  5. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js → Tooltip.vue.js} +2 -2
  6. package/dist/martyrs/src/components/Tooltip/Tooltip.vue.js.map +1 -0
  7. package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.cjs +13 -3
  8. package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.cjs.map +1 -1
  9. package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.js +14 -4
  10. package/dist/martyrs/src/modules/chats/components/pages/ChatPage.vue.js.map +1 -1
  11. package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.cjs +24 -6
  12. package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.cjs.map +1 -1
  13. package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.js +25 -7
  14. package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.js.map +1 -1
  15. package/dist/martyrs/src/modules/chats/store/chat.store.cjs +7 -8
  16. package/dist/martyrs/src/modules/chats/store/chat.store.cjs.map +1 -1
  17. package/dist/martyrs/src/modules/chats/store/chat.store.js +7 -8
  18. package/dist/martyrs/src/modules/chats/store/chat.store.js.map +1 -1
  19. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs +6 -8
  20. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.cjs.map +1 -1
  21. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js +6 -8
  22. package/dist/martyrs/src/modules/globals/views/classes/globals.websocket.js.map +1 -1
  23. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.cjs +1 -1
  24. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.js +1 -1
  25. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.cjs +1 -1
  26. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.cjs.map +1 -1
  27. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js +1 -1
  28. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js.map +1 -1
  29. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.cjs +7 -1
  30. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.cjs.map +1 -1
  31. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +7 -1
  32. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
  33. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.cjs +2 -2
  34. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.cjs.map +1 -1
  35. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.js +2 -2
  36. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderItem.vue.js.map +1 -1
  37. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.cjs +1 -1
  38. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +1 -1
  39. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +200 -92
  40. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs.map +1 -1
  41. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +213 -105
  42. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js.map +1 -1
  43. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +8 -11
  44. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
  45. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +9 -12
  46. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
  47. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +99 -99
  48. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs.map +1 -1
  49. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +102 -102
  50. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js.map +1 -1
  51. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.cjs +14 -8
  52. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.cjs.map +1 -1
  53. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +15 -9
  54. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js.map +1 -1
  55. package/dist/martyrs/src/modules/orders/store/orders.cjs +51 -0
  56. package/dist/martyrs/src/modules/orders/store/orders.cjs.map +1 -1
  57. package/dist/martyrs/src/modules/orders/store/orders.js +51 -0
  58. package/dist/martyrs/src/modules/orders/store/orders.js.map +1 -1
  59. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
  60. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +1 -1
  61. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
  62. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
  63. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs +15 -12
  64. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs.map +1 -1
  65. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js +15 -12
  66. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js.map +1 -1
  67. package/dist/martyrs/src/modules/spots/store/spots.cjs +11 -4
  68. package/dist/martyrs/src/modules/spots/store/spots.cjs.map +1 -1
  69. package/dist/martyrs/src/modules/spots/store/spots.js +11 -4
  70. package/dist/martyrs/src/modules/spots/store/spots.js.map +1 -1
  71. package/dist/orders.server.js +6 -0
  72. package/dist/orders.server.mjs +6 -0
  73. package/dist/spots.server.js +44 -3
  74. package/dist/spots.server.mjs +44 -3
  75. package/dist/style.css +17 -17
  76. package/package.json +1 -1
  77. package/src/modules/chats/components/pages/ChatPage.vue +18 -23
  78. package/src/modules/chats/components/sections/ChatWindow.vue +55 -38
  79. package/src/modules/chats/store/chat.store.js +20 -21
  80. package/src/modules/globals/views/classes/globals.websocket.js +10 -11
  81. package/src/modules/marketplace/views/components/sections/SectionMenu.vue +1 -1
  82. package/src/modules/notifications/components/elements/NotificationBadge.vue +7 -0
  83. package/src/modules/orders/components/blocks/CardOrderItem.vue +2 -2
  84. package/src/modules/orders/components/pages/OrderBackoffice.vue +146 -77
  85. package/src/modules/orders/components/pages/OrderCreate.vue +5 -10
  86. package/src/modules/orders/components/sections/FormDelivery.vue +35 -43
  87. package/src/modules/orders/components/sections/FormPayment.vue +17 -7
  88. package/src/modules/orders/controllers/orders.controller.js +10 -0
  89. package/src/modules/orders/store/orders.js +65 -0
  90. package/src/modules/spots/components/blocks/CardSpot.vue +8 -7
  91. package/src/modules/spots/controllers/spots.controller.js +49 -2
  92. package/src/modules/spots/routes/spots.routes.js +3 -1
  93. package/src/modules/spots/store/spots.js +12 -4
  94. 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.vue2.cjs");
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.vue2.js";
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.vue2.cjs.map
52
+ //# sourceMappingURL=Tooltip.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.vue2.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;;;;;;;;;;;;;;;;"}
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.vue2.js.map
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.createBlock(ChatWindow.default);
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 <!-- <div class=\"chat-page h-max-20r\"> -->\n <!-- <aside class=\"chat-list\"> -->\n <!-- Примерный список чатов. Должен быть дополнен реальной логикой -->\n <!-- <div v-for=\"chat in chats\" :key=\"chat.id\" @click=\"selectChat(chat.id)\">\n Чат {{ chat.name }}\n </div> -->\n <!-- </aside> -->\n <!-- <main class=\"chat-main\"> -->\n <ChatWindow />\n <!-- </main> -->\n <!-- </div> -->\n</template>\n\n<script setup>\nimport { ref, onMounted } 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 chatID: {\n type: String,\n required: true\n },\n})\n\n// const chats = ref([\n// // Примерный список. В реальном приложении, список чатов должен загружаться с сервера.\n// { id: 'chat1', name: 'Чат 1' },\n// { id: 'chat2', name: 'Чат 2' }\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(); // Подключение к WebSocket\n chatStore.methods.setCurrentChat(props.chatID);\n});\n</script>\n\n<style>\n/* Стили остаются без изменений */\n</style>\n"],"names":["onMounted","chatStore"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,UAAM,QAAQ;AAqBdA,QAAAA,UAAU,YAAW;AACnBC,iBAAS,QAAC,QAAQ,YAAY,MAAM,YAAY,MAAM;AACtD,YAAMA,WAAS,QAAC,QAAQ;AACxBA,iBAAAA,QAAU,QAAQ,eAAe,MAAM,MAAM;AAAA,IAC/C,CAAC;;;;;;;"}
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, createBlock, openBlock } from "vue";
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(), createBlock(_sfc_main$1);
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 <!-- <div class=\"chat-page h-max-20r\"> -->\n <!-- <aside class=\"chat-list\"> -->\n <!-- Примерный список чатов. Должен быть дополнен реальной логикой -->\n <!-- <div v-for=\"chat in chats\" :key=\"chat.id\" @click=\"selectChat(chat.id)\">\n Чат {{ chat.name }}\n </div> -->\n <!-- </aside> -->\n <!-- <main class=\"chat-main\"> -->\n <ChatWindow />\n <!-- </main> -->\n <!-- </div> -->\n</template>\n\n<script setup>\nimport { ref, onMounted } 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 chatID: {\n type: String,\n required: true\n },\n})\n\n// const chats = ref([\n// // Примерный список. В реальном приложении, список чатов должен загружаться с сервера.\n// { id: 'chat1', name: 'Чат 1' },\n// { id: 'chat2', name: 'Чат 2' }\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(); // Подключение к WebSocket\n chatStore.methods.setCurrentChat(props.chatID);\n});\n</script>\n\n<style>\n/* Стили остаются без изменений */\n</style>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAmBA,UAAM,QAAQ;AAqBd,cAAU,YAAW;AACnB,gBAAU,QAAQ,YAAY,MAAM,YAAY,MAAM;AACtD,YAAM,UAAU,QAAQ;AACxB,gBAAU,QAAQ,eAAe,MAAM,MAAM;AAAA,IAC/C,CAAC;;;;;;"}
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 sendMessage = () => {
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.watch(chat_store.default.state.messages, () => {
36
- allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight;
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 \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\">\n <ChatMessage\n v-for=\"message in messages\"\n :key=\"message._id\"\n :message=\"message\"\n />\n\n </TransitionGroup>\n </transition>\n \n </div>\n </div>\n\n \n <div class=\"flex-nowrap flex-v-center flex bg-white w-100 radius-big pd-small\">\n <IconAdd\n class=\"mn-r-thin t-transp i-regular\"\n />\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 } 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 sendMessage = () => {\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 console.log(allMessages.value.lastElementChild.offsetHeight)\n allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight\n \n newMessage.value = '';\n }\n};\n\n// // При добавлении нового сообщения автоматически прокручиваем вниз\nwatch(chatStore.state.messages, () => {\n allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight\n}, {deep: true});\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>\n"],"names":["ref","computed","chatStore","watch"],"mappings":";;;;;;;;;;;;;;;;;;AA4CA,UAAM,aAAaA,IAAG,IAAC,EAAE;AACzB,UAAM,cAAcA,IAAG,IAAC,IAAI;AAG5B,UAAM,WAAWC,IAAAA,SAAS,MAAMC,mBAAU,MAAM,QAAQ;AAGxD,UAAM,cAAc,MAAM;AACxB,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,gBAAQ,IAAI,YAAY,MAAM,iBAAiB,YAAY;AAC3D,oBAAY,MAAM,YAAY,YAAY,MAAM,iBAAiB;AAEjE,mBAAW,QAAQ;AAAA,MACvB;AAAA,IACA;AAGAC,QAAAA,MAAMD,WAAS,QAAC,MAAM,UAAU,MAAM;AACpC,kBAAY,MAAM,YAAY,YAAY,MAAM,iBAAiB;AAAA,IACnE,GAAG,EAAC,MAAM,KAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
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 sendMessage = () => {
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
- watch(chatStore.state.messages, () => {
34
- allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight;
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 \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\">\n <ChatMessage\n v-for=\"message in messages\"\n :key=\"message._id\"\n :message=\"message\"\n />\n\n </TransitionGroup>\n </transition>\n \n </div>\n </div>\n\n \n <div class=\"flex-nowrap flex-v-center flex bg-white w-100 radius-big pd-small\">\n <IconAdd\n class=\"mn-r-thin t-transp i-regular\"\n />\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 } 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 sendMessage = () => {\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 console.log(allMessages.value.lastElementChild.offsetHeight)\n allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight\n \n newMessage.value = '';\n }\n};\n\n// // При добавлении нового сообщения автоматически прокручиваем вниз\nwatch(chatStore.state.messages, () => {\n allMessages.value.scrollTop = allMessages.value.lastElementChild.offsetHeight\n}, {deep: true});\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>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA4CA,UAAM,aAAa,IAAI,EAAE;AACzB,UAAM,cAAc,IAAI,IAAI;AAG5B,UAAM,WAAW,SAAS,MAAM,UAAU,MAAM,QAAQ;AAGxD,UAAM,cAAc,MAAM;AACxB,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,gBAAQ,IAAI,YAAY,MAAM,iBAAiB,YAAY;AAC3D,oBAAY,MAAM,YAAY,YAAY,MAAM,iBAAiB;AAEjE,mBAAW,QAAQ;AAAA,MACvB;AAAA,IACA;AAGA,UAAM,UAAU,MAAM,UAAU,MAAM;AACpC,kBAAY,MAAM,YAAY,YAAY,MAAM,iBAAiB;AAAA,IACnE,GAAG,EAAC,MAAM,KAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
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
- const userId = window.__user_id || null;
16
- await globals_websocket.default.connect(userId);
17
- globals_websocket.default.addEventListener("message", (data) => {
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 console.log('process env')\n console.log(process.env.WSS_URL)\n\n // Use the global WebSocket instance\n try {\n // Get userId from auth store or another source if available\n const userId = window.__user_id || null;\n \n // Connect to the global WebSocket\n await globalWebSocket.connect(userId);\n \n // Register chat message event listener\n 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 addMessage(message) {\n 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 chat-specific listeners when leaving chat page\n globalWebSocket.removeModuleListeners('chat');\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,mBAAmB;AACvB,YAAQ,IAAI,aAAa;AACzB,YAAQ,IAAI,QAAQ,IAAI,OAAO;AAG/B,QAAI;AAEF,YAAM,SAAS,OAAO,aAAa;AAGnC,YAAMC,kBAAe,QAAC,QAAQ,MAAM;AAGpCA,wBAAAA,QAAgB,iBAAiB,WAAW,CAAC,SAAS;AACpD,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,WAAW,SAAS;AAClBA,sBAAe,QAAC,KAAK,OAAO;AAAA,EAC7B;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,EAChD;AACA;AAEA,MAAe,YAAA;AAAA,EACb,OAAOC,IAAQ,SAAC,KAAK;AAAA,EACrB;AACF;;"}
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
- const userId = window.__user_id || null;
14
- await globalWebSocket.connect(userId);
15
- globalWebSocket.addEventListener("message", (data) => {
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 console.log('process env')\n console.log(process.env.WSS_URL)\n\n // Use the global WebSocket instance\n try {\n // Get userId from auth store or another source if available\n const userId = window.__user_id || null;\n \n // Connect to the global WebSocket\n await globalWebSocket.connect(userId);\n \n // Register chat message event listener\n 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 addMessage(message) {\n 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 chat-specific listeners when leaving chat page\n globalWebSocket.removeModuleListeners('chat');\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,mBAAmB;AACvB,YAAQ,IAAI,aAAa;AACzB,YAAQ,IAAI,QAAQ,IAAI,OAAO;AAG/B,QAAI;AAEF,YAAM,SAAS,OAAO,aAAa;AAGnC,YAAM,gBAAgB,QAAQ,MAAM;AAGpC,sBAAgB,iBAAiB,WAAW,CAAC,SAAS;AACpD,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,WAAW,SAAS;AAClB,oBAAgB,KAAK,OAAO;AAAA,EAC7B;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,EAChD;AACA;AAEA,MAAe,YAAA;AAAA,EACb,OAAO,SAAS,KAAK;AAAA,EACrB;AACF;"}
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.connectPromise) {
53
- return this.connectPromise;
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.connectPromise) {
51
- return this.connectPromise;
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);