Untitled
user_6232722
plain_text
a year ago
11 kB
11
Indexable
'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;
Editor is loading...
Leave a Comment