164 lines
4.2 KiB
Vue
164 lines
4.2 KiB
Vue
<script setup lang="ts">
|
|
import { getRandomName } from '#shared/utils/name';
|
|
import { useForm } from 'vuestic-ui';
|
|
|
|
definePageMeta({
|
|
middleware: ['guest']
|
|
});
|
|
const { fetch } = useUserSession();
|
|
const router = useRouter();
|
|
const localePath = useLocalePath();
|
|
const { isValid, resetValidation, validate } = useForm('formRef');
|
|
const validation = useValidation();
|
|
|
|
const form = reactive({
|
|
name: getRandomName(),
|
|
email: '',
|
|
password: ''
|
|
});
|
|
|
|
const error = ref('');
|
|
|
|
async function submit() {
|
|
if (!validate()) {
|
|
return;
|
|
}
|
|
error.value = '';
|
|
try {
|
|
await $fetch('/api/auth/register', {
|
|
method: 'POST',
|
|
body: form
|
|
});
|
|
await fetch();
|
|
await router.push(localePath('/'));
|
|
return;
|
|
} catch (e) {
|
|
if (e instanceof Error && 'statusCode' in e && e.statusCode === 409) {
|
|
error.value = 'auth.conflict';
|
|
} else {
|
|
error.value = parseError(e);
|
|
}
|
|
}
|
|
form.password = '';
|
|
resetValidation();
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<h1 class="mb-4 text-center text-3xl">{{ $t('auth.login') }}</h1>
|
|
<div class="grid grid-cols-1 sm:grid-cols-3 lg:grid-cols-5">
|
|
<VaForm
|
|
ref="formRef"
|
|
tag="form"
|
|
class="flex flex-col items-baseline gap-6 sm:col-start-2 lg:col-start-3"
|
|
@submit.prevent="submit"
|
|
>
|
|
<VaInput
|
|
v-model="form.name"
|
|
class="w-full"
|
|
type="text"
|
|
autocomplete="name"
|
|
clearable
|
|
clear-value=""
|
|
:label="$t('auth.name')"
|
|
:placeholder="$t('auth.name')"
|
|
max-length="64"
|
|
min-length="5"
|
|
:rules="[
|
|
validation.required($t('auth.name')),
|
|
validation.max($t('auth.name'), 64),
|
|
validation.min($t('auth.name'), 5)
|
|
]"
|
|
required
|
|
>
|
|
<template #prependInner>
|
|
<VaIcon name="person" color="secondary" />
|
|
</template>
|
|
<template #appendInner>
|
|
<VaButton
|
|
icon="refresh"
|
|
preset="plain"
|
|
@click="form.name = getRandomName()"
|
|
/>
|
|
</template>
|
|
</VaInput>
|
|
<VaInput
|
|
v-model="form.email"
|
|
class="w-full"
|
|
type="email"
|
|
:label="$t('auth.email')"
|
|
autocomplete="email"
|
|
:rules="[validation.required($t('auth.email'))]"
|
|
:placeholder="$t('auth.email')"
|
|
required
|
|
>
|
|
<template #prependInner>
|
|
<VaIcon name="mail_outline" color="secondary" />
|
|
</template>
|
|
</VaInput>
|
|
<VaValue v-slot="isPasswordVisible" :default-value="false">
|
|
<VaInput
|
|
v-model="form.password"
|
|
class="w-full"
|
|
:type="isPasswordVisible.value ? 'text' : 'password'"
|
|
:label="$t('auth.password')"
|
|
:placeholder="$t('auth.password')"
|
|
:rules="[
|
|
validation.required($t('auth.password')),
|
|
validation.min($t('auth.password'), 8)
|
|
]"
|
|
autocomplete="current-password"
|
|
:minlength="8"
|
|
required
|
|
>
|
|
<template #prependInner>
|
|
<VaIcon name="key" color="secondary" />
|
|
</template>
|
|
|
|
<template #appendInner>
|
|
<VaButton
|
|
v-if="form.password"
|
|
preset="plain"
|
|
:title="
|
|
$t(
|
|
isPasswordVisible.value
|
|
? 'auth.hidePassword'
|
|
: 'auth.showPassword'
|
|
)
|
|
"
|
|
@click="isPasswordVisible.value = !isPasswordVisible.value"
|
|
>
|
|
<VaIcon
|
|
:name="
|
|
isPasswordVisible.value ? 'visibility_off' : 'visibility'
|
|
"
|
|
color="primary"
|
|
/>
|
|
</VaButton>
|
|
</template>
|
|
</VaInput>
|
|
</VaValue>
|
|
<VaAlert
|
|
v-if="error.length > 0"
|
|
color="danger"
|
|
class="w-full text-center"
|
|
>{{ $t(error) }}</VaAlert
|
|
>
|
|
|
|
<VaButtonGroup>
|
|
<VaButton color="success" type="submit" :disabled="!isValid">{{
|
|
$t('auth.register')
|
|
}}</VaButton>
|
|
<VaButton
|
|
:to="$localePath('/login')"
|
|
border-color="primary"
|
|
preset="secondary"
|
|
>{{ $t('auth.login_instead') }}</VaButton
|
|
>
|
|
</VaButtonGroup>
|
|
</VaForm>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped></style>
|