Files
speckle-server/packages/frontend-2/components/auth/LoginWithEmailBlock.vue
T
andrewwallacespeckle 91cb011ded feat(fe2): New user onboarding flow (#3932)
* CodeInput. verify-email page

* middleware

* Loading toast

* Countdown only for registration

* Improve middleware

* Fix middleware breaking auth flow

* Remove old notifications

* Remove old onboarding. New segmentation

* Remove skip button

* Block verify email when verified

* useUserEmails composable. Cancel addition

* Move user emails queries

* Fix fragments etc

* redirect updates

* HeaderWithEmptyPage

* Check env before enforcing

* Join workspace

* Updates

* Fix console warnings on login

* Fix register console warnings

* Working cache updates

* Verify secondary email

* Force onboarding off

* EMAIL WIP

* useIsJustRegistered state

* Improve isRequired

* Uneeded change

* Improved slots

* Updates from CR

* CR comments

* Only show message if forced

* Update onboarding middleware

* Update loading bar

* ref > computed to fix onboarding

* Resend tooltip. Better errors

* Add other to form.

* Email changes

* Updates to emails

* Remove force email FF

* Remove FF's

* Hide header on embed

* Update graphql.ts

* Re-add FF

* Update graphql.ts

* GQL Fragments

* Fix build
2025-02-14 10:20:14 +00:00

116 lines
3.1 KiB
Vue

<template>
<form method="post" @submit="onSubmit">
<div class="flex flex-col space-y-2">
<FormTextInput
type="email"
name="email"
label="E-mail"
placeholder="Enter your email"
size="lg"
color="foundation"
:rules="emailRules"
show-label
:disabled="!!(loading || shouldForceInviteEmail)"
auto-focus
autocomplete="email"
/>
<FormTextInput
type="password"
name="password"
label="Password"
placeholder="Enter your password"
color="foundation"
size="lg"
:rules="passwordRules"
show-label
:disabled="loading"
autocomplete="current-password"
/>
</div>
<FormButton
size="lg"
submit
full-width
class="mt-8 mb-4"
:disabled="loading || !isMounted"
>
Log in
</FormButton>
<div class="mt-1 text-center text-body-xs text-foreground-3 select-none">
Forgot your password?
<NuxtLink :to="forgottenPasswordRoute" class="text-foreground">
Reset password
</NuxtLink>
</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 { forgottenPasswordRoute } from '~~/lib/common/helpers/route'
import { useMounted } from '@vueuse/core'
import { graphql } from '~/lib/common/generated/gql'
import type { AuthLoginWithEmailBlock_PendingWorkspaceCollaboratorFragment } from '~/lib/common/generated/gql/graphql'
type FormValues = { email: string; password: string }
graphql(`
fragment AuthLoginWithEmailBlock_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {
id
email
user {
id
}
}
`)
const props = defineProps<{
challenge: string
workspaceInvite?: AuthLoginWithEmailBlock_PendingWorkspaceCollaboratorFragment
}>()
const { handleSubmit, setValues } = useForm<FormValues>()
const loading = ref(false)
const emailRules = [isEmail]
const passwordRules = [isRequired]
const isMounted = useMounted()
const { loginWithEmail } = useAuthManager()
const { triggerNotification } = useGlobalToast()
const inviteEmail = computed(() => props.workspaceInvite?.email)
const isInviteForExistingUser = computed(() => !!props.workspaceInvite?.user)
const shouldForceInviteEmail = computed(
() => !!(inviteEmail.value && isInviteForExistingUser.value)
)
const onSubmit = handleSubmit(async ({ email, password }) => {
try {
loading.value = true
await loginWithEmail({ email, password, challenge: props.challenge })
} catch (e) {
triggerNotification({
type: ToastNotificationType.Danger,
title: 'Login failed',
description: `${ensureError(e).message}`
})
} finally {
loading.value = false
}
})
watch(
shouldForceInviteEmail,
(shouldForce) => {
if (shouldForce) {
setValues({ email: inviteEmail.value || '' })
}
},
{ immediate: true }
)
</script>