Untitled
user_6232722
plain_text
18 days ago
11 kB
2
Indexable
Never
'use client'; import React, { useEffect, useState } from 'react'; import AsyncSelect from 'react-select/async'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { useToast } from '@/hooks/use-toast'; import DateTimePickerForm from '@/components/common/date-time-picker/time-picker-form'; import { getEventCategories } from '@/services/event-category'; import { convertToISO } from '@/utils/utils_functions'; import { useOrganisationStore, useEventStore } from '@/store'; import RichTextEditor from '@/components/common/rich-text-editor'; interface EventDetails { eventName: string; eventDescription: string; eventLocation: string; startDate: string; endDate: string; } interface EventCategoriesOption { value: string; label: string; } const CreateEventComponent: React.FC = () => { const { toast } = useToast(); const [selectedFile, setSelectedFile] = useState<File | null>(null); const [fileName, setFileName] = useState<string | null>(null); const { organisation, setOrganisation } = useOrganisationStore((state) => ({ organisation: state.organisation, setOrganisation: state.setOrganisation, })); const { addEvent } = useEventStore((state) => ({ addEvent: state.addEvent, })); const [eventDetails, setEventDetails] = React.useState<EventDetails>({ eventName: '', eventDescription: '', eventLocation: '', startDate: '', endDate: '', }); const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); const [selectedEventCategory, setSelectedEventCategory] = React.useState< EventCategoriesOption[] >([]); const initializeEventDetails = () => { setFileName(null); setSelectedFile(null); setEventDetails({ eventName: '', eventDescription: '', eventLocation: '', startDate: '', endDate: '', }); }; const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.files?.[0]) { setSelectedFile(e.target.files[0]); setFileName(e.target.files[0].name); } else { setSelectedFile(null); setFileName(null); } }; const handleCreateEvent = async () => { try { // Convert start and end dates to ISO format const startDateISO = convertToISO(eventDetails.startDate); const endDateISO = convertToISO(eventDetails.endDate); // Map selected categories to their IDs const selectedCategoryIds = selectedEventCategory.map( (category) => category.value ); let imageSignedUrl = null; // If a file is selected, upload it to S3 and get the signed URL if (selectedFile) { // Prepare the file for uploading (as a blob or file) const file = selectedFile as Blob; // Upload the image to S3 (this should be a separate function to handle the S3 upload) const uploadResponse = await fetch("/api/image-upload", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ fileContent: await file.arrayBuffer(), }), }); const uploadData = await uploadResponse.json(); // Capture the signed URL for the uploaded image if (uploadResponse.ok && uploadData.signedUrl) { imageSignedUrl = uploadData.signedUrl; } else { throw new Error("Failed to upload image"); } } const eventData = { organisationId: organisation.id, name: eventDetails.eventName, description: eventDetails.eventDescription, location: eventDetails.eventLocation, startDate: startDateISO, endDate: endDateISO, categoryIds: selectedCategoryIds, image: imageSignedUrl, }; // Send event data to backend const response = await addEvent(eventData); // Handle success or failure of event creation if (response.id) { toast({ description: "Event created successfully", variant: "default", duration: 2000, }); } else { throw new Error("Error creating event"); } } catch (error) { // Handle errors gracefully toast({ title: "Error creating event", description: "Please try again", variant: "destructive", duration: 2000, }); } // Reinitialize event details for future use initializeEventDetails(); }; const loadOptions = async (inputValue, callback) => { try { const response = await getEventCategories(); const options = response.data.map((item) => ({ value: item.id, label: item.name, })); callback( options.filter((option: EventCategoriesOption) => option.label.toLowerCase().includes(inputValue.toLowerCase()) ) ); } catch (error) { console.error('Error fetching options:', error); callback([]); } }; const handleEventCategoryChange = ( selectedOptions: EventCategoriesOption[] ) => { if (selectedOptions && selectedOptions.length <= 3) { setSelectedEventCategory(selectedOptions); } else if (selectedOptions && selectedOptions.length > 3) { setSelectedEventCategory(selectedOptions.slice(0, 3)); toast({ title: 'Please select a maximum of 3 categories', description: 'Only First 3 categories will be selected', variant: 'destructive', duration: 2000, }); } }; return ( <div id='create-event-container'> <p className='text-3xl font-medium'>Event Details</p> <p className='text-sm font-light'> Lets get started. Enter the details about your event below: </p> <div className='my-10 flex w-2/4 flex-col gap-4'> <div> <p className='mb-1 text-sm font-medium'>Event Name *</p> <Input id='eventname' type='text' className='mb-3 dark:border-white' onChange={(e) => setEventDetails({ ...eventDetails, eventName: e.target.value }) } value={eventDetails.eventName} required /> </div> <div> <p className='mb-1 text-sm font-medium'>Event Description *</p> <RichTextEditor onChange={(val) => setEventDetails({ ...eventDetails, eventDescription: val, }) } value={eventDetails.eventDescription} /> </div> <div> <p className='mb-1 text-sm font-medium'>Event Location *</p> <Input id='eventlocation' type='text' className='mb-3 dark:border-white' onChange={(e) => setEventDetails({ ...eventDetails, eventLocation: e.target.value, }) } value={eventDetails.eventLocation} required /> </div> <div> <p className='mb-1 text-sm font-medium'>Event Category *</p> {isClient && ( <AsyncSelect instanceId='event-category-select' isMulti cacheOptions={true} defaultOptions={true} loadOptions={loadOptions} onChange={handleEventCategoryChange} className='basic-multi-select' classNamePrefix='select' isClearable={false} noOptionsMessage={({ inputValue }) => !inputValue ? 'Start writing to show up options' : 'No options found' } /> )} </div> <div> <p className='mb-1 text-sm font-medium'>Date & Time *</p> <div className='flex flex-col gap-2 md:flex-row md:gap-10'> <div className='py-2'> <DateTimePickerForm pickerLabel='Start Date & Time' addDateTime={(data: any) => setEventDetails({ ...eventDetails, startDate: data }) } /> </div> <div className='py-2'> <DateTimePickerForm pickerLabel='End Date & Time' addDateTime={(data: any) => setEventDetails({ ...eventDetails, endDate: data }) } /> </div> </div> </div> <div className='mt-10'> <p className='text-2xl font-medium'>Additional Info</p> <p className='text-md mt-3 font-medium'>Image / Flyer</p> <p className='text-sm font-extralight'> Events with flyers attract more customers. Add your event flyer to sell more tickets! </p> {/* <Input type='file' id='eventimage' className='mt-5 max-w-96 rounded-md bg-primary p-2 text-sm text-white' accept='image/*' /> */} <div className='mt-5'> <input type='file' id='eventimage' className='hidden' accept='image/*' onChange={handleFileChange} /> <Button className='h-8'> <label htmlFor='eventimage'>Choose Image</label> </Button> {selectedFile && ( <span className='ml-2 text-sm text-gray-600'>{fileName}</span> )} </div> <p className='mt-2 text-sm font-extralight italic'> * Accepted file types: .jpg, .jpeg, .png. Recommended file size:{' '} <b>5MB</b> </p> </div> <div className={'mt-10 flex flex-row gap-10'}> <Button className='w-40' onClick={handleCreateEvent}> Save </Button> <Button variant='outline' className='w-40' onClick={initializeEventDetails} > Discard </Button> </div> <div className='my-10 h-0.5 w-full bg-gray-200' /> <div> <p className='text-3xl font-medium'>Publish Event</p> <p className='text-sm font-light'> Publish your event when you are ready to make people aware of your event </p> </div> <div className={'mt-2 flex flex-row gap-10'}> <Button variant='outline' className='w-40'> Save for later </Button> <Button variant='outline' className='w-40'> Publish Now </Button> <Button variant='outline' className='w-40'> Schedule for </Button> </div> </div> </div> ); }; export default CreateEventComponent;
Leave a Comment