 4ca5bd58ee
			
		
	
	
		4ca5bd58ee
		
			
		
	
	
	
	
		
			
			Co-authored-by: Omar López <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
		
			
				
	
	
		
			140 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { ExclamationIcon } from "@heroicons/react/solid";
 | |
| import { SchedulingType } from "@prisma/client";
 | |
| import { Dayjs } from "dayjs";
 | |
| import Link from "next/link";
 | |
| import { useRouter } from "next/router";
 | |
| import React, { FC, useEffect, useState } from "react";
 | |
| 
 | |
| import { nameOfDay } from "@calcom/lib/weekday";
 | |
| 
 | |
| import classNames from "@lib/classNames";
 | |
| import { useLocale } from "@lib/hooks/useLocale";
 | |
| import { useSlots } from "@lib/hooks/useSlots";
 | |
| 
 | |
| import Loader from "@components/Loader";
 | |
| 
 | |
| type AvailableTimesProps = {
 | |
|   timeFormat: string;
 | |
|   minimumBookingNotice: number;
 | |
|   beforeBufferTime: number;
 | |
|   afterBufferTime: number;
 | |
|   eventTypeId: number;
 | |
|   eventLength: number;
 | |
|   slotInterval: number | null;
 | |
|   date: Dayjs;
 | |
|   users: {
 | |
|     username: string | null;
 | |
|   }[];
 | |
|   schedulingType: SchedulingType | null;
 | |
| };
 | |
| 
 | |
| const AvailableTimes: FC<AvailableTimesProps> = ({
 | |
|   date,
 | |
|   eventLength,
 | |
|   eventTypeId,
 | |
|   slotInterval,
 | |
|   minimumBookingNotice,
 | |
|   timeFormat,
 | |
|   users,
 | |
|   schedulingType,
 | |
|   beforeBufferTime,
 | |
|   afterBufferTime,
 | |
| }) => {
 | |
|   const { t, i18n } = useLocale();
 | |
|   const router = useRouter();
 | |
|   const { rescheduleUid } = router.query;
 | |
|   const { slots, loading, error } = useSlots({
 | |
|     date,
 | |
|     slotInterval,
 | |
|     eventLength,
 | |
|     schedulingType,
 | |
|     users,
 | |
|     minimumBookingNotice,
 | |
|     beforeBufferTime,
 | |
|     afterBufferTime,
 | |
|     eventTypeId,
 | |
|   });
 | |
| 
 | |
|   const [brand, setBrand] = useState("#292929");
 | |
| 
 | |
|   useEffect(() => {
 | |
|     setBrand(getComputedStyle(document.documentElement).getPropertyValue("--brand-color").trim());
 | |
|   }, []);
 | |
| 
 | |
|   return (
 | |
|     <div className="mt-8 flex flex-col text-center sm:mt-0 sm:w-1/3 sm:pl-4 md:-mb-5">
 | |
|       <div className="mb-4 text-left text-lg font-light text-gray-600">
 | |
|         <span className="w-1/2 text-gray-600 dark:text-white">
 | |
|           <strong>{nameOfDay(i18n.language, Number(date.format("d")))}</strong>
 | |
|           <span className="text-gray-500">
 | |
|             {date.format(", D ")}
 | |
|             {date.toDate().toLocaleString(i18n.language, { month: "long" })}
 | |
|           </span>
 | |
|         </span>
 | |
|       </div>
 | |
|       <div className="flex-grow overflow-y-auto md:h-[364px]">
 | |
|         {!loading &&
 | |
|           slots?.length > 0 &&
 | |
|           slots.map((slot) => {
 | |
|             type BookingURL = {
 | |
|               pathname: string;
 | |
|               query: Record<string, string | number | string[] | undefined>;
 | |
|             };
 | |
|             const bookingUrl: BookingURL = {
 | |
|               pathname: "book",
 | |
|               query: {
 | |
|                 ...router.query,
 | |
|                 date: slot.time.format(),
 | |
|                 type: eventTypeId,
 | |
|               },
 | |
|             };
 | |
| 
 | |
|             if (rescheduleUid) {
 | |
|               bookingUrl.query.rescheduleUid = rescheduleUid as string;
 | |
|             }
 | |
| 
 | |
|             if (schedulingType === SchedulingType.ROUND_ROBIN) {
 | |
|               bookingUrl.query.user = slot.users;
 | |
|             }
 | |
| 
 | |
|             return (
 | |
|               <div key={slot.time.format()}>
 | |
|                 <Link href={bookingUrl}>
 | |
|                   <a
 | |
|                     className={classNames(
 | |
|                       "text-primary-500 hover:bg-brand hover:text-brandcontrast dark:hover:bg-darkmodebrand dark:hover:text-darkmodebrandcontrast mb-2 block rounded-sm border bg-white py-4 font-medium hover:text-white dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 dark:hover:border-black",
 | |
|                       brand === "#fff" || brand === "#ffffff" ? "border-brandcontrast" : "border-brand"
 | |
|                     )}
 | |
|                     data-testid="time">
 | |
|                     {slot.time.format(timeFormat)}
 | |
|                   </a>
 | |
|                 </Link>
 | |
|               </div>
 | |
|             );
 | |
|           })}
 | |
|         {!loading && !error && !slots.length && (
 | |
|           <div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
 | |
|             <h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
 | |
|           </div>
 | |
|         )}
 | |
| 
 | |
|         {loading && <Loader />}
 | |
| 
 | |
|         {error && (
 | |
|           <div className="border-l-4 border-yellow-400 bg-yellow-50 p-4">
 | |
|             <div className="flex">
 | |
|               <div className="flex-shrink-0">
 | |
|                 <ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
 | |
|               </div>
 | |
|               <div className="ltr:ml-3 rtl:mr-3">
 | |
|                 <p className="text-sm text-yellow-700">{t("slots_load_fail")}</p>
 | |
|               </div>
 | |
|             </div>
 | |
|           </div>
 | |
|         )}
 | |
|       </div>
 | |
|     </div>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export default AvailableTimes;
 |