Merge pull request #384 from emrysal/feature/minimum-booking-notice
Feature/minimum booking notice
This commit is contained in:
		
						commit
						3c55660537
					
				
					 8 changed files with 52 additions and 15 deletions
				
			
		|  | @ -7,6 +7,7 @@ const AvailableTimes = ({ | |||
|   date, | ||||
|   eventLength, | ||||
|   eventTypeId, | ||||
|   minimumBookingNotice, | ||||
|   workingHours, | ||||
|   timeFormat, | ||||
|   user, | ||||
|  | @ -20,6 +21,7 @@ const AvailableTimes = ({ | |||
|     eventLength, | ||||
|     workingHours, | ||||
|     organizerTimeZone, | ||||
|     minimumBookingNotice, | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ const DatePicker = ({ | |||
|   periodEndDate, | ||||
|   periodDays, | ||||
|   periodCountCalendarDays, | ||||
|   minimumBookingNotice, | ||||
| }) => { | ||||
|   const [calendar, setCalendar] = useState([]); | ||||
|   const [selectedMonth, setSelectedMonth] = useState<number>(); | ||||
|  | @ -77,6 +78,7 @@ const DatePicker = ({ | |||
|             !getSlots({ | ||||
|               inviteeDate: date, | ||||
|               frequency: eventLength, | ||||
|               minimumBookingNotice, | ||||
|               workingHours, | ||||
|               organizerTimeZone, | ||||
|             }).length | ||||
|  | @ -93,6 +95,7 @@ const DatePicker = ({ | |||
|             !getSlots({ | ||||
|               inviteeDate: date, | ||||
|               frequency: eventLength, | ||||
|               minimumBookingNotice, | ||||
|               workingHours, | ||||
|               organizerTimeZone, | ||||
|             }).length | ||||
|  | @ -106,6 +109,7 @@ const DatePicker = ({ | |||
|             !getSlots({ | ||||
|               inviteeDate: date, | ||||
|               frequency: eventLength, | ||||
|               minimumBookingNotice, | ||||
|               workingHours, | ||||
|               organizerTimeZone, | ||||
|             }).length | ||||
|  |  | |||
							
								
								
									
										17
									
								
								lib/slots.ts
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								lib/slots.ts
									
									
									
									
									
								
							|  | @ -1,7 +1,6 @@ | |||
| import dayjs, { Dayjs } from "dayjs"; | ||||
| import utc from "dayjs/plugin/utc"; | ||||
| import timezone from "dayjs/plugin/timezone"; | ||||
| 
 | ||||
| dayjs.extend(utc); | ||||
| dayjs.extend(timezone); | ||||
| 
 | ||||
|  | @ -119,10 +118,20 @@ const getSlots = ({ | |||
|   workingHours, | ||||
|   organizerTimeZone, | ||||
| }: GetSlots): Dayjs[] => { | ||||
|   const startTime = dayjs().utcOffset(inviteeDate.utcOffset()).isSame(inviteeDate, "day") | ||||
|     ? inviteeDate.hour() * 60 + inviteeDate.minute() + (minimumBookingNotice || 0) | ||||
|     : 0; | ||||
|   // current date in invitee tz
 | ||||
|   const currentDate = dayjs().utcOffset(inviteeDate.utcOffset()); | ||||
|   const startDate = currentDate.add(minimumBookingNotice, "minutes"); // + minimum notice period
 | ||||
|   // when the invitee date is not the same as the current date, reset the date to the start of day
 | ||||
|   if (inviteeDate.date() !== currentDate.date()) { | ||||
|     inviteeDate = inviteeDate.startOf("day"); | ||||
|   } | ||||
| 
 | ||||
|   const startTime = startDate.isAfter(inviteeDate) | ||||
|     ? // block out everything when inviteeDate is less than startDate
 | ||||
|       startDate.date() > inviteeDate.date() | ||||
|       ? 1440 | ||||
|       : startDate.hour() * 60 + startDate.minute() | ||||
|     : 0; | ||||
|   const inviteeBounds = inviteeBoundary(startTime, inviteeDate.utcOffset(), frequency); | ||||
| 
 | ||||
|   return getOverlaps( | ||||
|  |  | |||
|  | @ -167,14 +167,16 @@ export default function Type(props): Type { | |||
|                 organizerTimeZone={props.eventType.timeZone || props.user.timeZone} | ||||
|                 inviteeTimeZone={timeZone()} | ||||
|                 eventLength={props.eventType.length} | ||||
|                 minimumBookingNotice={props.eventType.minimumBookingNotice} | ||||
|               /> | ||||
|               {selectedDate && ( | ||||
|                 <AvailableTimes | ||||
|                   workingHours={props.workingHours} | ||||
|                   timeFormat={timeFormat} | ||||
|                   organizerTimeZone={props.eventType.timeZone || props.user.timeZone} | ||||
|                   eventLength={props.eventType.length} | ||||
|                   minimumBookingNotice={props.eventType.minimumBookingNotice} | ||||
|                   eventTypeId={props.eventType.id} | ||||
|                   eventLength={props.eventType.length} | ||||
|                   date={selectedDate} | ||||
|                   user={props.user} | ||||
|                 /> | ||||
|  | @ -238,6 +240,7 @@ export const getServerSideProps: GetServerSideProps = async (context: GetServerS | |||
|       "periodStartDate", | ||||
|       "periodEndDate", | ||||
|       "periodCountCalendarDays", | ||||
|       "minimumBookingNotice", | ||||
|     ] | ||||
|   ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,6 +55,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | |||
|       periodStartDate: req.body.periodStartDate, | ||||
|       periodEndDate: req.body.periodEndDate, | ||||
|       periodCountCalendarDays: req.body.periodCountCalendarDays, | ||||
|       minimumBookingNotice: req.body.minimumBookingNotice, | ||||
|     }; | ||||
| 
 | ||||
|     if (req.method == "POST") { | ||||
|  |  | |||
|  | @ -66,7 +66,8 @@ type EventTypeInput = { | |||
|   periodStartDate?: Date | string; | ||||
|   periodEndDate?: Date | string; | ||||
|   periodCountCalendarDays?: boolean; | ||||
|   enteredRequiresConfirmation: boolean; | ||||
|   requiresConfirmation: boolean; | ||||
|   minimumBookingNotice: number; | ||||
| }; | ||||
| 
 | ||||
| const PERIOD_TYPES = [ | ||||
|  | @ -92,7 +93,6 @@ export default function EventTypePage({ | |||
| }: Props): JSX.Element { | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   console.log(eventType); | ||||
|   const inputOptions: OptionBase[] = [ | ||||
|     { value: EventTypeCustomInputType.Text, label: "Text" }, | ||||
|     { value: EventTypeCustomInputType.TextLong, label: "Multiline Text" }, | ||||
|  | @ -174,6 +174,7 @@ export default function EventTypePage({ | |||
|   const lengthRef = useRef<HTMLInputElement>(); | ||||
|   const isHiddenRef = useRef<HTMLInputElement>(); | ||||
|   const requiresConfirmationRef = useRef<HTMLInputElement>(); | ||||
|   const minimumBookingNoticeRef = useRef<HTMLInputElement>(); | ||||
|   const eventNameRef = useRef<HTMLInputElement>(); | ||||
|   const periodDaysRef = useRef<HTMLInputElement>(); | ||||
|   const periodDaysTypeRef = useRef<HTMLSelectElement>(); | ||||
|  | @ -190,6 +191,7 @@ export default function EventTypePage({ | |||
|     const enteredDescription: string = descriptionRef.current.value; | ||||
|     const enteredLength: number = parseInt(lengthRef.current.value); | ||||
|     const enteredIsHidden: boolean = isHiddenRef.current.checked; | ||||
|     const enteredMinimumBookingNotice: number = parseInt(minimumBookingNoticeRef.current.value); | ||||
|     const enteredRequiresConfirmation: boolean = requiresConfirmationRef.current.checked; | ||||
|     const enteredEventName: string = eventNameRef.current.value; | ||||
| 
 | ||||
|  | @ -200,14 +202,6 @@ export default function EventTypePage({ | |||
|     const enteredPeriodStartDate = periodStartDate ? periodStartDate.toDate() : null; | ||||
|     const enteredPeriodEndDate = periodEndDate ? periodEndDate.toDate() : null; | ||||
| 
 | ||||
|     console.log("values", { | ||||
|       type, | ||||
|       periodDaysTypeRef, | ||||
|       enteredPeriodDays, | ||||
|       enteredPeriodDaysType, | ||||
|       enteredPeriodStartDate, | ||||
|       enteredPeriodEndDate, | ||||
|     }); | ||||
|     // TODO: Add validation
 | ||||
| 
 | ||||
|     const payload: EventTypeInput = { | ||||
|  | @ -226,6 +220,7 @@ export default function EventTypePage({ | |||
|       periodStartDate: enteredPeriodStartDate, | ||||
|       periodEndDate: enteredPeriodEndDate, | ||||
|       periodCountCalendarDays: enteredPeriodDaysType, | ||||
|       minimumBookingNotice: enteredMinimumBookingNotice, | ||||
|       requiresConfirmation: enteredRequiresConfirmation, | ||||
|     }; | ||||
| 
 | ||||
|  | @ -671,6 +666,25 @@ export default function EventTypePage({ | |||
| 
 | ||||
|                   <fieldset className="my-8"> | ||||
|                     <Text variant="largetitle">When can people book this event?</Text> | ||||
|                     <div className="my-4"> | ||||
|                       <label htmlFor="minimumAdvance" className="block text-sm font-medium text-gray-700"> | ||||
|                         Minimum booking notice | ||||
|                       </label> | ||||
|                       <div className="mt-1 relative rounded-md shadow-sm"> | ||||
|                         <input | ||||
|                           ref={minimumBookingNoticeRef} | ||||
|                           type="number" | ||||
|                           name="minimumAdvance" | ||||
|                           id="minimumAdvance" | ||||
|                           required | ||||
|                           className="focus:ring-blue-500 focus:border-blue-500 block w-full pr-20 sm:text-sm border-gray-300 rounded-md" | ||||
|                           defaultValue={eventType.minimumBookingNotice} | ||||
|                         /> | ||||
|                         <div className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 text-sm"> | ||||
|                           minutes | ||||
|                         </div> | ||||
|                       </div> | ||||
|                     </div> | ||||
|                     <hr className="my-8" /> | ||||
|                     <section className="space-y-12"> | ||||
|                       <div className="mb-4"> | ||||
|  | @ -1019,6 +1033,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ req, query | |||
|       periodEndDate: true, | ||||
|       periodCountCalendarDays: true, | ||||
|       requiresConfirmation: true, | ||||
|       minimumBookingNotice: true, | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| -- AlterTable | ||||
| ALTER TABLE "EventType" ADD COLUMN     "minimumBookingNotice" INTEGER NOT NULL DEFAULT 120; | ||||
|  | @ -31,6 +31,7 @@ model EventType { | |||
|   periodDays Int? | ||||
|   periodCountCalendarDays Boolean? | ||||
|   requiresConfirmation Boolean @default(false) | ||||
|   minimumBookingNotice Int @default(120) | ||||
| } | ||||
| 
 | ||||
| model Credential { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Bailey Pumfleet
						Bailey Pumfleet