Files
speckle-server/packages/frontend-2/components/auth/RegisterWithEmailBlock.vue
T
Kristaps Fabians Geikins 83d8035dc2 chore: upgrade to eslint 9 (#2348)
* root + server

* frontend

* frontend-2

* dui3

* dui3

* tailwind theme

* ui-components

* preview service

* viewer

* viewer-sandbox

* fileimport-service

* webhook service

* objectloader

* shared

* ui-components-nuxt

* WIP full config

* WIP full linter

* eslint projectwide util

* minor fix

* removing redundant ci

* clean up test errors

* fixed prettier formatting

* CI improvements

* TSC lint fix

* 'buildBatch' needs to be async since some batch types (like Text) require it. Removed a disabled liniting rule from ObjLoader

* removed unnecessary void

---------

Co-authored-by: AlexandruPopovici <alexandrupopoviciioan@gmail.com>
2024-06-12 14:38:02 +03:00

167 lines
4.8 KiB
Vue

<!-- eslint-disable vue/no-v-html -->
<template>
<form method="post" @submit="onSubmit">
<div class="flex flex-col space-y-2">
<FormTextInput
type="text"
name="name"
label="Full Name"
placeholder="My Name"
:size="isSmallerOrEqualSm ? 'lg' : 'xl'"
:rules="nameRules"
:custom-icon="UserIcon"
show-label
:disabled="loading"
auto-focus
/>
<FormTextInput
v-model="email"
type="email"
name="email"
label="Email"
placeholder="example@email.com"
:size="isSmallerOrEqualSm ? 'lg' : 'xl'"
:rules="emailRules"
show-label
:disabled="isEmailDisabled"
/>
<FormTextInput
v-model="password"
type="password"
name="password"
label="Password"
placeholder="Type a strong password"
:size="isSmallerOrEqualSm ? 'lg' : 'xl'"
:rules="passwordRules"
show-label
:disabled="loading"
@focus="pwdFocused = true"
@blur="pwdFocused = false"
/>
</div>
<AuthPasswordChecks
:password="password"
:class="`mt-2 overflow-hidden ${
pwdFocused ? 'h-12 sm:h-8' : 'h-0'
} transition-[height]`"
/>
<div
class="mt-3 text-xs flex items-center justify-center text-foreground-2 space-x-2"
>
<!--
Note the newsletter consent box is here because i got very confused re layout of the panel
and didn't figure out a better way to put it where i needed it to be
-->
<FormCheckbox
v-model="newsletterConsent"
name="newsletter"
label="Opt in for exclusive Speckle news and tips"
/>
</div>
<FormButton submit full-width class="mt-4" :disabled="loading">Sign up</FormButton>
<div
v-if="serverInfo.termsOfService"
class="mt-2 text-xs text-foreground-2 text-center terms-of-service"
v-html="serverInfo.termsOfService"
/>
<div class="mt-2 sm:mt-8 text-center text-xs sm:text-base">
<span class="mr-2">Already have an account?</span>
<CommonTextLink :to="finalLoginRoute" :icon-right="ArrowRightIcon">
Log in
</CommonTextLink>
</div>
</form>
</template>
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { isEmail, isRequired } from '~~/lib/common/helpers/validation'
import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables/toast'
import { ensureError } from '@speckle/shared'
import { useAuthManager } from '~~/lib/auth/composables/auth'
import { loginRoute } from '~~/lib/common/helpers/route'
import { passwordRules } from '~~/lib/auth/helpers/validation'
import { graphql } from '~~/lib/common/generated/gql'
import type { ServerTermsOfServicePrivacyPolicyFragmentFragment } from '~~/lib/common/generated/gql/graphql'
import { UserIcon, ArrowRightIcon } from '@heroicons/vue/20/solid'
import { useIsSmallerOrEqualThanBreakpoint } from '~~/composables/browser'
/**
* TODO:
* - (BE) Password strength check? Do we want to use it anymore?
* - Dim's answer: no, `passwordRules` are legit enough for now.
*/
graphql(`
fragment ServerTermsOfServicePrivacyPolicyFragment on ServerInfo {
termsOfService
}
`)
type FormValues = { email: string; password: string; name: string; company?: string }
const props = defineProps<{
challenge: string
serverInfo: ServerTermsOfServicePrivacyPolicyFragmentFragment
inviteEmail?: string
}>()
const { handleSubmit } = useForm<FormValues>()
const router = useRouter()
const { signUpWithEmail, inviteToken } = useAuthManager()
const { triggerNotification } = useGlobalToast()
const loading = ref(false)
const password = ref('')
const email = ref('')
const emailRules = [isEmail]
const nameRules = [isRequired]
const newsletterConsent = inject<Ref<boolean>>('newsletterconsent')
const pwdFocused = ref(false)
const { isSmallerOrEqualSm } = useIsSmallerOrEqualThanBreakpoint()
const isEmailDisabled = computed(() => !!props.inviteEmail?.length || loading.value)
const finalLoginRoute = computed(() => {
const result = router.resolve({
path: loginRoute,
query: inviteToken.value ? { token: inviteToken.value } : {}
})
return result.fullPath
})
const onSubmit = handleSubmit(async (fullUser) => {
try {
loading.value = true
const user = fullUser
await signUpWithEmail({
user,
challenge: props.challenge,
inviteToken: inviteToken.value,
newsletter: newsletterConsent?.value
})
} catch (e) {
triggerNotification({
type: ToastNotificationType.Danger,
title: 'Registration failed',
description: `${ensureError(e).message}`
})
} finally {
loading.value = false
}
})
watch(
() => props.inviteEmail,
(inviteEmail) => {
if (inviteEmail) {
email.value = inviteEmail
}
},
{ immediate: true }
)
</script>