Functionality works, only thing left is a bit of cleaning up and all done
This commit is contained in:
parent
03f583b021
commit
9d5186f1e3
12 changed files with 317 additions and 269 deletions
|
@ -1,100 +0,0 @@
|
|||
import {ClockIcon} from "@heroicons/react/outline";
|
||||
import {useRef} from "react";
|
||||
|
||||
export default function SetTimesModal(props) {
|
||||
|
||||
const isNew = props.isNew || false;
|
||||
const {startDate, endDate} = props.schedule;
|
||||
|
||||
const startHoursRef = useRef<HTMLInputElement>();
|
||||
const startMinsRef = useRef<HTMLInputElement>();
|
||||
const endHoursRef = useRef<HTMLInputElement>();
|
||||
const endMinsRef = useRef<HTMLInputElement>();
|
||||
|
||||
function updateStartEndTimesHandler(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);
|
||||
|
||||
props.onChange({
|
||||
startDate: startDate.minute(enteredStartMins).hour(enteredStartHours),
|
||||
endDate: endDate.minute(enteredEndMins).hour(enteredEndHours),
|
||||
});
|
||||
|
||||
props.onExit(0);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed z-10 inset-0 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
|
||||
<div
|
||||
className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
|
||||
<div className="sm:flex sm:items-start mb-4">
|
||||
<div
|
||||
className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ClockIcon className="h-6 w-6 text-blue-600"/>
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
Change when you are available for bookings
|
||||
</h3>
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">
|
||||
Set your work schedule
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={updateStartEndTimesHandler} noValidate>
|
||||
<div className="flex mb-4">
|
||||
<label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">Start time</label>
|
||||
<div>
|
||||
<label htmlFor="startHours" className="sr-only">Hours</label>
|
||||
<input ref={startHoursRef} type="number" min="0" max="23" maxLength="2" name="hours" id="startHours"
|
||||
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
placeholder="9" defaultValue={startDate.format('H')} />
|
||||
</div>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="startMinutes" className="sr-only">Minutes</label>
|
||||
<input ref={startMinsRef} type="number" min="0" max="59" step="15" maxLength="2" name="minutes" id="startMinutes"
|
||||
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={startDate.format('m')} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">End time</label>
|
||||
<div>
|
||||
<label htmlFor="endHours" className="sr-only">Hours</label>
|
||||
<input ref={endHoursRef} type="number" min="0" max="23" maxLength="2" name="hours" id="endHours"
|
||||
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
placeholder="17" defaultValue={endDate.format('H')} />
|
||||
</div>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="endMinutes" className="sr-only">Minutes</label>
|
||||
<input ref={endMinsRef} type="number" min="0" max="59" maxLength="2" step="15" name="minutes" id="endMinutes"
|
||||
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={endDate.format('m')} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
<button onClick={props.onExit} type="button" className="btn btn-white mr-2">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import React, {useEffect, useState} from "react";
|
||||
import TimezoneSelect from "react-timezone-select";
|
||||
import {PencilAltIcon, TrashIcon} from "@heroicons/react/outline";
|
||||
import {WeekdaySelect} from "./WeekdaySelect";
|
||||
import SetTimesModal from "../modal/SetTimesModal";
|
||||
import {WeekdaySelect, Weekday} from "./WeekdaySelect";
|
||||
import SetTimesModal from "./modal/SetTimesModal";
|
||||
import Schedule from '../../lib/schedule.model';
|
||||
import dayjs, {Dayjs} from "dayjs";
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
|
@ -12,44 +12,45 @@ dayjs.extend(timezone);
|
|||
|
||||
export const Scheduler = (props) => {
|
||||
|
||||
const [ showSetTimesModal, setShowSetTimesModal ]: boolean = useState(false);
|
||||
const [ schedules, setSchedules ]: Schedule[] = useState(
|
||||
props.schedules.map( (schedule, idx) => ({
|
||||
startDate: dayjs(schedule.startDate),
|
||||
endDate: dayjs(schedule.startDate).startOf('day').add(schedule.length, 'minutes'),
|
||||
key: idx
|
||||
}) )
|
||||
);
|
||||
const [ schedules, setSchedules ]: Schedule[] = useState(props.schedules.map( schedule => {
|
||||
const startDate = schedule.isOverride ? dayjs(schedule.startDate) : dayjs.utc().startOf('day').add(schedule.startTime, 'minutes')
|
||||
return (
|
||||
{
|
||||
days: schedule.days,
|
||||
startDate,
|
||||
endDate: startDate.add(schedule.length, 'minutes')
|
||||
}
|
||||
)
|
||||
}));
|
||||
|
||||
const [ timeZone, setTimeZone ] = useState(props.timeZone);
|
||||
const [ selectedSchedule, setSelectedSchedule ]: Schedule | null = useState(null);
|
||||
const [ editSchedule, setEditSchedule ] = useState(-1);
|
||||
|
||||
const addNewSchedule = () => {
|
||||
setSelectedSchedule({
|
||||
startDate: dayjs().startOf('day').add(0, 'minutes'),
|
||||
endDate: dayjs().startOf('day').add(1439, 'minutes'),
|
||||
});
|
||||
setShowSetTimesModal(true);
|
||||
useEffect( () => {
|
||||
props.onChange(schedules);
|
||||
}, [schedules])
|
||||
|
||||
const addNewSchedule = () => setEditSchedule(schedules.length);
|
||||
|
||||
const applyEditSchedule = (changed: Schedule) => {
|
||||
const replaceWith = {
|
||||
...schedules[editSchedule],
|
||||
...changed
|
||||
};
|
||||
schedules.splice(editSchedule, 1, replaceWith);
|
||||
setSchedules([].concat(schedules));
|
||||
}
|
||||
|
||||
const upsertSchedule = (changed: Schedule) => {
|
||||
if (changed.key) {
|
||||
schedules.splice(
|
||||
schedules.findIndex( (schedule) => changed.key === schedule.key ), 1, changed
|
||||
)
|
||||
setSchedules([].concat(schedules)); // update
|
||||
}
|
||||
else {
|
||||
console.log(changed);
|
||||
setSchedules(schedules.concat([changed])); // insert
|
||||
}
|
||||
}
|
||||
|
||||
const removeSchedule = (toRemove: Schedule) => {
|
||||
schedules.splice(schedules.findIndex( (schedule) => schedule.key === toRemove.key ), 1);
|
||||
const removeScheduleAt = (toRemove: number) => {
|
||||
schedules.splice(toRemove, 1);
|
||||
setSchedules([].concat(schedules));
|
||||
};
|
||||
|
||||
const setWeekdays = (idx: number, days: number[]) => {
|
||||
schedules[idx].days = days;
|
||||
setSchedules([].concat(schedules));
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="rounded border flex">
|
||||
|
@ -63,15 +64,15 @@ export const Scheduler = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
{schedules.length > 0 && schedules.map( (schedule) =>
|
||||
<li key={schedule.key} className="py-2 flex justify-between border-t">
|
||||
{schedules.map( (schedule, idx) =>
|
||||
<li key={idx} className="py-2 flex justify-between border-t">
|
||||
<div className="inline-flex ml-2">
|
||||
<WeekdaySelect />
|
||||
<button className="ml-2 text-sm px-2" type="button" onClick={() => { setSelectedSchedule(schedule); setShowSetTimesModal(true) }}>
|
||||
<WeekdaySelect defaultValue={schedules[idx].days} onSelect={(days: number[]) => setWeekdays(idx, days)} />
|
||||
<button className="ml-2 text-sm px-2" type="button" onClick={() => setEditSchedule(idx)}>
|
||||
{schedule.startDate.format(schedule.startDate.minute() === 0 ? 'ha' : 'h:mma')} until {schedule.endDate.format(schedule.endDate.minute() === 0 ? 'ha' : 'h:mma')}
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" onClick={() => removeSchedule(schedule)}
|
||||
<button type="button" onClick={() => removeScheduleAt(idx)}
|
||||
className="btn-sm bg-transparent px-2 py-1 ml-1">
|
||||
<TrashIcon className="h-6 w-6 inline text-gray-400 -mt-1" />
|
||||
</button>
|
||||
|
@ -88,10 +89,10 @@ export const Scheduler = (props) => {
|
|||
<button className="btn-sm btn-white">Add a date override</button>*/}
|
||||
</div>
|
||||
</div>
|
||||
{showSetTimesModal &&
|
||||
<SetTimesModal schedule={selectedSchedule}
|
||||
onChange={upsertSchedule}
|
||||
onExit={() => setShowSetTimesModal(false)} />
|
||||
{editSchedule >= 0 &&
|
||||
<SetTimesModal schedule={schedules[editSchedule]}
|
||||
onChange={applyEditSchedule}
|
||||
onExit={() => setEditSchedule(-1)} />
|
||||
}
|
||||
{/*{showDateOverrideModal &&
|
||||
<DateOverrideModal />
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import React, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
|
||||
export const WeekdaySelect = (props) => {
|
||||
|
||||
const [ activeDays, setActiveDays ] = useState([false, true, true, true, true, true, false]);
|
||||
const [ activeDays, setActiveDays ] = useState([1,2,3,4,5,6,7].map( (v) => (props.defaultValue || []).indexOf(v) !== -1));
|
||||
const days = [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ];
|
||||
|
||||
useEffect( () => {
|
||||
props.onSelect(activeDays.map( (isActive, idx) => isActive ? idx + 1 : 0).filter( (v) => 0 !== v ));
|
||||
}, [activeDays]);
|
||||
|
||||
const toggleDay = (e, idx: number) => {
|
||||
e.preventDefault();
|
||||
activeDays[idx] = !activeDays[idx];
|
||||
console.log(activeDays);
|
||||
setActiveDays([].concat(activeDays));
|
||||
}
|
||||
|
||||
|
|
101
components/ui/modal/SetTimesModal.tsx
Normal file
101
components/ui/modal/SetTimesModal.tsx
Normal file
|
@ -0,0 +1,101 @@
|
|||
import {ClockIcon} from "@heroicons/react/outline";
|
||||
import {useRef} from "react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export default function SetTimesModal(props) {
|
||||
|
||||
const {startDate, endDate} = props.schedule || {
|
||||
startDate: dayjs().startOf('day').add(540, 'minutes'),
|
||||
endDate: dayjs().startOf('day').add(1020, 'minutes'),
|
||||
};
|
||||
|
||||
const startHoursRef = useRef<HTMLInputElement>();
|
||||
const startMinsRef = useRef<HTMLInputElement>();
|
||||
const endHoursRef = useRef<HTMLInputElement>();
|
||||
const endMinsRef = useRef<HTMLInputElement>();
|
||||
|
||||
function updateStartEndTimesHandler(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);
|
||||
|
||||
props.onChange({
|
||||
startDate: startDate.minute(enteredStartMins).hour(enteredStartHours),
|
||||
endDate: endDate.minute(enteredEndMins).hour(enteredEndHours),
|
||||
});
|
||||
|
||||
props.onExit(0);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed z-10 inset-0 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
|
||||
<div
|
||||
className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
|
||||
<div className="sm:flex sm:items-start mb-4">
|
||||
<div
|
||||
className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ClockIcon className="h-6 w-6 text-blue-600"/>
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
Change when you are available for bookings
|
||||
</h3>
|
||||
<div>
|
||||
<p className="text-sm text-gray-500">
|
||||
Set your work schedule
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex mb-4">
|
||||
<label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">Start time</label>
|
||||
<div>
|
||||
<label htmlFor="startHours" className="sr-only">Hours</label>
|
||||
<input ref={startHoursRef} type="number" min="0" max="23" maxLength="2" name="hours" id="startHours"
|
||||
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
placeholder="9" defaultValue={startDate.format('H')} />
|
||||
</div>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="startMinutes" className="sr-only">Minutes</label>
|
||||
<input ref={startMinsRef} type="number" min="0" max="59" step="15" maxLength="2" name="minutes" id="startMinutes"
|
||||
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={startDate.format('m')} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<label className="w-1/4 pt-2 block text-sm font-medium text-gray-700">End time</label>
|
||||
<div>
|
||||
<label htmlFor="endHours" className="sr-only">Hours</label>
|
||||
<input ref={endHoursRef} type="number" min="0" max="23" maxLength="2" name="hours" id="endHours"
|
||||
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
placeholder="17" defaultValue={endDate.format('H')} />
|
||||
</div>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="endMinutes" className="sr-only">Minutes</label>
|
||||
<input ref={endMinsRef} type="number" min="0" max="59" maxLength="2" step="15" name="minutes" id="endMinutes"
|
||||
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={endDate.format('m')} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<button onClick={updateStartEndTimesHandler} type="submit" className="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
<button onClick={props.onExit} type="button" className="btn btn-white mr-2">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import {Dayjs} from "dayjs";
|
||||
|
||||
export default interface Schedule {
|
||||
key: number;
|
||||
id: number | null;
|
||||
startDate: Dayjs;
|
||||
endDate: Dayjs;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../lib/prisma';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getSession({req: req});
|
||||
|
||||
if (!session) {
|
||||
res.status(401).json({message: "Not authenticated"});
|
||||
return;
|
||||
}
|
||||
|
||||
PUT /api/availability/schedule/{id}/timezone
|
||||
{
|
||||
"timeZone": "Europe/London"
|
||||
}
|
||||
|
||||
PATCH /api/availability/schedule {
|
||||
"schedules": [
|
||||
{
|
||||
|
||||
}
|
||||
],
|
||||
"overrides": {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (req.method == "PATCH") {
|
||||
const startMins = req.body.start;
|
||||
const endMins = req.body.end;
|
||||
|
||||
const updateDay = await prisma.schedule.update({
|
||||
where: {
|
||||
id: session.user.id,
|
||||
},
|
||||
data: {
|
||||
startTime: startMins,
|
||||
endTime: endMins
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200).json({message: 'Start and end times updated successfully'});
|
||||
}
|
||||
}
|
69
pages/api/availability/schedule/[eventtype].ts
Normal file
69
pages/api/availability/schedule/[eventtype].ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
const session = await getSession({req});
|
||||
if (!session) {
|
||||
res.status(401).json({message: "Not authenticated"});
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method == "PUT") {
|
||||
|
||||
const openingHours = req.body.openingHours || [];
|
||||
const overrides = req.body.overrides || [];
|
||||
|
||||
const removeSchedule = await prisma.schedule.deleteMany({
|
||||
where: {
|
||||
eventTypeId: +req.query.eventtype,
|
||||
}
|
||||
})
|
||||
|
||||
const updateSchedule = Promise.all(openingHours.map( (schedule) => prisma.schedule.create({
|
||||
data: {
|
||||
eventTypeId: +req.query.eventtype,
|
||||
days: schedule.days,
|
||||
startTime: schedule.startTime,
|
||||
length: schedule.endTime - schedule.startTime,
|
||||
},
|
||||
})))
|
||||
.catch( (error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
res.status(200).json({message: 'Created schedule'});
|
||||
|
||||
/*if (req.method == "PATCH") {
|
||||
const openingHours = req.body.openingHours || [];
|
||||
const overrides = req.body.overrides || [];
|
||||
|
||||
openingHours.forEach( (schedule) => {
|
||||
const updateSchedule = await prisma.schedule.update({
|
||||
where: {
|
||||
id: req.body.id,
|
||||
},
|
||||
data: {
|
||||
eventTypeId: req.query.eventtype,
|
||||
days: req.body.days,
|
||||
startTime: 333,
|
||||
endTime: 540 - req.body.startTime,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
overrides.forEach( (schedule) => {
|
||||
const updateSchedule = await prisma.schedule.update({
|
||||
where: {
|
||||
id: req.body.id,
|
||||
},
|
||||
data: {
|
||||
eventTypeId: req.query.eventtype,
|
||||
startDate: req.body.startDate,
|
||||
length: 540,
|
||||
},
|
||||
});
|
||||
});*/
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import prisma from '../../../lib/prisma';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { user } = req.query
|
||||
|
||||
const schedules = await prisma.schedule.find({
|
||||
where: {
|
||||
eventTypeId: req.query.type,
|
||||
},
|
||||
select: {
|
||||
credentials: true,
|
||||
timeZone: true
|
||||
}
|
||||
});
|
||||
|
||||
return res.status(202).send(null);
|
||||
}
|
|
@ -29,6 +29,7 @@ export default function EventType(props) {
|
|||
const [ showLocationModal, setShowLocationModal ] = useState(false);
|
||||
const [ selectedLocation, setSelectedLocation ] = useState<OptionBase | undefined>(undefined);
|
||||
const [ locations, setLocations ] = useState(props.eventType.locations || []);
|
||||
const [ schedule, setSchedule ] = useState(undefined);
|
||||
|
||||
const titleRef = useRef<HTMLInputElement>();
|
||||
const slugRef = useRef<HTMLInputElement>();
|
||||
|
@ -40,8 +41,6 @@ export default function EventType(props) {
|
|||
return <p className="text-gray-400">Loading...</p>;
|
||||
}
|
||||
|
||||
console.log(props);
|
||||
|
||||
async function updateEventTypeHandler(event) {
|
||||
event.preventDefault();
|
||||
|
||||
|
@ -60,6 +59,31 @@ export default function EventType(props) {
|
|||
}
|
||||
});
|
||||
|
||||
if (schedule) {
|
||||
|
||||
let schedulePayload = { "overrides": [], "timeZone": props.user.timeZone, "openingHours": [] };
|
||||
schedule.forEach( (item) => {
|
||||
if (item.isOverride) {
|
||||
delete item.isOverride;
|
||||
schedulePayload.overrides.push(item);
|
||||
} else {
|
||||
schedulePayload.openingHours.push({
|
||||
days: item.days,
|
||||
startTime: item.startDate.hour() * 60 + item.startDate.minute(),
|
||||
endTime: item.endDate.hour() * 60 + item.endDate.minute()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch('/api/availability/schedule/' + props.eventType.id, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(schedulePayload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
router.push('/availability');
|
||||
}
|
||||
|
||||
|
@ -262,16 +286,16 @@ export default function EventType(props) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr className="my-4"/>
|
||||
<div>
|
||||
<h3 className="mb-2">How do you want to offer your availability for this event type?</h3>
|
||||
<Scheduler timeZone={props.user.timeZone} schedules={props.schedules} />
|
||||
<div className="py-4 flex justify-end">
|
||||
<Link href="/availability"><a className="mr-2 btn btn-white">Cancel</a></Link>
|
||||
<button type="submit" className="btn btn-primary">Update</button>
|
||||
<hr className="my-4"/>
|
||||
<div>
|
||||
<h3 className="mb-2">How do you want to offer your availability for this event type?</h3>
|
||||
<Scheduler onChange={setSchedule} timeZone={props.user.timeZone} schedules={props.schedules} />
|
||||
<div className="py-4 flex justify-end">
|
||||
<Link href="/availability"><a className="mr-2 btn btn-white">Cancel</a></Link>
|
||||
<button type="submit" className="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -340,52 +364,63 @@ export default function EventType(props) {
|
|||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await getSession(context);
|
||||
if (!session) {
|
||||
return { redirect: { permanent: false, destination: '/auth/login' } };
|
||||
const session = await getSession(context);
|
||||
if (!session) {
|
||||
return { redirect: { permanent: false, destination: '/auth/login' } };
|
||||
}
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: session.user.email,
|
||||
},
|
||||
select: {
|
||||
username: true,
|
||||
timeZone: true,
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
}
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: session.user.email,
|
||||
},
|
||||
select: {
|
||||
username: true,
|
||||
timeZone: true,
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const eventType = await prisma.eventType.findUnique({
|
||||
where: {
|
||||
id: parseInt(context.query.type),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
description: true,
|
||||
length: true,
|
||||
hidden: true,
|
||||
locations: true,
|
||||
}
|
||||
});
|
||||
const eventType = await prisma.eventType.findUnique({
|
||||
where: {
|
||||
id: parseInt(context.query.type),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
description: true,
|
||||
length: true,
|
||||
hidden: true,
|
||||
locations: true,
|
||||
}
|
||||
});
|
||||
|
||||
const utcOffset = dayjs().tz(user.timeZone).utcOffset();
|
||||
let schedules = await prisma.schedule.findMany({
|
||||
where: {
|
||||
eventTypeId: parseInt(context.query.type),
|
||||
},
|
||||
});
|
||||
|
||||
const schedules = [
|
||||
{
|
||||
key: 0,
|
||||
startDate: dayjs.utc().startOf('day').add(user.startTime - utcOffset, 'minutes').format(),
|
||||
length: user.endTime,
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
props: {
|
||||
user,
|
||||
eventType,
|
||||
schedules
|
||||
if (!schedules.length) {
|
||||
schedules = await prisma.schedule.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
if (!schedules.length) {
|
||||
schedules.push({
|
||||
days: [ 1, 2, 3, 4, 5, 6, 7 ],
|
||||
startTime: user.startTime,
|
||||
length: user.endTime >= 1440 ? 1439 : user.endTime,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
user,
|
||||
eventType,
|
||||
schedules
|
||||
},
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ model EventType {
|
|||
user User? @relation(fields: [userId], references: [id])
|
||||
userId Int?
|
||||
bookings Booking[]
|
||||
availability Interval[]
|
||||
availability Schedule[]
|
||||
}
|
||||
|
||||
model Credential {
|
||||
|
@ -50,7 +50,7 @@ model User {
|
|||
credentials Credential[]
|
||||
teams Membership[]
|
||||
bookings Booking[]
|
||||
availability Interval[]
|
||||
availability Schedule[]
|
||||
|
||||
@@map(name: "users")
|
||||
}
|
||||
|
@ -124,14 +124,16 @@ model Booking {
|
|||
updatedAt DateTime?
|
||||
}
|
||||
|
||||
model Interval {
|
||||
id Int @default(autoincrement()) @id
|
||||
model Schedule {
|
||||
id Int @default(autoincrement()) @id
|
||||
label String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId Int?
|
||||
eventType EventType? @relation(fields: [eventTypeId], references: [id])
|
||||
eventType EventType? @relation(fields: [eventTypeId], references: [id])
|
||||
eventTypeId Int?
|
||||
startTime DateTime
|
||||
days Int[]
|
||||
startTime Int?
|
||||
startDate DateTime? @db.Timestamptz(3)
|
||||
length Int
|
||||
isOverride Boolean @default(false)
|
||||
isOverride Boolean @default(false)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue