chore: update ProfileForm.vue and AccountForm
fix vee-validate initialValues on components with `componentField` slotProp
This commit is contained in:
parent
72ef22de60
commit
6be33b10fd
|
|
@ -83,32 +83,29 @@ async function handleSubmit(values: any) {
|
||||||
<Form
|
<Form
|
||||||
v-slot="{
|
v-slot="{
|
||||||
setValues,
|
setValues,
|
||||||
}" :validation-schema="accountFormSchema" class="space-y-8"
|
}" :validation-schema="accountFormSchema" class="space-y-8" @submit="handleSubmit"
|
||||||
@submit="handleSubmit"
|
|
||||||
>
|
>
|
||||||
<FormField v-slot="{ field }" name="name">
|
<FormField v-slot="{ componentField }" name="name">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Name</FormLabel>
|
<FormLabel>Name</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input type="text" placeholder="Your name" v-bind="field" />
|
<Input type="text" placeholder="Your name" v-bind="componentField" />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
This is your public display name. It can be your real name or a
|
This is the name that will be displayed on your profile and in emails.
|
||||||
pseudonym. You can only change this once every 30 days.
|
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<FormField v-slot="{ field, value }" name="dob">
|
<FormField v-slot="{ componentField, value }" name="dob">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Date of birth</FormLabel>
|
<FormLabel>Date of birth</FormLabel>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline" :class="cn(
|
||||||
:class="cn(
|
|
||||||
'w-[280px] pl-3 text-left font-normal',
|
'w-[280px] pl-3 text-left font-normal',
|
||||||
!value && 'text-muted-foreground',
|
!value && 'text-muted-foreground',
|
||||||
)"
|
)"
|
||||||
|
|
@ -119,7 +116,7 @@ async function handleSubmit(values: any) {
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent class="p-0">
|
<PopoverContent class="p-0">
|
||||||
<Calendar v-bind="field" />
|
<Calendar v-bind="componentField" />
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
|
|
@ -137,10 +134,7 @@ async function handleSubmit(values: any) {
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline" role="combobox" :aria-expanded="open" :class="cn(
|
||||||
role="combobox"
|
|
||||||
:aria-expanded="open"
|
|
||||||
:class="cn(
|
|
||||||
'w-[200px] justify-between',
|
'w-[200px] justify-between',
|
||||||
!value && 'text-muted-foreground',
|
!value && 'text-muted-foreground',
|
||||||
)"
|
)"
|
||||||
|
|
@ -159,10 +153,7 @@ async function handleSubmit(values: any) {
|
||||||
<CommandEmpty>No framework found.</CommandEmpty>
|
<CommandEmpty>No framework found.</CommandEmpty>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
<CommandItem
|
<CommandItem
|
||||||
v-for="language in languages"
|
v-for="language in languages" :key="language.value" :value="language.value" @select="(val) => {
|
||||||
:key="language.value"
|
|
||||||
:value="language.value"
|
|
||||||
@select="(val) => {
|
|
||||||
setValues({ language: val })
|
setValues({ language: val })
|
||||||
open = false
|
open = false
|
||||||
}"
|
}"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import { FieldArray, useForm } from 'vee-validate'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/default/ui/form'
|
||||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||||
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
||||||
import {
|
import {
|
||||||
|
|
@ -19,17 +21,7 @@ import { Button } from '@/lib/registry/new-york/ui/button'
|
||||||
|
|
||||||
const verifiedEmails = ref(['m@example.com', 'm@google.com', 'm@support.com'])
|
const verifiedEmails = ref(['m@example.com', 'm@google.com', 'm@support.com'])
|
||||||
|
|
||||||
const profileForm = ref({
|
const profileFormSchema = toTypedSchema(z.object({
|
||||||
username: '',
|
|
||||||
email: '',
|
|
||||||
bio: 'I own a computer.',
|
|
||||||
urls: [
|
|
||||||
{ value: 'https://shadcn.com' },
|
|
||||||
{ value: 'http://twitter.com/shadcn' },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
const profileFormSchema = z.object({
|
|
||||||
username: z
|
username: z
|
||||||
.string()
|
.string()
|
||||||
.min(2, {
|
.min(2, {
|
||||||
|
|
@ -51,20 +43,22 @@ const profileFormSchema = z.object({
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { handleSubmit, resetForm } = useForm({
|
||||||
|
validationSchema: profileFormSchema,
|
||||||
|
initialValues: {
|
||||||
|
bio: 'I own a computer.',
|
||||||
|
urls: [
|
||||||
|
{ value: 'https://shadcn.com' },
|
||||||
|
{ value: 'http://twitter.com/shadcn' },
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
type ProfileFormValues = z.infer<typeof profileFormSchema>
|
const onSubmit = handleSubmit((values, { resetForm }) => {
|
||||||
const errors = ref<z.ZodFormattedError<ProfileFormValues> | null>(null)
|
console.log(values)
|
||||||
|
})
|
||||||
async function handleSubmit() {
|
|
||||||
const result = profileFormSchema.safeParse(profileForm.value)
|
|
||||||
if (!result.success) {
|
|
||||||
errors.value = result.error.format()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
errors.value = null
|
|
||||||
console.log('Form submitted!')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -77,75 +71,103 @@ async function handleSubmit() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<form class="space-y-8" @submit.prevent="handleSubmit">
|
<form class="space-y-8" @submit="onSubmit">
|
||||||
<div class="grid gap-2">
|
<FormField v-slot="{ field }" name="username">
|
||||||
<Label for="username" :class="cn('text-sm', errors?.username && 'text-destructive')">
|
<FormItem>
|
||||||
Username
|
<FormLabel>Username</FormLabel>
|
||||||
</Label>
|
<FormControl>
|
||||||
<Input id="username" v-model="profileForm.username" placeholder="shadcn" />
|
<Input type="text" placeholder="shadcn" v-bind="field" />
|
||||||
<span class="text-muted-foreground text-sm">
|
</FormControl>
|
||||||
This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.
|
<FormDescription>
|
||||||
</span>
|
This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.
|
||||||
<div v-if="errors?.username" class="text-sm text-destructive">
|
</FormDescription>
|
||||||
<span v-for="error in errors.username._errors" :key="error">{{ error }}</span>
|
<FormMessage />
|
||||||
</div>
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<FormField v-slot="{ componentField }" name="email">
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Email</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Select v-bind="componentField">
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select an email" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem v-for="email in verifiedEmails" :key="email" :value="email">
|
||||||
|
{{ email }}
|
||||||
|
</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
You can manage verified email addresses in your email settings.
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<FormField v-slot="{ componentField }" name="bio">
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Bio</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Textarea placeholder="Tell us a little bit about yourself" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
You can <span>@mention</span> other users and organizations to link to them.
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<FieldArray v-slot="{ fields, push }" name="urls">
|
||||||
|
<div v-for="(fieldq, index) in fields" :key="`urls-${fieldq.key}`">
|
||||||
|
<!-- <button type="button" @click="remove(index)">
|
||||||
|
Remove
|
||||||
|
</button> -->
|
||||||
|
|
||||||
|
<FormField v-slot="{ componentField }" :name="`urls[${index}].value`">
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel :class="cn(index !== 0 && 'sr-only')">
|
||||||
|
URLs
|
||||||
|
</FormLabel>
|
||||||
|
<FormDescription :class="cn(index !== 0 && 'sr-only')">
|
||||||
|
Add links to your website, blog, or social media profiles.
|
||||||
|
</FormDescription>
|
||||||
|
<FormControl>
|
||||||
|
<Input type="url" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
class="text-xs w-20 mt-2"
|
||||||
|
@click="push({ value: '' })"
|
||||||
|
>
|
||||||
|
Add URL
|
||||||
|
</Button>
|
||||||
|
</FieldArray>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-2">
|
|
||||||
<Label for="email" :class="cn('text-sm', errors?.email && 'text-destructive')">
|
<div class="flex gap-2 justify-start">
|
||||||
Email
|
<Button type="submit">
|
||||||
</Label>
|
Update profile
|
||||||
<Select id="email" v-model="profileForm.email">
|
</Button>
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Select an email" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectItem v-for="email in verifiedEmails" :key="email" :value="email">
|
|
||||||
{{ email }}
|
|
||||||
</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<span class="text-muted-foreground text-sm">
|
|
||||||
You can manage verified email addresses in your email settings.
|
|
||||||
</span>
|
|
||||||
<div v-if="errors?.email" class="text-sm text-destructive">
|
|
||||||
<span v-for="error in errors.email._errors" :key="error">{{ error }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-2">
|
|
||||||
<Label for="bio" :class="cn('text-sm', errors?.bio && 'text-destructive')">
|
|
||||||
Bio
|
|
||||||
</Label>
|
|
||||||
<Textarea id="bio" v-model="profileForm.bio" placeholder="Tell us about yourself." />
|
|
||||||
<span class="text-muted-foreground text-sm">
|
|
||||||
You can @mention other users and organizations to link to them.
|
|
||||||
</span>
|
|
||||||
<div v-if="errors?.bio" class="text-sm text-destructive">
|
|
||||||
<span v-for="error in errors.bio._errors" :key="error">{{ error }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-2">
|
|
||||||
<Label for="urls" :class="cn('text-sm', errors?.urls && 'text-destructive')">
|
|
||||||
URLs
|
|
||||||
</Label>
|
|
||||||
<Input v-for="(url, index) in profileForm.urls" id="urls" :key="index" v-model="url.value" />
|
|
||||||
<div v-if="errors?.urls" class="text-sm text-destructive">
|
|
||||||
<span v-for="error in errors.urls._errors" :key="error">{{ error }}</span>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
@click="resetForm"
|
||||||
class="text-xs w-20 mt-2"
|
|
||||||
@click="profileForm.urls?.push({ value: '' })"
|
|
||||||
>
|
>
|
||||||
Add URL
|
Reset form
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-start">
|
|
||||||
<Button type="submit">
|
|
||||||
Update profile
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user