| 
									
										
										
										
											2021-06-24 22:15:18 +00:00
										 |  |  | import { ClockIcon } from "@heroicons/react/outline"; | 
					
						
							| 
									
										
										
										
											2022-02-23 00:23:52 +00:00
										 |  |  | import dayjs from "dayjs"; | 
					
						
							|  |  |  | import customParseFormat from "dayjs/plugin/customParseFormat"; | 
					
						
							|  |  |  | import { useRef, useState } from "react"; | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  | import { useLocale } from "@calcom/lib/hooks/useLocale"; | 
					
						
							| 
									
										
										
										
											2022-03-16 23:36:43 +00:00
										 |  |  | import showToast from "@calcom/lib/notification"; | 
					
						
							|  |  |  | import Button from "@calcom/ui/Button"; | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  | import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog"; | 
					
						
							| 
									
										
										
										
											2021-11-29 06:37:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-23 00:23:52 +00:00
										 |  |  | dayjs.extend(customParseFormat); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 00:05:13 +00:00
										 |  |  | interface SetTimesModalProps { | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |   isOpen: boolean; | 
					
						
							| 
									
										
										
										
											2022-02-09 00:05:13 +00:00
										 |  |  |   startTime: number; | 
					
						
							|  |  |  |   endTime: number; | 
					
						
							|  |  |  |   onChange: (times: { startTime: number; endTime: number }) => void; | 
					
						
							|  |  |  |   onExit: (...p: unknown[]) => void; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default function SetTimesModal(props: SetTimesModalProps) { | 
					
						
							| 
									
										
										
										
											2021-10-15 10:53:42 +00:00
										 |  |  |   const { t } = useLocale(); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:00:25 +00:00
										 |  |  |   const [startHours, startMinutes] = [Math.floor(props.startTime / 60), props.startTime % 60]; | 
					
						
							|  |  |  |   const [endHours, endMinutes] = [Math.floor(props.endTime / 60), props.endTime % 60]; | 
					
						
							| 
									
										
										
										
											2022-02-09 00:05:13 +00:00
										 |  |  |   const startHoursRef = useRef<HTMLInputElement>(null!); | 
					
						
							|  |  |  |   const startMinsRef = useRef<HTMLInputElement>(null!); | 
					
						
							|  |  |  |   const endHoursRef = useRef<HTMLInputElement>(null!); | 
					
						
							|  |  |  |   const endMinsRef = useRef<HTMLInputElement>(null!); | 
					
						
							| 
									
										
										
										
											2022-02-23 00:23:52 +00:00
										 |  |  |   const [endMinuteDisable, setEndMinuteDisable] = useState(false); | 
					
						
							|  |  |  |   const [maximumStartTime, setMaximumStartTime] = useState({ hour: endHours, minute: 59 }); | 
					
						
							|  |  |  |   const [minimumEndTime, setMinimumEndTime] = useState({ hour: startHours, minute: 59 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const STEP = 15; | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-10 09:37:00 +00:00
										 |  |  |   const isValidTime = (startTime: number, endTime: number) => { | 
					
						
							|  |  |  |     if (new Date(startTime) > new Date(endTime)) { | 
					
						
							|  |  |  |       showToast(t("error_end_time_before_start_time"), "error"); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (endTime > 1440) { | 
					
						
							|  |  |  |       showToast(t("error_end_time_next_day"), "error"); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-23 00:23:52 +00:00
										 |  |  |   // compute dynamic range for minimum and maximum allowed hours/minutes.
 | 
					
						
							|  |  |  |   const setEdgeTimes = ( | 
					
						
							|  |  |  |     (step) => | 
					
						
							|  |  |  |     ( | 
					
						
							|  |  |  |       startHoursRef: React.MutableRefObject<HTMLInputElement>, | 
					
						
							|  |  |  |       startMinsRef: React.MutableRefObject<HTMLInputElement>, | 
					
						
							|  |  |  |       endHoursRef: React.MutableRefObject<HTMLInputElement>, | 
					
						
							|  |  |  |       endMinsRef: React.MutableRefObject<HTMLInputElement> | 
					
						
							|  |  |  |     ) => { | 
					
						
							|  |  |  |       //parse all the refs
 | 
					
						
							|  |  |  |       const startHour = parseInt(startHoursRef.current.value); | 
					
						
							|  |  |  |       let startMinute = parseInt(startMinsRef.current.value); | 
					
						
							|  |  |  |       const endHour = parseInt(endHoursRef.current.value); | 
					
						
							|  |  |  |       let endMinute = parseInt(endMinsRef.current.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       //convert to dayjs object
 | 
					
						
							| 
									
										
										
										
											2022-02-23 16:16:04 +00:00
										 |  |  |       const startTime = dayjs(`${startHour}:${startMinute}`, "hh:mm"); | 
					
						
							|  |  |  |       const endTime = dayjs(`${endHour}:${endMinute}`, "hh:mm"); | 
					
						
							| 
									
										
										
										
											2022-02-23 00:23:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       //compute minimin and maximum allowed
 | 
					
						
							|  |  |  |       const maximumStartTime = endTime.subtract(step, "minute"); | 
					
						
							|  |  |  |       const maximumStartHour = maximumStartTime.hour(); | 
					
						
							|  |  |  |       const maximumStartMinute = startHour === endHour ? maximumStartTime.minute() : 59; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const minimumEndTime = startTime.add(step, "minute"); | 
					
						
							|  |  |  |       const minimumEndHour = minimumEndTime.hour(); | 
					
						
							|  |  |  |       const minimumEndMinute = startHour === endHour ? minimumEndTime.minute() : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       //check allow min/max minutes when the end/start hour matches
 | 
					
						
							|  |  |  |       if (startHoursRef.current.value === endHoursRef.current.value) { | 
					
						
							|  |  |  |         if (parseInt(startMinsRef.current.value) >= maximumStartMinute) | 
					
						
							|  |  |  |           startMinsRef.current.value = maximumStartMinute.toString(); | 
					
						
							|  |  |  |         if (parseInt(endMinsRef.current.value) <= minimumEndMinute) | 
					
						
							|  |  |  |           endMinsRef.current.value = minimumEndMinute.toString(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       //save into state
 | 
					
						
							|  |  |  |       setMaximumStartTime({ hour: maximumStartHour, minute: maximumStartMinute }); | 
					
						
							|  |  |  |       setMinimumEndTime({ hour: minimumEndHour, minute: minimumEndMinute }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   )(STEP); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |     <Dialog open={props.isOpen} onOpenChange={props.onExit}> | 
					
						
							|  |  |  |       <DialogContent> | 
					
						
							|  |  |  |         <div className="mb-4 sm:flex sm:items-start"> | 
					
						
							|  |  |  |           <div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> | 
					
						
							|  |  |  |             <ClockIcon className="h-6 w-6 text-black" /> | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |           <div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | 
					
						
							|  |  |  |             <h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title"> | 
					
						
							|  |  |  |               {t("change_bookings_availability")} | 
					
						
							|  |  |  |             </h3> | 
					
						
							|  |  |  |             <div> | 
					
						
							|  |  |  |               <p className="text-sm text-gray-500">{t("set_work_schedule")}</p> | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  |             </div> | 
					
						
							|  |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |         </div> | 
					
						
							|  |  |  |         <div className="mb-4 flex"> | 
					
						
							|  |  |  |           <label className="block w-1/4 pt-2 text-sm font-medium text-gray-700">{t("start_time")}</label> | 
					
						
							|  |  |  |           <div className="w-1/6"> | 
					
						
							|  |  |  |             <label htmlFor="startHours" className="sr-only"> | 
					
						
							|  |  |  |               {t("hours")} | 
					
						
							|  |  |  |             </label> | 
					
						
							|  |  |  |             <input | 
					
						
							|  |  |  |               ref={startHoursRef} | 
					
						
							|  |  |  |               type="number" | 
					
						
							|  |  |  |               min="0" | 
					
						
							|  |  |  |               max={maximumStartTime.hour} | 
					
						
							|  |  |  |               minLength={2} | 
					
						
							|  |  |  |               name="hours" | 
					
						
							|  |  |  |               id="startHours" | 
					
						
							|  |  |  |               className="focus:border-brand block w-full rounded-md border-gray-300 shadow-sm focus:ring-black sm:text-sm" | 
					
						
							|  |  |  |               placeholder="9" | 
					
						
							|  |  |  |               defaultValue={startHours} | 
					
						
							|  |  |  |               onChange={() => setEdgeTimes(startHoursRef, startMinsRef, endHoursRef, endMinsRef)} | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |           <span className="mx-2 pt-1">:</span> | 
					
						
							|  |  |  |           <div className="w-1/6"> | 
					
						
							|  |  |  |             <label htmlFor="startMinutes" className="sr-only"> | 
					
						
							|  |  |  |               {t("minutes")} | 
					
						
							|  |  |  |             </label> | 
					
						
							|  |  |  |             <input | 
					
						
							|  |  |  |               ref={startMinsRef} | 
					
						
							|  |  |  |               type="number" | 
					
						
							|  |  |  |               min="0" | 
					
						
							|  |  |  |               max={maximumStartTime.minute} | 
					
						
							|  |  |  |               step={STEP} | 
					
						
							|  |  |  |               maxLength={2} | 
					
						
							|  |  |  |               name="minutes" | 
					
						
							|  |  |  |               id="startMinutes" | 
					
						
							|  |  |  |               className="focus:border-brand block w-full rounded-md border-gray-300 shadow-sm focus:ring-black sm:text-sm" | 
					
						
							|  |  |  |               placeholder="30" | 
					
						
							|  |  |  |               defaultValue={startMinutes} | 
					
						
							|  |  |  |               onChange={() => setEdgeTimes(startHoursRef, startMinsRef, endHoursRef, endMinsRef)} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |         <div className="flex"> | 
					
						
							|  |  |  |           <label className="block w-1/4 pt-2 text-sm font-medium text-gray-700">{t("end_time")}</label> | 
					
						
							|  |  |  |           <div className="w-1/6"> | 
					
						
							|  |  |  |             <label htmlFor="endHours" className="sr-only"> | 
					
						
							|  |  |  |               {t("hours")} | 
					
						
							|  |  |  |             </label> | 
					
						
							|  |  |  |             <input | 
					
						
							|  |  |  |               ref={endHoursRef} | 
					
						
							|  |  |  |               type="number" | 
					
						
							|  |  |  |               min={minimumEndTime.hour} | 
					
						
							|  |  |  |               max="24" | 
					
						
							|  |  |  |               maxLength={2} | 
					
						
							|  |  |  |               name="hours" | 
					
						
							|  |  |  |               id="endHours" | 
					
						
							|  |  |  |               className="focus:border-brand block w-full rounded-md border-gray-300 shadow-sm focus:ring-black sm:text-sm" | 
					
						
							|  |  |  |               placeholder="17" | 
					
						
							|  |  |  |               defaultValue={endHours} | 
					
						
							|  |  |  |               onChange={(e) => { | 
					
						
							|  |  |  |                 if (endHoursRef.current.value === "24") endMinsRef.current.value = "0"; | 
					
						
							|  |  |  |                 setEdgeTimes(startHoursRef, startMinsRef, endHoursRef, endMinsRef); | 
					
						
							|  |  |  |                 setEndMinuteDisable(endHoursRef.current.value === "24"); | 
					
						
							| 
									
										
										
										
											2022-02-09 00:05:13 +00:00
										 |  |  |               }} | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |             /> | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |           <span className="mx-2 pt-1">:</span> | 
					
						
							|  |  |  |           <div className="w-1/6"> | 
					
						
							|  |  |  |             <label htmlFor="endMinutes" className="sr-only"> | 
					
						
							|  |  |  |               {t("minutes")} | 
					
						
							|  |  |  |             </label> | 
					
						
							|  |  |  |             <input | 
					
						
							|  |  |  |               ref={endMinsRef} | 
					
						
							|  |  |  |               type="number" | 
					
						
							|  |  |  |               min={minimumEndTime.minute} | 
					
						
							|  |  |  |               max="59" | 
					
						
							|  |  |  |               maxLength={2} | 
					
						
							|  |  |  |               step={STEP} | 
					
						
							|  |  |  |               name="minutes" | 
					
						
							|  |  |  |               id="endMinutes" | 
					
						
							|  |  |  |               className="focus:border-brand block w-full rounded-md border-gray-300 shadow-sm focus:ring-black sm:text-sm" | 
					
						
							|  |  |  |               placeholder="30" | 
					
						
							|  |  |  |               defaultValue={endMinutes} | 
					
						
							|  |  |  |               disabled={endMinuteDisable} | 
					
						
							|  |  |  |               onChange={() => setEdgeTimes(startHoursRef, startMinsRef, endHoursRef, endMinsRef)} | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2021-06-16 22:27:27 +00:00
										 |  |  |           </div> | 
					
						
							|  |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2022-03-17 13:20:49 +00:00
										 |  |  |         <DialogFooter> | 
					
						
							|  |  |  |           <Button | 
					
						
							|  |  |  |             onClick={(event) => { | 
					
						
							|  |  |  |               event.preventDefault(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               const enteredStartHours = parseInt(startHoursRef.current.value); | 
					
						
							|  |  |  |               const enteredStartMins = parseInt(startMinsRef.current.value); | 
					
						
							|  |  |  |               const enteredEndHours = parseInt(endHoursRef.current.value); | 
					
						
							|  |  |  |               const enteredEndMins = parseInt(endMinsRef.current.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               if ( | 
					
						
							|  |  |  |                 isValidTime(enteredStartHours * 60 + enteredStartMins, enteredEndHours * 60 + enteredEndMins) | 
					
						
							|  |  |  |               ) { | 
					
						
							|  |  |  |                 props.onChange({ | 
					
						
							|  |  |  |                   startTime: enteredStartHours * 60 + enteredStartMins, | 
					
						
							|  |  |  |                   endTime: enteredEndHours * 60 + enteredEndMins, | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |                 props.onExit(0); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }} | 
					
						
							|  |  |  |             type="submit"> | 
					
						
							|  |  |  |             {t("save")} | 
					
						
							|  |  |  |           </Button> | 
					
						
							|  |  |  |           <Button onClick={props.onExit} type="button" color="secondary" className="ltr:mr-2"> | 
					
						
							|  |  |  |             {t("cancel")} | 
					
						
							|  |  |  |           </Button> | 
					
						
							|  |  |  |         </DialogFooter> | 
					
						
							|  |  |  |       </DialogContent> | 
					
						
							|  |  |  |     </Dialog> | 
					
						
							| 
									
										
										
										
											2021-06-24 22:15:18 +00:00
										 |  |  |   ); | 
					
						
							|  |  |  | } |