166 lines
No EOL
7.1 KiB
JavaScript
166 lines
No EOL
7.1 KiB
JavaScript
"use client"
|
|
import { GoClock } from "react-icons/go";
|
|
import { PiMapPinLight, PiInfo, PiCalendarCheck } from "react-icons/pi";
|
|
import React, { useEffect, useState } from 'react'
|
|
import Link from "next/link";
|
|
import { format } from "date-fns";
|
|
import TimeDateSelection from "./TimeDateSelection";
|
|
import { Button } from "@/components/ui/button";
|
|
import UserFormInfo from "./UserFormInfo";
|
|
import { collection, doc, getDocs, getFirestore, query, setDoc, where } from "firebase/firestore";
|
|
import { app } from "@/config/FirebaseConfig";
|
|
import { toast } from "sonner";
|
|
import Plunk from "@plunk/node";
|
|
import { render } from '@react-email/render';
|
|
import Email from "@/emails";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
const MeetingEventSelection = ({meetingEventInfo, businessInfo}) => {
|
|
const [date, setDate] = useState(new Date());
|
|
const [timeSlots, setTimeSlots] = useState();
|
|
const [unavialableTime, setUnavialableTime] = useState(false);
|
|
const [selectedTime, setSelectedTime] = useState();
|
|
const router = useRouter();
|
|
|
|
//set user schedule data
|
|
const [userName, setUserName] = useState();
|
|
const [userEmail, setUserEmail] = useState();
|
|
const [userMessage, setUserMessage] = useState('');
|
|
|
|
//setup the next step
|
|
const [nextStep, setNextStep] = useState(1);
|
|
|
|
//meeting/event booking
|
|
const [booking, setBooking] = useState([])
|
|
|
|
const db = getFirestore(app);
|
|
|
|
//send an email using React Email and the Plunk Node.js SDK
|
|
const plunk = new Plunk(process.env.NEXT_PUBLIC_PLUNK_API_KEY);
|
|
|
|
//create time slot
|
|
const createTimeSlot = (interval) => {
|
|
const startTime = 8 * 60;
|
|
const endTime = 22 * 60;
|
|
const totalSlots = (endTime - startTime) / interval;
|
|
const slots = Array.from({length: totalSlots}, (_, i) => {
|
|
const totalMinutes = startTime + i * interval;
|
|
const hours = Math.floor(totalMinutes / 60);
|
|
const minutes = totalMinutes % 60;
|
|
const formattedHours = hours > 12 ? hours - 12: hours;
|
|
const period = hours >= 12? 'PM' : 'AM';
|
|
return `${String(formattedHours).padStart(2, '0')} : ${String(minutes).padStart(2, '0')} ${period}`
|
|
});
|
|
setTimeSlots(slots);
|
|
}
|
|
|
|
const handleDatechange = (date) => {
|
|
setDate(date);
|
|
const day = format(date, 'EEEE')
|
|
if(businessInfo?.availableDays?.[day]){
|
|
setUnavialableTime(true)
|
|
eventBooking(date)
|
|
} else{
|
|
setUnavialableTime(false)
|
|
}
|
|
}
|
|
|
|
//store user scheduale data
|
|
const handleSchedule = async () => {
|
|
const regex = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
|
|
if(regex.test(userEmail) == false){
|
|
toast('Please enter your valid email!')
|
|
return ;
|
|
}
|
|
|
|
const docId = Date.now().toString();
|
|
await setDoc(doc(db, 'ScheduleMeeting', docId), {
|
|
businessName: businessInfo.businessName,
|
|
businessEmail: businessInfo.email,
|
|
duration: meetingEventInfo.timeDuration,
|
|
urlMeeting: meetingEventInfo.urlMeeting,
|
|
eventId: meetingEventInfo.id,
|
|
id: docId,
|
|
userName: userName,
|
|
userEmail: userEmail,
|
|
selectedTime: selectedTime,
|
|
selectedDate: date,
|
|
formatedDate:format(date, 'PPP'),
|
|
formatedTimeStamp:format(date, 't'),
|
|
userMessage: userMessage
|
|
}).then(res => {
|
|
toast('Your schedule is created successfully');
|
|
sendEmail(userName)
|
|
})
|
|
}
|
|
|
|
//fetch data to blockout selection days and time
|
|
const eventBooking = async (datebooking) => {
|
|
const q = query(collection(db, 'ScheduleMeeting'), where('selectedDate', '==', datebooking), where('eventId', '==', meetingEventInfo.id));
|
|
const querySnapshot = await getDocs(q);
|
|
querySnapshot.forEach((doc) => {
|
|
console.log("--" , doc.data)
|
|
setBooking(prev => [...prev, doc.data()])
|
|
})
|
|
}
|
|
|
|
//create an email using Plunk
|
|
const sendEmail = (user) => {
|
|
const emailHtml = render(<Email
|
|
userFirstName={user}
|
|
businessName={businessInfo?.businessName}
|
|
meetingDate={format(date, 'PPP').toString()}
|
|
meetingTime={selectedTime}
|
|
duration={meetingEventInfo?.timeDuration}
|
|
meetingUrl={meetingEventInfo?.urlMeeting}/>);
|
|
|
|
plunk.emails.send({
|
|
to: userEmail,
|
|
subject: "Meeting Schedule Detail",
|
|
body: emailHtml,
|
|
}).then(res => {
|
|
console.log(res)
|
|
router.replace('/confirmation')
|
|
});
|
|
}
|
|
|
|
useEffect(() => {
|
|
meetingEventInfo?.timeDuration && createTimeSlot(meetingEventInfo?.timeDuration)
|
|
}, [meetingEventInfo])
|
|
|
|
|
|
return (
|
|
<div className='px-5 py-10 shadow-md m-4 border-t-8 mx-5 md:mx-20 lg:mx-40 my-10 xl:mx-60 lg:my-20' style={{borderTopColor: meetingEventInfo?.themeColor}}>
|
|
<p className='text-xl uppercase font-semibold tracking-wide'>Schedule.Me</p>
|
|
<div className='grid grid-cols-1 lg:grid-cols-3 mt-5'>
|
|
<div className='border-r'>
|
|
<p className='font-semibold mb-5 text-xl'>{businessInfo?.businessName}</p>
|
|
<p className="font-normal flex items-center gap-1"><PiInfo/> {meetingEventInfo?.eventName?meetingEventInfo?.eventName:'Meeting/Event Name'}</p>
|
|
<div className='mt-2 flex flex-col gap-2'>
|
|
<p className='flex gap-1 items-center'><PiCalendarCheck/>{format(date, 'PPP')}</p>
|
|
<p className='flex gap-1 items-center'><GoClock/>{meetingEventInfo?.timeDuration} minutes
|
|
{selectedTime && <span className="text-sm text-gray-500">({selectedTime})</span>}
|
|
</p>
|
|
<p className='flex gap-1 items-center'><PiMapPinLight/>{meetingEventInfo?.locationMeeting}</p>
|
|
<Link href={meetingEventInfo?.urlMeeting?meetingEventInfo?.urlMeeting:'#'} className="text-gray-500 underline text-sm">{meetingEventInfo?.urlMeeting}</Link>
|
|
</div>
|
|
</div>
|
|
{nextStep == 1 ?
|
|
<TimeDateSelection booking={booking} date={date} unavialableTime={unavialableTime} handleDatechange={handleDatechange} setSelectedTime={setSelectedTime} timeSlots={timeSlots} selectedTime={selectedTime}/>
|
|
:
|
|
<UserFormInfo setUserName={setUserName} setUserEmail={setUserEmail} setUserMessage={setUserMessage}/>
|
|
}
|
|
</div>
|
|
<div className="flex justify-end px-5 sm:px-10 gap-2">
|
|
{nextStep == 2 && <Button variant='outline' onClick={() => setNextStep(1)} className="mt-5 w-full sm:w-auto">Back</Button>}
|
|
{nextStep ==1 ?
|
|
<Button disabled={!selectedTime || !date} onClick={() => setNextStep(nextStep+1)} className="mt-5 w-full sm:w-auto">Next</Button>
|
|
:
|
|
<Button disabled={!userName || !userEmail} onClick={handleSchedule} className="mt-5 w-full sm:w-auto">Schedule</Button>
|
|
}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default MeetingEventSelection |