aboutsummaryrefslogtreecommitdiff
path: root/front-end/src/components/Settings/Registation.vue
blob: a0f208e44bf39ccf221f913b3da52bf21d6a08b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
120
121
122
123
124
125
126
127
128
129
130
<script setup lang="ts">
import { computed, defineAsyncComponent, ref, shallowReactive, shallowRef } from 'vue';
import { useStore } from '../../store';
import { get, set, useClipboard, useTimeAgo, useToggle } from '@vueuse/core';
import { apiCall, useVuelidateWrapper } from '@vnuge/vnlib.browser';
import { defaultTo } from 'lodash-es';
import { useVuelidate } from '@vuelidate/core'
import { required, maxLength, minLength, helpers, email } from '@vuelidate/validators'
const Dialog = defineAsyncComponent(() => import('../global/Dialog.vue'));

const store = useStore();
const { copy, copied } = useClipboard()

const [isOpen, toggleOpen] = useToggle(false)
const vState = shallowReactive({ email: '' })

const canInvite = ref<boolean>(false)
const inviteLink = shallowRef<string | undefined>()

const expirationDate = computed(() => Date.now() + (1000 * defaultTo(store.registation.status?.link_expiration, 0)))
const fromNowTime = useTimeAgo(expirationDate)

const rules = computed(() => {
    return {
        email: { 
            required: helpers.withMessage('Email is required', required), 
            maxLength: helpers.withMessage('Email must be less than 255 characters', maxLength(255)),
            minLength: helpers.withMessage('Email must be at least 3 characters', minLength(3)),
            email: helpers.withMessage('Email must be a valid email', email)
        },
    }
})

const v$ = useVuelidate(rules, vState)
const { validate } = useVuelidateWrapper(v$ as any)

const onSubmit = async () => {
    if (!await validate()) return

    apiCall(async () => {
        //Rest password and pass totp code
        const { link } = await store.registation.api.createSignupLink(vState.email, get(canInvite))
        set(inviteLink, link)
    })
}

const onCancel = () => {
    vState.email = ''
    v$.value.$reset()
    set(canInvite, false)
    set(inviteLink, undefined)
    toggleOpen(false)
}

</script>

<template>
    <div class="">

        <div class="flex flex-row justify-between w-full">
            <h3 class="text-xl font-bold">Registation</h3>

            <div class="flex flex-row justify-end">
                <button class="btn blue" @click="toggleOpen(true)">Invite User</button>
            </div>
        </div>
        <p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
            Create a one-time invite link you can send to add a new user to your server.
        </p>
        <p class="text-sm text-gray-500 dark:text-gray-400">
            Links expire <span class="text-blue-500">{{ fromNowTime }}</span>
        </p>
        <Dialog :open="isOpen" title="Invite User" @cancel="onCancel">
            <template #body>
                <div class="p-4">

                    <div v-if="inviteLink" class="">
                         <p class="my-2 text-lg font-medium text-center text-gray-900 dark:text-white">
                            Link expires {{ fromNowTime }}
                        </p>

                        <label for="invite-link" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
                            Invite link
                        </label>
                        <input 
                            :value="inviteLink" 
                            type="url" 
                            id="invite-link" 
                            class="input"
                            readonly
                        >

                        <div class="mt-4 ml-auto w-fit">
                            <button @click="copy(inviteLink)" type="submit" :disabled="copied" class="btn blue">
                                {{ copied ? 'Copied!' : 'Copy' }}
                            </button>
                        </div>

                    </div>

                    <form v-else @submit.prevent="onSubmit">

                        <fieldset class="mb-4">
                            <label for="user-email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Email address</label>
                            <input v-model="v$.email.$model" type="email" id="user-email" class="input"
                                :class="{ 'error': v$.email.$error, 'dirty': v$.email.$dirty }" 
                                placeholder="user@simplebookmark.com"
                                required
                            >
                        </fieldset>

                        <fieldset class="px-2">
                            <h4 class="font-bold text-gray-700 dark:text-white">Permissions</h4>
                            <div class="flex items-center mt-2 mb-4">
                                <input id="can-invite-input" type="checkbox" v-model="canInvite" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
                                <label for="can-invite-input" class="text-sm font-medium text-gray-900 ms-2 dark:text-gray-300">Can invite users</label>
                            </div>
                        </fieldset>

                        <div class="ml-auto w-fit">
                            <button type="submit" class="btn blue">
                                Create Link
                            </button>
                        </div>
                    </form>
                </div>
            </template>
        </Dialog>
    </div>
</template>