Untitled

 avatar
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