Merge pull request #384 from emrysal/feature/minimum-booking-notice

Feature/minimum booking notice
This commit is contained in:
Bailey Pumfleet 2021-07-26 11:54:22 +01:00 committed by GitHub
commit 3c55660537
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 52 additions and 15 deletions

View file

@ -7,6 +7,7 @@ const AvailableTimes = ({
date, date,
eventLength, eventLength,
eventTypeId, eventTypeId,
minimumBookingNotice,
workingHours, workingHours,
timeFormat, timeFormat,
user, user,
@ -20,6 +21,7 @@ const AvailableTimes = ({
eventLength, eventLength,
workingHours, workingHours,
organizerTimeZone, organizerTimeZone,
minimumBookingNotice,
}); });
return ( return (

View file

@ -23,6 +23,7 @@ const DatePicker = ({
periodEndDate, periodEndDate,
periodDays, periodDays,
periodCountCalendarDays, periodCountCalendarDays,
minimumBookingNotice,
}) => { }) => {
const [calendar, setCalendar] = useState([]); const [calendar, setCalendar] = useState([]);
const [selectedMonth, setSelectedMonth] = useState<number>(); const [selectedMonth, setSelectedMonth] = useState<number>();
@ -77,6 +78,7 @@ const DatePicker = ({
!getSlots({ !getSlots({
inviteeDate: date, inviteeDate: date,
frequency: eventLength, frequency: eventLength,
minimumBookingNotice,
workingHours, workingHours,
organizerTimeZone, organizerTimeZone,
}).length }).length
@ -93,6 +95,7 @@ const DatePicker = ({
!getSlots({ !getSlots({
inviteeDate: date, inviteeDate: date,
frequency: eventLength, frequency: eventLength,
minimumBookingNotice,
workingHours, workingHours,
organizerTimeZone, organizerTimeZone,
}).length }).length
@ -106,6 +109,7 @@ const DatePicker = ({
!getSlots({ !getSlots({
inviteeDate: date, inviteeDate: date,
frequency: eventLength, frequency: eventLength,
minimumBookingNotice,
workingHours, workingHours,
organizerTimeZone, organizerTimeZone,
}).length }).length

View file

@ -1,7 +1,6 @@
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone"; import timezone from "dayjs/plugin/timezone";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
@ -119,10 +118,20 @@ const getSlots = ({
workingHours, workingHours,
organizerTimeZone, organizerTimeZone,
}: GetSlots): Dayjs[] => { }: GetSlots): Dayjs[] => {
const startTime = dayjs().utcOffset(inviteeDate.utcOffset()).isSame(inviteeDate, "day") // current date in invitee tz
? inviteeDate.hour() * 60 + inviteeDate.minute() + (minimumBookingNotice || 0) const currentDate = dayjs().utcOffset(inviteeDate.utcOffset());
: 0; 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); const inviteeBounds = inviteeBoundary(startTime, inviteeDate.utcOffset(), frequency);
return getOverlaps( return getOverlaps(

View file

@ -167,14 +167,16 @@ export default function Type(props): Type {
organizerTimeZone={props.eventType.timeZone || props.user.timeZone} organizerTimeZone={props.eventType.timeZone || props.user.timeZone}
inviteeTimeZone={timeZone()} inviteeTimeZone={timeZone()}
eventLength={props.eventType.length} eventLength={props.eventType.length}
minimumBookingNotice={props.eventType.minimumBookingNotice}
/> />
{selectedDate && ( {selectedDate && (
<AvailableTimes <AvailableTimes
workingHours={props.workingHours} workingHours={props.workingHours}
timeFormat={timeFormat} timeFormat={timeFormat}
organizerTimeZone={props.eventType.timeZone || props.user.timeZone} organizerTimeZone={props.eventType.timeZone || props.user.timeZone}
eventLength={props.eventType.length} minimumBookingNotice={props.eventType.minimumBookingNotice}
eventTypeId={props.eventType.id} eventTypeId={props.eventType.id}
eventLength={props.eventType.length}
date={selectedDate} date={selectedDate}
user={props.user} user={props.user}
/> />
@ -238,6 +240,7 @@ export const getServerSideProps: GetServerSideProps = async (context: GetServerS
"periodStartDate", "periodStartDate",
"periodEndDate", "periodEndDate",
"periodCountCalendarDays", "periodCountCalendarDays",
"minimumBookingNotice",
] ]
); );

View file

@ -55,6 +55,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
periodStartDate: req.body.periodStartDate, periodStartDate: req.body.periodStartDate,
periodEndDate: req.body.periodEndDate, periodEndDate: req.body.periodEndDate,
periodCountCalendarDays: req.body.periodCountCalendarDays, periodCountCalendarDays: req.body.periodCountCalendarDays,
minimumBookingNotice: req.body.minimumBookingNotice,
}; };
if (req.method == "POST") { if (req.method == "POST") {

View file

@ -66,7 +66,8 @@ type EventTypeInput = {
periodStartDate?: Date | string; periodStartDate?: Date | string;
periodEndDate?: Date | string; periodEndDate?: Date | string;
periodCountCalendarDays?: boolean; periodCountCalendarDays?: boolean;
enteredRequiresConfirmation: boolean; requiresConfirmation: boolean;
minimumBookingNotice: number;
}; };
const PERIOD_TYPES = [ const PERIOD_TYPES = [
@ -92,7 +93,6 @@ export default function EventTypePage({
}: Props): JSX.Element { }: Props): JSX.Element {
const router = useRouter(); const router = useRouter();
console.log(eventType);
const inputOptions: OptionBase[] = [ const inputOptions: OptionBase[] = [
{ value: EventTypeCustomInputType.Text, label: "Text" }, { value: EventTypeCustomInputType.Text, label: "Text" },
{ value: EventTypeCustomInputType.TextLong, label: "Multiline Text" }, { value: EventTypeCustomInputType.TextLong, label: "Multiline Text" },
@ -174,6 +174,7 @@ export default function EventTypePage({
const lengthRef = useRef<HTMLInputElement>(); const lengthRef = useRef<HTMLInputElement>();
const isHiddenRef = useRef<HTMLInputElement>(); const isHiddenRef = useRef<HTMLInputElement>();
const requiresConfirmationRef = useRef<HTMLInputElement>(); const requiresConfirmationRef = useRef<HTMLInputElement>();
const minimumBookingNoticeRef = useRef<HTMLInputElement>();
const eventNameRef = useRef<HTMLInputElement>(); const eventNameRef = useRef<HTMLInputElement>();
const periodDaysRef = useRef<HTMLInputElement>(); const periodDaysRef = useRef<HTMLInputElement>();
const periodDaysTypeRef = useRef<HTMLSelectElement>(); const periodDaysTypeRef = useRef<HTMLSelectElement>();
@ -190,6 +191,7 @@ export default function EventTypePage({
const enteredDescription: string = descriptionRef.current.value; const enteredDescription: string = descriptionRef.current.value;
const enteredLength: number = parseInt(lengthRef.current.value); const enteredLength: number = parseInt(lengthRef.current.value);
const enteredIsHidden: boolean = isHiddenRef.current.checked; const enteredIsHidden: boolean = isHiddenRef.current.checked;
const enteredMinimumBookingNotice: number = parseInt(minimumBookingNoticeRef.current.value);
const enteredRequiresConfirmation: boolean = requiresConfirmationRef.current.checked; const enteredRequiresConfirmation: boolean = requiresConfirmationRef.current.checked;
const enteredEventName: string = eventNameRef.current.value; const enteredEventName: string = eventNameRef.current.value;
@ -200,14 +202,6 @@ export default function EventTypePage({
const enteredPeriodStartDate = periodStartDate ? periodStartDate.toDate() : null; const enteredPeriodStartDate = periodStartDate ? periodStartDate.toDate() : null;
const enteredPeriodEndDate = periodEndDate ? periodEndDate.toDate() : null; const enteredPeriodEndDate = periodEndDate ? periodEndDate.toDate() : null;
console.log("values", {
type,
periodDaysTypeRef,
enteredPeriodDays,
enteredPeriodDaysType,
enteredPeriodStartDate,
enteredPeriodEndDate,
});
// TODO: Add validation // TODO: Add validation
const payload: EventTypeInput = { const payload: EventTypeInput = {
@ -226,6 +220,7 @@ export default function EventTypePage({
periodStartDate: enteredPeriodStartDate, periodStartDate: enteredPeriodStartDate,
periodEndDate: enteredPeriodEndDate, periodEndDate: enteredPeriodEndDate,
periodCountCalendarDays: enteredPeriodDaysType, periodCountCalendarDays: enteredPeriodDaysType,
minimumBookingNotice: enteredMinimumBookingNotice,
requiresConfirmation: enteredRequiresConfirmation, requiresConfirmation: enteredRequiresConfirmation,
}; };
@ -671,6 +666,25 @@ export default function EventTypePage({
<fieldset className="my-8"> <fieldset className="my-8">
<Text variant="largetitle">When can people book this event?</Text> <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" /> <hr className="my-8" />
<section className="space-y-12"> <section className="space-y-12">
<div className="mb-4"> <div className="mb-4">
@ -1019,6 +1033,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ req, query
periodEndDate: true, periodEndDate: true,
periodCountCalendarDays: true, periodCountCalendarDays: true,
requiresConfirmation: true, requiresConfirmation: true,
minimumBookingNotice: true,
}, },
}); });

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "EventType" ADD COLUMN "minimumBookingNotice" INTEGER NOT NULL DEFAULT 120;

View file

@ -31,6 +31,7 @@ model EventType {
periodDays Int? periodDays Int?
periodCountCalendarDays Boolean? periodCountCalendarDays Boolean?
requiresConfirmation Boolean @default(false) requiresConfirmation Boolean @default(false)
minimumBookingNotice Int @default(120)
} }
model Credential { model Credential {