156 lines
4.4 KiB
Vue
156 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import type { AuthFormField, FormSubmitEvent } from '@nuxt/ui'
|
|
import { useForm } from '@inertiajs/vue3'
|
|
import * as v from 'valibot'
|
|
import { computed } from 'vue'
|
|
import { useAuth } from '@/composables/useAuth'
|
|
import AuthLayout from '@/layouts/AuthLayout.vue'
|
|
|
|
const { config } = useAuth()
|
|
|
|
const form = useForm('RegisterForm', {
|
|
username: '',
|
|
first_name: '',
|
|
last_name: '',
|
|
email: '',
|
|
password: '',
|
|
password_confirmation: '',
|
|
})
|
|
|
|
const fields: AuthFormField[] = [
|
|
{
|
|
name: 'username',
|
|
type: 'text',
|
|
label: 'Username',
|
|
placeholder: 'Choose a username',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'first_name',
|
|
type: 'text',
|
|
label: 'First name',
|
|
placeholder: 'Enter your first name',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'last_name',
|
|
type: 'text',
|
|
label: 'Last name',
|
|
placeholder: 'Enter your last name',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'email',
|
|
type: 'email',
|
|
label: 'Email',
|
|
placeholder: 'Enter your email',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'password',
|
|
type: 'password',
|
|
label: 'Password',
|
|
placeholder: 'Create a password',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'password_confirmation',
|
|
type: 'password',
|
|
label: 'Confirm password',
|
|
placeholder: 'Confirm your password',
|
|
required: true,
|
|
},
|
|
]
|
|
|
|
const providers = computed(() =>
|
|
config.value.providers.map(provider => ({
|
|
label: provider.label,
|
|
icon: provider.icon,
|
|
to: `/auth/${provider.key}`,
|
|
})),
|
|
)
|
|
|
|
const schema = v.pipe(
|
|
v.object({
|
|
username: v.pipe(
|
|
v.string('Username is required'),
|
|
v.nonEmpty('Username is required'),
|
|
v.minLength(3, 'Username must be at least 3 characters'),
|
|
v.regex(/^[\w-]+$/, 'Username can only contain letters, numbers, dashes and underscores'),
|
|
),
|
|
first_name: v.pipe(v.string('First name is required'), v.nonEmpty('First name is required')),
|
|
last_name: v.pipe(v.string('Last name is required'), v.nonEmpty('Last name is required')),
|
|
email: v.pipe(v.string('Email is required'), v.nonEmpty('Email is required'), v.email('Please enter a valid email')),
|
|
password: v.pipe(v.string('Password is required'), v.nonEmpty('Password is required'), v.minLength(8, 'Password must be at least 8 characters')),
|
|
password_confirmation: v.pipe(v.string('Please confirm your password'), v.nonEmpty('Please confirm your password')),
|
|
}),
|
|
v.forward(
|
|
v.partialCheck(
|
|
[['password'], ['password_confirmation']],
|
|
input => input.password === input.password_confirmation,
|
|
'Passwords do not match',
|
|
),
|
|
['password_confirmation'],
|
|
),
|
|
)
|
|
|
|
type Schema = v.InferOutput<typeof schema>
|
|
|
|
function onSubmit(event: FormSubmitEvent<Schema>) {
|
|
form.username = event.data.username
|
|
form.first_name = event.data.first_name
|
|
form.last_name = event.data.last_name
|
|
form.email = event.data.email
|
|
form.password = event.data.password
|
|
form.password_confirmation = event.data.password_confirmation
|
|
|
|
form.post('/register')
|
|
}
|
|
|
|
const hasErrors = computed(() => Object.keys(form.errors).length > 0)
|
|
const firstError = computed(() => Object.values(form.errors)[0])
|
|
</script>
|
|
|
|
<template>
|
|
<AuthLayout>
|
|
<UAuthForm
|
|
:schema="schema"
|
|
:fields="fields"
|
|
:providers="providers"
|
|
:submit="{ label: config.register.submit_label, loading: form.processing }"
|
|
:disabled="form.processing"
|
|
:ui="{ header: 'hidden' }"
|
|
@submit="onSubmit"
|
|
>
|
|
<template v-if="hasErrors" #validation>
|
|
<UAlert
|
|
color="error"
|
|
icon="i-lucide-alert-circle"
|
|
:title="firstError"
|
|
/>
|
|
</template>
|
|
|
|
<template #footer>
|
|
<div v-if="config.legal.show_in_register && (config.legal.terms_url || config.legal.privacy_url)" class="mb-2">
|
|
By creating an account, you agree to our
|
|
<ULink v-if="config.legal.terms_url" :to="config.legal.terms_url" class="text-primary font-medium">
|
|
Terms of Service
|
|
</ULink>
|
|
<template v-if="config.legal.terms_url && config.legal.privacy_url">
|
|
and
|
|
</template>
|
|
<ULink v-if="config.legal.privacy_url" :to="config.legal.privacy_url" class="text-primary font-medium">
|
|
Privacy Policy
|
|
</ULink>.
|
|
</div>
|
|
<span class="text-muted">
|
|
Already have an account?
|
|
<ULink to="/login" class="text-primary font-medium">
|
|
Sign in
|
|
</ULink>
|
|
</span>
|
|
</template>
|
|
</UAuthForm>
|
|
</AuthLayout>
|
|
</template>
|