@ozdao/martyrs 0.2.581 → 0.2.583

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 (86) hide show
  1. package/dist/martyrs/src/components/Feed/Feed.vue.js +1 -1
  2. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +6 -12
  3. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js.map +1 -1
  4. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js +1 -1
  5. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js.map +1 -1
  6. package/dist/martyrs/src/modules/auth/views/components/pages/UserDashboard.vue.js +182 -89
  7. package/dist/martyrs/src/modules/auth/views/components/pages/UserDashboard.vue.js.map +1 -1
  8. package/dist/martyrs/src/modules/auth/views/configs/navigation.user.config.js +11 -5
  9. package/dist/martyrs/src/modules/auth/views/configs/navigation.user.config.js.map +1 -1
  10. package/dist/martyrs/src/modules/auth/views/router/users.router.js +1 -2
  11. package/dist/martyrs/src/modules/auth/views/router/users.router.js.map +1 -1
  12. package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js +1 -1
  13. package/dist/martyrs/src/modules/core/views/classes/ws.manager.js +16 -1
  14. package/dist/martyrs/src/modules/core/views/classes/ws.manager.js.map +1 -1
  15. package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
  16. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
  17. package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js +7 -0
  18. package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js.map +1 -1
  19. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
  20. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +1 -1
  21. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
  22. package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +1 -1
  23. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +3 -3
  24. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
  25. package/dist/martyrs/src/modules/notifications/components/layouts/NotificationsLayout.vue.js +11 -40
  26. package/dist/martyrs/src/modules/notifications/components/layouts/NotificationsLayout.vue.js.map +1 -1
  27. package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js +26 -21
  28. package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js.map +1 -1
  29. package/dist/martyrs/src/modules/notifications/components/sections/NotificationPreferences.vue.js +54 -48
  30. package/dist/martyrs/src/modules/notifications/components/sections/NotificationPreferences.vue.js.map +1 -1
  31. package/dist/martyrs/src/modules/notifications/components/sections/NotificationsList.vue.js +37 -117
  32. package/dist/martyrs/src/modules/notifications/components/sections/NotificationsList.vue.js.map +1 -1
  33. package/dist/martyrs/src/modules/notifications/notifications.client.js +18 -15
  34. package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
  35. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +90 -175
  36. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js.map +1 -1
  37. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +6 -6
  38. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js.map +1 -1
  39. package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js +41 -28
  40. package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js.map +1 -1
  41. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
  42. package/dist/martyrs/src/modules/orders/orders.client.js +14 -14
  43. package/dist/martyrs/src/modules/orders/orders.client.js.map +1 -1
  44. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  45. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +88 -39
  46. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js.map +1 -1
  47. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +1 -1
  48. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +1 -1
  49. package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +1 -1
  50. package/dist/style.css +73 -265
  51. package/package.json +1 -1
  52. package/src/modules/TASKS.MD +26 -1
  53. package/src/modules/auth/views/components/pages/Profile.vue +9 -15
  54. package/src/modules/auth/views/components/pages/ProfileEdit.vue +1 -1
  55. package/src/modules/auth/views/components/pages/UserDashboard.vue +214 -125
  56. package/src/modules/auth/views/configs/navigation.user.config.js +17 -11
  57. package/src/modules/auth/views/router/users.router.js +0 -1
  58. package/src/modules/core/views/classes/ws.manager.js +20 -1
  59. package/src/modules/core/views/utils/vue-app-renderer.js +9 -3
  60. package/src/modules/notifications/components/elements/NotificationBadge.vue +1 -1
  61. package/src/modules/notifications/components/layouts/NotificationsLayout.vue +9 -53
  62. package/src/modules/notifications/components/pages/Notifications.vue +21 -22
  63. package/src/modules/notifications/components/sections/NotificationPreferences.vue +41 -180
  64. package/src/modules/notifications/components/sections/NotificationsList.vue +39 -219
  65. package/src/modules/notifications/notifications.client.js +17 -16
  66. package/src/modules/orders/components/blocks/CardOrderUser.vue +88 -190
  67. package/src/modules/orders/components/pages/OrderBackoffice.vue +5 -5
  68. package/src/modules/orders/components/pages/Orders.vue +56 -50
  69. package/src/modules/organizations/components/pages/OrganizationEdit.vue +42 -11
  70. package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue.js +0 -625
  71. package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue.js.map +0 -1
  72. package/dist/martyrs/src/modules/auth/views/components/blocks/ProfileCard.vue.js +0 -44
  73. package/dist/martyrs/src/modules/auth/views/components/blocks/ProfileCard.vue.js.map +0 -1
  74. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
  75. package/dist/martyrs/src/modules/orders/components/icons/IconStatusCanceled.vue.js +0 -32
  76. package/dist/martyrs/src/modules/orders/components/icons/IconStatusCanceled.vue.js.map +0 -1
  77. package/dist/martyrs/src/modules/orders/components/icons/IconStatusConfirmed.vue.js +0 -32
  78. package/dist/martyrs/src/modules/orders/components/icons/IconStatusConfirmed.vue.js.map +0 -1
  79. package/dist/martyrs/src/modules/orders/components/icons/IconStatusCreated.vue.js +0 -32
  80. package/dist/martyrs/src/modules/orders/components/icons/IconStatusCreated.vue.js.map +0 -1
  81. package/dist/martyrs/src/modules/orders/components/icons/IconStatusDelay.vue.js +0 -32
  82. package/dist/martyrs/src/modules/orders/components/icons/IconStatusDelay.vue.js.map +0 -1
  83. package/dist/martyrs/src/modules/orders/components/icons/IconStatusFinished.vue.js +0 -32
  84. package/dist/martyrs/src/modules/orders/components/icons/IconStatusFinished.vue.js.map +0 -1
  85. package/dist/martyrs/src/modules/orders/components/icons/IconStatusInUse.vue.js +0 -32
  86. package/dist/martyrs/src/modules/orders/components/icons/IconStatusInUse.vue.js.map +0 -1
@@ -1,160 +1,249 @@
1
1
  <template>
2
- <div class="pd-medium bg-white">
3
- <h2 class="mn-b-small">Overview</h2>
4
- <div class="mn-b-medium cols-3 mobile:cols-1 gap-thin">
5
- <Block class="pos-relative">
6
- <span class="t-green fw-semi pos-absolute pos-t-small pos-r-small">+12.5%</span>
7
- <div class="mn-b-medium radius-small w-max bg-main"><IconGroups class="i-medium mn-small"/></div>
8
- <p class="h3 mn-b-thin">{{ stats.organizations || 0 }}</p>
9
- <p>My Groups</p>
10
- </Block>
11
-
12
- <Block class="pos-relative">
13
- <span class="t-green fw-semi pos-absolute pos-t-small pos-r-small">+14.8%</span>
14
- <div class="mn-b-medium radius-small w-max bg-main"><IconOrders class="i-medium mn-small"/></div>
15
- <p class="h3 mn-b-thin">{{ stats.orders || 0 }}</p>
16
- <p>My Orders</p>
17
- </Block>
18
-
19
- <Block class="pos-relative">
20
- <span class="t-green fw-semi pos-absolute pos-t-small pos-r-small">+25.1%</span>
21
- <div class="mn-b-medium radius-small w-max bg-main"><IconEvents class="i-medium mn-small"/></div>
22
- <p class="h3 mn-b-thin">{{ stats.events || 0 }}</p>
23
- <p>My Events</p>
24
- </Block>
2
+ <div class="pd-medium">
3
+ <h2 class="mn-b-medium">Overview</h2>
4
+
5
+ <!-- Stats Cards -->
6
+ <div class="mn-b-medium cols-3 mobile:cols-1 gap-small">
7
+ <router-link
8
+ :to="`/users/${auth.state.user._id}/organizations`"
9
+ class="d-block bg-light pd-medium radius-medium hover-scale-1 transition-default"
10
+ >
11
+ <div class="flex flex-v-center gap-small mn-b-small">
12
+ <div class="radius-small bg-main flex flex-center">
13
+ <IconGroups class="i-medium mn-small" :fill="'rgb(var(--white))'"/>
14
+ </div>
15
+ <span class="t-grey t-small">My Groups</span>
16
+ </div>
17
+ <p class="h2 fw-semi">{{ stats.organizations || 0 }}</p>
18
+ </router-link>
19
+
20
+ <router-link
21
+ :to="`/users/${auth.state.user._id}/orders`"
22
+ class="d-block bg-light pd-medium radius-medium hover-scale-1 transition-default"
23
+ >
24
+ <div class="flex flex-v-center gap-small mn-b-small">
25
+ <div class="radius-small bg-main flex flex-center">
26
+ <IconOrders class="i-medium mn-small" :fill="'rgb(var(--white))'"/>
27
+ </div>
28
+ <span class="t-grey t-small">My Orders</span>
29
+ </div>
30
+ <p class="h2 fw-semi">{{ stats.orders || 0 }}</p>
31
+ </router-link>
32
+
33
+ <router-link
34
+ :to="`/users/${auth.state.user._id}/events`"
35
+ class="d-block bg-light pd-medium radius-medium hover-scale-1 transition-default"
36
+ >
37
+ <div class="flex flex-v-center gap-small mn-b-small">
38
+ <div class="radius-small bg-main flex flex-center">
39
+ <IconEvents class="i-medium mn-small" :fill="'rgb(var(--white))'"/>
40
+ </div>
41
+ <span class="t-grey t-small">My Events</span>
42
+ </div>
43
+ <p class="h2 fw-semi">{{ stats.events || 0 }}</p>
44
+ </router-link>
25
45
  </div>
26
46
 
27
- <div class="cols-2 mobile:cols-1 gap-thin">
28
- <Block
29
- title="Recent Orders"
30
- class="pos-relative"
31
- >
47
+ <!-- Content Grid -->
48
+ <div class="cols-2 mobile:cols-1 gap-small">
49
+ <!-- Recent Orders -->
50
+ <Block title="Recent Orders">
32
51
  <Feed
33
- :showLoadMore="false"
34
- :LoadMore="false"
35
- :states="{
36
- empty: {
37
- title: 'No Orders',
38
- description: 'You have no orders yet.'
39
- }
40
- }"
41
- :store="{
42
- read: (options) => orders.actions.read(options),
43
- state: orders.state
44
- }"
45
- :options="{
46
- customer: auth.state.user._id,
47
- limit: 5,
48
- page: 1
49
- }"
50
- v-slot="{
51
- items
52
- }"
53
- class="cols-1 gap-thin"
54
- >
52
+ :showLoadMore="false"
53
+ :states="{
54
+ empty: {
55
+ title: 'No Orders',
56
+ description: 'You have no orders yet.'
57
+ }
58
+ }"
59
+ :store="{
60
+ read: (options) => orders.actions.read(options),
61
+ state: orders.state
62
+ }"
63
+ :options="{
64
+ customer: auth.state.user._id,
65
+ limit: 5,
66
+ page: 1
67
+ }"
68
+ v-slot="{ items }"
69
+ >
55
70
  <Table
56
- class="radius-semi bg-white"
71
+ class="radius-small bg-white"
57
72
  :items="items"
58
- :columns="[{
59
- key: '_id',
60
- label: 'ID',
61
- formatter: (value) => `#${value.slice(0, 4)}...${value.slice(-4)}`
62
- },
63
- {
64
- key: 'positions',
65
- label: 'Items',
66
- formatter: (value) => value?.length || 0
67
- },
68
- {
69
- key: 'status',
70
- label: 'Status',
71
- component: StatusBadge
72
- },
73
- {
74
- key: 'createdAt',
75
- label: 'Date',
76
- formatter: (value) => new Date(value).toLocaleDateString()
77
- }]"
78
- />
79
- </Feed>
80
-
73
+ :columns="columns.orders"
74
+ >
75
+ <template #cell-_id="{ value }">
76
+ <span class="t-dark fw-medium">#{{ formatId(value) }}</span>
77
+ </template>
78
+ <template #cell-positions="{ value }">
79
+ <span class="t-dark">{{ value?.length || 0 }} items</span>
80
+ </template>
81
+ <template #cell-status="{ value }">
82
+ <span
83
+ class="pd-thin pd-l-small pd-r-small radius-small t-small fw-medium"
84
+ :class="getStatusClass(value)"
85
+ >
86
+ {{ value }}
87
+ </span>
88
+ </template>
89
+ <template #cell-createdAt="{ value }">
90
+ <span class="t-grey t-small">{{ formatDate(value) }}</span>
91
+ </template>
92
+ </Table>
93
+ </Feed>
81
94
  </Block>
82
95
 
83
- <Block
84
- title="Upcoming Events"
85
- class="pos-relative"
86
- >
96
+ <!-- Upcoming Events -->
97
+ <Block title="Upcoming Events">
87
98
  <Feed
88
- :showLoadMore="false"
89
- :LoadMore="false"
90
- :states="{
91
- empty: {
92
- title: 'No Events',
93
- description: 'You have no upcoming events.'
94
- }
95
- }"
96
- :store="{
97
- read: (options) => events.read(options),
98
- }"
99
- :options="{
100
- creator: auth.state.user._id,
101
- sortParam: 'date.start',
102
- sortOrder: 'asc',
103
- limit: 5,
104
- page: 1
105
- }"
106
- v-slot="{
107
- items
108
- }"
109
- class="cols-1 gap-thin"
110
- >
111
- <CardEvent
112
- v-for="event in items"
113
- :key="event._id"
114
- :event="event"
115
- :user="auth.state.user._id"
116
- :type="'compact'"
117
- class="bg-light radius-medium"
118
- />
119
- </Feed>
99
+ :showLoadMore="false"
100
+ :states="{
101
+ empty: {
102
+ title: 'No Events',
103
+ description: 'You have no upcoming events.'
104
+ }
105
+ }"
106
+ :store="{
107
+ read: (options) => events.read(options)
108
+ }"
109
+ :options="{
110
+ creator: auth.state.user._id,
111
+ sortParam: 'date.start',
112
+ sortOrder: 'asc',
113
+ limit: 5,
114
+ page: 1
115
+ }"
116
+ v-slot="{ items }"
117
+ class="flex flex-column gap-thin"
118
+ >
119
+ <router-link
120
+ v-for="event in items"
121
+ :key="event._id"
122
+ :to="`/events/${event._id}`"
123
+ class="d-block bg-white pd-small radius-small hover-scale-1 transition-default"
124
+ >
125
+ <div class="flex flex-v-center gap-small">
126
+ <div
127
+ class="flex-none w-3r h-3r radius-small bg-main-transp flex flex-center o-hidden"
128
+ >
129
+ <img
130
+ v-if="event.cover"
131
+ :src="(FILE_SERVER_URL || '') + event.cover"
132
+ class="w-100 h-100 object-fit-cover"
133
+ alt=""
134
+ />
135
+ <IconEvents v-else class="i-regular" :fill="'rgb(var(--main))'"/>
136
+ </div>
137
+ <div class="flex-child o-hidden">
138
+ <p class="fw-medium t-truncate mn-b-nano">{{ event.name }}</p>
139
+ <p class="t-grey t-small">{{ formatEventDate(event.date) }}</p>
140
+ </div>
141
+ <div class="flex-none">
142
+ <span
143
+ class="pd-thin pd-l-small pd-r-small radius-small t-small fw-medium"
144
+ :class="getEventStatusClass(event.date)"
145
+ >
146
+ {{ getEventStatus(event.date) }}
147
+ </span>
148
+ </div>
149
+ </div>
150
+ </router-link>
151
+ </Feed>
120
152
  </Block>
121
153
  </div>
122
-
123
154
  </div>
124
-
125
-
126
155
  </template>
127
156
 
128
157
  <script setup>
129
- import { ref, onMounted } from 'vue';
130
- import { useRoute, useRouter } from 'vue-router'
158
+ import { ref, onMounted, inject } from 'vue'
159
+ import { useRouter } from 'vue-router'
131
160
 
132
161
  import Block from '@martyrs/src/components/Block/Block.vue'
133
162
  import Feed from '@martyrs/src/components/Feed/Feed.vue'
134
163
  import Table from '@martyrs/src/components/Table/Table.vue'
135
- import StatusBadge from '@martyrs/src/components/Table/StatusBadge.vue'
136
-
137
- import CardEvent from '@martyrs/src/modules/events/components/blocks/CardEvent.vue';
138
164
 
139
165
  import IconGroups from '@martyrs/src/modules/icons/entities/IconGroups.vue'
140
166
  import IconEvents from '@martyrs/src/modules/icons/entities/IconEvents.vue'
141
167
  import IconOrders from '@martyrs/src/modules/icons/entities/IconOrders.vue'
142
168
 
143
- import * as auth from '@martyrs/src/modules/auth/views/store/auth.js'
144
- import * as orders from '@martyrs/src/modules/orders/store/orders.js'
169
+ import * as auth from '@martyrs/src/modules/auth/views/store/auth.js'
170
+ import * as orders from '@martyrs/src/modules/orders/store/orders.js'
145
171
  import * as events from '@martyrs/src/modules/events/store/events.js'
146
172
 
147
- const route = useRoute()
173
+ const FILE_SERVER_URL = inject('FILE_SERVER_URL', '')
148
174
  const router = useRouter()
149
175
 
150
176
  const stats = ref({
151
- organizations: 0,
152
- orders: 0,
153
- events: 0
177
+ organizations: 0,
178
+ orders: 0,
179
+ events: 0
154
180
  })
155
181
 
182
+ const columns = {
183
+ orders: [
184
+ { key: '_id', label: 'Order' },
185
+ { key: 'positions', label: 'Items' },
186
+ { key: 'status', label: 'Status' },
187
+ { key: 'createdAt', label: 'Date' }
188
+ ]
189
+ }
190
+
191
+ // Formatters
192
+ const formatId = (id) => id ? `${id.slice(0, 4)}...${id.slice(-4)}` : ''
193
+
194
+ const formatDate = (date) => {
195
+ if (!date) return ''
196
+ return new Date(date).toLocaleDateString()
197
+ }
198
+
199
+ const formatEventDate = (date) => {
200
+ if (!date?.start) return ''
201
+ const start = new Date(date.start)
202
+ return start.toLocaleDateString(undefined, { day: '2-digit', month: 'short', year: 'numeric' })
203
+ }
204
+
205
+ const getStatusClass = (status) => {
206
+ const classes = {
207
+ pending: 'bg-second-transp t-second',
208
+ processing: 'bg-main-transp t-main',
209
+ completed: 'bg-green-transp t-green',
210
+ cancelled: 'bg-red-transp t-red'
211
+ }
212
+ return classes[status] || 'bg-light t-grey'
213
+ }
214
+
215
+ const getEventStatus = (date) => {
216
+ if (!date?.start) return 'No date'
217
+ const now = new Date()
218
+ const start = new Date(date.start)
219
+ const end = date.end ? new Date(date.end) : start
220
+
221
+ if (now > end) return 'Finished'
222
+ if (now >= start && now <= end) return 'Live'
223
+
224
+ const diffDays = Math.ceil((start - now) / (1000 * 60 * 60 * 24))
225
+ if (diffDays <= 1) return 'Tomorrow'
226
+ if (diffDays <= 7) return `In ${diffDays} days`
227
+ return 'Upcoming'
228
+ }
229
+
230
+ const getEventStatusClass = (date) => {
231
+ const status = getEventStatus(date)
232
+ if (status === 'Finished') return 'bg-light t-grey'
233
+ if (status === 'Live') return 'bg-green-transp t-green'
234
+ if (status === 'Tomorrow') return 'bg-second-transp t-second'
235
+ return 'bg-main-transp t-main'
236
+ }
237
+
156
238
  onMounted(async () => {
157
- // Load user stats if needed
239
+ // Load stats
240
+ try {
241
+ const [orgsData, ordersData, eventsData] = await Promise.all([
242
+ // Load counts if needed
243
+ ])
244
+ } catch (e) {
245
+ console.error('Failed to load dashboard stats:', e)
246
+ }
158
247
  })
159
248
  </script>
160
249
 
@@ -3,6 +3,7 @@ import IconHome from '@martyrs/src/modules/icons/entities/IconHome.vue';
3
3
  import IconEvents from '@martyrs/src/modules/icons/entities/IconEvents.vue';
4
4
  import IconGroups from '@martyrs/src/modules/icons/entities/IconGroups.vue';
5
5
  import IconOrders from '@martyrs/src/modules/icons/entities/IconOrders.vue';
6
+ import IconCommunity from '@martyrs/src/modules/icons/entities/IconCommunity.vue';
6
7
  import IconBell from '@martyrs/src/modules/icons/entities/IconBell.vue';
7
8
  import IconSettings from '@martyrs/src/modules/icons/entities/IconSettings.vue';
8
9
  import IconProfile from '@martyrs/src/modules/icons/entities/IconProfile.vue';
@@ -60,25 +61,30 @@ export const navigationItems = [
60
61
  route: (auth, route) => `/users/${route.params._id}/organizations`,
61
62
  visible: () => isModuleInstalled('organizations')
62
63
  },
64
+ {
65
+ title: 'Posts',
66
+ iconComponent: IconCommunity,
67
+ route: (auth, route) => `/users/${route.params._id}/blogposts`,
68
+ visible: () => isModuleInstalled('community')
69
+ },
63
70
  ]
64
71
  },
65
72
  {
66
73
  category: 'Orders',
67
- visible: () => true,
74
+ visible: (auth, route) => isModuleInstalled('orders') && (
75
+ auth.user && (
76
+ auth.user._id === route.params._id ||
77
+ (auth.access.roles &&
78
+ (auth.access.roles.includes('ROLE_MODERATOR') ||
79
+ auth.access.roles.includes('ROLE_ADMIN'))
80
+ )
81
+ )
82
+ ),
68
83
  items: [
69
84
  {
70
85
  title: 'Orders',
71
86
  iconComponent: IconOrders,
72
- route: (auth, route) => `/users/${route.params._id}/orders`,
73
- visible: (auth, route) => isModuleInstalled('orders') && (
74
- auth.user && (
75
- auth.user._id === route.params._id ||
76
- (auth.access.roles &&
77
- (auth.access.roles.includes('ROLE_MODERATOR') ||
78
- auth.access.roles.includes('ROLE_ADMIN'))
79
- )
80
- )
81
- )
87
+ route: (auth, route) => `/users/${route.params._id}/orders`
82
88
  },
83
89
  ]
84
90
  },
@@ -33,7 +33,6 @@ export function getUsersRoutes(options = {}) {
33
33
  },
34
34
  sidebar_hover: false,
35
35
  sidebar_navigation_items: navigationItems,
36
- sidebar_header_component: ProfileCard,
37
36
  sidebar_footer_component: HelpCard,
38
37
  sidebarOpenOnEnter: true,
39
38
  sidebarCloseOnLeave: true
@@ -1,7 +1,8 @@
1
+ import { reactive } from 'vue';
2
+
1
3
  class WebSocketManager {
2
4
  constructor() {
3
5
  this.socket = null;
4
- this.isConnected = false;
5
6
  this.reconnectAttempts = 0;
6
7
  this.maxReconnectAttempts = 5;
7
8
  this.reconnectDelay = 3000;
@@ -17,6 +18,24 @@ class WebSocketManager {
17
18
  this.rpcCallbacks = new Map();
18
19
  this.rpcTimeout = 30000; // 30 секунд таймаут по умолчанию
19
20
  this.rpcIdCounter = 0;
21
+
22
+ // Реактивное состояние
23
+ this.state = reactive({
24
+ isConnected: false,
25
+ wasConnected: false, // был ли когда-либо подключен
26
+ });
27
+ }
28
+
29
+ // Геттер для обратной совместимости
30
+ get isConnected() {
31
+ return this.state.isConnected;
32
+ }
33
+
34
+ set isConnected(value) {
35
+ this.state.isConnected = value;
36
+ if (value) {
37
+ this.state.wasConnected = true;
38
+ }
20
39
  }
21
40
 
22
41
  initialize(options = {}) {
@@ -78,9 +78,6 @@ export function renderAndMountApp({ createApp, hooks = {} }) {
78
78
  initialState = null;
79
79
  }
80
80
 
81
-
82
-
83
-
84
81
  if (initialState) {
85
82
  console.log('[AUTH COOKIE DEBUG] Browser initialState.auth:', initialState.auth);
86
83
  console.log('[AUTH COOKIE DEBUG] Has token?', !!initialState?.auth?.access?.token);
@@ -89,6 +86,15 @@ export function renderAndMountApp({ createApp, hooks = {} }) {
89
86
  // Применяем начальное состояние ко всем модулям (true = гидратация)
90
87
  store.setInitialState(initialState, true);
91
88
 
89
+ // Гидратация session из auth данных — напрямую в reactive state
90
+ if (initialState?.auth?.user?._id && store.core?.state?.session) {
91
+ store.core.state.session.userId = initialState.auth.user._id;
92
+ store.core.state.session.token = initialState.auth.access?.token;
93
+ store.core.state.session.roles = initialState.auth.access?.roles;
94
+ store.core.state.session.accesses = initialState.auth.accesses || [];
95
+ console.log('[AUTH COOKIE DEBUG] Session hydrated with userId:', initialState.auth.user._id);
96
+ }
97
+
92
98
  if (initialState?.auth?.access?.token) {
93
99
  console.log('[AUTH COOKIE DEBUG] Setting auth token from initialState');
94
100
 
@@ -47,7 +47,7 @@
47
47
  Mark all read
48
48
  </button>
49
49
 
50
- <router-link class="w-100 bg-black t-white radius-small button" to="/notifications" @click="closeNotifications">
50
+ <router-link class="w-100 bg-black t-white radius-small button" :to="`/users/${auth.state.user?._id}/notifications`" @click="closeNotifications">
51
51
  View all
52
52
  </router-link>
53
53
  </div>
@@ -1,69 +1,25 @@
1
1
  <template>
2
- <div class="notifications-layout">
3
- <div class="">
4
- <router-view></router-view>
5
- </div>
6
-
7
- <div v-if="!wsConnected" class="connection-status">
8
- <div class="connection-warning">
9
- <span class="warning-icon">⚠️</span>
10
- <span class="warning-text">
11
- Notification service disconnected.
12
- <button @click="reconnect" class="reconnect-btn">Reconnect</button>
13
- </span>
14
- </div>
2
+ <div>
3
+ <router-view />
4
+
5
+ <!-- Показываем только если WS был подключен и потом отвалился -->
6
+ <div v-if="wsManager.state.wasConnected && !wsManager.state.isConnected" class="pos-fixed pos-b-0 pos-l-0 pos-r-0 pd-small bg-warning t-center">
7
+ <span>⚠️ Notification service disconnected.</span>
8
+ <button class="mn-l-thin bg-none bd-none cursor-pointer t-main" @click="reconnect">Reconnect</button>
15
9
  </div>
16
10
  </div>
17
11
  </template>
18
12
 
19
13
  <script setup>
20
- import { computed, inject, ref, onMounted, onUnmounted } from 'vue';
14
+ import { computed, inject } from 'vue';
21
15
  import wsManager from '@martyrs/src/modules/core/views/classes/ws.manager.js';
22
16
 
23
- // Get notification manager from store
24
17
  const store = inject('store');
25
-
26
18
  const notificationManager = computed(() => store.notificationManager || null);
27
19
 
28
- // Реактивное состояние WebSocket
29
- const wsConnected = ref(wsManager.isConnected);
30
-
31
- // ID слушателей для очистки
32
- const openListenerId = ref(null);
33
- const closeListenerId = ref(null);
34
-
35
- onMounted(() => {
36
- // Подписываемся на события WebSocket
37
- openListenerId.value = wsManager.addEventListener('open', () => {
38
- wsConnected.value = true;
39
- });
40
-
41
- closeListenerId.value = wsManager.addEventListener('close', () => {
42
- wsConnected.value = false;
43
- });
44
-
45
- // Устанавливаем начальное состояние
46
- wsConnected.value = wsManager.isConnected;
47
- });
48
-
49
- onUnmounted(() => {
50
- // Очищаем слушатели
51
- if (openListenerId.value) {
52
- wsManager.removeEventListener('open', openListenerId.value);
53
- }
54
- if (closeListenerId.value) {
55
- wsManager.removeEventListener('close', closeListenerId.value);
56
- }
57
- });
58
-
59
-
60
- // Methods
61
20
  const reconnect = () => {
62
21
  if (notificationManager.value) {
63
22
  notificationManager.value.initialize();
64
23
  }
65
24
  };
66
- </script>
67
-
68
- <style scoped>
69
- </style>
25
+ </script>
@@ -1,36 +1,35 @@
1
1
  <template>
2
- <div class="notifications-page pd-small">
3
- <Tab
4
- v-model:selected="activeTab"
5
- :tabs="[
6
- { label: `All Notifications${unreadCount > 0 ? ` (${unreadCount})` : ''}`, value: 'all' },
7
- { label: 'Notification Settings', value: 'preferences' }
2
+ <div class="mobile:pd-thin pd-medium">
3
+ <SectionPageTitle
4
+ v-if="!MOBILE_APP"
5
+ :title="`Notifications${unreadCount > 0 ? ` (${unreadCount})` : ''}`"
6
+ :actions="[
7
+ { method: () => isSettingsPopup = true, label: 'Settings' }
8
8
  ]"
9
- class="flex-child-default gap-micro scroll-hide bg-light radius-medium h-max pd-thin mn-b-thin o-x-scroll"
10
- classTab="bg-white"
9
+ class="mn-b-small"
11
10
  />
12
-
13
- <div class="tab-content">
14
- <notifications-list v-if="activeTab === 'all'" />
15
- <notification-preferences v-else-if="activeTab === 'preferences'" />
16
- </div>
11
+
12
+ <NotificationsList />
13
+
14
+ <Popup
15
+ :isPopupOpen="isSettingsPopup"
16
+ @close-popup="isSettingsPopup = false"
17
+ title="Notification Settings"
18
+ class="bg-white pd-medium w-m-30r radius-big"
19
+ >
20
+ <NotificationPreferences />
21
+ </Popup>
17
22
  </div>
18
23
  </template>
19
24
 
20
25
  <script setup>
21
26
  import { ref, inject } from 'vue';
22
- import { useRoute } from 'vue-router';
23
- import Tab from "@martyrs/src/components/Tab/Tab.vue";
27
+ import SectionPageTitle from '@martyrs/src/modules/core/views/components/sections/SectionPageTitle.vue';
28
+ import Popup from '@martyrs/src/components/Popup/Popup.vue';
24
29
  import NotificationsList from '../sections/NotificationsList.vue';
25
30
  import NotificationPreferences from '../sections/NotificationPreferences.vue';
26
31
 
27
- // Get route and notification state
28
- const route = useRoute();
29
32
  const { unreadCount } = inject('useNotifications')();
30
33
 
31
- // Set initial active tab based on route query param or default to 'all'
32
- const activeTab = ref(route.query.tab || 'all');
34
+ const isSettingsPopup = ref(false);
33
35
  </script>
34
-
35
- <style scoped>
36
- </style>