Fix account/member form validation, add member number to tables
- Fix account create form blocking on empty name when includeFirstMember - Add noValidate to forms to prevent browser native validation on optional fields - Show member number column on account members tab - Replace DOB with phone in members table for better at-a-glance info
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { zodResolver } from '@hookform/resolvers/zod'
|
import { zodResolver } from '@hookform/resolvers/zod'
|
||||||
|
import { z } from 'zod'
|
||||||
import { AccountCreateSchema } from '@forte/shared/schemas'
|
import { AccountCreateSchema } from '@forte/shared/schemas'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
@@ -17,7 +18,7 @@ interface AccountFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AccountForm({ defaultValues, onSubmit, loading, includeFirstMember }: AccountFormProps) {
|
export function AccountForm({ defaultValues, onSubmit, loading, includeFirstMember }: AccountFormProps) {
|
||||||
const optionalNameSchema = AccountCreateSchema.extend({ name: AccountCreateSchema.shape.name.optional() })
|
const optionalNameSchema = AccountCreateSchema.extend({ name: z.string().max(255).optional() })
|
||||||
const schema = includeFirstMember ? optionalNameSchema : AccountCreateSchema
|
const schema = includeFirstMember ? optionalNameSchema : AccountCreateSchema
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -29,7 +30,7 @@ export function AccountForm({ defaultValues, onSubmit, loading, includeFirstMemb
|
|||||||
} = useForm({
|
} = useForm({
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: defaultValues?.name ?? '',
|
name: defaultValues?.name ?? (includeFirstMember ? undefined : ''),
|
||||||
email: defaultValues?.email ?? undefined,
|
email: defaultValues?.email ?? undefined,
|
||||||
phone: defaultValues?.phone ?? undefined,
|
phone: defaultValues?.phone ?? undefined,
|
||||||
billingMode: defaultValues?.billingMode ?? 'consolidated',
|
billingMode: defaultValues?.billingMode ?? 'consolidated',
|
||||||
@@ -60,7 +61,7 @@ export function AccountForm({ defaultValues, onSubmit, loading, includeFirstMemb
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="account-form" onSubmit={handleSubmit(handleFormSubmit)} className="space-y-4 max-w-lg">
|
<form id="account-form" onSubmit={handleSubmit(handleFormSubmit)} noValidate className="space-y-4 max-w-lg">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="name">Account Name {includeFirstMember ? '' : '*'}</Label>
|
<Label htmlFor="name">Account Name {includeFirstMember ? '' : '*'}</Label>
|
||||||
<Input id="name" {...register('name')} placeholder={includeFirstMember ? 'Auto-generated from member name if blank' : 'e.g. Smith Family, Lincoln Elementary'} />
|
<Input id="name" {...register('name')} placeholder={includeFirstMember ? 'Auto-generated from member name if blank' : 'e.g. Smith Family, Lincoln Elementary'} />
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function MemberForm({ accountId, defaultValues, onSubmit, loading }: Memb
|
|||||||
const dateOfBirth = watch('dateOfBirth')
|
const dateOfBirth = watch('dateOfBirth')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
<form onSubmit={handleSubmit(onSubmit)} noValidate className="space-y-4">
|
||||||
<input type="hidden" {...register('accountId')} />
|
<input type="hidden" {...register('accountId')} />
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
|||||||
@@ -93,9 +93,10 @@ function MembersTab() {
|
|||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
<TableHead>#</TableHead>
|
||||||
<TableHead>Name</TableHead>
|
<TableHead>Name</TableHead>
|
||||||
<TableHead>Email</TableHead>
|
<TableHead>Email</TableHead>
|
||||||
<TableHead>Date of Birth</TableHead>
|
<TableHead>Phone</TableHead>
|
||||||
<TableHead>Status</TableHead>
|
<TableHead>Status</TableHead>
|
||||||
<TableHead className="w-24">Actions</TableHead>
|
<TableHead className="w-24">Actions</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -103,9 +104,10 @@ function MembersTab() {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
{members.map((m) => (
|
{members.map((m) => (
|
||||||
<TableRow key={m.id}>
|
<TableRow key={m.id}>
|
||||||
|
<TableCell className="font-mono text-sm text-muted-foreground">{m.memberNumber ?? '-'}</TableCell>
|
||||||
<TableCell className="font-medium">{m.firstName} {m.lastName}</TableCell>
|
<TableCell className="font-medium">{m.firstName} {m.lastName}</TableCell>
|
||||||
<TableCell>{m.email ?? '-'}</TableCell>
|
<TableCell>{m.email ?? '-'}</TableCell>
|
||||||
<TableCell>{m.dateOfBirth ?? '-'}</TableCell>
|
<TableCell>{m.phone ?? '-'}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{m.isMinor ? <Badge variant="secondary">Minor</Badge> : <Badge>Adult</Badge>}
|
{m.isMinor ? <Badge variant="secondary">Minor</Badge> : <Badge>Adult</Badge>}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
Reference in New Issue
Block a user