@live-change/user-frontend 0.0.3
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/LICENSE +21 -0
- package/e2e/codecept.conf.js +60 -0
- package/e2e/connectEmailCode.test.js +61 -0
- package/e2e/connectEmailLink.test.js +60 -0
- package/e2e/delete.test.js +44 -0
- package/e2e/disconnectEmail.test.js +42 -0
- package/e2e/resetPasswordWithEmailCode.test.js +62 -0
- package/e2e/resetPasswordWithEmailLink.test.js +62 -0
- package/e2e/setPassword.test.js +70 -0
- package/e2e/signInEmailCode.test.js +52 -0
- package/e2e/signInEmailLink.test.js +52 -0
- package/e2e/signInEmailPassword.test.js +47 -0
- package/e2e/signOut.test.js +41 -0
- package/e2e/signUpEmailCode.test.js +41 -0
- package/e2e/signUpEmailLink.test.js +41 -0
- package/e2e/steps.d.ts +12 -0
- package/e2e/steps_file.js +89 -0
- package/front/index.html +11 -0
- package/front/public/favicon.ico +0 -0
- package/front/public/images/empty-photo.svg +38 -0
- package/front/public/images/empty-user-photo.svg +33 -0
- package/front/public/images/logo.svg +34 -0
- package/front/public/images/logo128.png +0 -0
- package/front/src/App.vue +31 -0
- package/front/src/Index.vue +14 -0
- package/front/src/NavBar.vue +103 -0
- package/front/src/SettingsTabs.vue +48 -0
- package/front/src/connected/Connect.vue +58 -0
- package/front/src/connected/ConnectFinished.vue +16 -0
- package/front/src/connected/Connected.vue +84 -0
- package/front/src/connected/routes.js +16 -0
- package/front/src/delete/Delete.vue +53 -0
- package/front/src/delete/DeleteFeedbackSent.vue +16 -0
- package/front/src/delete/DeleteFinished.vue +32 -0
- package/front/src/delete/routes.js +16 -0
- package/front/src/entry-client.js +6 -0
- package/front/src/entry-server.js +6 -0
- package/front/src/identification/IdentificationSettings.vue +116 -0
- package/front/src/identification/ObjectIdentification.vue +36 -0
- package/front/src/identification/UserIdentification.vue +101 -0
- package/front/src/identification/routes.js +12 -0
- package/front/src/message-auth/ConnectEmail.vue +105 -0
- package/front/src/message-auth/MessageLink.vue +95 -0
- package/front/src/message-auth/MessageSent.vue +103 -0
- package/front/src/message-auth/ResetPasswordEmail.vue +105 -0
- package/front/src/message-auth/SignInEmail.vue +105 -0
- package/front/src/message-auth/SignUpEmail.vue +105 -0
- package/front/src/message-auth/routes.js +25 -0
- package/front/src/notifications/NotificationButtons.vue +70 -0
- package/front/src/notifications/NotificationListPage.vue +22 -0
- package/front/src/notifications/NotificationsIcon.vue +75 -0
- package/front/src/notifications/NotificationsList.vue +144 -0
- package/front/src/notifications/NotificationsSettings.vue +117 -0
- package/front/src/notifications/SimpleNotification.vue +34 -0
- package/front/src/notifications/TestNotification.vue +25 -0
- package/front/src/notifications/UnknownNotification.vue +25 -0
- package/front/src/notifications/notificationTypes.js +11 -0
- package/front/src/notifications/routes.js +37 -0
- package/front/src/password/ChangePassword.vue +106 -0
- package/front/src/password/ChangePasswordFinished.vue +16 -0
- package/front/src/password/ResetPassword.vue +56 -0
- package/front/src/password/ResetPasswordFinished.vue +16 -0
- package/front/src/password/ResetPasswordForm.vue +118 -0
- package/front/src/password/routes.js +41 -0
- package/front/src/router.js +90 -0
- package/front/src/settings/Settings.vue +33 -0
- package/front/src/settings/SettingsIndex.vue +22 -0
- package/front/src/settings/SettingsMenu.vue +81 -0
- package/front/src/settings/SettingsMenuItem.vue +35 -0
- package/front/src/sign/SignIn.vue +93 -0
- package/front/src/sign/SignInFinished.vue +27 -0
- package/front/src/sign/SignOut.vue +37 -0
- package/front/src/sign/SignOutFinished.vue +16 -0
- package/front/src/sign/SignUp.vue +51 -0
- package/front/src/sign/SignUpFinished.vue +16 -0
- package/front/src/sign/routes.js +24 -0
- package/front/vite.config.js +11 -0
- package/index.js +11 -0
- package/package.json +87 -0
- package/server/init.js +53 -0
- package/server/security.config.js +53 -0
- package/server/services.config.js +74 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
|
|
3
|
+
|
|
4
|
+
<div class="surface-card border-round shadow-2 p-4" v-if="isUnknown">
|
|
5
|
+
<div class="text-900 font-medium mb-3 text-xl">Unknown link</div>
|
|
6
|
+
<p class="mt-0 mb-2 p-0 line-height-3">We can't find your secret link. Check if you copied the address correctly.</p>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="surface-card border-round shadow-2 p-4" v-if="isUsed">
|
|
10
|
+
<div class="text-900 font-medium mb-3 text-xl">Link used</div>
|
|
11
|
+
<p class="mt-0 mb-2 p-0 line-height-3">This link was already used.</p>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div class="surface-card border-round shadow-2 p-4" v-if="isExpired && !isUsed">
|
|
15
|
+
<div class="text-900 font-medium mb-3 text-xl">Link expired</div>
|
|
16
|
+
<p class="mt-0 mb-4 p-0 line-height-3">Your secret link already expired. To send another link click button below.</p>
|
|
17
|
+
<Button label="Resend" class="p-button-lg" @click="resend"></Button>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="surface-card border-round shadow-2 p-4 flex justify-content-center" v-if="isReady">
|
|
21
|
+
<ProgressSpinner class="m-3" />
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup>
|
|
27
|
+
import Button from "primevue/button"
|
|
28
|
+
import ProgressSpinner from "primevue/progressspinner"
|
|
29
|
+
|
|
30
|
+
import { computed, inject } from 'vue'
|
|
31
|
+
import { useRouter } from 'vue-router'
|
|
32
|
+
import { useNow } from '@vueuse/core'
|
|
33
|
+
import { path, live, actions } from '@live-change/vue3-ssr'
|
|
34
|
+
|
|
35
|
+
const { secretCode } = defineProps({
|
|
36
|
+
secretCode: {
|
|
37
|
+
type: String,
|
|
38
|
+
required: true
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const now = useNow({ interval: 1000 })
|
|
43
|
+
|
|
44
|
+
const workingZone = inject('workingZone')
|
|
45
|
+
const router = useRouter()
|
|
46
|
+
|
|
47
|
+
const { finishMessageAuthentication, resendMessageAuthentication } = actions().messageAuthentication
|
|
48
|
+
|
|
49
|
+
function resend() {
|
|
50
|
+
workingZone.addPromise('resendMessageAuthentication', (async () => {
|
|
51
|
+
const { authentication } = await resendMessageAuthentication({
|
|
52
|
+
authentication: link?.value?.authenticationData?.id
|
|
53
|
+
})
|
|
54
|
+
router.push({
|
|
55
|
+
name: 'user:sent',
|
|
56
|
+
params: {
|
|
57
|
+
authentication
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
})())
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const [ link ] = await Promise.all([
|
|
64
|
+
live(
|
|
65
|
+
path().secretLink.link({ secretCode })
|
|
66
|
+
.with(link => path().messageAuthentication.authentication({
|
|
67
|
+
authentication: link.authentication.$nonEmpty()
|
|
68
|
+
}).bind('authenticationData')
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
const authenticationState = computed(() => link?.value?.authenticationData?.state )
|
|
74
|
+
|
|
75
|
+
const isUnknown = computed(() => link.value === null)
|
|
76
|
+
const isExpired = computed(() => link.value ? (now.value.toISOString() > link.value.expire) : false )
|
|
77
|
+
const isUsed = computed(() => authenticationState.value && authenticationState.value == 'used')
|
|
78
|
+
const isReady = computed(() => !(isUnknown.value || isExpired.value || isUsed.value))
|
|
79
|
+
|
|
80
|
+
//const targetPage = computed(() => link.value?.authentication?.targetPage )
|
|
81
|
+
|
|
82
|
+
if(typeof window != 'undefined') setTimeout(() => { /// timeout "fixes" suspense bug
|
|
83
|
+
if(isReady.value) {
|
|
84
|
+
workingZone.addPromise('finishMessageAuthentication', (async () => {
|
|
85
|
+
const { result, targetPage } = await finishMessageAuthentication({ secretType: 'link', secret: secretCode })
|
|
86
|
+
router.push(targetPage)
|
|
87
|
+
})())
|
|
88
|
+
}
|
|
89
|
+
}, 10)
|
|
90
|
+
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
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 border-round shadow-2 p-4" v-if="authenticationData?.state == 'used' && !submitted">
|
|
4
|
+
<div class="text-900 font-medium mb-3 text-xl">Authentication done</div>
|
|
5
|
+
<p class="mt-0 mb-1 p-0 line-height-3">You authenticated in a different tab.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="surface-card border-round shadow-2 p-4" v-else>
|
|
8
|
+
<div class="text-900 font-medium mb-3 text-xl">Message sent</div>
|
|
9
|
+
<p class="mt-0 mb-1 p-0 line-height-3">We sent special secret message to your email.</p>
|
|
10
|
+
<p class="mt-0 mb-4 p-0 line-height-3">Click on the link or enter the code you found in that message.</p>
|
|
11
|
+
<Secured :events="['wrong-secret-code']" :actions="['checkSecretCode']">
|
|
12
|
+
<command-form service="messageAuthentication" action="finishMessageAuthentication"
|
|
13
|
+
:parameters="{ secretType: 'code', authentication }"
|
|
14
|
+
@submit="handleSubmit" @done="handleAuthenticated" @error="handleError"
|
|
15
|
+
v-slot="{ data }">
|
|
16
|
+
<div class="flex justify-content-center">
|
|
17
|
+
<div class="p-field mr-1 flex flex-column">
|
|
18
|
+
<label for="code" class="p-sr-only">Code</label>
|
|
19
|
+
<InputMask id="code" class="p-inputtext-lg" mask="999999" slotChar="######" placeholder="Enter code"
|
|
20
|
+
v-model="data.secret"
|
|
21
|
+
aria-describedby="code-help" :class="{ 'p-invalid': data.secretError }" />
|
|
22
|
+
<span v-if="data.secretError" id="code-help" class="p-error">{{ data.secretError }}</span>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="flex flex-column">
|
|
25
|
+
<Button label="OK" type="submit" class="p-button-lg flex-grow-0"></Button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div v-if="data.secretError == 'codeExpired'">
|
|
29
|
+
<p class="mt-0 mb-4 p-0 line-height-3">To send another code click button below.</p>
|
|
30
|
+
<Button label="Resend" class="p-button-lg" @click="resend"></Button>
|
|
31
|
+
</div>
|
|
32
|
+
</command-form>
|
|
33
|
+
</Secured>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup>
|
|
39
|
+
import InputMask from "primevue/inputmask"
|
|
40
|
+
import Button from "primevue/button"
|
|
41
|
+
|
|
42
|
+
import { Secured } from "@live-change/security-frontend"
|
|
43
|
+
|
|
44
|
+
import { useRouter } from 'vue-router'
|
|
45
|
+
import { ref } from 'vue'
|
|
46
|
+
|
|
47
|
+
const router = useRouter()
|
|
48
|
+
|
|
49
|
+
const { authentication } = defineProps({
|
|
50
|
+
authentication: {
|
|
51
|
+
type: String,
|
|
52
|
+
required: true
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
function handleAuthenticated({ parameters, result }) {
|
|
57
|
+
const { targetPage } = result
|
|
58
|
+
console.log("TARGET ROUTE", targetPage)
|
|
59
|
+
router.push(targetPage)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const submitted = ref(false)
|
|
63
|
+
|
|
64
|
+
function handleSubmit() {
|
|
65
|
+
submitted.value = true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function handleError() {
|
|
69
|
+
submitted.value = false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
import { inject } from 'vue'
|
|
73
|
+
import { actions } from '@live-change/vue3-ssr'
|
|
74
|
+
const workingZone = inject('workingZone')
|
|
75
|
+
const { resendMessageAuthentication } = actions().messageAuthentication
|
|
76
|
+
function resend() {
|
|
77
|
+
workingZone.addPromise('resendMessageAuthentication', (async () => {
|
|
78
|
+
const { authentication: newAuthentication } = await resendMessageAuthentication({
|
|
79
|
+
authentication
|
|
80
|
+
})
|
|
81
|
+
router.push({
|
|
82
|
+
name: 'user:sent',
|
|
83
|
+
params: {
|
|
84
|
+
authentication: newAuthentication
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
})())
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
import { live, path } from '@live-change/vue3-ssr'
|
|
91
|
+
const [ authenticationData ] = await Promise.all([
|
|
92
|
+
live(
|
|
93
|
+
path().messageAuthentication.authentication({ authentication })
|
|
94
|
+
)
|
|
95
|
+
])
|
|
96
|
+
if(authenticationData?.value?.state == 'used') {
|
|
97
|
+
router.push(authenticationData.value.targetPage)
|
|
98
|
+
}
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<style>
|
|
102
|
+
|
|
103
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<pre data-headers>{{ JSON.stringify(metadata, null, ' ') }}</pre>
|
|
3
|
+
<div data-html class="message m-6">
|
|
4
|
+
<p class="text-lg">
|
|
5
|
+
Hello!
|
|
6
|
+
</p>
|
|
7
|
+
<p>
|
|
8
|
+
You are trying to reset password to your DEMO account.
|
|
9
|
+
In order to confirm that, please enter secret code:
|
|
10
|
+
</p>
|
|
11
|
+
<p class="text-3xl font-medium">{{ code }}</p>
|
|
12
|
+
<p>
|
|
13
|
+
Or click the button below:
|
|
14
|
+
</p>
|
|
15
|
+
<div>
|
|
16
|
+
<a :href="linkAddress" class="no-underline">
|
|
17
|
+
<Button label="Confirm email" class="p-button-lg" />
|
|
18
|
+
</a>
|
|
19
|
+
</div>
|
|
20
|
+
<p>
|
|
21
|
+
Or copy this address to your browser address bar:<br>
|
|
22
|
+
<a :href="linkAddress">
|
|
23
|
+
{{ linkAddress }}
|
|
24
|
+
</a>
|
|
25
|
+
</p>
|
|
26
|
+
<p>
|
|
27
|
+
Let us know in case it's not you.
|
|
28
|
+
</p>
|
|
29
|
+
<p>
|
|
30
|
+
See you soon<br>
|
|
31
|
+
Live Change Team
|
|
32
|
+
</p>
|
|
33
|
+
<img src="/images/logo128.png">
|
|
34
|
+
</div>
|
|
35
|
+
<pre class="message" data-text>
|
|
36
|
+
Hello!
|
|
37
|
+
|
|
38
|
+
You are trying to reset password to your DEMO account.
|
|
39
|
+
In order to confirm that, please enter secret code:
|
|
40
|
+
{{ code }}
|
|
41
|
+
|
|
42
|
+
Or please click link below or copy address to your browser address bar:
|
|
43
|
+
|
|
44
|
+
{{ linkAddress }}
|
|
45
|
+
|
|
46
|
+
Let us know in case it's not you.
|
|
47
|
+
|
|
48
|
+
See you soon
|
|
49
|
+
Live Change Team
|
|
50
|
+
</pre>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup>
|
|
54
|
+
import Button from "primevue/button"
|
|
55
|
+
|
|
56
|
+
const { action, contact, json } = defineProps({
|
|
57
|
+
action: {
|
|
58
|
+
type: String,
|
|
59
|
+
required: true
|
|
60
|
+
},
|
|
61
|
+
contact: {
|
|
62
|
+
type: String,
|
|
63
|
+
required: true
|
|
64
|
+
},
|
|
65
|
+
json: {
|
|
66
|
+
type: String,
|
|
67
|
+
required: true
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const data = JSON.parse(json)
|
|
72
|
+
const secrets = data.secrets
|
|
73
|
+
|
|
74
|
+
const secretLink = secrets.find(secret => secret.type == 'link')
|
|
75
|
+
|
|
76
|
+
const secretCode = secrets.find(secret => secret.type == 'code')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
const metadata = {
|
|
80
|
+
from: 'admin@flipchart.live',
|
|
81
|
+
subject: 'Confirm your email address.',
|
|
82
|
+
to: contact
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const linkAddress = ENV_BASE_HREF + '/link/' + secretLink.secret.secretCode
|
|
86
|
+
|
|
87
|
+
const code = secretCode.secret.secretCode
|
|
88
|
+
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<style scoped>
|
|
92
|
+
img {
|
|
93
|
+
width: 100%;
|
|
94
|
+
max-width: 100px;
|
|
95
|
+
}
|
|
96
|
+
.message {
|
|
97
|
+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
|
98
|
+
color: #495057;
|
|
99
|
+
font-weight: 400;
|
|
100
|
+
}
|
|
101
|
+
pre {
|
|
102
|
+
border-top: 1px solid black;
|
|
103
|
+
border-bottom: 1px solid black;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<pre data-headers>{{ JSON.stringify(metadata, null, ' ') }}</pre>
|
|
3
|
+
<div data-html class="message m-6">
|
|
4
|
+
<p class="text-lg">
|
|
5
|
+
Hello!
|
|
6
|
+
</p>
|
|
7
|
+
<p>
|
|
8
|
+
We are glad to see you have just signed in for DEMO with your email.
|
|
9
|
+
In order to confirm that, please enter secret code:
|
|
10
|
+
</p>
|
|
11
|
+
<p class="text-3xl font-medium">{{ code }}</p>
|
|
12
|
+
<p>
|
|
13
|
+
Or click the button below:
|
|
14
|
+
</p>
|
|
15
|
+
<div>
|
|
16
|
+
<a :href="linkAddress" class="no-underline">
|
|
17
|
+
<Button label="Confirm email" class="p-button-lg" />
|
|
18
|
+
</a>
|
|
19
|
+
</div>
|
|
20
|
+
<p>
|
|
21
|
+
Or copy this address to your browser address bar:<br>
|
|
22
|
+
<a :href="linkAddress">
|
|
23
|
+
{{ linkAddress }}
|
|
24
|
+
</a>
|
|
25
|
+
</p>
|
|
26
|
+
<p>
|
|
27
|
+
Let us know in case it's not you.
|
|
28
|
+
</p>
|
|
29
|
+
<p>
|
|
30
|
+
See you soon<br>
|
|
31
|
+
Live Change Team
|
|
32
|
+
</p>
|
|
33
|
+
<img src="/images/logo128.png">
|
|
34
|
+
</div>
|
|
35
|
+
<pre class="message" data-text>
|
|
36
|
+
Hello!
|
|
37
|
+
|
|
38
|
+
We are glad to see you have just signed in for DEMO with your email.
|
|
39
|
+
In order to confirm that, please enter secret code:
|
|
40
|
+
{{ code }}
|
|
41
|
+
|
|
42
|
+
Or please click link below or copy address to your browser address bar:
|
|
43
|
+
|
|
44
|
+
{{ linkAddress }}
|
|
45
|
+
|
|
46
|
+
Let us know in case it's not you.
|
|
47
|
+
|
|
48
|
+
See you soon
|
|
49
|
+
Live Change Team
|
|
50
|
+
</pre>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup>
|
|
54
|
+
import Button from "primevue/button"
|
|
55
|
+
|
|
56
|
+
const { action, contact, json } = defineProps({
|
|
57
|
+
action: {
|
|
58
|
+
type: String,
|
|
59
|
+
required: true
|
|
60
|
+
},
|
|
61
|
+
contact: {
|
|
62
|
+
type: String,
|
|
63
|
+
required: true
|
|
64
|
+
},
|
|
65
|
+
json: {
|
|
66
|
+
type: String,
|
|
67
|
+
required: true
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const data = JSON.parse(json)
|
|
72
|
+
const secrets = data.secrets
|
|
73
|
+
|
|
74
|
+
const secretLink = secrets.find(secret => secret.type == 'link')
|
|
75
|
+
|
|
76
|
+
const secretCode = secrets.find(secret => secret.type == 'code')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
const metadata = {
|
|
80
|
+
from: 'admin@flipchart.live',
|
|
81
|
+
subject: 'Confirm your email address.',
|
|
82
|
+
to: contact
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const linkAddress = ENV_BASE_HREF + '/link/' + secretLink.secret.secretCode
|
|
86
|
+
|
|
87
|
+
const code = secretCode.secret.secretCode
|
|
88
|
+
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<style scoped>
|
|
92
|
+
img {
|
|
93
|
+
width: 100%;
|
|
94
|
+
max-width: 100px;
|
|
95
|
+
}
|
|
96
|
+
.message {
|
|
97
|
+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
|
98
|
+
color: #495057;
|
|
99
|
+
font-weight: 400;
|
|
100
|
+
}
|
|
101
|
+
pre {
|
|
102
|
+
border-top: 1px solid black;
|
|
103
|
+
border-bottom: 1px solid black;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<pre data-headers>{{ JSON.stringify(metadata, null, ' ') }}</pre>
|
|
3
|
+
<div data-html class="message m-6">
|
|
4
|
+
<p class="text-lg">
|
|
5
|
+
Hello!
|
|
6
|
+
</p>
|
|
7
|
+
<p>
|
|
8
|
+
We are glad to see you have just signed up for DEMO with your email.
|
|
9
|
+
In order to confirm that, please enter secret code:
|
|
10
|
+
</p>
|
|
11
|
+
<p class="text-3xl font-medium">{{ code }}</p>
|
|
12
|
+
<p>
|
|
13
|
+
Or click the button below:
|
|
14
|
+
</p>
|
|
15
|
+
<div>
|
|
16
|
+
<a :href="linkAddress" class="no-underline">
|
|
17
|
+
<Button label="Confirm email" class="p-button-lg" />
|
|
18
|
+
</a>
|
|
19
|
+
</div>
|
|
20
|
+
<p>
|
|
21
|
+
Or copy this address to your browser address bar:<br>
|
|
22
|
+
<a :href="linkAddress">
|
|
23
|
+
{{ linkAddress }}
|
|
24
|
+
</a>
|
|
25
|
+
</p>
|
|
26
|
+
<p>
|
|
27
|
+
Let us know in case it's not you.
|
|
28
|
+
</p>
|
|
29
|
+
<p>
|
|
30
|
+
See you soon<br>
|
|
31
|
+
Live Change Team
|
|
32
|
+
</p>
|
|
33
|
+
<img src="/images/logo128.png">
|
|
34
|
+
</div>
|
|
35
|
+
<pre class="message" data-text>
|
|
36
|
+
Hello!
|
|
37
|
+
|
|
38
|
+
We are glad to see you have just signed up for DEMO with your email.
|
|
39
|
+
In order to confirm that, please enter secret code:
|
|
40
|
+
{{ code }}
|
|
41
|
+
|
|
42
|
+
Or please click link below or copy address to your browser address bar:
|
|
43
|
+
|
|
44
|
+
{{ linkAddress }}
|
|
45
|
+
|
|
46
|
+
Let us know in case it's not you.
|
|
47
|
+
|
|
48
|
+
See you soon
|
|
49
|
+
Live Change Team
|
|
50
|
+
</pre>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup>
|
|
54
|
+
import Button from "primevue/button"
|
|
55
|
+
|
|
56
|
+
const { action, contact, json } = defineProps({
|
|
57
|
+
action: {
|
|
58
|
+
type: String,
|
|
59
|
+
required: true
|
|
60
|
+
},
|
|
61
|
+
contact: {
|
|
62
|
+
type: String,
|
|
63
|
+
required: true
|
|
64
|
+
},
|
|
65
|
+
json: {
|
|
66
|
+
type: String,
|
|
67
|
+
required: true
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const data = JSON.parse(json)
|
|
72
|
+
const secrets = data.secrets
|
|
73
|
+
|
|
74
|
+
const secretLink = secrets.find(secret => secret.type == 'link')
|
|
75
|
+
|
|
76
|
+
const secretCode = secrets.find(secret => secret.type == 'code')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
const metadata = {
|
|
80
|
+
from: 'admin@flipchart.live',
|
|
81
|
+
subject: 'Confirm your email address.',
|
|
82
|
+
to: contact
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const linkAddress = ENV_BASE_HREF + '/link/' + secretLink.secret.secretCode
|
|
86
|
+
|
|
87
|
+
const code = secretCode.secret.secretCode
|
|
88
|
+
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<style scoped>
|
|
92
|
+
img {
|
|
93
|
+
width: 100%;
|
|
94
|
+
max-width: 100px;
|
|
95
|
+
}
|
|
96
|
+
.message {
|
|
97
|
+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
|
98
|
+
color: #495057;
|
|
99
|
+
font-weight: 400;
|
|
100
|
+
}
|
|
101
|
+
pre {
|
|
102
|
+
border-top: 1px solid black;
|
|
103
|
+
border-bottom: 1px solid black;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
export function routes(config = {}) {
|
|
3
|
+
const { prefix = '/', route = (r) => r } = config
|
|
4
|
+
|
|
5
|
+
return [
|
|
6
|
+
|
|
7
|
+
/// Message based authentication
|
|
8
|
+
route({ name: 'user:sent', path: prefix + 'sent/:authentication', props: true,
|
|
9
|
+
component: () => import("./MessageSent.vue") }),
|
|
10
|
+
route({ name: 'user:link', path: prefix + 'link/:secretCode', props: true,
|
|
11
|
+
component: () => import("./MessageLink.vue") }),
|
|
12
|
+
|
|
13
|
+
route({ name: 'user:email:signUpWithMessage', path: '/_email/signUpWithMessage/:contact/:json', props: true,
|
|
14
|
+
meta: { raw: true }, component: () => import("./SignUpEmail.vue") }),
|
|
15
|
+
route({ name: 'user:email:signInWithMessage', path: '/_email/signInWithMessage/:contact/:json', props: true,
|
|
16
|
+
meta: { raw: true }, component: () => import("./SignInEmail.vue") }),
|
|
17
|
+
route({ name: 'user:email:connectWithMessage', path: '/_email/connectWithMessage/:contact/:json', props: true,
|
|
18
|
+
meta: { raw: true }, component: () => import("./ConnectEmail.vue") }),
|
|
19
|
+
route({ name: 'user:email:startResetPasswordWithMessage', path: '/_email/startResetPasswordWithMessage/:contact/:json',
|
|
20
|
+
props: true, meta: { raw: true }, component: () => import("./ResetPasswordEmail.vue") }),
|
|
21
|
+
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default routes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="notification-buttons">
|
|
3
|
+
<Button v-if="notification.readState == 'new'" @click="markRead()"
|
|
4
|
+
icon="pi pi-eye" class="p-button-rounded p-button-outlined surface-0" />
|
|
5
|
+
<Button v-if="notification.readState == 'read'" @click="markUnread()"
|
|
6
|
+
icon="pi pi-eye-slash" class="p-button-rounded p-button-outlined surface-0" />
|
|
7
|
+
<Button @click="deleteNotification()"
|
|
8
|
+
icon="pi pi-trash" class="p-button-rounded p-button-outlined ml-1 surface-0" />
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import Button from "primevue/button"
|
|
14
|
+
import Menu from "primevue/menu"
|
|
15
|
+
|
|
16
|
+
import { useToast } from 'primevue/usetoast'
|
|
17
|
+
import { useConfirm } from 'primevue/useconfirm'
|
|
18
|
+
const confirm = useConfirm()
|
|
19
|
+
const toast = useToast()
|
|
20
|
+
|
|
21
|
+
import { actions } from "@live-change/vue3-ssr"
|
|
22
|
+
|
|
23
|
+
const { notification } = defineProps({
|
|
24
|
+
notification: {
|
|
25
|
+
type: Object,
|
|
26
|
+
required: true
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
import { inject } from "vue"
|
|
31
|
+
|
|
32
|
+
const workingZone = inject('workingZone')
|
|
33
|
+
|
|
34
|
+
const notificationApi = actions().notification
|
|
35
|
+
|
|
36
|
+
function markRead() {
|
|
37
|
+
workingZone.addPromise('markNotificationRead', (async () => {
|
|
38
|
+
await notificationApi.markRead({ notification: notification.to || notification.id })
|
|
39
|
+
toast.add({
|
|
40
|
+
severity: 'success', summary: 'Notification read',
|
|
41
|
+
detail:'Notification has been marked as read', life: 3000
|
|
42
|
+
})
|
|
43
|
+
})())
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function markUnread() {
|
|
47
|
+
workingZone.addPromise('markNotificationUnread', (async () => {
|
|
48
|
+
await notificationApi.markUnread({ notification: notification.to || notification.id })
|
|
49
|
+
toast.add({
|
|
50
|
+
severity: 'success', summary: 'Notification unread',
|
|
51
|
+
detail:'Notification has been marked as unread', life: 3000
|
|
52
|
+
})
|
|
53
|
+
})())
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function deleteNotification() {
|
|
57
|
+
workingZone.addPromise('deleteNotification', (async () => {
|
|
58
|
+
await notificationApi.delete({ notification: notification.to || notification.id })
|
|
59
|
+
toast.add({
|
|
60
|
+
severity: 'warn', summary: 'Notification deleted',
|
|
61
|
+
detail: 'Notification has been deleted', life: 3000
|
|
62
|
+
})
|
|
63
|
+
})())
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<style scoped>
|
|
69
|
+
|
|
70
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-6 md:w-9">
|
|
3
|
+
<div v-if="isMounted" class="surface-card border-round shadow-2 p-4">
|
|
4
|
+
<NotificationsList />
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
|
|
11
|
+
import NotificationsList from "./NotificationsList.vue"
|
|
12
|
+
|
|
13
|
+
import { ref, onMounted } from "vue"
|
|
14
|
+
|
|
15
|
+
const isMounted = ref(false)
|
|
16
|
+
onMounted(() => isMounted.value = true)
|
|
17
|
+
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<style scoped>
|
|
21
|
+
|
|
22
|
+
</style>
|