feat(forms): migrate remaining native date inputs to <DatePicker> / <DateTimePicker>
Sweeps the last ~17 native `<Input type="date"|"datetime-local">`
call sites onto the shared `<DatePicker>` / `<DateTimePicker>`
primitives so date entry is uniform across the app (calendar popover
on desktop, native OS picker on mobile via the primitive's
viewport-aware fallback).
Three patterns handled:
1. Controlled value/onChange — direct swap to <DatePicker
value/onChange>:
audit-log-list.tsx (audit-from / audit-to filters)
reports/generate-report-form.tsx (date range)
scan/scan-shell.tsx (expense date)
reservations/reservation-detail.tsx (end-reservation dialog)
shared/filter-bar.tsx ('date' filter variant)
2. RHF `register('field')` pattern — wrapped in <Controller> with
field.value/field.onChange bridge. The picker's '' → undefined
normalisation kicks in via `field.onChange(v || undefined)`:
berths/berth-form.tsx (tenureStartDate + tenureEndDate)
reservations/berth-reserve-dialog.tsx (startDate)
companies/add-membership-dialog.tsx (startDate)
yachts/yacht-transfer-dialog.tsx (effectiveDate)
invoices/invoice-detail.tsx (paymentDate)
3. RHF + Date-typed schema — same Controller wrap, plus a
Date<->YYYY-MM-DD bridge in the render() since the zod schema
coerces these to Date:
expenses/expense-form-dialog.tsx (expenseDate)
companies/company-form.tsx (incorporationDate)
4. Datetime variants — swapped onto <DateTimePicker>:
interests/interest-contact-log-tab.tsx (occurredAt + followUpAt)
Skipped because they ARE picker primitives or internal date variants:
- ui/date-picker.tsx, ui/date-time-picker.tsx (the primitives)
- shared/inline-editable-field.tsx (the InlineEditableField date variant)
- dashboard/date-range-picker.tsx (its own popover with min/max gating
that doesn't map cleanly onto the shared primitive)
Removed now-unused Input imports from four files.
Verified: tsc clean, vitest 1448/1448.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { PageHeader } from '@/components/shared/page-header';
|
||||
import { EmptyState } from '@/components/shared/empty-state';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
@@ -530,12 +531,11 @@ export function AuditLogList() {
|
||||
<Label htmlFor="audit-from" className="text-xs">
|
||||
From
|
||||
</Label>
|
||||
<Input
|
||||
<DatePicker
|
||||
id="audit-from"
|
||||
type="date"
|
||||
className="w-44 h-9"
|
||||
value={dateFrom}
|
||||
onChange={(e) => setDateFrom(e.target.value)}
|
||||
onChange={setDateFrom}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -543,13 +543,7 @@ export function AuditLogList() {
|
||||
<Label htmlFor="audit-to" className="text-xs">
|
||||
To
|
||||
</Label>
|
||||
<Input
|
||||
id="audit-to"
|
||||
type="date"
|
||||
className="w-44 h-9"
|
||||
value={dateTo}
|
||||
onChange={(e) => setDateTo(e.target.value)}
|
||||
/>
|
||||
<DatePicker id="audit-to" className="w-44 h-9" value={dateTo} onChange={setDateTo} />
|
||||
</div>
|
||||
|
||||
{/* M-AU03: CSV export inherits the current filter set. The
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
@@ -9,6 +9,7 @@ import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -120,6 +121,7 @@ export function BerthForm({ berth, open, onOpenChange }: BerthFormProps) {
|
||||
handleSubmit,
|
||||
setValue,
|
||||
watch,
|
||||
control,
|
||||
formState: { isSubmitting },
|
||||
} = useForm<z.input<typeof updateBerthSchema>, unknown, UpdateBerthInput>({
|
||||
resolver: zodResolver(updateBerthSchema),
|
||||
@@ -449,11 +451,29 @@ export function BerthForm({ berth, open, onOpenChange }: BerthFormProps) {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>Start Date</Label>
|
||||
<Input type="date" {...register('tenureStartDate')} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="tenureStartDate"
|
||||
render={({ field }) => (
|
||||
<DatePicker
|
||||
value={field.value ?? ''}
|
||||
onChange={(v) => field.onChange(v || undefined)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>End Date</Label>
|
||||
<Input type="date" {...register('tenureEndDate')} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="tenureEndDate"
|
||||
render={({ field }) => (
|
||||
<DatePicker
|
||||
value={field.value ?? ''}
|
||||
onChange={(v) => field.onChange(v || undefined)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -69,6 +70,7 @@ export function AddMembershipDialog({ open, onOpenChange, companyId }: AddMember
|
||||
watch,
|
||||
setValue,
|
||||
reset,
|
||||
control,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
@@ -180,7 +182,14 @@ export function AddMembershipDialog({ open, onOpenChange, companyId }: AddMember
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="startDate">Start date</Label>
|
||||
<Input id="startDate" type="date" {...register('startDate', { required: true })} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="startDate"
|
||||
rules={{ required: true }}
|
||||
render={({ field }) => (
|
||||
<DatePicker id="startDate" value={field.value ?? ''} onChange={field.onChange} />
|
||||
)}
|
||||
/>
|
||||
{errors.startDate && <p className="text-xs text-destructive">Required</p>}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -11,6 +11,7 @@ import { z } from 'zod';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Select,
|
||||
@@ -117,6 +118,7 @@ export function CompanyForm({ open, onOpenChange, company, prefill }: CompanyFor
|
||||
watch,
|
||||
setValue,
|
||||
reset,
|
||||
control,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<CompanyFormValues>({
|
||||
resolver: zodResolver(createCompanySchema),
|
||||
@@ -327,7 +329,27 @@ export function CompanyForm({ open, onOpenChange, company, prefill }: CompanyFor
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label>Incorporation Date</Label>
|
||||
<Input type="date" {...register('incorporationDate')} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="incorporationDate"
|
||||
render={({ field }) => {
|
||||
// Schema coerces incorporationDate to a Date; the picker
|
||||
// speaks YYYY-MM-DD. Bridge both directions so validation
|
||||
// + downstream API payload stay unchanged.
|
||||
const isoValue =
|
||||
field.value instanceof Date
|
||||
? field.value.toISOString().split('T')[0]
|
||||
: typeof field.value === 'string'
|
||||
? (field.value as string).split('T')[0]
|
||||
: '';
|
||||
return (
|
||||
<DatePicker
|
||||
value={isoValue}
|
||||
onChange={(v) => field.onChange(v ? new Date(v) : undefined)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{errors.incorporationDate && (
|
||||
<p className="text-xs text-destructive">{errors.incorporationDate.message}</p>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { AlertTriangle, Loader2, Upload, X } from 'lucide-react';
|
||||
@@ -10,6 +10,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { FormErrorSummary } from '@/components/forms/form-error-summary';
|
||||
import { useFormScrollToError } from '@/hooks/use-form-scroll-to-error';
|
||||
@@ -69,6 +70,7 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
setValue,
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<z.input<typeof createExpenseSchema>, unknown, CreateExpenseInput>({
|
||||
resolver: zodResolver(createExpenseSchema),
|
||||
@@ -230,17 +232,33 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
/>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="expenseDate">Date *</Label>
|
||||
<Input
|
||||
id="expenseDate"
|
||||
type="date"
|
||||
{...register('expenseDate', {
|
||||
setValueAs: (v) => (v ? new Date(v) : undefined),
|
||||
})}
|
||||
<Controller
|
||||
control={control}
|
||||
name="expenseDate"
|
||||
defaultValue={
|
||||
expense?.expenseDate
|
||||
? new Date(expense.expenseDate).toISOString().split('T')[0]
|
||||
: new Date().toISOString().split('T')[0]
|
||||
? (new Date(expense.expenseDate) as unknown as Date)
|
||||
: (new Date() as unknown as Date)
|
||||
}
|
||||
render={({ field }) => {
|
||||
// Schema stores expenseDate as a Date; the picker speaks
|
||||
// YYYY-MM-DD strings. Bridge both directions on the fly so
|
||||
// upstream validation + downstream API payload stay
|
||||
// unchanged.
|
||||
const isoValue =
|
||||
field.value instanceof Date
|
||||
? field.value.toISOString().split('T')[0]
|
||||
: typeof field.value === 'string'
|
||||
? field.value.split('T')[0]
|
||||
: '';
|
||||
return (
|
||||
<DatePicker
|
||||
id="expenseDate"
|
||||
value={isoValue}
|
||||
onChange={(v) => field.onChange(v ? new Date(v) : undefined)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{errors.expenseDate && (
|
||||
<p className="text-xs text-destructive">{errors.expenseDate.message}</p>
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
@@ -497,12 +497,7 @@ function ComposeDialogBody({
|
||||
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="cl-occurred">When did the conversation happen?</Label>
|
||||
<Input
|
||||
id="cl-occurred"
|
||||
type="datetime-local"
|
||||
value={occurredAt}
|
||||
onChange={(e) => setOccurredAt(e.target.value)}
|
||||
/>
|
||||
<DateTimePicker id="cl-occurred" value={occurredAt} onChange={setOccurredAt} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
@@ -588,11 +583,10 @@ function ComposeDialogBody({
|
||||
<Label htmlFor="cl-followup" className="text-xs text-muted-foreground">
|
||||
Remind me on
|
||||
</Label>
|
||||
<Input
|
||||
<DateTimePicker
|
||||
id="cl-followup"
|
||||
type="datetime-local"
|
||||
value={followUpAt}
|
||||
onChange={(e) => setFollowUpAt(e.target.value)}
|
||||
onChange={setFollowUpAt}
|
||||
className="max-w-xs"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { Loader2, Send, CreditCard } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
@@ -15,6 +15,7 @@ import { PermissionGate } from '@/components/shared/permission-gate';
|
||||
import { toast } from 'sonner';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -397,10 +398,16 @@ export function InvoiceDetail({ invoiceId }: InvoiceDetailProps) {
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="paymentDate">Payment Date</Label>
|
||||
<Input
|
||||
id="paymentDate"
|
||||
type="date"
|
||||
{...paymentForm.register('paymentDate')}
|
||||
<Controller
|
||||
control={paymentForm.control}
|
||||
name="paymentDate"
|
||||
render={({ field }) => (
|
||||
<DatePicker
|
||||
id="paymentDate"
|
||||
value={field.value ?? ''}
|
||||
onChange={(v) => field.onChange(v || undefined)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{paymentForm.formState.errors.paymentDate && (
|
||||
<p className="text-xs text-destructive">
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -148,23 +149,16 @@ export function GenerateReportForm() {
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dateFrom">Date From (optional)</Label>
|
||||
<Input
|
||||
<DatePicker
|
||||
id="dateFrom"
|
||||
type="date"
|
||||
value={dateFrom}
|
||||
onChange={(e) => setDateFrom(e.target.value)}
|
||||
onChange={setDateFrom}
|
||||
className="w-auto"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dateTo">Date To (optional)</Label>
|
||||
<Input
|
||||
id="dateTo"
|
||||
type="date"
|
||||
value={dateTo}
|
||||
onChange={(e) => setDateTo(e.target.value)}
|
||||
className="w-auto"
|
||||
/>
|
||||
<DatePicker id="dateTo" value={dateTo} onChange={setDateTo} className="w-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Select,
|
||||
@@ -55,6 +55,7 @@ export function BerthReserveDialog({ open, onOpenChange, berthId }: BerthReserve
|
||||
watch,
|
||||
setValue,
|
||||
reset,
|
||||
control,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
@@ -186,7 +187,14 @@ export function BerthReserveDialog({ open, onOpenChange, berthId }: BerthReserve
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="startDate">Start date</Label>
|
||||
<Input id="startDate" type="date" {...register('startDate', { required: true })} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="startDate"
|
||||
rules={{ required: true }}
|
||||
render={({ field }) => (
|
||||
<DatePicker id="startDate" value={field.value ?? ''} onChange={field.onChange} />
|
||||
)}
|
||||
/>
|
||||
{errors.startDate && <p className="text-xs text-destructive">Required</p>}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { PageHeader } from '@/components/shared/page-header';
|
||||
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
|
||||
import { EmptyState } from '@/components/ui/empty-state';
|
||||
@@ -96,13 +96,7 @@ function EndReservationDialog({ reservationId, open, onOpenChange }: EndReservat
|
||||
<form onSubmit={handleSubmit} className="space-y-4 pt-2">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="end-date">End date</Label>
|
||||
<Input
|
||||
id="end-date"
|
||||
type="date"
|
||||
value={endDate}
|
||||
onChange={(e) => setEndDate(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<DatePicker id="end-date" value={endDate} onChange={setEndDate} />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -239,13 +240,7 @@ function VerifyForm({
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="expenseDate">Date</Label>
|
||||
<Input
|
||||
id="expenseDate"
|
||||
type="date"
|
||||
value={expenseDate}
|
||||
onChange={(e) => setExpenseDate(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<DatePicker id="expenseDate" value={expenseDate} onChange={setExpenseDate} />
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="category">Category</Label>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { X, Filter, ChevronDown } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import {
|
||||
@@ -272,10 +273,9 @@ function FilterField({
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{definition.label}</Label>
|
||||
<Input
|
||||
type="date"
|
||||
<DatePicker
|
||||
value={(value as string) ?? ''}
|
||||
onChange={(e) => onChange(e.target.value || undefined)}
|
||||
onChange={(v) => onChange(v || undefined)}
|
||||
className="h-8"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -16,8 +16,8 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -62,6 +62,7 @@ export function YachtTransferDialog({
|
||||
watch,
|
||||
setValue,
|
||||
reset,
|
||||
control,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
@@ -150,10 +151,17 @@ export function YachtTransferDialog({
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="effectiveDate">Effective date</Label>
|
||||
<Input
|
||||
id="effectiveDate"
|
||||
type="date"
|
||||
{...register('effectiveDate', { required: true })}
|
||||
<Controller
|
||||
control={control}
|
||||
name="effectiveDate"
|
||||
rules={{ required: true }}
|
||||
render={({ field }) => (
|
||||
<DatePicker
|
||||
id="effectiveDate"
|
||||
value={field.value ?? ''}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.effectiveDate && <p className="text-xs text-destructive">Required</p>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user