@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.
- package/dist/martyrs/src/components/Feed/Feed.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +6 -12
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/UserDashboard.vue.js +182 -89
- package/dist/martyrs/src/modules/auth/views/components/pages/UserDashboard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/configs/navigation.user.config.js +11 -5
- package/dist/martyrs/src/modules/auth/views/configs/navigation.user.config.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/router/users.router.js +1 -2
- package/dist/martyrs/src/modules/auth/views/router/users.router.js.map +1 -1
- package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/classes/ws.manager.js +16 -1
- package/dist/martyrs/src/modules/core/views/classes/ws.manager.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
- package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js +7 -0
- package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +1 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +3 -3
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/layouts/NotificationsLayout.vue.js +11 -40
- package/dist/martyrs/src/modules/notifications/components/layouts/NotificationsLayout.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js +26 -21
- package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/sections/NotificationPreferences.vue.js +54 -48
- package/dist/martyrs/src/modules/notifications/components/sections/NotificationPreferences.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/sections/NotificationsList.vue.js +37 -117
- package/dist/martyrs/src/modules/notifications/components/sections/NotificationsList.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.js +18 -15
- package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +90 -175
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +6 -6
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js +41 -28
- package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/orders.client.js +14 -14
- package/dist/martyrs/src/modules/orders/orders.client.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +88 -39
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +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.js +1 -1
- package/dist/style.css +73 -265
- package/package.json +1 -1
- package/src/modules/TASKS.MD +26 -1
- package/src/modules/auth/views/components/pages/Profile.vue +9 -15
- package/src/modules/auth/views/components/pages/ProfileEdit.vue +1 -1
- package/src/modules/auth/views/components/pages/UserDashboard.vue +214 -125
- package/src/modules/auth/views/configs/navigation.user.config.js +17 -11
- package/src/modules/auth/views/router/users.router.js +0 -1
- package/src/modules/core/views/classes/ws.manager.js +20 -1
- package/src/modules/core/views/utils/vue-app-renderer.js +9 -3
- package/src/modules/notifications/components/elements/NotificationBadge.vue +1 -1
- package/src/modules/notifications/components/layouts/NotificationsLayout.vue +9 -53
- package/src/modules/notifications/components/pages/Notifications.vue +21 -22
- package/src/modules/notifications/components/sections/NotificationPreferences.vue +41 -180
- package/src/modules/notifications/components/sections/NotificationsList.vue +39 -219
- package/src/modules/notifications/notifications.client.js +17 -16
- package/src/modules/orders/components/blocks/CardOrderUser.vue +88 -190
- package/src/modules/orders/components/pages/OrderBackoffice.vue +5 -5
- package/src/modules/orders/components/pages/Orders.vue +56 -50
- package/src/modules/organizations/components/pages/OrganizationEdit.vue +42 -11
- package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue.js +0 -625
- package/dist/martyrs/src/components/SelectMulti/SelectMulti.vue.js.map +0 -1
- package/dist/martyrs/src/modules/auth/views/components/blocks/ProfileCard.vue.js +0 -44
- package/dist/martyrs/src/modules/auth/views/components/blocks/ProfileCard.vue.js.map +0 -1
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusCanceled.vue.js +0 -32
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusCanceled.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusConfirmed.vue.js +0 -32
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusConfirmed.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusCreated.vue.js +0 -32
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusCreated.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusDelay.vue.js +0 -32
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusDelay.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusFinished.vue.js +0 -32
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusFinished.vue.js.map +0 -1
- package/dist/martyrs/src/modules/orders/components/icons/IconStatusInUse.vue.js +0 -32
- 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
|
|
3
|
-
<h2 class="mn-b-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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-
|
|
71
|
+
class="radius-small bg-white"
|
|
57
72
|
:items="items"
|
|
58
|
-
:columns="
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
class="pos-relative"
|
|
86
|
-
>
|
|
96
|
+
<!-- Upcoming Events -->
|
|
97
|
+
<Block title="Upcoming Events">
|
|
87
98
|
<Feed
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 {
|
|
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
|
|
144
|
-
import * as orders
|
|
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
|
|
173
|
+
const FILE_SERVER_URL = inject('FILE_SERVER_URL', '')
|
|
148
174
|
const router = useRouter()
|
|
149
175
|
|
|
150
176
|
const stats = ref({
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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: () =>
|
|
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
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
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
|
|
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="
|
|
3
|
-
<
|
|
4
|
-
v-
|
|
5
|
-
:
|
|
6
|
-
|
|
7
|
-
{
|
|
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="
|
|
10
|
-
classTab="bg-white"
|
|
9
|
+
class="mn-b-small"
|
|
11
10
|
/>
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
23
|
-
import
|
|
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
|
-
|
|
32
|
-
const activeTab = ref(route.query.tab || 'all');
|
|
34
|
+
const isSettingsPopup = ref(false);
|
|
33
35
|
</script>
|
|
34
|
-
|
|
35
|
-
<style scoped>
|
|
36
|
-
</style>
|