Merge pull request #275 from Malte-D/feature/add-buffer-times-for-appointments
Implemented a configurable buffer between events
This commit is contained in:
		
						commit
						9f0a80ac87
					
				
					 5 changed files with 39 additions and 14 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| import type { NextApiRequest, NextApiResponse } from 'next'; | import type { NextApiRequest, NextApiResponse } from 'next'; | ||||||
| import prisma from '../../../lib/prisma'; | import prisma from '../../../lib/prisma'; | ||||||
| import { getBusyTimes } from '../../../lib/calendarClient'; | import { getBusyTimes } from '../../../lib/calendarClient'; | ||||||
|  | import dayjs from "dayjs"; | ||||||
| 
 | 
 | ||||||
| export default async function handler(req: NextApiRequest, res: NextApiResponse) { | export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||||||
|     const { user } = req.query |     const { user } = req.query | ||||||
|  | @ -11,16 +12,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|         }, |         }, | ||||||
|         select: { |         select: { | ||||||
|             credentials: true, |             credentials: true, | ||||||
|             timeZone: true |             timeZone: true, | ||||||
|  |             bufferTime: true | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     const selectedCalendars = (await prisma.selectedCalendar.findMany({ |     let availability = await getBusyTimes(currentUser.credentials, req.query.dateFrom, req.query.dateTo); | ||||||
|         where: { | 
 | ||||||
|             userId: currentUser.id |     availability = availability.map(a => ({ | ||||||
|         } |         start: dayjs(a.start).subtract(currentUser.bufferTime, 'minute').toString(), | ||||||
|  |         end: dayjs(a.end).add(currentUser.bufferTime, 'minute').toString() | ||||||
|     })); |     })); | ||||||
|    |    | ||||||
|     const availability = await getBusyTimes(currentUser.credentials, req.query.dateFrom, req.query.dateTo, selectedCalendars); |  | ||||||
|     res.status(200).json(availability); |     res.status(200).json(availability); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     if (req.method == "PATCH") { |     if (req.method == "PATCH") { | ||||||
|         const startMins = req.body.start; |         const startMins = req.body.start; | ||||||
|         const endMins = req.body.end; |         const endMins = req.body.end; | ||||||
|  |         const bufferMins = req.body.buffer; | ||||||
| 
 | 
 | ||||||
|         const updateDay = await prisma.user.update({ |         const updateDay = await prisma.user.update({ | ||||||
|             where: { |             where: { | ||||||
|  | @ -20,7 +21,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|             }, |             }, | ||||||
|             data: { |             data: { | ||||||
|                 startTime: startMins, |                 startTime: startMins, | ||||||
|                 endTime: endMins |                 endTime: endMins, | ||||||
|  |                 bufferTime: bufferMins | ||||||
|             }, |             }, | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,6 +25,8 @@ export default function Availability(props) { | ||||||
|     const startMinsRef = useRef<HTMLInputElement>(); |     const startMinsRef = useRef<HTMLInputElement>(); | ||||||
|     const endHoursRef = useRef<HTMLInputElement>(); |     const endHoursRef = useRef<HTMLInputElement>(); | ||||||
|     const endMinsRef = useRef<HTMLInputElement>(); |     const endMinsRef = useRef<HTMLInputElement>(); | ||||||
|  |     const bufferHoursRef = useRef<HTMLInputElement>(); | ||||||
|  |     const bufferMinsRef = useRef<HTMLInputElement>(); | ||||||
| 
 | 
 | ||||||
|     if (loading) { |     if (loading) { | ||||||
|         return <p className="text-gray-400">Loading...</p>; |         return <p className="text-gray-400">Loading...</p>; | ||||||
|  | @ -80,15 +82,18 @@ export default function Availability(props) { | ||||||
|         const enteredStartMins = parseInt(startMinsRef.current.value); |         const enteredStartMins = parseInt(startMinsRef.current.value); | ||||||
|         const enteredEndHours = parseInt(endHoursRef.current.value); |         const enteredEndHours = parseInt(endHoursRef.current.value); | ||||||
|         const enteredEndMins = parseInt(endMinsRef.current.value); |         const enteredEndMins = parseInt(endMinsRef.current.value); | ||||||
|  |         const enteredBufferHours = parseInt(bufferHoursRef.current.value); | ||||||
|  |         const enteredBufferMins = parseInt(bufferMinsRef.current.value); | ||||||
| 
 | 
 | ||||||
|         const startMins = enteredStartHours * 60 + enteredStartMins; |         const startMins = enteredStartHours * 60 + enteredStartMins; | ||||||
|         const endMins = enteredEndHours * 60 + enteredEndMins; |         const endMins = enteredEndHours * 60 + enteredEndMins; | ||||||
|  |         const bufferMins = enteredBufferHours * 60 + enteredBufferMins; | ||||||
| 
 | 
 | ||||||
|         // TODO: Add validation
 |         // TODO: Add validation
 | ||||||
| 
 | 
 | ||||||
|         const response = await fetch('/api/availability/day', { |         const response = await fetch('/api/availability/day', { | ||||||
|             method: 'PATCH', |             method: 'PATCH', | ||||||
|             body: JSON.stringify({start: startMins, end: endMins}), |             body: JSON.stringify({start: startMins, end: endMins, buffer: bufferMins}), | ||||||
|             headers: { |             headers: { | ||||||
|                 'Content-Type': 'application/json' |                 'Content-Type': 'application/json' | ||||||
|             } |             } | ||||||
|  | @ -298,7 +303,7 @@ export default function Availability(props) { | ||||||
|                                         </h3> |                                         </h3> | ||||||
|                                         <div> |                                         <div> | ||||||
|                                             <p className="text-sm text-gray-500"> |                                             <p className="text-sm text-gray-500"> | ||||||
|                                                 Set the start and end time of your day. |                                                 Set the start and end time of your day and a minimum buffer between your meetings. | ||||||
|                                             </p> |                                             </p> | ||||||
|                                         </div> |                                         </div> | ||||||
|                                     </div> |                                     </div> | ||||||
|  | @ -316,7 +321,7 @@ export default function Availability(props) { | ||||||
|                                             <input ref={startMinsRef} type="number" name="minutes" id="minutes" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="30" defaultValue={convertMinsToHrsMins(props.user.startTime).split(":")[1]} /> |                                             <input ref={startMinsRef} type="number" name="minutes" id="minutes" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="30" defaultValue={convertMinsToHrsMins(props.user.startTime).split(":")[1]} /> | ||||||
|                                         </div> |                                         </div> | ||||||
|                                     </div> |                                     </div> | ||||||
|                                     <div className="flex"> |                                     <div className="flex mb-4"> | ||||||
|                                         <label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">End time</label> |                                         <label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">End time</label> | ||||||
|                                         <div> |                                         <div> | ||||||
|                                             <label htmlFor="hours" className="sr-only">Hours</label> |                                             <label htmlFor="hours" className="sr-only">Hours</label> | ||||||
|  | @ -328,6 +333,18 @@ export default function Availability(props) { | ||||||
|                                             <input ref={endMinsRef} type="number" name="minutes" id="minutes" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="30" defaultValue={convertMinsToHrsMins(props.user.endTime).split(":")[1]} /> |                                             <input ref={endMinsRef} type="number" name="minutes" id="minutes" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="30" defaultValue={convertMinsToHrsMins(props.user.endTime).split(":")[1]} /> | ||||||
|                                         </div> |                                         </div> | ||||||
|                                     </div> |                                     </div> | ||||||
|  |                                     <div className="flex mb-4"> | ||||||
|  |                                         <label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">Buffer</label> | ||||||
|  |                                         <div> | ||||||
|  |                                             <label htmlFor="hours" className="sr-only">Hours</label> | ||||||
|  |                                             <input ref={bufferHoursRef} type="number" name="hours" id="hours" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="0" defaultValue={convertMinsToHrsMins(props.user.bufferTime).split(":")[0]} /> | ||||||
|  |                                         </div> | ||||||
|  |                                         <span className="mx-2 pt-1">:</span> | ||||||
|  |                                         <div> | ||||||
|  |                                             <label htmlFor="minutes" className="sr-only">Minutes</label> | ||||||
|  |                                             <input ref={bufferMinsRef} type="number" name="minutes" id="minutes" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="10" defaultValue={convertMinsToHrsMins(props.user.bufferTime).split(":")[1]} /> | ||||||
|  |                                         </div> | ||||||
|  |                                     </div> | ||||||
|                                     <div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse"> |                                     <div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse"> | ||||||
|                                         <button type="submit" className="btn btn-primary"> |                                         <button type="submit" className="btn btn-primary"> | ||||||
|                                             Update |                                             Update | ||||||
|  | @ -361,7 +378,8 @@ export async function getServerSideProps(context) { | ||||||
|             id: true, |             id: true, | ||||||
|             username: true, |             username: true, | ||||||
|             startTime: true, |             startTime: true, | ||||||
|             endTime: true |             endTime: true, | ||||||
|  |             bufferTime: true | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | -- AlterTable | ||||||
|  | ALTER TABLE "users" ADD COLUMN     "bufferTime" INTEGER NOT NULL DEFAULT 0; | ||||||
|  | @ -45,6 +45,7 @@ model User { | ||||||
|   weekStart     String? @default("Sunday") |   weekStart     String? @default("Sunday") | ||||||
|   startTime     Int @default(0) |   startTime     Int @default(0) | ||||||
|   endTime       Int @default(1440) |   endTime       Int @default(1440) | ||||||
|  |   bufferTime    Int @default(0) | ||||||
|   createdDate   DateTime  @default(now()) @map(name: "created") |   createdDate   DateTime  @default(now()) @map(name: "created") | ||||||
|   eventTypes    EventType[] |   eventTypes    EventType[] | ||||||
|   credentials   Credential[] |   credentials   Credential[] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Bailey Pumfleet
						Bailey Pumfleet