Untitled

 avatar
unknown
typescript
5 months ago
13 kB
3
Indexable
'use client';
import slugify from 'slugify';
import {
    Form,
    FormControl,
    FormField,
    FormItem,
    FormLabel,
    FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { useToast } from '@/components/ui/use-toast';
import { createEvent, updateEvent } from '@/lib/actions/event.actions';
import { insertEventSchema, updateEventSchema } from '@/lib/validator';
import { Event } from '@/types';
import { zodResolver } from '@hookform/resolvers/zod';
import { useRouter } from 'next/navigation';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Card, CardContent } from '@/components/ui/card';
import Image from 'next/image';
import { UploadButton } from '@/lib/uploadthing';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { useEffect } from 'react';

// Define the ClientUploadedFileData type
type ClientUploadedFileData<T> = {
    url: string;
    key: string;
    uploadedBy?: T;
};

export default function EventForm({
    type,
    event,
    eventId,
}: {
    type: 'Create' | 'Update';
    event?: Event;
    eventId?: string;
}) {
    const router = useRouter();
    const { toast } = useToast();

    const form = useForm<z.infer<typeof insertEventSchema>>({
        resolver: type === 'Update' ? zodResolver(updateEventSchema) : zodResolver(insertEventSchema),
        defaultValues: event && type === 'Update'
            ? {
                ...event,
                title: event.name, // Map `event.name` to `title`
                ticketPrice: Number(event.ticketPrice),
                availableTickets: Number(event.availableTickets),
                isFeatured: event.isFeatured || false,
                date: new Date(event.date), // Convert back to Date object
            }
            : {
                title: '',
                slug: '',
                date: new Date(), // Set as Date object
                venue: '',
                ticketPrice: 0,
                availableTickets: 0,
                images: [],
                description: '',
                isFeatured: false,
            },
    });

    useEffect(() => {
        if (event && type === 'Update') {
            form.setValue('date', new Date(event.date.toISOString().split('T')[0])); // Ensure date is set as Date object
        }
    }, [event, type, form]);

    async function onSubmit(values: z.infer<typeof insertEventSchema>) {
        const formattedValues = {
            ...values,
            name: values.title, // Map `title` back to `name`
            ticketPrice: Number(values.ticketPrice),
            availableTickets: Number(values.availableTickets),
            date: new Date(values.date), // Convert to Date object for backend
        };

        try {
            if (type === 'Create') {
                const res = await createEvent(formattedValues);
                if (!res.success) {
                    throw new Error(res.message);
                }
                toast({ description: res.message });
                router.push(`/admin/events`);
            } else if (type === 'Update') {
                if (!eventId) {
                    router.push(`/admin/events`);
                    return;
                }
                const res = await updateEvent({ ...formattedValues, id: eventId });
                if (!res.success) {
                    throw new Error(res.message);
                }
                toast({ description: res.message });
                router.push(`/admin/events`);
            }
        } catch (error) {
            toast({
                variant: 'destructive',
                description: (error as Error).message,
            });
        }
    }

    const images: string[] = form.watch('images') || [];

    return (
        <Form {...form}>
            <form
                method="post"
                onSubmit={form.handleSubmit(onSubmit)}
                className="space-y-8"
            >
                <div className="flex flex-col gap-5 md:flex-row">
                    <FormField
                        control={form.control}
                        name="title"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Event Title</FormLabel>
                                <FormControl>
                                    <Input placeholder="Enter event title" {...field} />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                    <FormField
                        control={form.control}
                        name="slug"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Slug</FormLabel>
                                <FormControl>
                                    <div className="relative">
                                        <Input
                                            placeholder="Enter event slug"
                                            className="pl-8"
                                            {...field}
                                        />
                                        <button
                                            type="button"
                                            onClick={() => {
                                                form.setValue(
                                                    'slug',
                                                    slugify(form.getValues('title'), { lower: true })
                                                );
                                            }}
                                        >
                                            Generate
                                        </button>
                                    </div>
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                </div>
                <div className="flex flex-col gap-5 md:flex-row">
                    <FormField
                        control={form.control}
                        name="date"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Date</FormLabel>
                                <FormControl>
                                    <Input
                                        type="date"
                                        value={field.value instanceof Date ? field.value.toISOString().split('T')[0] : field.value}
                                        onChange={e => field.onChange(e.target.value)} // Ensure value is a string
                                        onBlur={field.onBlur}
                                        name={field.name}
                                        ref={field.ref}
                                    />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                </div>
                <div className="flex flex-col gap-5 md:flex-row">
                    <FormField
                        control={form.control}
                        name="venue"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Venue</FormLabel>
                                <FormControl>
                                    <Input placeholder="Enter event venue" {...field} />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                </div>
                <div className="flex flex-col gap-5 md:flex-row">
                    <FormField
                        control={form.control}
                        name="ticketPrice"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Ticket Price</FormLabel>
                                <FormControl>
                                    <Input
                                        type="number"
                                        placeholder="Enter ticket price"
                                        {...field}
                                    />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                    <FormField
                        control={form.control}
                        name="availableTickets"
                        render={({ field }) => (
                            <FormItem className="w-full">
                                <FormLabel>Available Tickets</FormLabel>
                                <FormControl>
                                    <Input
                                        type="number"
                                        placeholder="Enter available tickets"
                                        {...field}
                                    />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                </div>
                <div className="flex flex-col gap-5 md:flex-row">
                    <FormField
                        control={form.control}
                        name="images"
                        render={() => (
                            <FormItem className="w-full">
                                <FormLabel>Images</FormLabel>
                                <Card>
                                    <CardContent className="space-y-2 mt-2 min-h-48">
                                        <div className="flex-start space-x-2">
                                            {images.map((image: string) => (
                                                <Image
                                                    key={image}
                                                    src={image}
                                                    alt="Event Image"
                                                    width={100}
                                                    height={100}
                                                />
                                            ))}
                                        </div>
                                        <UploadButton
                                            endpoint="imageUploader"
                                            onClientUploadComplete={(res: ClientUploadedFileData<{ uploadedBy: string | undefined; }>[]) => {
                                                const currentImages = form.getValues('images') || [];
                                                const newImages = res.map(file => file.url);
                                                form.setValue('images', [...currentImages, ...newImages]);
                                            }}
                                        />
                                    </CardContent>
                                </Card>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                </div>
                <FormField
                    control={form.control}
                    name="description"
                    render={({ field }) => (
                        <FormItem className="w-full">
                            <FormLabel>Description</FormLabel>
                            <FormControl>
                                <Textarea placeholder="Enter event description" {...field} />
                            </FormControl>
                            <FormMessage />
                        </FormItem>
                    )}
                />
                <div className="flex justify-end space-x-2">
                    <Button type="submit">
                        {type === 'Create' ? 'Create Event' : 'Update Event'}
                    </Button>
                </div>
            </form>
        </Form>
    );
}
Editor is loading...
Leave a Comment