Skip to content

Instantly share code, notes, and snippets.

@razbakov
Created June 4, 2024 19:51
Show Gist options
  • Save razbakov/949ff865fd99cb341a17f1ccdfb40148 to your computer and use it in GitHub Desktop.
Save razbakov/949ff865fd99cb341a17f1ccdfb40148 to your computer and use it in GitHub Desktop.
shadcn-vue: AutoForm: registration
<script setup lang="ts">
defineProps({
register: Boolean,
});
import { useForm } from "vee-validate";
import { toTypedSchema } from "@vee-validate/zod";
import * as z from "zod";
import { toast } from "vue-sonner";
const { $client } = useNuxtApp();
const { login } = useAppAuth();
const noMultiplePeriods = (value: string) => !value.includes("..");
const notEndingInPeriod = (value: string) => !value.endsWith(".");
const usernameValidator = async (username: string) => {
const { data } = await $client.profiles.get.useQuery({ username });
if (data.value?.id) {
return false;
}
return true;
};
const schema = z.object({
username: z
.string()
.min(2, "Username must be at least 2 characters.")
.max(30)
.refine(
noMultiplePeriods,
"Username cannot have multiple periods in a row."
)
.refine(notEndingInPeriod, "Username cannot end in a period.")
.refine(usernameValidator, "Username is already taken."),
city: z.string(),
email: z.string().email().default("me@example.com"),
password: z.string().min(8),
acceptTerms: z.boolean().refine((value) => value, {
message: "You must accept the terms and conditions.",
}),
});
const form = useForm({
validationSchema: toTypedSchema(schema),
});
const onSubmit = form.handleSubmit(async (values) => {
const error = await login("register", values);
if (error) {
toast.error(error);
}
});
</script>
<template>
<AutoForm
class="space-y-4"
:form="form"
:schema="schema"
:field-config="{
username: {
inputProps: {
trim: '[^a-z0-9._\-]+',
lowercase: true,
},
},
email: { inputProps: { type: 'email' } },
password: { inputProps: { type: 'password' } },
acceptTerms: {
label: 'Accept terms and conditions.',
inputProps: {
required: true,
},
},
}"
@submit="onSubmit"
>
<template #city>
<FormField v-slot="slotProps" name="city">
<FormItem>
<FormLabel>Your city *</FormLabel>
<FormControl>
<CityInput v-bind="slotProps" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</template>
<template #acceptTerms="slotProps">
<AutoFormField v-bind="slotProps" />
<TermsInfo />
</template>
<div class="flex justify-end">
<Button type="submit"> Register </Button>
</div>
</AutoForm>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment