@live-change/user-frontend 0.8.10 → 0.8.11
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/.nx/cache/file-map.json +433 -0
- package/.nx/cache/nx_files.nxt +0 -0
- package/.nx/cache/project-graph.json +6 -0
- package/build-stats/ssr-srcentryserverjs-outDir-distserver.html +4842 -0
- package/build-stats/ssrManifest-outDir-distclient.html +4842 -0
- package/front/components.d.ts +13 -0
- package/front/src/App.vue +2 -0
- package/front/src/NavBar.vue +39 -99
- package/front/src/connected/{Connect.vue → ConnectEmail.vue} +8 -4
- package/front/src/connected/ConnectPhone.vue +62 -0
- package/front/src/connected/Connected.vue +5 -4
- package/front/src/connected/routes.js +7 -2
- package/front/src/entry-server.js +4 -3
- package/front/src/identification/IdentificationSettings.vue +6 -5
- package/front/src/nav/UserIcon.vue +18 -27
- package/front/src/notifications/NotificationsIcon.vue +8 -17
- package/front/src/notifications/NotificationsList.vue +4 -8
- package/front/src/notifications/UnknownNotification.vue +6 -2
- package/front/src/router.js +2 -3
- package/front/vite.config.js.timestamp-1711533638521-1cea1a18c0069.mjs +12 -0
- package/index.js +2 -1
- package/package.json +30 -30
- package/server/{services.config.js → app.config.js} +14 -3
- package/server/security.config.js +2 -2
- package/server/services.list.js +38 -0
- package/server/start.js +37 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/* prettier-ignore */
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
// Generated by unplugin-vue-components
|
|
5
|
+
// Read more: https://github.com/vuejs/core/pull/3399
|
|
6
|
+
export {}
|
|
7
|
+
|
|
8
|
+
declare module 'vue' {
|
|
9
|
+
export interface GlobalComponents {
|
|
10
|
+
RouterLink: typeof import('vue-router')['RouterLink']
|
|
11
|
+
RouterView: typeof import('vue-router')['RouterView']
|
|
12
|
+
}
|
|
13
|
+
}
|
package/front/src/App.vue
CHANGED
|
@@ -37,8 +37,10 @@
|
|
|
37
37
|
|
|
38
38
|
const api = useApi()
|
|
39
39
|
import emailValidator from "@live-change/email-service/clientEmailValidator.js"
|
|
40
|
+
import phoneValidator from "@live-change/smsapi-service/clientPhoneValidator.js"
|
|
40
41
|
import passwordValidator from "@live-change/password-authentication-service/clientPasswordValidator.js"
|
|
41
42
|
api.validators.email = emailValidator
|
|
43
|
+
api.validators.phone = phoneValidator
|
|
42
44
|
api.validators.password = passwordValidator
|
|
43
45
|
|
|
44
46
|
</script>
|
package/front/src/NavBar.vue
CHANGED
|
@@ -3,125 +3,65 @@
|
|
|
3
3
|
relative md:sticky top-0 z-5"
|
|
4
4
|
style="min-height: 80px" key="navbar">
|
|
5
5
|
|
|
6
|
-
<router-link to="
|
|
7
|
-
<
|
|
6
|
+
<router-link :to="{ name: 'index' }" class="no-underline text-gray-700 text-2xl font-medium">
|
|
7
|
+
<div class="flex align-items-center">
|
|
8
|
+
<img src="/images/logo.svg" class="w-3rem mr-4">
|
|
9
|
+
<span>
|
|
10
|
+
User
|
|
11
|
+
</span>
|
|
12
|
+
</div>
|
|
8
13
|
</router-link>
|
|
9
|
-
<div class="hidden lg:flex">
|
|
10
|
-
<!-- place for desktop menu -->
|
|
11
|
-
</div>
|
|
12
|
-
<div class="flex flex-grow-1"></div>
|
|
13
|
-
<UserIcon />
|
|
14
14
|
|
|
15
|
-
<div class="
|
|
16
|
-
|
|
15
|
+
<div class="align-items-center flex-grow-1 justify-content-between hidden lg:block absolute lg:static w-full
|
|
16
|
+
surface-overlay left-0 top-100 z-1 shadow-2 lg:shadow-none top-menu">
|
|
17
|
+
<!-- <ul class="list-none p-0 m-0 flex lg:align-items-center select-none flex-column lg:flex-row-reverse">
|
|
17
18
|
<li>
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
<router-link :to="{ name: 'xml:search' }" v-ripple
|
|
20
|
+
class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900
|
|
21
|
+
hover:surface-100 font-medium border-round cursor-pointer transition-colors
|
|
22
|
+
transition-duration-150 p-ripple no-underline">
|
|
23
|
+
<i class="pi pi-search mr-2"></i>
|
|
24
|
+
<span>XML Search</span>
|
|
25
|
+
</router-link>
|
|
22
26
|
</li>
|
|
23
27
|
<li>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
<router-link :to="{ name: 'urls' }" v-ripple
|
|
29
|
+
class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900
|
|
30
|
+
hover:surface-100 font-medium border-round cursor-pointer transition-colors
|
|
31
|
+
transition-duration-150 p-ripple no-underline">
|
|
32
|
+
<i class="pi pi-link mr-2"></i>
|
|
33
|
+
<span>XMLs</span>
|
|
34
|
+
</router-link>
|
|
28
35
|
</li>
|
|
29
|
-
</ul
|
|
36
|
+
</ul>-->
|
|
30
37
|
</div>
|
|
31
38
|
|
|
39
|
+
<div class="flex flex-grow-1"></div>
|
|
40
|
+
|
|
41
|
+
<NotificationsIcon />
|
|
42
|
+
|
|
43
|
+
<UserIcon />
|
|
44
|
+
|
|
32
45
|
<a v-ripple class="cursor-pointer block lg:hidden text-700 p-ripple ml-2 hover:surface-100 p-2"
|
|
33
|
-
v-styleclass="{ selector: '
|
|
46
|
+
v-styleclass="{ selector: '.top-menu', enterClass: 'hidden', leaveToClass: 'hidden', hideOnOutsideClick: true }">
|
|
34
47
|
<i class="pi pi-bars text-4xl"></i>
|
|
35
48
|
</a>
|
|
36
49
|
|
|
37
|
-
<div class="align-items-center flex-grow-1 justify-content-between hidden absolute lg:static w-full surface-overlay left-0 top-100 z-1 shadow-2 lg:shadow-none">
|
|
38
|
-
<ul class="list-none p-0 m-0 flex lg:align-items-center select-none flex-column lg:flex-row">
|
|
39
|
-
<li>
|
|
40
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
41
|
-
<i class="pi pi-home mr-2"></i>
|
|
42
|
-
<span>Home</span>
|
|
43
|
-
</a>
|
|
44
|
-
</li>
|
|
45
|
-
<li class="lg:relative">
|
|
46
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple"
|
|
47
|
-
v-styleclass="{ selector: '@next', enterClass: 'hidden', enterActiveClass: 'scalein', leaveToClass: 'hidden', leaveActiveClass: 'fadeout', hideOnOutsideClick: true }">
|
|
48
|
-
<i class="pi pi-users mr-2"></i>
|
|
49
|
-
<span>Customers</span>
|
|
50
|
-
<i class="pi pi-angle-down ml-auto lg:ml-3"></i>
|
|
51
|
-
</a>
|
|
52
|
-
<ul class="list-none py-3 px-6 m-0 lg:px-0 lg:py-0 border-round shadow-0 lg:shadow-2 lg:border-1 border-50 lg:absolute surface-overlay hidden origin-top w-full lg:w-15rem cursor-pointer">
|
|
53
|
-
<li>
|
|
54
|
-
<a v-ripple class="flex p-3 align-items-center text-600 hover:text-900 hover:surface-100 transition-colors transition-duration-150 p-ripple">
|
|
55
|
-
<i class="pi pi-user-plus mr-2"></i>
|
|
56
|
-
<span class="font-medium">Add New</span>
|
|
57
|
-
</a>
|
|
58
|
-
</li>
|
|
59
|
-
<li class="relative">
|
|
60
|
-
<a v-ripple class="flex p-3 align-items-center text-600 hover:text-900 hover:surface-100 transition-colors transition-duration-150 p-ripple"
|
|
61
|
-
v-styleclass="{ selector: '@next', enterClass: 'hidden', enterActiveClass: 'scalein', leaveToClass: 'hidden', leaveActiveClass: 'fadeout', hideOnOutsideClick: true }">
|
|
62
|
-
<i class="pi pi-search mr-2"></i>
|
|
63
|
-
<span class="font-medium">Search</span>
|
|
64
|
-
<i class="pi pi-angle-down ml-auto lg:-rotate-90"></i>
|
|
65
|
-
</a>
|
|
66
|
-
<ul class="list-none py-3 pl-3 m-0 lg:px-0 lg:py-0 border-round shadow-0 lg:shadow-2 lg:border-1 border-50 lg:absolute surface-overlay hidden origin-top w-full lg:w-15rem cursor-pointer left-100 top-0">
|
|
67
|
-
<li>
|
|
68
|
-
<a v-ripple class="flex p-3 align-items-center text-600 hover:text-900 hover:surface-100 transition-colors transition-duration-150 p-ripple">
|
|
69
|
-
<i class="pi pi-shopping-cart mr-2"></i>
|
|
70
|
-
<span class="font-medium">Purchases</span>
|
|
71
|
-
</a>
|
|
72
|
-
</li>
|
|
73
|
-
<li class="relative">
|
|
74
|
-
<a v-ripple class="flex p-3 align-items-center text-600 hover:text-900 hover:surface-100 transition-colors transition-duration-150 p-ripple">
|
|
75
|
-
<i class="pi pi-comments mr-2"></i>
|
|
76
|
-
<span class="font-medium">Messages</span>
|
|
77
|
-
</a>
|
|
78
|
-
</li>
|
|
79
|
-
</ul>
|
|
80
|
-
</li>
|
|
81
|
-
</ul>
|
|
82
|
-
</li>
|
|
83
|
-
<li>
|
|
84
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
85
|
-
<i class="pi pi-calendar mr-2"></i>
|
|
86
|
-
<span>Calendar</span>
|
|
87
|
-
</a>
|
|
88
|
-
</li>
|
|
89
|
-
<li>
|
|
90
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
91
|
-
<i class="pi pi-chart-line mr-2"></i>
|
|
92
|
-
<span>Stats</span>
|
|
93
|
-
</a>
|
|
94
|
-
</li>
|
|
95
|
-
</ul>
|
|
96
|
-
<ul class="list-none p-0 m-0 flex lg:align-items-center select-none flex-column lg:flex-row border-top-1 surface-border lg:border-top-none">
|
|
97
|
-
<li>
|
|
98
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
99
|
-
<i class="pi pi-inbox text-base lg:text-2xl mr-2 lg:mr-0"></i>
|
|
100
|
-
<span class="block lg:hidden font-medium">Inbox</span>
|
|
101
|
-
</a>
|
|
102
|
-
</li>
|
|
103
|
-
<li class="border-top-1 surface-border lg:border-top-none">
|
|
104
|
-
<a v-ripple class="flex px-6 p-3 lg:px-3 lg:py-2 align-items-center hover:surface-100 font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
105
|
-
<img src="/images/empty-user-photo.svg" class="mr-3 lg:mr-0 border-circle" style="width: 28px; height: 28px"/>
|
|
106
|
-
<div class="block lg:hidden">
|
|
107
|
-
<div class="text-900 font-medium">Josephine Lillard</div>
|
|
108
|
-
<span class="text-600 font-medium text-sm">Marketing Specialist</span>
|
|
109
|
-
</div>
|
|
110
|
-
</a>
|
|
111
|
-
</li>
|
|
112
|
-
</ul>
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
50
|
</div>
|
|
116
51
|
</template>
|
|
117
52
|
|
|
118
53
|
<script setup>
|
|
119
54
|
|
|
120
|
-
import { NotificationsIcon } from "@live-change/user-frontend"
|
|
55
|
+
import { NotificationsIcon } from "@live-change/user-frontend"
|
|
56
|
+
|
|
57
|
+
import { UserIcon } from "@live-change/user-frontend"
|
|
121
58
|
|
|
122
|
-
import {
|
|
59
|
+
import { useApi } from "@live-change/vue3-ssr"
|
|
60
|
+
import { computed } from "vue"
|
|
123
61
|
|
|
62
|
+
const api = useApi()
|
|
124
63
|
|
|
64
|
+
const isMember = computed(() => api.client.value.roles.includes('member'))
|
|
125
65
|
|
|
126
66
|
</script>
|
|
127
67
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
|
|
3
3
|
<div class="surface-card p-4 shadow-2 border-round">
|
|
4
4
|
<div class="text-center mb-5">
|
|
5
|
-
<div class="text-900 text-3xl font-medium mb-3">
|
|
5
|
+
<div class="text-900 text-3xl font-medium mb-3">Add email</div>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<command-form service="messageAuthentication" action="connectEmail" v-slot="{ data }"
|
|
@@ -18,14 +18,18 @@
|
|
|
18
18
|
<small v-if="data.emailError" id="email-help" class="p-error">{{ data.emailError }}</small>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<Button label="
|
|
21
|
+
<Button label="Add Email" icon="pi pi-envelope" class="w-full" type="submit" />
|
|
22
22
|
|
|
23
23
|
<Divider align="center" class="my-4">
|
|
24
24
|
<span class="text-600 font-normal text-sm">OR</span>
|
|
25
25
|
</Divider>
|
|
26
26
|
|
|
27
|
-
<
|
|
28
|
-
|
|
27
|
+
<router-link :to="{ name: 'user:connect-phone' }">
|
|
28
|
+
<Button label="Add Phone" icon="pi pi-github" class="w-full p-button-secondary mb-2" />
|
|
29
|
+
</router-link>
|
|
30
|
+
|
|
31
|
+
<!-- <Button label="Connect GitHub account" icon="pi pi-github" class="w-full p-button-secondary mb-2"></Button>
|
|
32
|
+
<Button label="Connect Google account" icon="pi pi-google" class="w-full p-button-secondary mb-1"></Button>-->
|
|
29
33
|
|
|
30
34
|
</command-form>
|
|
31
35
|
</div>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
|
|
3
|
+
<div class="surface-card p-4 shadow-2 border-round">
|
|
4
|
+
<div class="text-center mb-5">
|
|
5
|
+
<div class="text-900 text-3xl font-medium mb-3">Add phone number</div>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<command-form service="messageAuthentication" action="connectPhone" v-slot="{ data }"
|
|
9
|
+
@done="handleSent" keepOnDone>
|
|
10
|
+
|
|
11
|
+
<div class="p-field mb-3">
|
|
12
|
+
<label for="email" class="block text-900 font-medium mb-2">
|
|
13
|
+
Phone number
|
|
14
|
+
</label>
|
|
15
|
+
<InputText id="email" type="text" class="w-full"
|
|
16
|
+
aria-describedby="email-help" :class="{ 'p-invalid': data.phoneError}"
|
|
17
|
+
v-model="data.phone" />
|
|
18
|
+
<small v-if="data.phoneError" id="email-help" class="p-error">{{ data.phoneError }}</small>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<Button label="Add Phone" icon="pi pi-mobile" class="w-full" type="submit" />
|
|
22
|
+
|
|
23
|
+
<Divider align="center" class="my-4">
|
|
24
|
+
<span class="text-600 font-normal text-sm">OR</span>
|
|
25
|
+
</Divider>
|
|
26
|
+
|
|
27
|
+
<router-link :to="{ name: 'user:connect-email' }">
|
|
28
|
+
<Button label="Add Email" icon="pi pi-github" class="w-full p-button-secondary mb-2" />
|
|
29
|
+
</router-link>
|
|
30
|
+
|
|
31
|
+
<!-- <Button label="Connect GitHub account" icon="pi pi-github" class="w-full p-button-secondary mb-2"></Button>-->
|
|
32
|
+
<!-- <Button label="Connect Google account" icon="pi pi-google" class="w-full p-button-secondary mb-1"></Button>-->
|
|
33
|
+
|
|
34
|
+
</command-form>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup>
|
|
40
|
+
import InputText from "primevue/inputtext"
|
|
41
|
+
import Checkbox from "primevue/checkbox"
|
|
42
|
+
import Button from "primevue/button"
|
|
43
|
+
import Divider from "primevue/divider"
|
|
44
|
+
|
|
45
|
+
import { useRouter } from 'vue-router'
|
|
46
|
+
const router = useRouter()
|
|
47
|
+
|
|
48
|
+
function handleSent({ parameters, result }) {
|
|
49
|
+
const { authentication } = result
|
|
50
|
+
router.push({
|
|
51
|
+
name: 'user:sent',
|
|
52
|
+
params: {
|
|
53
|
+
authentication
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
|
|
62
|
+
</style>
|
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
|
|
23
23
|
</ul>
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
<router-link :to="{ name: 'user:connect-email' }" class="mr-2 no-underline block mb-1">
|
|
26
|
+
<Button label="Add email" icon="pi pi-envelope" id="connect"></Button>
|
|
27
|
+
</router-link>
|
|
28
|
+
<router-link :to="{ name: 'user:connect-phone' }" class="mr-2 no-underline block mb-1">
|
|
29
|
+
<Button label="Add phone number" icon="pi pi-envelope" id="connect"></Button>
|
|
28
30
|
</router-link>
|
|
29
|
-
</div>
|
|
30
31
|
</div>
|
|
31
32
|
|
|
32
33
|
</div>
|
|
@@ -5,8 +5,13 @@ export function routes(config = {}) {
|
|
|
5
5
|
|
|
6
6
|
route({ name: 'user:connected', path: prefix + 'connected',
|
|
7
7
|
component: () => import("./Connected.vue") }),
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
route({ name: 'user:connect-email', path: prefix + 'connect-email',
|
|
10
|
+
component: () => import("./ConnectEmail.vue") }),
|
|
11
|
+
route({ name: 'user:connect-phone', path: prefix + 'connect-phone',
|
|
12
|
+
component: () => import("./ConnectPhone.vue") }),
|
|
13
|
+
|
|
14
|
+
|
|
10
15
|
route({ name: 'user:connectFinished', path: prefix + 'connect-finished',
|
|
11
16
|
component: () => import("./ConnectFinished.vue") }),
|
|
12
17
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { serverEntry } from '@live-change/frontend-base/server-entry.js'
|
|
1
|
+
import { serverEntry, sitemapEntry } from '@live-change/frontend-base/server-entry.js'
|
|
2
2
|
import App from './App.vue'
|
|
3
|
-
import { createRouter } from './router'
|
|
3
|
+
import { createRouter, sitemap as routerSitemap } from './router'
|
|
4
4
|
|
|
5
5
|
const render = serverEntry(App, createRouter)
|
|
6
|
-
|
|
6
|
+
const sitemap = sitemapEntry(App, createRouter, routerSitemap)
|
|
7
|
+
export { render, sitemap }
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
|
|
63
63
|
const workingZone = inject('workingZone')
|
|
64
64
|
|
|
65
|
+
const [ userData ] = await Promise.all([ dataPromise ])
|
|
66
|
+
|
|
67
|
+
const updateMethod = computed(() => userData.value ? 'updateMyIdentification' : 'setMyIdentification')
|
|
65
68
|
|
|
66
69
|
function openImageEditor() {
|
|
67
70
|
dialog.open(ComponentDialog, {
|
|
@@ -80,7 +83,8 @@
|
|
|
80
83
|
data: {
|
|
81
84
|
component: shallowRef(ImageEditor),
|
|
82
85
|
props: {
|
|
83
|
-
type: 'circle'
|
|
86
|
+
type: 'circle',
|
|
87
|
+
modelValue: userData.value?.image,
|
|
84
88
|
}
|
|
85
89
|
},
|
|
86
90
|
onClose: (options) => {
|
|
@@ -88,7 +92,7 @@
|
|
|
88
92
|
console.log("EDITOR RESULT", data)
|
|
89
93
|
console.log("WZ", workingZone)
|
|
90
94
|
workingZone.addPromise('update user image', (async () => {
|
|
91
|
-
await api.command(['userIdentification', updateMethod.value], { image: data
|
|
95
|
+
await api.command(['userIdentification', updateMethod.value], { image: data?.value })
|
|
92
96
|
toast.add({ severity:'info', summary: 'User image saved', life: 1500 })
|
|
93
97
|
})())
|
|
94
98
|
}
|
|
@@ -99,9 +103,6 @@
|
|
|
99
103
|
toast.add({ severity:'info', summary: 'User name saved', life: 1500 })
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
const [ userData ] = await Promise.all([ dataPromise ])
|
|
103
|
-
|
|
104
|
-
const updateMethod = computed(() => userData.value ? 'updateMyIdentification' : 'setMyIdentification')
|
|
105
106
|
|
|
106
107
|
</script>
|
|
107
108
|
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<a v-ripple
|
|
3
3
|
v-styleclass="{ selector: '@next', enterClass: 'hidden', leaveToClass: 'hidden', hideOnOutsideClick: true }"
|
|
4
|
-
class="relative
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
</span>
|
|
16
|
-
</li>
|
|
17
|
-
</ul>
|
|
4
|
+
class="relative shadow-none">
|
|
5
|
+
<span class="flex mx-0 px-3 align-items-center font-medium
|
|
6
|
+
cursor-pointer transition-colors transition-duration-150 border-round">
|
|
7
|
+
<Image v-if="myIdentification?.image" :image="myIdentification.image"
|
|
8
|
+
class="mr-0 border-circle border-1 surface-border" style="width: 3rem; " />
|
|
9
|
+
<img v-else-if="ownerType == 'session_Session'" src="/images/empty-user-photo.svg"
|
|
10
|
+
class="mr-0 border-circle" style="width: 3rem;" />
|
|
11
|
+
<img v-else :src="identiconUrl"
|
|
12
|
+
class="mr-0 border-circle border-1 surface-border" style="width: 3rem;" />
|
|
13
|
+
</span>
|
|
14
|
+
|
|
18
15
|
</a>
|
|
19
16
|
<div class="align-items-center flex-grow-1 justify-content-between hidden absolute w-full md:w-auto surface-overlay
|
|
20
17
|
right-0 top-100 z-1 shadow-2">
|
|
21
|
-
<!-- <OverlayPanel v-if="isMounted" ref="overlayPanel" class="notifications-panel">-->
|
|
22
18
|
<loading-zone suspense>
|
|
23
19
|
<template v-slot:loading>
|
|
24
20
|
<div class="flex align-items-center justify-content-center top-0 left-0 notifications-loading">
|
|
@@ -40,7 +36,6 @@
|
|
|
40
36
|
</working-zone>
|
|
41
37
|
</template>
|
|
42
38
|
</loading-zone>
|
|
43
|
-
<!-- </OverlayPanel>-->
|
|
44
39
|
</div>
|
|
45
40
|
</template>
|
|
46
41
|
|
|
@@ -49,18 +44,12 @@
|
|
|
49
44
|
import ProgressSpinner from "primevue/progressspinner"
|
|
50
45
|
import UserMenu from "./UserMenu.vue"
|
|
51
46
|
|
|
52
|
-
import { ref, computed, onMounted } from 'vue'
|
|
47
|
+
import { ref, computed, onMounted, toRefs } from 'vue'
|
|
53
48
|
|
|
54
49
|
const isMounted = ref(false)
|
|
55
50
|
onMounted(() => isMounted.value = true)
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
overlayPanel.value.toggle(event)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
import { path, live, actions } from '@live-change/vue3-ssr'
|
|
62
|
-
import { client as useClient } from '@live-change/vue3-ssr'
|
|
63
|
-
import { toRefs } from '@vueuse/core'
|
|
52
|
+
import { usePath, live, useClient } from '@live-change/vue3-ssr'
|
|
64
53
|
|
|
65
54
|
const client = useClient()
|
|
66
55
|
|
|
@@ -70,12 +59,14 @@
|
|
|
70
59
|
: ['session_Session', client.value.session]
|
|
71
60
|
)
|
|
72
61
|
|
|
73
|
-
const
|
|
62
|
+
const identiconUrl = computed(
|
|
63
|
+
() => `/api/identicon/jdenticon/${ownerData.value[0]}:${ownerData.value[1]}/28.svg`
|
|
64
|
+
)
|
|
74
65
|
|
|
75
|
-
const
|
|
66
|
+
const path = usePath()
|
|
76
67
|
|
|
77
68
|
const [ myIdentification ] = await Promise.all([
|
|
78
|
-
live(path
|
|
69
|
+
live(path.userIdentification.myIdentification())
|
|
79
70
|
])
|
|
80
71
|
|
|
81
72
|
</script>
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
<a v-if="unreadNotificationsCount"
|
|
3
3
|
v-ripple
|
|
4
4
|
v-styleclass="{ selector: '@next', enterClass: 'hidden', leaveToClass: 'hidden', hideOnOutsideClick: true }"
|
|
5
|
-
class="flex mx-0
|
|
5
|
+
class="flex mx-0 pl-3 pr-5 p-3 py-3 align-items-center text-600 hover:text-900 overflow-visible
|
|
6
6
|
font-medium border-round cursor-pointer transition-colors transition-duration-150 p-ripple">
|
|
7
7
|
<i class="pi pi-bell text-base text-2xl p-overlay-badge">
|
|
8
8
|
<Badge v-if="unreadNotificationsCount?.count" :value="unreadNotificationsCount?.count ?? 0"></Badge>
|
|
9
9
|
</i>
|
|
10
10
|
</a>
|
|
11
|
-
<div
|
|
12
|
-
|
|
11
|
+
<div v-if="isMounted"
|
|
12
|
+
class="align-items-center flex-grow-1 justify-content-between hidden absolute w-full md:w-auto surface-overlay
|
|
13
|
+
right-0 top-100 z-1 shadow-2 overflow-x-hidden overflow-y-auto"
|
|
14
|
+
style="max-height: calc(100vh - 8rem)">
|
|
13
15
|
<loading-zone suspense>
|
|
14
16
|
<template v-slot:loading>
|
|
15
17
|
<div class="flex align-items-center justify-content-center top-0 left-0 notifications-loading">
|
|
@@ -46,26 +48,15 @@
|
|
|
46
48
|
const isMounted = ref(false)
|
|
47
49
|
onMounted(() => isMounted.value = true)
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
overlayPanel.value.toggle(event)
|
|
51
|
-
}
|
|
51
|
+
import { live, usePath } from '@live-change/vue3-ssr'
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
const path = usePath()
|
|
54
54
|
|
|
55
|
-
const unreadNotificationsCount = await live(path
|
|
55
|
+
const unreadNotificationsCount = await live(path.notification.myUnreadCount({ }))
|
|
56
56
|
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
59
|
<style>
|
|
60
|
-
.notifications-panel .p-overlaypanel-content {
|
|
61
|
-
padding: 0px;
|
|
62
|
-
max-height: calc(90vh - 50px);
|
|
63
|
-
overflow-y: auto;
|
|
64
|
-
}
|
|
65
|
-
.notifications-panel {
|
|
66
|
-
width: 500px;
|
|
67
|
-
max-width: 80%;
|
|
68
|
-
}
|
|
69
60
|
.notifications-loading {
|
|
70
61
|
height: 300px;
|
|
71
62
|
max-height: 80%;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
:style="{ backgroundz: `hsl(${bucket.id * 11}, 100%, 80%)` }">
|
|
13
13
|
<div v-for="(notification, index) in bucket.data" :key="notification.id" :ref="el => bucket.domElements[index] = el"
|
|
14
14
|
class="notification border-bottom-1 surface-border"
|
|
15
|
-
:class="{ selected: selectedNotification
|
|
15
|
+
:class="{ selected: selectedNotification === notification.to }">
|
|
16
16
|
<component :is="notificationComponent(notification)" :notification="notification" />
|
|
17
17
|
<Button @click="() => selectNotification(notification)"
|
|
18
18
|
icon="pi pi-ellipsis-h" class="p-button-rounded p-button-text notification-more-button" />
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
|
|
46
46
|
import NotificationButtons from "./NotificationButtons.vue"
|
|
47
47
|
|
|
48
|
-
import {
|
|
48
|
+
import { actions, api, rangeBuckets, reverseRange } from '@live-change/vue3-ssr'
|
|
49
49
|
|
|
50
50
|
const notificationApi = actions().notification
|
|
51
51
|
|
|
@@ -90,16 +90,12 @@
|
|
|
90
90
|
},
|
|
91
91
|
]
|
|
92
92
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
const [ notificationsBuckets ] = await Promise.all([
|
|
93
|
+
/* const [ notificationsBuckets ] = await Promise.all([
|
|
96
94
|
rangeBuckets(
|
|
97
95
|
(range, p) => p.notification.myNotifications(reverseRange(range)),
|
|
98
96
|
{ bucketSize: 10 }
|
|
99
97
|
)
|
|
100
|
-
])
|
|
101
|
-
|
|
102
|
-
await wait
|
|
98
|
+
])*/
|
|
103
99
|
|
|
104
100
|
</script>
|
|
105
101
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<SimpleNotification :notification="notification">
|
|
3
3
|
<div class="text-orange-600 text-2xl">
|
|
4
|
-
Unknown notification!
|
|
4
|
+
Unknown notification {{ notification.notificationType }}!
|
|
5
5
|
</div>
|
|
6
6
|
<pre class="w-full overflow-hidden">{{ notification }}</pre>
|
|
7
7
|
</SimpleNotification>
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
|
|
12
12
|
import SimpleNotification from "./SimpleNotification.vue"
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
import { toRefs, watch } from 'vue'
|
|
15
|
+
|
|
16
|
+
const props = defineProps({
|
|
15
17
|
notification: {
|
|
16
18
|
type: Object,
|
|
17
19
|
required: true
|
|
18
20
|
}
|
|
19
21
|
})
|
|
20
22
|
|
|
23
|
+
const { notification } = toRefs(props)
|
|
24
|
+
|
|
21
25
|
</script>
|
|
22
26
|
|
|
23
27
|
<style scoped>
|
package/front/src/router.js
CHANGED
|
@@ -49,8 +49,7 @@ export {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export async function sitemap(route, api) {
|
|
52
|
-
route({ name: '
|
|
53
|
-
route({ name: 'SignUp' })
|
|
52
|
+
route({ name: 'index' })
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
import { client as useClient } from '@live-change/vue3-ssr'
|
|
@@ -85,7 +84,7 @@ export function createRouter(app, config) {
|
|
|
85
84
|
// import.meta.env.SSR is injected by Vite.
|
|
86
85
|
history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
|
|
87
86
|
routes: [
|
|
88
|
-
{ path: '/', component: () => import('./Index.vue') },
|
|
87
|
+
{ name: 'index', path: '/', component: () => import('./Index.vue') },
|
|
89
88
|
...userRoutes(config),
|
|
90
89
|
...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) })
|
|
91
90
|
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// vite.config.js
|
|
2
|
+
import { defineConfig } from "file:///home/m8/IdeaProjects/live-change/node_modules/vite/dist/node/index.js";
|
|
3
|
+
import baseViteConfig from "file:///home/m8/IdeaProjects/live-change/live-change-stack/frontend/frontend-base/vite-config.js";
|
|
4
|
+
var vite_config_default = defineConfig(async ({ command, mode }) => {
|
|
5
|
+
return {
|
|
6
|
+
...await baseViteConfig({ command, mode })
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
export {
|
|
10
|
+
vite_config_default as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9tOC9JZGVhUHJvamVjdHMvbGl2ZS1jaGFuZ2UvbGl2ZS1jaGFuZ2Utc3RhY2svZnJvbnRlbmQvdXNlci1mcm9udGVuZC9mcm9udFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvbTgvSWRlYVByb2plY3RzL2xpdmUtY2hhbmdlL2xpdmUtY2hhbmdlLXN0YWNrL2Zyb250ZW5kL3VzZXItZnJvbnRlbmQvZnJvbnQvdml0ZS5jb25maWcuanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvbTgvSWRlYVByb2plY3RzL2xpdmUtY2hhbmdlL2xpdmUtY2hhbmdlLXN0YWNrL2Zyb250ZW5kL3VzZXItZnJvbnRlbmQvZnJvbnQvdml0ZS5jb25maWcuanNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xuXG5pbXBvcnQgYmFzZVZpdGVDb25maWcgZnJvbSAnQGxpdmUtY2hhbmdlL2Zyb250ZW5kLWJhc2Uvdml0ZS1jb25maWcuanMnXG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyhhc3luYyAoeyBjb21tYW5kLCBtb2RlIH0pID0+IHtcbiAgcmV0dXJuIHtcbiAgICAuLi4oYXdhaXQgYmFzZVZpdGVDb25maWcoeyBjb21tYW5kLCBtb2RlIH0pKSxcblxuXG4gIH1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQWthLFNBQVMsb0JBQW9CO0FBRS9iLE9BQU8sb0JBQW9CO0FBRTNCLElBQU8sc0JBQVEsYUFBYSxPQUFPLEVBQUUsU0FBUyxLQUFLLE1BQU07QUFDdkQsU0FBTztBQUFBLElBQ0wsR0FBSSxNQUFNLGVBQWUsRUFBRSxTQUFTLEtBQUssQ0FBQztBQUFBLEVBRzVDO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|
package/index.js
CHANGED
|
@@ -4,8 +4,9 @@ export { UserIdentification, ObjectIdentification }
|
|
|
4
4
|
|
|
5
5
|
import NotificationsIcon from "./front/src/notifications/NotificationsIcon.vue"
|
|
6
6
|
import SimpleNotification from "./front/src/notifications/SimpleNotification.vue"
|
|
7
|
+
import UnknownNotification from './front/src/notifications/UnknownNotification.vue'
|
|
7
8
|
import { notificationTypes } from "./front/src/notifications/notificationTypes.js"
|
|
8
|
-
export { NotificationsIcon, SimpleNotification, notificationTypes }
|
|
9
|
+
export { NotificationsIcon, SimpleNotification, notificationTypes, UnknownNotification }
|
|
9
10
|
|
|
10
11
|
import UserIcon from "./front/src/nav/UserIcon.vue"
|
|
11
12
|
export { UserIcon }
|