upd
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useEffect, useState } from "react";
|
||||
import Timeline from "./Timeline";
|
||||
import { format, setHours, startOfDay } from "date-fns";
|
||||
// import useEventStore from "../stores/useEventStore";
|
||||
import Button from "./Button";
|
||||
import CloseIcon from "./icons/CloseIcon";
|
||||
import Input from "./Input";
|
||||
import Label from "./Label";
|
||||
import api from "../utils/api";
|
||||
import useStore from "../stores/useStore";
|
||||
|
||||
interface Props {
|
||||
slots: number;
|
||||
events: any[];
|
||||
}
|
||||
|
||||
function Schedule({ slots, events }: Props) {
|
||||
const { selectedBuild } = useStore();
|
||||
const [draftMode, setDraftMode] = useState<boolean>(false);
|
||||
const [slot, setSlot] = useState<number>();
|
||||
const [startAt, setStartAt] = useState<Date>();
|
||||
const [duration, setDuration] = useState<number>();
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [name, setName] = useState<string>("");
|
||||
const [phone, setPhone] = useState<string>("");
|
||||
|
||||
function handleChangeSlot(slot: number) {
|
||||
setSlot(slot);
|
||||
}
|
||||
|
||||
function handleChangeDraftMode(draftMode: boolean) {
|
||||
setDraftMode(draftMode);
|
||||
}
|
||||
|
||||
function handleChangeStartAt(startAt: Date) {
|
||||
setStartAt(startAt);
|
||||
}
|
||||
|
||||
function handleChangeDuration(duration: number) {
|
||||
setDuration(duration);
|
||||
}
|
||||
|
||||
async function handleClickSave() {
|
||||
if (!slot || !startAt || !duration) return;
|
||||
|
||||
await addSchesuledSession();
|
||||
|
||||
// setEvents([
|
||||
// ...events,
|
||||
// {
|
||||
// slot,
|
||||
// startAt,
|
||||
// endAt: addMinutes(startAt, duration),
|
||||
// },
|
||||
// ]);
|
||||
|
||||
setDraftMode(false);
|
||||
}
|
||||
|
||||
function handleClickCancel() {
|
||||
setDraftMode(false);
|
||||
}
|
||||
|
||||
async function addSchesuledSession() {
|
||||
// setIsLoading(true);
|
||||
|
||||
try {
|
||||
await api
|
||||
.post(`scheduled_sessions`, {
|
||||
json: {
|
||||
buildId: selectedBuild?.id,
|
||||
slot,
|
||||
startAt,
|
||||
duration,
|
||||
client: {
|
||||
email,
|
||||
phone,
|
||||
name,
|
||||
},
|
||||
},
|
||||
})
|
||||
.json();
|
||||
} catch (error) {
|
||||
alert((error as Error).message);
|
||||
}
|
||||
|
||||
// setIsLoading(false);
|
||||
// setModal(null);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("events", events);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative h-screen overflow-y-auto bg-[#F2F2F2] text-sm">
|
||||
<div className="fixed z-10 flex">
|
||||
<div className="bg-white h-10 w-[84px] flex items-center justify-center border-r border-b border-[#DAE0E5]">
|
||||
<p className="font-semibold">{format(new Date(), "HH:mm")}</p>
|
||||
</div>
|
||||
<div className="flex">
|
||||
{slots &&
|
||||
Array.from({ length: slots }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="border-r border-b border-[#DAE0E5] w-[264px] h-10 flex items-center pl-3 bg-[#F0F1F2]"
|
||||
>
|
||||
<p className="font-semibold">Слот {index + 1}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex mt-10">
|
||||
<div className="">
|
||||
{Array.from({ length: 24 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center justify-center h-[180px] w-[84px] border-r border-b border-[#DAE0E5]"
|
||||
>
|
||||
<p className="font-semibold">
|
||||
{format(setHours(startOfDay(new Date()), index), "HH:mm")}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{slots &&
|
||||
Array.from({ length: slots }).map((_, index) => (
|
||||
<Timeline
|
||||
key={index}
|
||||
slot={index + 1}
|
||||
timelineEvents={events.filter(
|
||||
(event) => event.slot === index + 1
|
||||
)}
|
||||
draftMode={draftMode}
|
||||
onChangeSlot={handleChangeSlot}
|
||||
onChangeDraftMode={handleChangeDraftMode}
|
||||
onChangeStartAt={handleChangeStartAt}
|
||||
onChangeDuration={handleChangeDuration}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{draftMode && startAt && (
|
||||
<div className="fixed top-0 right-0 flex flex-col justify-between h-screen overflow-y-auto bg-white shadow w-[320px]">
|
||||
<div className="space-y-4">
|
||||
<div className="p-2 pl-4 flex items-center justify-between border-b border-[#DAE0E5]">
|
||||
<p className="font-semibold">Запланировать демонстрацию</p>
|
||||
<Button
|
||||
color="tertiary"
|
||||
icon={<CloseIcon />}
|
||||
onlyIcon
|
||||
handleClick={handleClickCancel}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-4 space-y-2">
|
||||
<p className="font-semibold">Демонстрация</p>
|
||||
<div className="">
|
||||
<div className="grid items-center grid-cols-2 gap-4 py-1 text-xs">
|
||||
<p className="text-[#77828C]">Дата и время</p>
|
||||
<p className="">{format(startAt, "dd.MM.yyyy HH:mm")}</p>
|
||||
</div>
|
||||
<div className="grid items-center grid-cols-2 gap-4 py-1 text-xs">
|
||||
<p className="text-[#77828C]">Длительность сеанса</p>
|
||||
<p className="">{duration} мин.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-4 space-y-2">
|
||||
<p className="font-semibold">Клиент</p>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<Label value="Email" />
|
||||
<Input
|
||||
type="email"
|
||||
className="w-full h-10"
|
||||
value={email}
|
||||
handleChange={(value) => setEmail(value)}
|
||||
/>
|
||||
<span className="text-[#77828C] text-xs">
|
||||
На указанный почтовый адрес придет необходимая для
|
||||
подключения информация
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label value="Телефон" />
|
||||
<Input
|
||||
type="tel"
|
||||
className="w-full h-10"
|
||||
value={phone}
|
||||
handleChange={(value) => setPhone(value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label value="Имя" />
|
||||
<Input
|
||||
className="w-full h-10"
|
||||
value={name}
|
||||
handleChange={(value) => setName(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 p-4">
|
||||
<Button type="submit" handleClick={handleClickSave}>
|
||||
Запланировать
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
color="secondary"
|
||||
handleClick={handleClickCancel}
|
||||
>
|
||||
Отмена
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Schedule;
|
||||
@@ -0,0 +1,203 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useState, MouseEvent, useEffect, useRef } from "react";
|
||||
import TimelineSlot from "./TimelineSlot";
|
||||
import { addMinutes, differenceInMinutes, format, startOfDay } from "date-fns";
|
||||
import Button from "./Button";
|
||||
|
||||
interface Props {
|
||||
timelineEvents: any[];
|
||||
slot: number;
|
||||
draftMode: boolean;
|
||||
onChangeDraftMode: (draftMode: boolean) => void;
|
||||
onChangeStartAt: (startAt: Date) => void;
|
||||
onChangeDuration: (duration: number) => void;
|
||||
onChangeSlot: (slot: number) => void;
|
||||
}
|
||||
|
||||
const timelineSlotHeight = 180;
|
||||
const minutePx = timelineSlotHeight / 60;
|
||||
|
||||
function Timeline({
|
||||
timelineEvents,
|
||||
slot,
|
||||
draftMode,
|
||||
onChangeDraftMode,
|
||||
onChangeStartAt,
|
||||
onChangeDuration,
|
||||
onChangeSlot,
|
||||
}: Props) {
|
||||
const [pressed, setPressed] = useState(false);
|
||||
const [startPosY, setStartPosY] = useState<number>();
|
||||
const [currentPosY, setCurrentPosY] = useState<number>();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [startAt, setStartAt] = useState<string>();
|
||||
const [duration, setDuration] = useState<number>(30); // min
|
||||
|
||||
function handleMouseDown(e: MouseEvent<HTMLDivElement>) {
|
||||
if (draftMode) return;
|
||||
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
const y = e.clientY - rect.top;
|
||||
const roundedY = Math.floor(y / (minutePx * 10)) * (minutePx * 10);
|
||||
|
||||
ref.current!.style.top = `${roundedY}px`;
|
||||
|
||||
setStartPosY(roundedY);
|
||||
setCurrentPosY(roundedY + minutePx * duration);
|
||||
setPressed(true);
|
||||
|
||||
if (!duration) {
|
||||
setDuration(30);
|
||||
}
|
||||
|
||||
setStartAt(
|
||||
addMinutes(startOfDay(new Date()), roundedY / minutePx).toISOString()
|
||||
);
|
||||
|
||||
onChangeSlot(slot);
|
||||
}
|
||||
|
||||
function handleMouseMove(e: MouseEvent) {
|
||||
if (!pressed || startPosY === undefined) return;
|
||||
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
const y = e.clientY - rect.top;
|
||||
|
||||
// if (y < startPosY + minutePx * 30) return;
|
||||
|
||||
// if (y < startPosY + minutePx * 30) return;
|
||||
|
||||
if (y < startPosY + minutePx * 30) {
|
||||
setDuration(30);
|
||||
} else {
|
||||
const roundedY =
|
||||
Math.round((y - startPosY) / (minutePx * 10)) * (minutePx * 10);
|
||||
|
||||
setCurrentPosY(y);
|
||||
setDuration(roundedY / minutePx);
|
||||
|
||||
ref.current!.style.height = `${roundedY}px`;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseUp() {
|
||||
if (!pressed) return;
|
||||
|
||||
setPressed(false);
|
||||
onChangeDraftMode(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!startPosY) return;
|
||||
|
||||
console.log("startPosY", startPosY);
|
||||
}, [startPosY]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentPosY) return;
|
||||
|
||||
console.log("currentPosY", currentPosY);
|
||||
}, [currentPosY]);
|
||||
|
||||
// useEffect(() => {
|
||||
// setTimelineEvents(
|
||||
// timelineEvents.filter((event: IEvent) => event.slot === slot)
|
||||
// );
|
||||
// }, [timelineEvents]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("startAt", startAt);
|
||||
|
||||
if (!startAt) return;
|
||||
|
||||
onChangeStartAt(new Date(startAt));
|
||||
}, [startAt]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!duration || !ref.current) return;
|
||||
|
||||
if (ref.current.clientHeight === 0) {
|
||||
ref.current.style.height = `${minutePx * 30}px`;
|
||||
}
|
||||
|
||||
onChangeDuration(duration);
|
||||
}, [duration]);
|
||||
|
||||
useEffect(() => {
|
||||
if (draftMode || !ref.current) return;
|
||||
|
||||
setStartAt(undefined);
|
||||
setDuration(0);
|
||||
ref.current.style.height = "0px";
|
||||
console.log(ref.current.clientHeight);
|
||||
}, [draftMode]);
|
||||
|
||||
return (
|
||||
<div className="relative text-xs select-none">
|
||||
<div
|
||||
className={`${pressed ? "cursor-move" : ""}`}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
>
|
||||
{Array.from({ length: 24 }).map((_, index) => (
|
||||
<TimelineSlot
|
||||
key={index}
|
||||
height={timelineSlotHeight}
|
||||
// date={setHours(setMinutes(new Date(), 0), index)}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div ref={ref} className="absolute w-full">
|
||||
{ref.current?.clientHeight !== 0 && (
|
||||
<div className="h-full bg-black/20 animate-pulse border border-[#DAE0E5] p-3">
|
||||
{startAt && format(new Date(startAt), "HH:mm")} -{" "}
|
||||
{startAt &&
|
||||
duration &&
|
||||
format(addMinutes(new Date(startAt), duration), "HH:mm")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{timelineEvents.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
data-type="event"
|
||||
className="absolute w-full bg-white border-b border-r border-[#DAE0E5] p-3"
|
||||
style={{
|
||||
top: `${
|
||||
differenceInMinutes(
|
||||
new Date(event.startAt),
|
||||
startOfDay(new Date(event.startAt))
|
||||
) * minutePx
|
||||
}px`,
|
||||
height: `${
|
||||
differenceInMinutes(
|
||||
new Date(event.endAt),
|
||||
new Date(event.startAt)
|
||||
) * minutePx
|
||||
}px`,
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<p>
|
||||
{format(new Date(event.startAt), "HH:mm")} -{" "}
|
||||
{format(new Date(event.endAt), "HH:mm")}
|
||||
</p>
|
||||
<a
|
||||
href={`https://stream.graff.tech/scheduled/${event.id}?admin=true`}
|
||||
target="_blank"
|
||||
className="self-end"
|
||||
>
|
||||
<Button className="">Начать</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Timeline;
|
||||
@@ -0,0 +1,14 @@
|
||||
interface Props {
|
||||
height: number; // px
|
||||
}
|
||||
|
||||
function TimelineSlot({ height }: Props) {
|
||||
return (
|
||||
<div
|
||||
style={{ height: `${height}px` }}
|
||||
className="border-r border-b border-[#DAE0E5] w-[264px]"
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TimelineSlot;
|
||||
@@ -9,26 +9,21 @@ import {
|
||||
isEqual,
|
||||
} from "date-fns";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Card from "../components/Card";
|
||||
import EmptyCard from "../components/EmptyCard";
|
||||
import TabButton from "../components/TabButton";
|
||||
import api from "../utils/api";
|
||||
import { ru } from "date-fns/locale";
|
||||
import { Transition } from "react-transition-group";
|
||||
import _ from "lodash";
|
||||
import useStore from "../stores/useStore";
|
||||
import useAuthStore from "../stores/useAuthStore";
|
||||
import Menu from "../components/Menu";
|
||||
import Button from "../components/Button";
|
||||
import Calendar from "../components/Calendar";
|
||||
import Managers from "../components/Managers";
|
||||
import Schedules from "../components/Schedules";
|
||||
import SpinnerIcon from "../components/icons/SpinnerIcon";
|
||||
import ModalContainer from "../components/ModalContainer";
|
||||
import ChevronLeftIcon from "../components/icons/ChevronLeftIcon";
|
||||
import ChevronRightIcon from "../components/icons/ChevronRightIcon";
|
||||
import IUser from "../types/IUser";
|
||||
import IError from "../types/IError";
|
||||
import Schedule from "../components/Schedule";
|
||||
|
||||
function DashboardPage() {
|
||||
const { user } = useAuthStore();
|
||||
@@ -46,16 +41,12 @@ function DashboardPage() {
|
||||
selectedDay,
|
||||
setSelectedDay,
|
||||
} = useStore();
|
||||
const [duration, setDuration] = useState<number>();
|
||||
const [, setDuration] = useState<number>();
|
||||
const [scheduledSessions, setScheduledSessions] = useState<any[]>();
|
||||
const [generatedScheduledSessions, setGeneratedScheduledSessions] =
|
||||
useState<any[]>();
|
||||
const [, setGeneratedScheduledSessions] = useState<any[]>();
|
||||
const [dateTimes, setDateTimes] = useState<Date[]>();
|
||||
const [currentTime, setCurrentTime] = useState<string>(
|
||||
format(new Date(), "HH:mm")
|
||||
);
|
||||
const [isLoadingScheduledSessions, setIsLoadingScheduledSessions] =
|
||||
useState(true);
|
||||
const [, setCurrentTime] = useState<string>(format(new Date(), "HH:mm"));
|
||||
const [, setIsLoadingScheduledSessions] = useState(true);
|
||||
const scheduledSessionsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
function selectNextDay() {
|
||||
@@ -231,33 +222,33 @@ function DashboardPage() {
|
||||
if (useLoader) setIsLoadingScheduledSessions(false);
|
||||
}
|
||||
|
||||
async function updateScheduledSessionManager(
|
||||
scheduledSessionId: string,
|
||||
managerId: string | null
|
||||
) {
|
||||
if (!company || !scheduledSessions) return;
|
||||
// async function updateScheduledSessionManager(
|
||||
// scheduledSessionId: string,
|
||||
// managerId: string | null
|
||||
// ) {
|
||||
// if (!company || !scheduledSessions) return;
|
||||
|
||||
try {
|
||||
const result: any = await api
|
||||
.put(
|
||||
`companies/${company.id}/scheduled_sessions/${scheduledSessionId}`,
|
||||
{
|
||||
json: { userId: managerId },
|
||||
}
|
||||
)
|
||||
.json();
|
||||
// try {
|
||||
// const result: any = await api
|
||||
// .put(
|
||||
// `companies/${company.id}/scheduled_sessions/${scheduledSessionId}`,
|
||||
// {
|
||||
// json: { userId: managerId },
|
||||
// }
|
||||
// )
|
||||
// .json();
|
||||
|
||||
setScheduledSessions(
|
||||
scheduledSessions.map((scheduledSession) =>
|
||||
scheduledSession.id === result.id ? result : scheduledSession
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
// setScheduledSessions(
|
||||
// scheduledSessions.map((scheduledSession) =>
|
||||
// scheduledSession.id === result.id ? result : scheduledSession
|
||||
// )
|
||||
// );
|
||||
// } catch (error) {
|
||||
// if (error instanceof Error) {
|
||||
// console.log("Error: ", error.message);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
async function getSchedules() {
|
||||
if (!company || !selectedBuild) return;
|
||||
@@ -316,8 +307,8 @@ function DashboardPage() {
|
||||
}, [selectedDay, selectedBuild]);
|
||||
|
||||
return (
|
||||
<div className="main h-screen flex">
|
||||
<div className="left flex flex-col w-full">
|
||||
<div className="flex h-screen main">
|
||||
<div className="flex flex-col w-full left">
|
||||
<div className="flex bg-[#F0F1F2]">
|
||||
<Menu />
|
||||
{builds?.map((build) => (
|
||||
@@ -358,7 +349,7 @@ function DashboardPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex bg-[#F2F2F2]">
|
||||
{/* <div className="flex bg-[#F2F2F2]">
|
||||
<div className="w-[84px] h-[40px] flex justify-center items-center text-sm font-semibold bg-white border-r border-b border-[#DAE0E5]">
|
||||
{currentTime}
|
||||
</div>
|
||||
@@ -371,9 +362,9 @@ function DashboardPage() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div
|
||||
{/* <div
|
||||
ref={scheduledSessionsRef}
|
||||
className={`overflow-y-auto overflow-x-hidden flex-1 bg-[#F2F2F2] border-r border-[#DAE0E5]`}
|
||||
>
|
||||
@@ -443,7 +434,14 @@ function DashboardPage() {
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
{selectedBuild?.sessionLimit && scheduledSessions && (
|
||||
<Schedule
|
||||
slots={selectedBuild.sessionLimit}
|
||||
events={scheduledSessions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="right w-[384px] flex flex-col">
|
||||
@@ -457,9 +455,9 @@ function DashboardPage() {
|
||||
Статистика
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto overflow-x-hidden">
|
||||
<div className="overflow-x-hidden overflow-y-auto">
|
||||
<Calendar />
|
||||
<Schedules />
|
||||
{/* <Schedules /> */}
|
||||
<Managers />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { create } from "zustand";
|
||||
import IEvent from "../types/IEvent";
|
||||
|
||||
interface EventState {
|
||||
events: IEvent[];
|
||||
setEvents: (events: IEvent[]) => void;
|
||||
}
|
||||
|
||||
const useEventStore = create<EventState>()((set) => ({
|
||||
events: [],
|
||||
setEvents: (events) => set({ events }),
|
||||
}));
|
||||
|
||||
export default useEventStore;
|
||||
@@ -0,0 +1,7 @@
|
||||
interface IEvent {
|
||||
slot: number;
|
||||
startAt: Date;
|
||||
endAt: Date;
|
||||
}
|
||||
|
||||
export default IEvent;
|
||||
@@ -16,10 +16,18 @@ const scheduledSessionSchema = new Schema(
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
},
|
||||
slot: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
startAt: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
endAt: {
|
||||
type: Date,
|
||||
required: true,
|
||||
|
||||
@@ -75,12 +75,12 @@ router.get("/:buildId", async (req, res) => {
|
||||
});
|
||||
|
||||
router.post("/", async (req, res) => {
|
||||
const { buildId, startAt, client, duration } = req.body;
|
||||
const { buildId, slot, startAt, client, duration } = req.body;
|
||||
|
||||
if (!buildId || !startAt) {
|
||||
if (!buildId || !startAt || !slot) {
|
||||
return res.json({
|
||||
status: "error",
|
||||
message: "Parameters `buildId`, `startAt` are required!", // Параметры `buildId`, `startAt` обязательны!
|
||||
message: "Parameters `buildId`, `startAt`, `slot` are required!", // Параметры `buildId`, `startAt`, `slot` обязательны!
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ router.post("/", async (req, res) => {
|
||||
if (duration) {
|
||||
const scheduledSessions = await ScheduledSession.find({
|
||||
buildId,
|
||||
slot,
|
||||
startAt: {
|
||||
$gte: startOfDay(startAtISO),
|
||||
$lte: endOfDay(startAtISO),
|
||||
@@ -141,7 +142,9 @@ router.post("/", async (req, res) => {
|
||||
|
||||
const scheduledSession = await ScheduledSession.create({
|
||||
buildId,
|
||||
slot,
|
||||
startAt: startAtISO,
|
||||
duration,
|
||||
endAt: endAtISO,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user