@ozdao/martyrs 0.2.519 → 0.2.520
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/chats.server.cjs +198 -1
- package/dist/chats.server.js +198 -1
- package/dist/{main-Wr1_4rwl.cjs → main-BM3GslOO.cjs} +6 -6
- package/dist/{main-DgGUrhjT.js → main-Qcn7YlTx.js} +1832 -1828
- package/dist/martyrs/src/components/Address/{Address.vue2.cjs → Address.vue.cjs} +2 -2
- package/dist/martyrs/src/components/Address/{Address.vue2.js.map → Address.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/Address/{Address.vue2.js → Address.vue.js} +2 -2
- package/dist/martyrs/src/components/Address/Address.vue.js.map +1 -0
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs +0 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js +0 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js.map +1 -1
- package/dist/martyrs/src/components/LocationMarker/{LocationMarker.vue2.cjs → LocationMarker.vue.cjs} +2 -2
- package/dist/martyrs/src/components/LocationMarker/{LocationMarker.vue2.js.map → LocationMarker.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/LocationMarker/{LocationMarker.vue2.js → LocationMarker.vue.js} +2 -2
- package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue.js.map +1 -0
- package/dist/martyrs/src/components/Select/{Select.vue2.cjs → Select.vue.cjs} +2 -2
- package/dist/martyrs/src/components/Select/{Select.vue2.js.map → Select.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/Select/{Select.vue2.js → Select.vue.js} +2 -2
- package/dist/martyrs/src/components/Select/Select.vue.js.map +1 -0
- package/dist/martyrs/src/modules/auth/views/components/blocks/CardUser.vue.cjs +2 -2
- package/dist/martyrs/src/modules/auth/views/components/blocks/CardUser.vue.js +2 -2
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.cjs +2 -2
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +4 -4
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.cjs +40 -50
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +59 -69
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/sections/SliderFeatures.vue.cjs +11 -13
- package/dist/martyrs/src/modules/auth/views/components/sections/SliderFeatures.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/sections/SliderFeatures.vue.js +11 -13
- package/dist/martyrs/src/modules/auth/views/components/sections/SliderFeatures.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/store/auth.cjs +9 -0
- package/dist/martyrs/src/modules/auth/views/store/auth.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/store/auth.js +9 -0
- package/dist/martyrs/src/modules/auth/views/store/auth.js.map +1 -1
- package/dist/martyrs/src/modules/chats/components/blocks/ChatMessage.vue.cjs +27 -11
- package/dist/martyrs/src/modules/chats/components/blocks/ChatMessage.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/chats/components/blocks/ChatMessage.vue.js +28 -12
- package/dist/martyrs/src/modules/chats/components/blocks/ChatMessage.vue.js.map +1 -1
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.cjs +62 -0
- 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 +63 -1
- package/dist/martyrs/src/modules/chats/components/sections/ChatWindow.vue.js.map +1 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.cjs +60 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.cjs.map +1 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.js +60 -1
- package/dist/martyrs/src/modules/chats/store/chat.store.js.map +1 -1
- package/dist/martyrs/src/modules/community/components/layouts/Community.vue.cjs +3 -3
- package/dist/martyrs/src/modules/community/components/layouts/Community.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/community/components/layouts/Community.vue.js +3 -3
- package/dist/martyrs/src/modules/community/components/layouts/Community.vue.js.map +1 -1
- package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.cjs +1 -1
- package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/pages/Posts.vue.cjs +50 -368
- package/dist/martyrs/src/modules/community/components/pages/Posts.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/community/components/pages/Posts.vue.js +53 -371
- package/dist/martyrs/src/modules/community/components/pages/Posts.vue.js.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.cjs +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.cjs +0 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +0 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Events.vue.cjs +2 -2
- package/dist/martyrs/src/modules/events/components/pages/Events.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Events.vue.js +2 -2
- package/dist/martyrs/src/modules/events/components/pages/Events.vue.js.map +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.cjs +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +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/globals/views/components/partials/Header.vue.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/components/partials/Header.vue.js +1 -1
- package/dist/martyrs/src/modules/globals/views/components/partials/LocationSelection.vue.cjs +2 -2
- package/dist/martyrs/src/modules/globals/views/components/partials/LocationSelection.vue.js +2 -2
- package/dist/martyrs/src/modules/globals/views/components/sections/Walkthrough.vue.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/mixins/mixins.cjs +7 -0
- package/dist/martyrs/src/modules/globals/views/mixins/mixins.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/mixins/mixins.js +7 -0
- package/dist/martyrs/src/modules/globals/views/mixins/mixins.js.map +1 -1
- package/dist/martyrs/src/modules/icons/pages/IconsPage.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.cjs +180 -19
- package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.js +181 -20
- package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/router/music.cjs +0 -1
- package/dist/martyrs/src/modules/music/router/music.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/router/music.js +0 -1
- package/dist/martyrs/src/modules/music/router/music.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderBackoffice.vue.cjs +2 -2
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderBackoffice.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderBackoffice.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderBackoffice.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/forms/FormApplicationDetails.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/forms/FormApplicationDetails.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/forms/FormCustomerDetails.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/forms/FormCustomerDetails.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +2 -3
- 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 +2 -3
- 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 +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/CardDepartment.vue.cjs +2 -24
- package/dist/martyrs/src/modules/organizations/components/blocks/CardDepartment.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/CardDepartment.vue.js +5 -27
- package/dist/martyrs/src/modules/organizations/components/blocks/CardDepartment.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/Socials.vue.cjs +4 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/Socials.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/Socials.vue.js +4 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/Socials.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.cjs +3 -3
- package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.js +3 -3
- package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.cjs +195 -0
- package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.js +195 -0
- package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.js.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.cjs +402 -0
- package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.js +402 -0
- package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.js.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.cjs +86 -0
- package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.js +86 -0
- package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.js.map +1 -0
- package/dist/martyrs/src/modules/organizations/components/pages/Department.vue.cjs +10 -10
- package/dist/martyrs/src/modules/organizations/components/pages/Department.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Department.vue.js +11 -11
- package/dist/martyrs/src/modules/organizations/components/pages/Department.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +279 -191
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +285 -197
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.cjs +5 -5
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +5 -5
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.cjs +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.cjs +3 -3
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +3 -3
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Publics.vue.cjs +4 -4
- package/dist/martyrs/src/modules/organizations/components/sections/Publics.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Publics.vue.js +4 -4
- package/dist/martyrs/src/modules/organizations/components/sections/Publics.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/configs/navigation.organization.config.cjs +42 -41
- package/dist/martyrs/src/modules/organizations/configs/navigation.organization.config.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/configs/navigation.organization.config.js +53 -52
- package/dist/martyrs/src/modules/organizations/configs/navigation.organization.config.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/organizations.client.cjs +23 -16
- package/dist/martyrs/src/modules/organizations/organizations.client.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/organizations.client.js +35 -28
- package/dist/martyrs/src/modules/organizations/organizations.client.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/router/departments.router.cjs +0 -18
- package/dist/martyrs/src/modules/organizations/router/departments.router.cjs.map +1 -1
- package/dist/martyrs/src/modules/organizations/router/departments.router.js +0 -18
- package/dist/martyrs/src/modules/organizations/router/departments.router.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/store/departments.store.cjs +6 -0
- package/dist/martyrs/src/modules/organizations/store/departments.store.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/store/departments.store.js +6 -0
- package/dist/martyrs/src/modules/organizations/store/departments.store.js.map +1 -0
- package/dist/martyrs/src/modules/organizations/store/invites.store.cjs +6 -0
- package/dist/martyrs/src/modules/organizations/store/invites.store.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/store/invites.store.js +6 -0
- package/dist/martyrs/src/modules/organizations/store/invites.store.js.map +1 -0
- package/dist/martyrs/src/modules/organizations/store/memberships.store.cjs +20 -0
- package/dist/martyrs/src/modules/organizations/store/memberships.store.cjs.map +1 -0
- package/dist/martyrs/src/modules/organizations/store/memberships.store.js +20 -0
- package/dist/martyrs/src/modules/organizations/store/memberships.store.js.map +1 -0
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +2 -3
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +2 -3
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +1 -1
- package/dist/martyrs/src/modules/reports/components/sections/FormReport.vue.cjs +1 -1
- package/dist/martyrs/src/modules/reports/components/sections/FormReport.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs +2 -2
- 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 +2 -2
- package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs +3 -3
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +3 -3
- package/dist/martyrs/src/modules/spots/components/pages/Spots.vue.cjs +60 -272
- package/dist/martyrs/src/modules/spots/components/pages/Spots.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/Spots.vue.js +62 -274
- package/dist/martyrs/src/modules/spots/components/pages/Spots.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.js +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.cjs +2 -2
- package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.js +2 -2
- package/dist/martyrs.cjs.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/notifications.server.cjs +0 -24
- package/dist/notifications.server.js +0 -24
- package/dist/orders.server.cjs +1 -4
- package/dist/orders.server.js +1 -4
- package/dist/organizations.server.cjs +115 -39
- package/dist/organizations.server.js +115 -39
- package/dist/style.css +9 -9
- package/dist/{web-42I-Howt.cjs → web-B0cfxzgu.cjs} +1 -1
- package/dist/{web-ByhZ_fIu.js → web-DVR8m2fm.js} +1 -1
- package/package.json +1 -1
- package/src/components/Feed/Feed.old.vue +0 -1
- package/src/components/Feed/Feed.vue +0 -30
- package/src/modules/auth/FIXES.md +2 -26
- package/src/modules/auth/views/components/blocks/CardUser.vue +2 -2
- package/src/modules/auth/views/components/layouts/Auth.vue +1 -1
- package/src/modules/auth/views/components/pages/Invite.vue +2 -2
- package/src/modules/auth/views/components/pages/Profile.vue +33 -48
- package/src/modules/auth/views/components/sections/SliderFeatures.vue +5 -7
- package/src/modules/auth/views/store/auth.js +15 -0
- package/src/modules/chats/CLAUDE.md +137 -0
- package/src/modules/chats/components/blocks/ChatMessage.vue +12 -0
- package/src/modules/chats/components/sections/ChatWindow.vue +84 -2
- package/src/modules/chats/controllers/chats.controller.js +187 -0
- package/src/modules/chats/models/chat.model.js +21 -0
- package/src/modules/chats/routes/chats.routes.js +46 -0
- package/src/modules/chats/store/chat.store.js +67 -0
- package/src/modules/community/components/layouts/Community.vue +2 -2
- package/src/modules/community/components/pages/Posts.vue +3 -328
- package/src/modules/events/components/pages/EditEventTickets.vue +1 -1
- package/src/modules/events/components/pages/Events.vue +2 -2
- package/src/modules/globals/views/mixins/mixins.js +7 -0
- package/src/modules/marketplace/views/components/layouts/Marketplace.vue +160 -8
- package/src/modules/notifications/controllers/notifications.controller.js +0 -6
- package/src/modules/notifications/services/notification.service.js +1 -17
- package/src/modules/notifications/services/web-push.service.js +0 -2
- package/src/modules/orders/components/blocks/CardOrderBackoffice.vue +2 -2
- package/src/modules/orders/components/blocks/CardOrderVar1.vue +1 -1
- package/src/modules/orders/controllers/orders.controller.js +2 -4
- package/src/modules/organizations/CLAUDE.md +259 -0
- package/src/modules/organizations/components/blocks/CardDepartment.vue +1 -22
- package/src/modules/organizations/components/blocks/Socials.vue +1 -1
- package/src/modules/organizations/components/elements/ButtonToggleMembership.vue +3 -3
- package/src/modules/organizations/components/forms/AddExistingMembersForm.vue +191 -0
- package/src/modules/organizations/components/forms/DepartmentForm.vue +390 -0
- package/src/modules/organizations/components/forms/InviteForm.vue +81 -0
- package/src/modules/organizations/components/pages/Department.vue +10 -10
- package/src/modules/organizations/components/pages/DepartmentEdit.vue +8 -8
- package/src/modules/organizations/components/pages/Members.vue +265 -171
- package/src/modules/organizations/components/pages/Organization.new.vue +172 -183
- package/src/modules/organizations/components/pages/Organization.vue +6 -6
- package/src/modules/organizations/components/pages/OrganizationEdit.vue +1 -1
- package/src/modules/organizations/components/pages/Organizations.vue +1 -1
- package/src/modules/organizations/components/sections/Organizations.vue +2 -2
- package/src/modules/organizations/components/sections/Publics.vue +4 -4
- package/src/modules/organizations/configs/navigation.organization.config.js +40 -39
- package/src/modules/organizations/controllers/departments.controller.js +53 -34
- package/src/modules/organizations/controllers/invites.controller.js +44 -5
- package/src/modules/organizations/controllers/memberships.controller.js +43 -4
- package/src/modules/organizations/organizations.client.js +24 -15
- package/src/modules/organizations/router/departments.router.js +0 -18
- package/src/modules/organizations/routes/departments.routes.js +6 -8
- package/src/modules/organizations/routes/invites.routes.js +6 -4
- package/src/modules/organizations/routes/memberships.routes.js +6 -5
- package/src/modules/organizations/store/departments.store.js +5 -0
- package/src/modules/organizations/store/invites.store.js +5 -0
- package/src/modules/organizations/store/memberships.store.js +23 -0
- package/src/modules/products/components/pages/Products.vue +0 -1
- package/src/modules/spots/components/blocks/CardSpot.vue +1 -1
- package/src/modules/spots/components/pages/Spots.vue +3 -203
- package/src/styles/base/all.scss +0 -15
- package/src/styles/typography.scss +20 -5
- package/dist/martyrs/src/components/Address/Address.vue2.cjs.map +0 -1
- package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue2.cjs.map +0 -1
- package/dist/martyrs/src/components/Select/Select.vue2.cjs.map +0 -1
- package/dist/martyrs/src/modules/globals/views/components/blocks/BlockFilter.vue.cjs +0 -76
- package/dist/martyrs/src/modules/globals/views/components/blocks/BlockFilter.vue.cjs.map +0 -1
- package/dist/martyrs/src/modules/globals/views/components/blocks/BlockFilter.vue.js +0 -76
- package/dist/martyrs/src/modules/globals/views/components/blocks/BlockFilter.vue.js.map +0 -1
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.cjs +0 -280
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.cjs.map +0 -1
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.js +0 -280
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.js.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/departments.cjs +0 -121
- package/dist/martyrs/src/modules/organizations/store/departments.cjs.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/departments.js +0 -121
- package/dist/martyrs/src/modules/organizations/store/departments.js.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/invites.cjs +0 -64
- package/dist/martyrs/src/modules/organizations/store/invites.cjs.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/invites.js +0 -64
- package/dist/martyrs/src/modules/organizations/store/invites.js.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/memberships.cjs +0 -87
- package/dist/martyrs/src/modules/organizations/store/memberships.cjs.map +0 -1
- package/dist/martyrs/src/modules/organizations/store/memberships.js +0 -87
- package/dist/martyrs/src/modules/organizations/store/memberships.js.map +0 -1
- package/src/CLAUDE.MD +0 -15
- package/src/modules/globals/controllers/classes/globals.websocket.ws.js +0 -102
- package/src/modules/globals/views/components/blocks/BlockFilter.vue +0 -60
- package/src/modules/organizations/store/departments.js +0 -137
- package/src/modules/organizations/store/invites.js +0 -76
- package/src/modules/organizations/store/memberships.js +0 -110
|
@@ -7,6 +7,7 @@ import { Preferences } from '@capacitor/preferences';
|
|
|
7
7
|
import { reactive, watch } from 'vue';
|
|
8
8
|
// Globals
|
|
9
9
|
import { setError } from '@martyrs/src/modules/globals/views/store/globals.js';
|
|
10
|
+
import globalWebSocket from '@martyrs/src/modules/globals/views/classes/globals.websocket.js';
|
|
10
11
|
// State
|
|
11
12
|
import * as twofa from './twofa.js';
|
|
12
13
|
|
|
@@ -101,6 +102,11 @@ const actions = {
|
|
|
101
102
|
});
|
|
102
103
|
|
|
103
104
|
await this.initialize();
|
|
105
|
+
|
|
106
|
+
// Переподключаем WebSocket с новым userId после входа
|
|
107
|
+
console.log('[AUTH] Reconnecting WebSocket after login for user:', response.data._id);
|
|
108
|
+
globalWebSocket.disconnect();
|
|
109
|
+
await globalWebSocket.connect(response.data._id);
|
|
104
110
|
|
|
105
111
|
return response.data;
|
|
106
112
|
} catch (error) {
|
|
@@ -159,6 +165,11 @@ const actions = {
|
|
|
159
165
|
});
|
|
160
166
|
|
|
161
167
|
await this.initialize();
|
|
168
|
+
|
|
169
|
+
// Переподключаем WebSocket с новым userId после регистрации
|
|
170
|
+
console.log('[AUTH] Reconnecting WebSocket after signup for user:', response.data._id);
|
|
171
|
+
globalWebSocket.disconnect();
|
|
172
|
+
await globalWebSocket.connect(response.data._id);
|
|
162
173
|
|
|
163
174
|
return response.data;
|
|
164
175
|
} catch (error) {
|
|
@@ -174,6 +185,10 @@ const actions = {
|
|
|
174
185
|
await removeCookie('user');
|
|
175
186
|
setAuthToken(null);
|
|
176
187
|
this.resetState();
|
|
188
|
+
|
|
189
|
+
// Отключаем WebSocket при выходе
|
|
190
|
+
console.log('[AUTH] Disconnecting WebSocket on logout');
|
|
191
|
+
globalWebSocket.disconnect();
|
|
177
192
|
},
|
|
178
193
|
|
|
179
194
|
async resetPassword(user, type) {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Модуль чатов
|
|
2
|
+
|
|
3
|
+
## Обзор архитектуры
|
|
4
|
+
|
|
5
|
+
Модуль реализует real-time чат с использованием WebSocket и MongoDB для хранения истории сообщений.
|
|
6
|
+
|
|
7
|
+
### Структура файлов
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
chats/
|
|
11
|
+
├── chats.client.js # Точка входа клиентской части
|
|
12
|
+
├── chats.server.js # Точка входа серверной части
|
|
13
|
+
├── components/
|
|
14
|
+
│ ├── pages/
|
|
15
|
+
│ │ └── ChatPage.vue # Главная страница чата
|
|
16
|
+
│ ├── sections/
|
|
17
|
+
│ │ └── ChatWindow.vue # Окно чата с сообщениями
|
|
18
|
+
│ └── blocks/
|
|
19
|
+
│ └── ChatMessage.vue # Компонент отдельного сообщения
|
|
20
|
+
├── controllers/
|
|
21
|
+
│ └── chats.controller.js # Бизнес-логика (сохранение/получение сообщений)
|
|
22
|
+
├── models/
|
|
23
|
+
│ └── chat.model.js # MongoDB модель сообщения
|
|
24
|
+
├── routes/
|
|
25
|
+
│ └── chats.routes.js # HTTP маршруты и WebSocket обработчики
|
|
26
|
+
└── store/
|
|
27
|
+
└── chat.store.js # Управление состоянием на клиенте
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Ключевые компоненты
|
|
31
|
+
|
|
32
|
+
### WebSocket интеграция
|
|
33
|
+
|
|
34
|
+
Модуль использует глобальный WebSocket класс из `@martyrs/src/modules/globals/views/classes/globals.websocket.js`:
|
|
35
|
+
|
|
36
|
+
- Подключение: `globalWebSocket.connect(userId)`
|
|
37
|
+
- Подписка на модуль: `globalWebSocket.subscribeModule('chat')`
|
|
38
|
+
- Отправка сообщений: `globalWebSocket.send({ type: 'message', module: 'chat', ... })`
|
|
39
|
+
|
|
40
|
+
### Store (chat.store.js)
|
|
41
|
+
|
|
42
|
+
Управляет состоянием чата на клиенте:
|
|
43
|
+
- `state.messages` - массив сообщений текущего чата
|
|
44
|
+
- `state.currentChatId` - ID активного чата
|
|
45
|
+
- `state.username` - имя текущего пользователя
|
|
46
|
+
|
|
47
|
+
Основные методы:
|
|
48
|
+
- `connectWebSocket(userId)` - подключение к WebSocket
|
|
49
|
+
- `setCurrentChat(chatId)` - переключение чата и загрузка истории
|
|
50
|
+
- `addMessage(message)` - отправка нового сообщения
|
|
51
|
+
|
|
52
|
+
### Серверные обработчики
|
|
53
|
+
|
|
54
|
+
WebSocket обработчики регистрируются через `wss.registerModule('chat', handler)`:
|
|
55
|
+
|
|
56
|
+
1. `joinChat` - присоединение к чату (добавление chatId в ws.activeChats)
|
|
57
|
+
2. `message` - обработка входящего сообщения:
|
|
58
|
+
- Сохранение в БД
|
|
59
|
+
- Рассылка всем участникам чата через `broadcastToModuleWithFilter`
|
|
60
|
+
|
|
61
|
+
REST API:
|
|
62
|
+
- `GET /messages/:chatId` - получение истории сообщений
|
|
63
|
+
|
|
64
|
+
## Модель данных
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
ChatMessageSchema = {
|
|
68
|
+
username: String, // Имя отправителя
|
|
69
|
+
chatId: String, // ID чата
|
|
70
|
+
text: String, // Текст сообщения
|
|
71
|
+
createdAt: Date // Время создания (автоматически)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Проблемы и TODO
|
|
76
|
+
|
|
77
|
+
### Критические проблемы
|
|
78
|
+
|
|
79
|
+
1. **Нет авторизации** в WebSocket обработчиках
|
|
80
|
+
- Любой может отправлять сообщения от имени любого пользователя
|
|
81
|
+
- Нет проверки прав доступа к чату
|
|
82
|
+
|
|
83
|
+
3. **Отсутствует валидация данных**
|
|
84
|
+
- Нет проверки обязательных полей
|
|
85
|
+
- Нет санитизации входящих данных
|
|
86
|
+
|
|
87
|
+
### Улучшения
|
|
88
|
+
|
|
89
|
+
1. **Обработка ошибок**
|
|
90
|
+
- Добавить try/catch в компоненты
|
|
91
|
+
- Показывать уведомления об ошибках пользователю
|
|
92
|
+
|
|
93
|
+
2. **Оптимизация**
|
|
94
|
+
- Пагинация для истории сообщений
|
|
95
|
+
- Виртуальный скроллинг для больших чатов
|
|
96
|
+
|
|
97
|
+
3. **Функциональность**
|
|
98
|
+
- Индикатор набора текста
|
|
99
|
+
- Статусы доставки сообщений
|
|
100
|
+
- Поддержка файлов/изображений
|
|
101
|
+
- Уведомления о новых сообщениях
|
|
102
|
+
|
|
103
|
+
## Использование
|
|
104
|
+
|
|
105
|
+
### Инициализация на клиенте
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import ModuleChats from '@martyrs/src/modules/chats/chats.client.js';
|
|
109
|
+
|
|
110
|
+
// В главном приложении
|
|
111
|
+
ModuleChats.initialize(app, store, router);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Использование в компоненте
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<ChatPage
|
|
118
|
+
:username="currentUser.name"
|
|
119
|
+
:user="currentUser.id"
|
|
120
|
+
:chatID="selectedChatId"
|
|
121
|
+
/>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Инициализация на сервере
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { initialize } from '@martyrs/src/modules/chats/chats.server.js';
|
|
128
|
+
|
|
129
|
+
// При старте сервера
|
|
130
|
+
initialize(app, db, wss, origins, publicPath);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Зависимости
|
|
134
|
+
|
|
135
|
+
- `globals.websocket.js` - глобальный WebSocket класс
|
|
136
|
+
- `auth/controllers/middlewares` - middleware для авторизации (не используется)
|
|
137
|
+
- `globals/controllers/utils/mailing.js` - отправка уведомлений (импортирован, но не используется)
|
|
@@ -2,22 +2,34 @@
|
|
|
2
2
|
<div
|
|
3
3
|
class="pd-small"
|
|
4
4
|
:class="{'bg-main-nano': message.username === 'Support'}"
|
|
5
|
+
:data-message-id="message._id"
|
|
5
6
|
>
|
|
6
7
|
<p class="flex-v-center gap-thin flex-nowrap flex w-100 p-small">
|
|
7
8
|
<!-- <img loading="lazy" v-if="message.username === 'Weeder Support'" src="/logo/logo.png" class="i-medium"> -->
|
|
8
9
|
<strong class="mn-r-auto"><span class="t-semi">{{ message.username }}</span> <span class="t-transp">{{formatDate(message.createdAt)}}</span></strong>
|
|
10
|
+
<IconCheckmark v-if="isMessageRead" class="i-small t-main" />
|
|
9
11
|
</p>
|
|
10
12
|
<p>{{ message.text }}</p>
|
|
11
13
|
</div>
|
|
12
14
|
</template>
|
|
13
15
|
|
|
14
16
|
<script>
|
|
17
|
+
import IconCheckmark from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';
|
|
18
|
+
|
|
15
19
|
export default {
|
|
20
|
+
components: {
|
|
21
|
+
IconCheckmark
|
|
22
|
+
},
|
|
16
23
|
props: {
|
|
17
24
|
message: {
|
|
18
25
|
type: Object,
|
|
19
26
|
required: true
|
|
20
27
|
}
|
|
28
|
+
},
|
|
29
|
+
computed: {
|
|
30
|
+
isMessageRead() {
|
|
31
|
+
return this.message.readBy && this.message.readBy.length > 0;
|
|
32
|
+
}
|
|
21
33
|
}
|
|
22
34
|
};
|
|
23
35
|
</script>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script setup>
|
|
31
|
-
import { ref, computed, watch, onMounted, nextTick } from 'vue';
|
|
31
|
+
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
|
|
32
32
|
|
|
33
33
|
import IconAdd from '@martyrs/src/modules/icons/navigation/IconAdd.vue'
|
|
34
34
|
import PlaceholderChat from '@martyrs/src/modules/icons/placeholders/PlaceholderChat.vue'
|
|
@@ -38,6 +38,8 @@ import chatStore from '../../store/chat.store.js';
|
|
|
38
38
|
|
|
39
39
|
const newMessage = ref('');
|
|
40
40
|
const allMessages = ref(null);
|
|
41
|
+
const visibleMessageIds = ref(new Set());
|
|
42
|
+
let messageObserver = null;
|
|
41
43
|
|
|
42
44
|
// Вычисляемые свойства
|
|
43
45
|
const messages = computed(() => chatStore.state.messages);
|
|
@@ -69,12 +71,86 @@ const sendMessage = async () => {
|
|
|
69
71
|
}
|
|
70
72
|
};
|
|
71
73
|
|
|
74
|
+
// Отслеживание видимых сообщений
|
|
75
|
+
const observeMessages = () => {
|
|
76
|
+
console.log('[CHAT] Setting up message observer');
|
|
77
|
+
|
|
78
|
+
// Очищаем предыдущий observer если есть
|
|
79
|
+
if (messageObserver) {
|
|
80
|
+
messageObserver.disconnect();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
messageObserver = new IntersectionObserver((entries) => {
|
|
84
|
+
console.log('[CHAT] Observer triggered for', entries.length, 'entries');
|
|
85
|
+
entries.forEach(entry => {
|
|
86
|
+
const messageId = entry.target.dataset.messageId;
|
|
87
|
+
if (entry.isIntersecting) {
|
|
88
|
+
visibleMessageIds.value.add(messageId);
|
|
89
|
+
} else {
|
|
90
|
+
visibleMessageIds.value.delete(messageId);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Отправляем прочтение видимых сообщений
|
|
95
|
+
if (visibleMessageIds.value.size > 0) {
|
|
96
|
+
const unreadVisibleMessages = messages.value
|
|
97
|
+
.filter(msg => {
|
|
98
|
+
// Проверяем, что сообщение видимо
|
|
99
|
+
if (!visibleMessageIds.value.has(msg._id)) return false;
|
|
100
|
+
|
|
101
|
+
// Проверяем, что сообщение не от текущего пользователя
|
|
102
|
+
console.log('[CHAT] Checking if own message:', {
|
|
103
|
+
msgUserId: msg.userId,
|
|
104
|
+
currentUserId: chatStore.state.userId,
|
|
105
|
+
isEqual: msg.userId === chatStore.state.userId,
|
|
106
|
+
msgUserIdType: typeof msg.userId,
|
|
107
|
+
currentUserIdType: typeof chatStore.state.userId
|
|
108
|
+
});
|
|
109
|
+
if (msg.userId && msg.userId === chatStore.state.userId) return false;
|
|
110
|
+
|
|
111
|
+
// Проверяем, что сообщение еще не прочитано текущим пользователем
|
|
112
|
+
if (msg.readBy?.some(r => r.userId === chatStore.state.userId)) return false;
|
|
113
|
+
|
|
114
|
+
console.log('[CHAT] Message can be marked as read:', {
|
|
115
|
+
msgId: msg._id,
|
|
116
|
+
msgUserId: msg.userId,
|
|
117
|
+
currentUserId: chatStore.state.userId,
|
|
118
|
+
readBy: msg.readBy
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
})
|
|
123
|
+
.map(msg => msg._id);
|
|
124
|
+
|
|
125
|
+
console.log('[CHAT] Unread visible messages to mark:', unreadVisibleMessages);
|
|
126
|
+
|
|
127
|
+
if (unreadVisibleMessages.length > 0) {
|
|
128
|
+
console.log('[CHAT] Sending markAsRead for messages:', unreadVisibleMessages);
|
|
129
|
+
chatStore.methods.markMessagesAsRead(unreadVisibleMessages);
|
|
130
|
+
} else {
|
|
131
|
+
console.log('[CHAT] No unread messages to mark');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, {
|
|
135
|
+
root: allMessages.value,
|
|
136
|
+
threshold: 0.5
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Наблюдаем за всеми сообщениями
|
|
140
|
+
nextTick(() => {
|
|
141
|
+
const messageElements = allMessages.value?.querySelectorAll('[data-message-id]');
|
|
142
|
+
console.log('[CHAT] Found message elements to observe:', messageElements?.length);
|
|
143
|
+
messageElements?.forEach(el => messageObserver.observe(el));
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
72
147
|
// Прокрутка вниз при монтировании
|
|
73
148
|
onMounted(() => {
|
|
74
149
|
nextTick(() => {
|
|
75
150
|
if (allMessages.value) {
|
|
76
151
|
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
77
152
|
}
|
|
153
|
+
observeMessages();
|
|
78
154
|
});
|
|
79
155
|
});
|
|
80
156
|
|
|
@@ -84,10 +160,16 @@ watch(messages, () => {
|
|
|
84
160
|
if (allMessages.value) {
|
|
85
161
|
allMessages.value.scrollTop = allMessages.value.scrollHeight;
|
|
86
162
|
}
|
|
163
|
+
observeMessages();
|
|
87
164
|
});
|
|
88
165
|
}, { deep: true });
|
|
89
166
|
|
|
90
|
-
//
|
|
167
|
+
// Очистка observer при размонтировании
|
|
168
|
+
onUnmounted(() => {
|
|
169
|
+
if (messageObserver) {
|
|
170
|
+
messageObserver.disconnect();
|
|
171
|
+
}
|
|
172
|
+
});
|
|
91
173
|
</script>
|
|
92
174
|
|
|
93
175
|
<style>
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import mailing from '@martyrs/src/modules/globals/controllers/utils/mailing.js';
|
|
2
2
|
const { sendChatMessageTelegram } = mailing;
|
|
3
|
+
|
|
3
4
|
const controllerFactory = db => {
|
|
4
5
|
const ChatMessage = db.chat;
|
|
6
|
+
const Department = db.department;
|
|
7
|
+
const Order = db.order;
|
|
8
|
+
|
|
9
|
+
// Хранилище таймеров для отложенных нотификаций
|
|
10
|
+
const notificationTimers = new Map();
|
|
11
|
+
const NOTIFICATION_DELAY = 3000; // 30 секунд
|
|
12
|
+
|
|
5
13
|
const saveMessage = async msg => {
|
|
6
14
|
try {
|
|
7
15
|
const message = new ChatMessage(msg);
|
|
8
16
|
await message.save();
|
|
17
|
+
console.log('[CHAT CONTROLLER] Saved message with userId:', msg.userId);
|
|
9
18
|
return message;
|
|
10
19
|
} catch (error) {
|
|
11
20
|
console.error('Error saving message to database:', error);
|
|
12
21
|
}
|
|
13
22
|
};
|
|
23
|
+
|
|
14
24
|
const getMessages = async chatId => {
|
|
15
25
|
try {
|
|
16
26
|
const messages = await ChatMessage.find({ chatId }).sort({ createdAt: 1 });
|
|
@@ -19,9 +29,186 @@ const controllerFactory = db => {
|
|
|
19
29
|
console.error('Error retrieving messages from database:', error);
|
|
20
30
|
}
|
|
21
31
|
};
|
|
32
|
+
|
|
33
|
+
const markMessagesAsRead = async (messageIds, userId) => {
|
|
34
|
+
try {
|
|
35
|
+
console.log('[CHAT CONTROLLER] markMessagesAsRead called:', { messageIds, userId });
|
|
36
|
+
|
|
37
|
+
// Сначала проверим сообщения
|
|
38
|
+
const messages = await ChatMessage.find({ _id: { $in: messageIds } });
|
|
39
|
+
console.log('[CHAT CONTROLLER] Found messages to mark:', messages.map(m => ({
|
|
40
|
+
id: m._id,
|
|
41
|
+
userId: m.userId,
|
|
42
|
+
isOwnMessage: m.userId?.toString() === userId.toString(),
|
|
43
|
+
alreadyRead: m.readBy?.some(r => r.userId.toString() === userId.toString())
|
|
44
|
+
})));
|
|
45
|
+
|
|
46
|
+
// Обновляем только чужие непрочитанные сообщения
|
|
47
|
+
const result = await ChatMessage.updateMany(
|
|
48
|
+
{
|
|
49
|
+
_id: { $in: messageIds },
|
|
50
|
+
userId: { $ne: userId }, // НЕ свои сообщения
|
|
51
|
+
'readBy.userId': { $ne: userId } // еще не прочитанные
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
$push: {
|
|
55
|
+
readBy: {
|
|
56
|
+
userId: userId,
|
|
57
|
+
readAt: new Date()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
console.log('[CHAT CONTROLLER] Mark as read result:', result);
|
|
64
|
+
return result;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Error marking messages as read:', error);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Получить пользователей с доступом orders.confirm для организации
|
|
71
|
+
const getUsersWithOrdersConfirmAccess = async (organizationId) => {
|
|
72
|
+
const pipeline = [
|
|
73
|
+
{ $match: {
|
|
74
|
+
organization: new db.mongoose.Types.ObjectId(organizationId),
|
|
75
|
+
'accesses.orders.confirm': true
|
|
76
|
+
}},
|
|
77
|
+
{ $unwind: '$members' },
|
|
78
|
+
{ $group: {
|
|
79
|
+
_id: '$members.user'
|
|
80
|
+
}},
|
|
81
|
+
{ $project: { userId: '$_id' }}
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const result = await Department.aggregate(pipeline);
|
|
85
|
+
return result.map(item => item.userId);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Отправка нотификаций (как в orders.controller)
|
|
89
|
+
const sendChatNotifications = async (message, recipientIds) => {
|
|
90
|
+
if (!recipientIds || recipientIds.length === 0) return;
|
|
91
|
+
|
|
92
|
+
const notifications = recipientIds.map(userId => ({
|
|
93
|
+
title: 'New Message',
|
|
94
|
+
body: `${message.username}: ${message.text.substring(0, 100)}`,
|
|
95
|
+
type: 'chat_message',
|
|
96
|
+
metadata: {
|
|
97
|
+
type: 'chat_message',
|
|
98
|
+
chatId: message.chatId,
|
|
99
|
+
messageId: message._id,
|
|
100
|
+
context: 'chat'
|
|
101
|
+
},
|
|
102
|
+
userId: userId
|
|
103
|
+
}));
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const response = await fetch(`${process.env.API_URL || ''}/api/notifications/batch`, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
'Content-Type': 'application/json',
|
|
110
|
+
'X-Service-Key': process.env.SERVICE_KEY,
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify({ notifications }),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const errorData = await response.text();
|
|
117
|
+
throw new Error(`Notification API failed: ${response.status} - ${errorData}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const result = await response.json();
|
|
121
|
+
console.log('Chat notifications sent:', result);
|
|
122
|
+
return result;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('Failed to send chat notifications:', error);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Запланировать отправку нотификаций
|
|
129
|
+
const scheduleNotifications = async (message, wss, senderUserId) => {
|
|
130
|
+
console.log('[CHAT CONTROLLER] scheduleNotifications called for message:', message);
|
|
131
|
+
console.log('[CHAT CONTROLLER] Sender userId:', senderUserId);
|
|
132
|
+
console.log('[CHAT CONTROLLER] Chat type:', message.chatType);
|
|
133
|
+
console.log('[CHAT CONTROLLER] Chat ID:', message.chatId);
|
|
134
|
+
|
|
135
|
+
// Определяем получателей в зависимости от типа чата
|
|
136
|
+
let recipientIds = [];
|
|
137
|
+
|
|
138
|
+
if (message.chatType === 'order') {
|
|
139
|
+
// Для чатов типа order - chatId это ID заказа
|
|
140
|
+
try {
|
|
141
|
+
const order = await Order.findById(message.chatId);
|
|
142
|
+
console.log('[CHAT CONTROLLER] Found order:', order?._id, 'Owner:', order?.owner);
|
|
143
|
+
|
|
144
|
+
const organizationId = order?.owner?.target?._id || order?.owner?.target;
|
|
145
|
+
|
|
146
|
+
if (order && organizationId) {
|
|
147
|
+
console.log('[CHAT CONTROLLER] Looking for users with orders.confirm access in org:', organizationId);
|
|
148
|
+
recipientIds = await getUsersWithOrdersConfirmAccess(organizationId);
|
|
149
|
+
console.log('[CHAT CONTROLLER] Found recipient IDs:', recipientIds);
|
|
150
|
+
} else {
|
|
151
|
+
console.log('[CHAT CONTROLLER] Order not found or has no organization');
|
|
152
|
+
}
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('[CHAT CONTROLLER] Error fetching order:', error);
|
|
155
|
+
}
|
|
156
|
+
} else if (message.chatType === 'group') {
|
|
157
|
+
// Групповые нотификации замокированы
|
|
158
|
+
console.log('[CHAT CONTROLLER] Group notifications are mocked for now');
|
|
159
|
+
return;
|
|
160
|
+
} else {
|
|
161
|
+
console.log('[CHAT CONTROLLER] Unknown chat type:', message.chatType);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Исключаем отправителя из списка получателей
|
|
166
|
+
const filteredRecipientIds = recipientIds.filter(userId =>
|
|
167
|
+
userId.toString() !== senderUserId?.toString()
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
console.log('[CHAT CONTROLLER] Recipients after filtering out sender:', filteredRecipientIds);
|
|
171
|
+
|
|
172
|
+
if (filteredRecipientIds.length === 0) {
|
|
173
|
+
console.log('[CHAT CONTROLLER] No recipients after filtering, skipping notifications');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Планируем отправку через 30 секунд для каждого получателя
|
|
178
|
+
filteredRecipientIds.forEach(userId => {
|
|
179
|
+
const timerKey = `${message._id}_${userId}`;
|
|
180
|
+
console.log(`[CHAT CONTROLLER] Setting timer for user ${userId}, key: ${timerKey}`);
|
|
181
|
+
|
|
182
|
+
const timer = setTimeout(async () => {
|
|
183
|
+
console.log(`[CHAT CONTROLLER] Timer fired for user ${userId}, checking if message is read`);
|
|
184
|
+
|
|
185
|
+
// Проверяем, не прочитано ли сообщение
|
|
186
|
+
const currentMessage = await ChatMessage.findById(message._id);
|
|
187
|
+
const isRead = currentMessage.readBy.some(r => r.userId.toString() === userId.toString());
|
|
188
|
+
|
|
189
|
+
console.log(`[CHAT CONTROLLER] Message read status for user ${userId}:`, isRead);
|
|
190
|
+
|
|
191
|
+
if (!isRead) {
|
|
192
|
+
console.log(`[CHAT CONTROLLER] Sending notification to user ${userId}`);
|
|
193
|
+
await sendChatNotifications(message, [userId]);
|
|
194
|
+
} else {
|
|
195
|
+
console.log(`[CHAT CONTROLLER] Message already read by user ${userId}, skipping notification`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
notificationTimers.delete(timerKey);
|
|
199
|
+
}, NOTIFICATION_DELAY);
|
|
200
|
+
|
|
201
|
+
notificationTimers.set(timerKey, timer);
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
|
|
22
205
|
return {
|
|
23
206
|
saveMessage,
|
|
24
207
|
getMessages,
|
|
208
|
+
markMessagesAsRead,
|
|
209
|
+
scheduleNotifications,
|
|
210
|
+
notificationTimers
|
|
25
211
|
};
|
|
26
212
|
};
|
|
213
|
+
|
|
27
214
|
export default controllerFactory;
|
|
@@ -4,14 +4,35 @@ export default db => {
|
|
|
4
4
|
type: String,
|
|
5
5
|
required: true,
|
|
6
6
|
},
|
|
7
|
+
userId: {
|
|
8
|
+
type: db.mongoose.Schema.Types.ObjectId,
|
|
9
|
+
ref: 'User',
|
|
10
|
+
required: true
|
|
11
|
+
},
|
|
7
12
|
chatId: {
|
|
8
13
|
type: String,
|
|
9
14
|
required: true,
|
|
10
15
|
},
|
|
16
|
+
chatType: {
|
|
17
|
+
type: String,
|
|
18
|
+
required: true,
|
|
19
|
+
enum: ['order', 'group', 'support', 'private'],
|
|
20
|
+
default: 'private'
|
|
21
|
+
},
|
|
11
22
|
text: {
|
|
12
23
|
type: String,
|
|
13
24
|
required: true,
|
|
14
25
|
},
|
|
26
|
+
readBy: [{
|
|
27
|
+
userId: {
|
|
28
|
+
type: db.mongoose.Schema.Types.ObjectId,
|
|
29
|
+
ref: 'User'
|
|
30
|
+
},
|
|
31
|
+
readAt: {
|
|
32
|
+
type: Date,
|
|
33
|
+
default: Date.now
|
|
34
|
+
}
|
|
35
|
+
}],
|
|
15
36
|
createdAt: {
|
|
16
37
|
type: Date,
|
|
17
38
|
default: Date.now,
|
|
@@ -3,6 +3,8 @@ import controllerFactory from '../controllers/chats.controller.js';
|
|
|
3
3
|
export default (function (app, db, wss) {
|
|
4
4
|
const controller = controllerFactory(db);
|
|
5
5
|
const { verifySignUp, verifyUser } = middlewareFactory(db);
|
|
6
|
+
|
|
7
|
+
|
|
6
8
|
// WebSocket-обработчик для модуля "chat"
|
|
7
9
|
wss.registerModule('chat', async (ws, msg) => {
|
|
8
10
|
if (msg.type === 'joinChat') {
|
|
@@ -11,8 +13,13 @@ export default (function (app, db, wss) {
|
|
|
11
13
|
if (!ws.activeChats) ws.activeChats = new Set();
|
|
12
14
|
ws.activeChats.add(msg.chatId);
|
|
13
15
|
}
|
|
16
|
+
|
|
14
17
|
if (msg.type === 'message') {
|
|
18
|
+
console.log('[CHAT] Received message:', msg);
|
|
19
|
+
|
|
15
20
|
const savedMessage = await controller.saveMessage(msg);
|
|
21
|
+
console.log('[CHAT] Saved message:', savedMessage);
|
|
22
|
+
|
|
16
23
|
// Отправить сообщение всем в этом чате
|
|
17
24
|
wss.broadcastToModuleWithFilter(
|
|
18
25
|
'chat',
|
|
@@ -21,6 +28,45 @@ export default (function (app, db, wss) {
|
|
|
21
28
|
},
|
|
22
29
|
savedMessage
|
|
23
30
|
);
|
|
31
|
+
|
|
32
|
+
// Запланировать отправку нотификаций через 30 секунд
|
|
33
|
+
console.log('[CHAT] Scheduling notifications for message:', savedMessage._id, 'from user:', ws.userId);
|
|
34
|
+
controller.scheduleNotifications(savedMessage, wss, ws.userId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (msg.type === 'markAsRead') {
|
|
38
|
+
console.log('[CHAT] markAsRead request:', { messageIds: msg.messageIds, userId: ws.userId });
|
|
39
|
+
|
|
40
|
+
if (!msg.messageIds || !msg.chatId || !ws.userId) {
|
|
41
|
+
console.log('[CHAT] markAsRead missing params:', { hasMessageIds: !!msg.messageIds, hasChatId: !!msg.chatId, hasUserId: !!ws.userId });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Отметить сообщения как прочитанные
|
|
46
|
+
const updatedMessages = await controller.markMessagesAsRead(msg.messageIds, ws.userId);
|
|
47
|
+
|
|
48
|
+
// Отменить запланированные нотификации для этого пользователя
|
|
49
|
+
msg.messageIds.forEach(messageId => {
|
|
50
|
+
const timerKey = `${messageId}_${ws.userId}`;
|
|
51
|
+
if (controller.notificationTimers.has(timerKey)) {
|
|
52
|
+
clearTimeout(controller.notificationTimers.get(timerKey));
|
|
53
|
+
controller.notificationTimers.delete(timerKey);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Уведомить других участников чата о прочтении
|
|
58
|
+
wss.broadcastToModuleWithFilter(
|
|
59
|
+
'chat',
|
|
60
|
+
client => {
|
|
61
|
+
return client.activeChats?.has(msg.chatId) && client.userId !== ws.userId;
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'readReceipt',
|
|
65
|
+
messageIds: msg.messageIds,
|
|
66
|
+
userId: ws.userId,
|
|
67
|
+
readAt: new Date()
|
|
68
|
+
}
|
|
69
|
+
);
|
|
24
70
|
}
|
|
25
71
|
});
|
|
26
72
|
// REST API: получить историю сообщений
|