Feat: Add searchable customer combobox to ReservationForm

This commit is contained in:
2025-12-03 22:27:48 +03:00
parent e4adb85498
commit a84985b40f
5 changed files with 276 additions and 15 deletions

View File

@@ -7,7 +7,7 @@ export default async function NewReservationPage() {
// Fetch necessary data for the form
const { data: halls } = await supabase.from('halls').select('id, name')
const { data: customers } = await supabase.from('customers').select('id, full_name').order('created_at', { ascending: false }).limit(50)
const { data: customers } = await supabase.from('customers').select('id, full_name, phone').order('created_at', { ascending: false }).limit(100)
const { data: packages } = await supabase.from('packages').select('id, name, price').eq('is_active', true)
return (

View File

@@ -18,6 +18,21 @@ import { Textarea } from "@/components/ui/textarea"
import { createReservation } from "./actions"
import { useState } from "react"
import { toast } from "sonner"
import { Check, ChevronsUpDown } from "lucide-react"
import { cn } from "@/lib/utils"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
const formSchema = z.object({
hall_id: z.string().min(1, "Salon seçmelisiniz."),
@@ -31,13 +46,14 @@ const formSchema = z.object({
interface ReservationFormProps {
halls: { id: string, name: string }[]
customers: { id: string, full_name: string }[]
customers: { id: string, full_name: string, phone?: string | null }[]
packages: { id: string, name: string, price: number }[]
}
export function ReservationForm({ halls, customers, packages }: ReservationFormProps) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [openCustomer, setOpenCustomer] = useState(false)
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
@@ -123,20 +139,63 @@ export function ReservationForm({ halls, customers, packages }: ReservationFormP
control={form.control}
name="customer_id"
render={({ field }) => (
<FormItem>
<FormItem className="flex flex-col">
<FormLabel>Müşteri</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Müşteri Seçin" />
</SelectTrigger>
</FormControl>
<SelectContent>
{customers.map(c => (
<SelectItem key={c.id} value={c.id}>{c.full_name}</SelectItem>
))}
</SelectContent>
</Select>
<Popover open={openCustomer} onOpenChange={setOpenCustomer}>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
role="combobox"
aria-expanded={openCustomer}
className={cn(
"w-full justify-between",
!field.value && "text-muted-foreground"
)}
>
{field.value
? customers.find((customer) => customer.id === field.value)?.full_name
: "Müşteri Seçin"}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-[300px] p-0">
<Command>
<CommandInput placeholder="Müşteri ara (İsim veya Telefon)..." />
<CommandList>
<CommandEmpty>Müşteri bulunamadı.</CommandEmpty>
<CommandGroup>
{customers.map((customer) => (
<CommandItem
value={`${customer.full_name} ${customer.phone || ''}`}
key={customer.id}
onSelect={() => {
form.setValue("customer_id", customer.id)
setOpenCustomer(false)
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
customer.id === field.value
? "opacity-100"
: "opacity-0"
)}
/>
<div className="flex flex-col">
<span>{customer.full_name}</span>
{customer.phone && (
<span className="text-xs text-muted-foreground">{customer.phone}</span>
)}
</div>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}