upd
This commit is contained in:
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
# VITE_API_URL=http://localhost:3001
|
# VITE_API_URL=http://localhost:3001
|
||||||
# VITE_API_URL=http://192.168.1.171:3001
|
VITE_API_URL=http://192.168.1.171:3001
|
||||||
VITE_API_URL=https://crm.stream.graff.tech/api
|
# VITE_API_URL=https://crm.stream.graff.tech/api
|
||||||
VITE_STREAM_URL=https://stream.graff.tech
|
VITE_STREAM_URL=https://stream.graff.tech
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-input/mask": "^1.2.5",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"ky": "^1.0.1",
|
"ky": "^1.0.1",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function Button({
|
|||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
type={type}
|
type={type}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className={`relative outline-none rounded-lg transition-all font-semibold flex justify-center items-center gap-1 disabled:bg-[#F2F2F2] disabled:text-[#CCCCCC] ${
|
className={`outline-none rounded-lg transition-all font-semibold flex justify-center items-center gap-1 disabled:bg-[#F2F2F2] disabled:text-[#CCCCCC] ${
|
||||||
(color === "primary" && "bg-[#49A1F5] text-white hover:bg-[#4190DB]") ||
|
(color === "primary" && "bg-[#49A1F5] text-white hover:bg-[#4190DB]") ||
|
||||||
(color === "secondary" &&
|
(color === "secondary" &&
|
||||||
"bg-[#F0F1F2] text-[#77828C] hover:bg-[#E6ECF2]") ||
|
"bg-[#F0F1F2] text-[#77828C] hover:bg-[#E6ECF2]") ||
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ interface CardProps {
|
|||||||
buildId: string;
|
buildId: string;
|
||||||
scheduledSessionId: string;
|
scheduledSessionId: string;
|
||||||
scheduleSessionStartAt: string;
|
scheduleSessionStartAt: string;
|
||||||
client: {
|
client?: {
|
||||||
name: string;
|
name: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -65,7 +65,7 @@ function Card({
|
|||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div className="">
|
<div className="">
|
||||||
<p className="text-[10px] font-semibold text-[#77828C]">Клиент</p>
|
<p className="text-[10px] font-semibold text-[#77828C]">Клиент</p>
|
||||||
<p className="text-sm">{client.name}</p>
|
<p className="text-sm">{client?.name || "Имя не указано"}</p>
|
||||||
</div>
|
</div>
|
||||||
{manager ? (
|
{manager ? (
|
||||||
<div className="bg-[#E6F2FE] rounded-full px-2 h-[20px] flex items-center gap-1">
|
<div className="bg-[#E6F2FE] rounded-full px-2 h-[20px] flex items-center gap-1">
|
||||||
@@ -85,10 +85,10 @@ function Card({
|
|||||||
</div>
|
</div>
|
||||||
<div className="border-b border-[#DAE0E5] pb-2">
|
<div className="border-b border-[#DAE0E5] pb-2">
|
||||||
<p className="text-xs text-[#77828C] leading-tight">
|
<p className="text-xs text-[#77828C] leading-tight">
|
||||||
{client.phone}
|
{client?.phone || "Телефон не указан"}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-[#77828C] leading-tight">
|
<p className="text-xs text-[#77828C] leading-tight">
|
||||||
{client.email}
|
{client?.email || "Email не указан"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ interface Props {
|
|||||||
|
|
||||||
function DatePicker({ defaultValue, startDate, onChange }: Props) {
|
function DatePicker({ defaultValue, startDate, onChange }: Props) {
|
||||||
const [value, setValue] = useState<Date>(
|
const [value, setValue] = useState<Date>(
|
||||||
startDate && isAfter(startOfDay(startDate), new Date())
|
(defaultValue && startOfDay(defaultValue)) ||
|
||||||
? startOfDay(startDate)
|
(startDate && startOfDay(startDate)) ||
|
||||||
: defaultValue || startOfDay(new Date())
|
startOfDay(new Date())
|
||||||
);
|
);
|
||||||
const [selectedMonth, setSelectedMonth] = useState(startOfMonth(value));
|
const [selectedMonth, setSelectedMonth] = useState(startOfMonth(value));
|
||||||
const [isShowCalendar, setIsShowCalendar] = useState<boolean>(false);
|
const [isShowCalendar, setIsShowCalendar] = useState<boolean>(false);
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ import Button from "./Button";
|
|||||||
import PlusIcon from "./icons/PlusIcon";
|
import PlusIcon from "./icons/PlusIcon";
|
||||||
import CreateScheduledSessionModal from "./modals/CreateScheduledSessionModal";
|
import CreateScheduledSessionModal from "./modals/CreateScheduledSessionModal";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
buildId: string;
|
||||||
|
startAt: Date;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyCard({ buildId, startAt, duration }: Props) {
|
||||||
function EmptyCard() {
|
|
||||||
const { setModal } = useModalStore();
|
const { setModal } = useModalStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -17,7 +21,11 @@ function EmptyCard() {
|
|||||||
className="group-hover:opacity-100 opacity-0"
|
className="group-hover:opacity-100 opacity-0"
|
||||||
handleClick={() =>
|
handleClick={() =>
|
||||||
setModal(
|
setModal(
|
||||||
<CreateScheduledSessionModal />
|
<CreateScheduledSessionModal
|
||||||
|
buildId={buildId}
|
||||||
|
startAt={startAt}
|
||||||
|
duration={duration}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
import { useMask } from "@react-input/mask";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
type?: "text" | "email" | "password" | "time";
|
type?: "text" | "email" | "password" | "time" | "tel";
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
@@ -24,16 +25,20 @@ function Input({
|
|||||||
handleChange,
|
handleChange,
|
||||||
handleFocus,
|
handleFocus,
|
||||||
}: InputProps) {
|
}: InputProps) {
|
||||||
const [value, setValue] = useState<string | undefined>(defaultValue);
|
const inputRef = useMask({
|
||||||
|
mask: "+7 (___) ___-__-__",
|
||||||
|
replacement: { _: /\d/ },
|
||||||
|
});
|
||||||
|
|
||||||
|
const [value, setValue] = useState<string>(defaultValue || "");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value && handleChange) {
|
handleChange && handleChange(value);
|
||||||
handleChange(value);
|
|
||||||
}
|
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
|
ref={type === "tel" ? inputRef : undefined}
|
||||||
type={type}
|
type={type}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
autoFocus={autoFocus}
|
autoFocus={autoFocus}
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import BurgerIcon from "./icons/BurgerIcon";
|
||||||
|
import { Transition } from "react-transition-group";
|
||||||
|
import BellIcon from "./icons/BellIcon";
|
||||||
|
import ParamsIcon from "./icons/ParamsIcon";
|
||||||
|
import WorkIcon from "./icons/WorkIcon";
|
||||||
|
import ExitIcon from "./icons/ExitIcon";
|
||||||
|
import useAuthStore from "../stores/useAuthStore";
|
||||||
|
|
||||||
|
function Menu() {
|
||||||
|
const [isShow, setIsShow] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const { user, setAccessToken } = useAuthStore();
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
setAccessToken(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsShow((prev) => !prev)}
|
||||||
|
className={`p-3 transition-colors relative z-20 ${
|
||||||
|
isShow ? "bg-[#49A1F5] text-white" : "hover:bg-neutral-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<BurgerIcon />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Transition in={isShow} timeout={150} mountOnEnter unmountOnExit>
|
||||||
|
{(state) => (
|
||||||
|
<div className={`transition-opacity ${state}`}>
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-10 z-10"></div>
|
||||||
|
<div className="absolute z-20 ml-2 mt-3.5">
|
||||||
|
<div className="relative">
|
||||||
|
<svg
|
||||||
|
width="12"
|
||||||
|
height="10"
|
||||||
|
viewBox="0 0 12 10"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="absolute -top-2.5 left-2.5 drop-shadow"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5.14251 1.42916C5.53091 0.781817 6.46909 0.781816 6.85749 1.42915L12 10H0L5.14251 1.42916Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<div className="relative w-[240px] bg-white rounded-lg shadow">
|
||||||
|
<div className="border-b border-[#DAE0E5] p-6 flex flex-col items-center justify-center gap-4">
|
||||||
|
<div className="rounded-full bg-[#E6ECF2] w-[88px] h-[88px] flex justify-center items-center">
|
||||||
|
<p className="text-2xl font-semibold ml-0.5 mt-0.5">{user?.name[0]}</p>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 text-center">
|
||||||
|
<p className="text-sm">{user?.name}</p>
|
||||||
|
<p className="text-[#77828C] text-xs">{user?.username}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-b border-[#DAE0E5] py-3 space-y-2">
|
||||||
|
<button
|
||||||
|
disabled
|
||||||
|
className="text-sm flex items-center gap-2 px-4 w-full hover:bg-[#E6ECF2] transition-colors disabled:hover:bg-inherit disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<span className="text-[#77828C] py-1">
|
||||||
|
<BellIcon />
|
||||||
|
</span>
|
||||||
|
Уведомления
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
disabled
|
||||||
|
className="text-sm flex items-center gap-2 px-4 w-full hover:bg-[#E6ECF2] transition-colors disabled:hover:bg-inherit disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<span className="text-[#77828C] py-1">
|
||||||
|
<ParamsIcon />
|
||||||
|
</span>
|
||||||
|
Настройки
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="border-b border-[#DAE0E5] py-2">
|
||||||
|
<button
|
||||||
|
disabled
|
||||||
|
className="text-sm flex items-center gap-2 px-4 w-full hover:bg-[#E6ECF2] transition-colors disabled:hover:bg-inherit disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<span className="text-[#77828C] py-1">
|
||||||
|
<WorkIcon />
|
||||||
|
</span>
|
||||||
|
Компания
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="py-2">
|
||||||
|
<button
|
||||||
|
onClick={logout}
|
||||||
|
className="text-sm flex items-center gap-2 px-4 w-full hover:bg-[#E6ECF2] transition-colors disabled:hover:bg-inherit disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<span className="text-[#77828C] py-1">
|
||||||
|
<ExitIcon />
|
||||||
|
</span>
|
||||||
|
Выход
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Menu;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
function BellIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M14.857 17.082L20 17C18.5094 15.3488 17.9967 11.9745 18 9.75V9.05V9C18 7.4087 17.3679 5.88258 16.2426 4.75736C15.1174 3.63214 13.5913 3 12 3C10.4087 3 8.88258 3.63214 7.75736 4.75736C6.63215 5.88258 6 7.4087 6 9V9.75C6.00302 11.9746 5.49099 15.431 4 17.082H9.143M14.857 17.082H9.143M14.857 17.082C15.0011 17.5319 15.0369 18.0094 14.9616 18.4757C14.8862 18.942 14.7018 19.384 14.4234 19.7656C14.1449 20.1472 13.7803 20.4576 13.3592 20.6716C12.9381 20.8856 12.4724 20.9972 12 20.9972C11.5276 20.9972 11.0619 20.8856 10.6408 20.6716C10.2197 20.4576 9.85508 20.1472 9.57662 19.7656C9.29817 19.384 9.11377 18.942 9.03842 18.4757C8.96307 18.0094 8.9989 17.5319 9.143 17.082"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BellIcon;
|
||||||
@@ -11,7 +11,7 @@ function BurgerIcon() {
|
|||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
clipRule="evenodd"
|
clipRule="evenodd"
|
||||||
d="M19 8H5C4.44772 8 4 7.55228 4 7C4 6.44772 4.44772 6 5 6L19 6C19.5523 6 20 6.44772 20 7C20 7.55228 19.5523 8 19 8ZM4 12C4 11.4477 4.44772 11 5 11H19C19.5523 11 20 11.4477 20 12C20 12.5523 19.5523 13 19 13H5C4.44772 13 4 12.5523 4 12ZM4 17C4 16.4477 4.44772 16 5 16H19C19.5523 16 20 16.4477 20 17C20 17.5523 19.5523 18 19 18H5C4.44772 18 4 17.5523 4 17Z"
|
d="M19 8H5C4.44772 8 4 7.55228 4 7C4 6.44772 4.44772 6 5 6L19 6C19.5523 6 20 6.44772 20 7C20 7.55228 19.5523 8 19 8ZM4 12C4 11.4477 4.44772 11 5 11H19C19.5523 11 20 11.4477 20 12C20 12.5523 19.5523 13 19 13H5C4.44772 13 4 12.5523 4 12ZM4 17C4 16.4477 4.44772 16 5 16H19C19.5523 16 20 16.4477 20 17C20 17.5523 19.5523 18 19 18H5C4.44772 18 4 17.5523 4 17Z"
|
||||||
fill="#111C26"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
function ExitIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.5 20L7 20C5.89543 20 5 19.1046 5 18L5 6C5 4.89543 5.89543 4 7 4L15.5 4M19 12L8.50016 11.9997M19 12L15.5 15.5556M19 12L15.5 8.44444"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExitIcon;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
function ParamsIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8 17C9.10457 17 10 16.1046 10 15C10 13.8954 9.10457 13 8 13M8 17C6.89543 17 6 16.1046 6 15C6 13.8954 6.89543 13 8 13M8 17V19M8 13V5"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M16 7C17.1046 7 18 7.89543 18 9C18 10.1046 17.1046 11 16 11M16 7C14.8954 7 14 7.89543 14 9C14 10.1046 14.8954 11 16 11M16 7V5M16 11V19"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParamsIcon;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
function WorkIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M3.75 9C3.75 8.30964 4.30964 7.75 5 7.75H19C19.6904 7.75 20.25 8.30964 20.25 9V18C20.25 18.6904 19.6904 19.25 19 19.25H5C4.30964 19.25 3.75 18.6904 3.75 18V9Z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.89482 6.90002C8.13696 5.99633 8.67053 5.19779 9.41276 4.62825C10.155 4.05871 11.0644 3.75 12 3.75C12.9356 3.75 13.845 4.05871 14.5872 4.62825C15.3295 5.19779 15.863 5.99633 16.1052 6.90002"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WorkIcon;
|
||||||
@@ -8,7 +8,13 @@ import { useEffect, useState } from "react";
|
|||||||
import Select from "../Select";
|
import Select from "../Select";
|
||||||
import useModalStore from "../../stores/useModalStore";
|
import useModalStore from "../../stores/useModalStore";
|
||||||
import Input from "../Input";
|
import Input from "../Input";
|
||||||
import { eachMinuteOfInterval, parse, parseISO, startOfDay } from "date-fns";
|
import {
|
||||||
|
addDays,
|
||||||
|
eachMinuteOfInterval,
|
||||||
|
parse,
|
||||||
|
parseISO,
|
||||||
|
startOfDay,
|
||||||
|
} from "date-fns";
|
||||||
import api from "../../utils/api";
|
import api from "../../utils/api";
|
||||||
import ChoiceChips from "../ChoiceChips";
|
import ChoiceChips from "../ChoiceChips";
|
||||||
// import ISchedule from "../../types/ISchedule";
|
// import ISchedule from "../../types/ISchedule";
|
||||||
@@ -46,6 +52,8 @@ function CreateScheduleModal({
|
|||||||
|
|
||||||
if (!result || !result.startAt) return;
|
if (!result || !result.startAt) return;
|
||||||
|
|
||||||
|
console.log("result.startAt", result.startAt);
|
||||||
|
|
||||||
setStartDate(startOfDay(parseISO(result.startAt)));
|
setStartDate(startOfDay(parseISO(result.startAt)));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert((error as Error).message);
|
alert((error as Error).message);
|
||||||
@@ -77,6 +85,8 @@ function CreateScheduleModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createSchedule() {
|
async function createSchedule() {
|
||||||
|
console.log("date", date);
|
||||||
|
|
||||||
await api.post(`companies/${companyId}/builds/${buildId}/schedules`, {
|
await api.post(`companies/${companyId}/builds/${buildId}/schedules`, {
|
||||||
json: {
|
json: {
|
||||||
startDate: date,
|
startDate: date,
|
||||||
@@ -131,10 +141,13 @@ function CreateScheduleModal({
|
|||||||
<div className="w-[296px] flex flex-col gap-3">
|
<div className="w-[296px] flex flex-col gap-3">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label value="Начало" />
|
<Label value="Начало" />
|
||||||
<DatePicker
|
{startDate && (
|
||||||
startDate={startDate}
|
<DatePicker
|
||||||
onChange={(date) => (setDate(date), console.log(date))}
|
defaultValue={addDays(startDate, 1)}
|
||||||
/>
|
startDate={addDays(startDate, 1)}
|
||||||
|
onChange={(date) => (setDate(date), console.log(date))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,12 +6,56 @@ import CloseIcon from "../icons/CloseIcon";
|
|||||||
import Input from "../Input";
|
import Input from "../Input";
|
||||||
import Label from "../Label";
|
import Label from "../Label";
|
||||||
import useModalStore from "../../stores/useModalStore";
|
import useModalStore from "../../stores/useModalStore";
|
||||||
|
import api from "../../utils/api";
|
||||||
|
import { FormEvent, useState } from "react";
|
||||||
|
|
||||||
function CreateScheduledSessionModal() {
|
interface Props {
|
||||||
|
buildId: string;
|
||||||
|
startAt: Date;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CreateScheduledSessionModal({ buildId, startAt, duration }: Props) {
|
||||||
const { setModal } = useModalStore();
|
const { setModal } = useModalStore();
|
||||||
|
const [email, setEmail] = useState<string>("");
|
||||||
|
const [phone, setPhone] = useState<string>("");
|
||||||
|
const [name, setName] = useState<string>("");
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
async function addSchesuledSession(e: FormEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await api
|
||||||
|
.post(`scheduled_sessions`, {
|
||||||
|
json: {
|
||||||
|
buildId,
|
||||||
|
startAt,
|
||||||
|
client: {
|
||||||
|
email,
|
||||||
|
phone,
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
|
||||||
|
console.log("result", result);
|
||||||
|
} catch (error) {
|
||||||
|
alert((error as Error).message);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
setModal(null);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="w-[600px] bg-white shadow-md rounded-lg">
|
<form
|
||||||
|
className="w-[600px] bg-white shadow-md rounded-lg"
|
||||||
|
onSubmit={addSchesuledSession}
|
||||||
|
>
|
||||||
<div className="p-2 pl-6 flex justify-between items-center border-b border-[#DAE0E5]">
|
<div className="p-2 pl-6 flex justify-between items-center border-b border-[#DAE0E5]">
|
||||||
<p className="font-semibold text-sm">Запланировать демонстрацию</p>
|
<p className="font-semibold text-sm">Запланировать демонстрацию</p>
|
||||||
<span className="text-[#77828C]">
|
<span className="text-[#77828C]">
|
||||||
@@ -31,16 +75,16 @@ function CreateScheduledSessionModal() {
|
|||||||
<div className="w-[296px]">
|
<div className="w-[296px]">
|
||||||
<div className="grid grid-cols-2 gap-4 text-xs py-1">
|
<div className="grid grid-cols-2 gap-4 text-xs py-1">
|
||||||
<p className="text-[#77828C]">Дата и время</p>
|
<p className="text-[#77828C]">Дата и время</p>
|
||||||
<p className="">{format(new Date(), "dd.MM.yyyy HH:mm")}</p>
|
<p className="">{format(startAt, "dd.MM.yyyy HH:mm")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-4 text-xs py-1">
|
<div className="grid grid-cols-2 gap-4 text-xs py-1">
|
||||||
<p className="text-[#77828C]">Длительность сеанса</p>
|
<p className="text-[#77828C]">Длительность сеанса</p>
|
||||||
<p className="">30 мин.</p>
|
<p className="">{duration} мин.</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-4 text-xs py-1">
|
{/* <div className="grid grid-cols-2 gap-4 text-xs py-1">
|
||||||
<p className="text-[#77828C]">Жилой комплекс</p>
|
<p className="text-[#77828C]">Жилой комплекс</p>
|
||||||
<p className="">Название ЖК</p>
|
<p className="">Название ЖК</p>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className="bg-[#DAE0E5]" />
|
<hr className="bg-[#DAE0E5]" />
|
||||||
@@ -63,23 +107,39 @@ function CreateScheduledSessionModal() {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label value="Email" />
|
<Label value="Email" />
|
||||||
<Input type="email" className="h-10" />
|
<Input
|
||||||
|
type="email"
|
||||||
|
className="h-10"
|
||||||
|
defaultValue={email}
|
||||||
|
handleChange={(value) => setEmail(value)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label value="Телефон" />
|
<Label value="Телефон" />
|
||||||
<Input className="h-10" />
|
<Input
|
||||||
|
type="tel"
|
||||||
|
className="h-10"
|
||||||
|
defaultValue={phone}
|
||||||
|
handleChange={(value) => setPhone(value)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label value="Имя" />
|
<Label value="Имя" />
|
||||||
<Input className="h-10" />
|
<Input
|
||||||
|
className="h-10"
|
||||||
|
defaultValue={name}
|
||||||
|
handleChange={(value) => setName(value)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-3 flex gap-2 border-b border-[#DAE0E5]">
|
<div className="px-6 py-3 flex gap-2 border-b border-[#DAE0E5]">
|
||||||
<Button handleClick={() => console.log("Click")}>Запланировать</Button>
|
<Button disabled={isLoading} type="submit">
|
||||||
<Button type="submit" color="secondary" handleClick={() => setModal(null)}>
|
Запланировать
|
||||||
|
</Button>
|
||||||
|
<Button color="secondary" handleClick={() => setModal(null)}>
|
||||||
Отмена
|
Отмена
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
parse,
|
parse,
|
||||||
addDays,
|
addDays,
|
||||||
subDays,
|
subDays,
|
||||||
isWithinInterval,
|
isAfter,
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import Button from "../components/Button";
|
import Button from "../components/Button";
|
||||||
import { ru } from "date-fns/locale";
|
import { ru } from "date-fns/locale";
|
||||||
@@ -28,6 +28,9 @@ import MoreIcon from "../components/icons/MoreIcon";
|
|||||||
import ISchedule from "../types/ISchedule";
|
import ISchedule from "../types/ISchedule";
|
||||||
import Calendar from "../components/Calendar";
|
import Calendar from "../components/Calendar";
|
||||||
import ChevronUpIcon from "../components/icons/ChevronUpIcon";
|
import ChevronUpIcon from "../components/icons/ChevronUpIcon";
|
||||||
|
import { isEqual } from "lodash";
|
||||||
|
import _ from "lodash";
|
||||||
|
import Menu from "../components/Menu";
|
||||||
|
|
||||||
function DashboardPage() {
|
function DashboardPage() {
|
||||||
const [user, setAccessToken] = useAuthStore((state) => [
|
const [user, setAccessToken] = useAuthStore((state) => [
|
||||||
@@ -39,9 +42,10 @@ function DashboardPage() {
|
|||||||
const [builds, setBuilds] = useState<any[]>();
|
const [builds, setBuilds] = useState<any[]>();
|
||||||
const [selectedBuild, setSelectedBuild] = useState<{ [key: string]: any }>();
|
const [selectedBuild, setSelectedBuild] = useState<{ [key: string]: any }>();
|
||||||
const [schedules, setSchedules] = useState<ISchedule[]>();
|
const [schedules, setSchedules] = useState<ISchedule[]>();
|
||||||
|
const [duration, setDuration] = useState<number>();
|
||||||
const [scheduledSessions, setScheduledSessions] = useState<any[]>();
|
const [scheduledSessions, setScheduledSessions] = useState<any[]>();
|
||||||
const [generatedScheduledSessions, setGeneratedScheduledSessions] =
|
const [generatedScheduledSessions, setGeneratedScheduledSessions] =
|
||||||
useState<any[][]>();
|
useState<any[]>();
|
||||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||||
const [dateTimes, setDateTimes] = useState<Date[]>();
|
const [dateTimes, setDateTimes] = useState<Date[]>();
|
||||||
const [currentTime, setCurrentTime] = useState<string>(
|
const [currentTime, setCurrentTime] = useState<string>(
|
||||||
@@ -107,6 +111,71 @@ function DashboardPage() {
|
|||||||
// }
|
// }
|
||||||
// }, [selectedDate, selectedBuild, schedules]);
|
// }, [selectedDate, selectedBuild, schedules]);
|
||||||
|
|
||||||
|
function findSessionsByTime(time: Date) {
|
||||||
|
if (!scheduledSessions) return [];
|
||||||
|
|
||||||
|
const foundScheduledSessions = scheduledSessions?.filter(
|
||||||
|
(scheduledSession) => isEqual(new Date(scheduledSession.startAt), time)
|
||||||
|
);
|
||||||
|
|
||||||
|
return foundScheduledSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateScheduledSessions() {
|
||||||
|
const newGeneratedScheduledSession: any[] = [];
|
||||||
|
|
||||||
|
dateTimes?.forEach((time) => {
|
||||||
|
const foundSessionsByTime = findSessionsByTime(time);
|
||||||
|
const sessions: any[] = [];
|
||||||
|
|
||||||
|
if (foundSessionsByTime) {
|
||||||
|
sessions.push(...foundSessionsByTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (
|
||||||
|
let index = 0;
|
||||||
|
index < selectedBuild?.sessionLimit - foundSessionsByTime.length;
|
||||||
|
index++
|
||||||
|
) {
|
||||||
|
sessions.push({});
|
||||||
|
}
|
||||||
|
|
||||||
|
newGeneratedScheduledSession.push({
|
||||||
|
time,
|
||||||
|
sessions,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setGeneratedScheduledSessions(newGeneratedScheduledSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!scheduledSessions) return;
|
||||||
|
generateScheduledSessions();
|
||||||
|
}, [scheduledSessions]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!schedules || !selectedDate || !selectedBuild) return;
|
||||||
|
|
||||||
|
const foundSchedule = schedules.find((schedule) =>
|
||||||
|
isAfter(new Date(), new Date(schedule.startDate))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!foundSchedule) return;
|
||||||
|
|
||||||
|
const step = foundSchedule.sessionDuration + foundSchedule.sessionBreak; // 35
|
||||||
|
const newTimes = eachMinuteOfInterval(
|
||||||
|
{
|
||||||
|
start: parse(foundSchedule.startTime, "HH:mm", new Date(selectedDate)), // 11:00
|
||||||
|
end: parse(foundSchedule.endTime, "HH:mm", new Date(selectedDate)), // 20:00
|
||||||
|
},
|
||||||
|
{ step }
|
||||||
|
);
|
||||||
|
|
||||||
|
setDateTimes(newTimes);
|
||||||
|
setDuration(foundSchedule.sessionDuration);
|
||||||
|
}, [schedules, selectedDate, selectedBuild]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!schedules) return;
|
if (!schedules) return;
|
||||||
// const schedule = schedules.find(schedule => schedule.startDate);
|
// const schedule = schedules.find(schedule => schedule.startDate);
|
||||||
@@ -195,37 +264,35 @@ function DashboardPage() {
|
|||||||
if (useLoader) setIsLoadingScheduledSessions(false);
|
if (useLoader) setIsLoadingScheduledSessions(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logout() {
|
// function generateScheduledSessions() {
|
||||||
setAccessToken(null);
|
// if (!dateTimes || !scheduledSessions || !selectedBuild) return;
|
||||||
}
|
|
||||||
|
|
||||||
function generateScheduledSessions() {
|
// const arr: any[][] = [];
|
||||||
if (!dateTimes || !scheduledSessions || !selectedBuild) return;
|
|
||||||
|
|
||||||
const arr: any[][] = [];
|
// dateTimes.forEach((dateTime) => {
|
||||||
|
// const arr2 = [];
|
||||||
|
|
||||||
dateTimes.forEach((dateTime) => {
|
// const foundSessionsCount = scheduledSessions.filter((session) =>
|
||||||
const arr2 = [];
|
// isEqual(session.startAt, dateTime)
|
||||||
|
// );
|
||||||
|
|
||||||
const foundSessionsCount = scheduledSessions.filter(
|
// arr2.push(dateTime);
|
||||||
(session) => session.startAt === dateTime.toISOString()
|
|
||||||
);
|
|
||||||
|
|
||||||
arr2.push(dateTime);
|
// for (let i = 0; i < selectedBuild.sessionLimit; i++) {
|
||||||
|
// if (foundSessionsCount[i]) {
|
||||||
|
// arr2.push(foundSessionsCount[i]);
|
||||||
|
// } else {
|
||||||
|
// arr2.push({});
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
for (let i = 0; i < selectedBuild.sessionLimit; i++) {
|
// arr.push(arr2);
|
||||||
if (foundSessionsCount[i]) {
|
|
||||||
arr2.push(foundSessionsCount[i]);
|
|
||||||
} else {
|
|
||||||
arr2.push({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arr.push(arr2);
|
// console.log("arr2", arr2);
|
||||||
});
|
// });
|
||||||
|
|
||||||
setGeneratedScheduledSessions(arr);
|
// setGeneratedScheduledSessions(arr);
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function updateScheduledSessionManager(
|
async function updateScheduledSessionManager(
|
||||||
scheduledSessionId: string,
|
scheduledSessionId: string,
|
||||||
@@ -306,10 +373,10 @@ function DashboardPage() {
|
|||||||
getSchedules();
|
getSchedules();
|
||||||
}, [selectedBuild]);
|
}, [selectedBuild]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (!scheduledSessions) return;
|
// if (!scheduledSessions) return;
|
||||||
generateScheduledSessions();
|
// generateScheduledSessions();
|
||||||
}, [scheduledSessions]);
|
// }, [scheduledSessions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// setIsLoadingScheduledSessions(true);
|
// setIsLoadingScheduledSessions(true);
|
||||||
@@ -319,13 +386,8 @@ function DashboardPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="main h-screen flex">
|
<div className="main h-screen flex">
|
||||||
<div className="left flex flex-col w-full">
|
<div className="left flex flex-col w-full">
|
||||||
<div className="flex bg-[#F0F1F2] ">
|
<div className="flex bg-[#F0F1F2]">
|
||||||
<button
|
<Menu />
|
||||||
onClick={() => alert("В разработке")}
|
|
||||||
className="p-3 transition-colors hover:bg-neutral-200"
|
|
||||||
>
|
|
||||||
<BurgerIcon />
|
|
||||||
</button>
|
|
||||||
{builds?.map((build) => (
|
{builds?.map((build) => (
|
||||||
<TabButton
|
<TabButton
|
||||||
key={build.id}
|
key={build.id}
|
||||||
@@ -396,7 +458,56 @@ function DashboardPage() {
|
|||||||
)}
|
)}
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
{company &&
|
{generatedScheduledSessions?.map(
|
||||||
|
(generatedScheduledSession, index) => (
|
||||||
|
<div key={index} className="flex">
|
||||||
|
<div className="w-[84px] h-[164px] flex justify-center items-center text-sm font-semibold bg-white border-r border-b border-[#DAE0E5]">
|
||||||
|
<p>{format(generatedScheduledSession.time, "HH:mm")}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
{generatedScheduledSession.sessions.map(
|
||||||
|
(session: any, index2: number) => {
|
||||||
|
const selectedManager = selectedBuildManagers?.find(
|
||||||
|
(manager) => manager.id == session.userId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!_.isEmpty(session)) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
key={index2}
|
||||||
|
companyId={company?.id}
|
||||||
|
buildId={selectedBuild?.id}
|
||||||
|
scheduledSessionId={session.id}
|
||||||
|
scheduleSessionStartAt={session.startAt}
|
||||||
|
client={session.client}
|
||||||
|
manager={selectedManager}
|
||||||
|
managers={selectedBuildManagers || []}
|
||||||
|
handleSelect={(scheduledSessionId, managerId) =>
|
||||||
|
updateScheduledSessionManager(
|
||||||
|
scheduledSessionId,
|
||||||
|
managerId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<EmptyCard
|
||||||
|
key={index2}
|
||||||
|
buildId={selectedBuild?.id}
|
||||||
|
startAt={generatedScheduledSession.time}
|
||||||
|
duration={duration!}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* {company &&
|
||||||
selectedBuild &&
|
selectedBuild &&
|
||||||
user &&
|
user &&
|
||||||
generatedScheduledSessions?.map(
|
generatedScheduledSessions?.map(
|
||||||
@@ -449,20 +560,12 @@ function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="right w-[384px] flex flex-col">
|
<div className="right w-[384px] flex flex-col">
|
||||||
<div className="min-h-[48px] bg-[#F0F1F2] flex justify-between items-center">
|
<div className="min-h-[48px] bg-[#F0F1F2] flex justify-between items-center"></div>
|
||||||
<p className="text-xs font-semibold px-3 text-green-600">
|
|
||||||
{company?.name}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs font-semibold px-3">{user?.username}</p>
|
|
||||||
<TabButton handleClick={logout} className="text-red-600">
|
|
||||||
Выйти
|
|
||||||
</TabButton>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2 h-[48px] border-b border-[#DAE0E5]">
|
<div className="flex gap-2 h-[48px] border-b border-[#DAE0E5]">
|
||||||
<button className="p-4 text-sm font-semibold">Параметры</button>
|
<button className="p-4 text-sm font-semibold">Параметры</button>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -238,6 +238,18 @@
|
|||||||
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
|
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
|
||||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||||
|
|
||||||
|
"@react-input/core@^1.0.12":
|
||||||
|
version "1.0.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/@react-input/core/-/core-1.0.12.tgz#b76e2474ad544a02e476baa9184ee7ff788c3c3c"
|
||||||
|
integrity sha512-lZDQjphsJenWCD0mcflsyneLnb2a7bFAgAVzih9diEcUjKopcK+QOXhz0a0PHEp8k5LEKpYadjwyltAGOOhL2g==
|
||||||
|
|
||||||
|
"@react-input/mask@^1.2.5":
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@react-input/mask/-/mask-1.2.5.tgz#0ce9c48e36dfcb56705eda811b0143454e146e55"
|
||||||
|
integrity sha512-xouBATnitQqhgKLgu6/J2IZRu7kzqm/tFw2ToFnk6EkRzWs5dawlcF8asASMu7LCDrCqSkjwN+/sscEMG7IXog==
|
||||||
|
dependencies:
|
||||||
|
"@react-input/core" "^1.0.12"
|
||||||
|
|
||||||
"@remix-run/router@1.8.0":
|
"@remix-run/router@1.8.0":
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz"
|
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz"
|
||||||
|
|||||||
+2
-2
@@ -7,11 +7,11 @@ import registrationRouter from "./routes/registration";
|
|||||||
import authMiddleware from "./middlewares/auth";
|
import authMiddleware from "./middlewares/auth";
|
||||||
import appRouter from "./routes/app";
|
import appRouter from "./routes/app";
|
||||||
import companiesRouter from "./routes/companies";
|
import companiesRouter from "./routes/companies";
|
||||||
import scheduledSessionsRouter from "./routes/scheduledSessions";
|
|
||||||
import usersRouter from "./routes/users";
|
import usersRouter from "./routes/users";
|
||||||
import buildsRouter from "./routes/builds";
|
import buildsRouter from "./routes/builds";
|
||||||
import actionsRouter from "./routes/actions";
|
import actionsRouter from "./routes/actions";
|
||||||
import schedulesRouter from "./routes/schedules";
|
import schedulesRouter from "./routes/schedules";
|
||||||
|
import scheduledSessionsRoute from "./routes/scheduledSessions";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
@@ -25,7 +25,7 @@ app.use("/login", loginRouter);
|
|||||||
app.use("/registration", registrationRouter);
|
app.use("/registration", registrationRouter);
|
||||||
app.use("/actions", actionsRouter);
|
app.use("/actions", actionsRouter);
|
||||||
app.use("/builds", buildsRouter);
|
app.use("/builds", buildsRouter);
|
||||||
app.use("/scheduled_sessions", scheduledSessionsRouter);
|
app.use("/scheduled_sessions", scheduledSessionsRoute);
|
||||||
app.use("/schedules", schedulesRouter);
|
app.use("/schedules", schedulesRouter);
|
||||||
app.use("/app", authMiddleware, appRouter);
|
app.use("/app", authMiddleware, appRouter);
|
||||||
app.use("/companies", authMiddleware, companiesRouter);
|
app.use("/companies", authMiddleware, companiesRouter);
|
||||||
|
|||||||
@@ -256,11 +256,10 @@ router.post("/:id/builds/:buildId/schedules", async (req, res) => {
|
|||||||
router.get(
|
router.get(
|
||||||
"/:companyId/builds/:buildId/last_scheduled_session",
|
"/:companyId/builds/:buildId/last_scheduled_session",
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { companyId, buildId } = req.params;
|
const { buildId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const lastScheduledSession = await ScheduledSession.findOne({
|
const lastScheduledSession = await ScheduledSession.findOne({
|
||||||
companyId,
|
|
||||||
buildId,
|
buildId,
|
||||||
}).sort({ startAt: -1 });
|
}).sort({ startAt: -1 });
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import {
|
|||||||
startOfDay,
|
startOfDay,
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
|
|
||||||
const scheduledSessionsRouter = Router();
|
const router = Router();
|
||||||
|
|
||||||
scheduledSessionsRouter.get("/", async (_req, res) => {
|
router.get("/", async (_req, res) => {
|
||||||
const scheduledSessions = await ScheduledSession.find({
|
const scheduledSessions = await ScheduledSession.find({
|
||||||
startAt: { $gte: startOfDay(new Date()) },
|
startAt: { $gte: startOfDay(new Date()) },
|
||||||
endAt: { $lte: endOfDay(new Date()) },
|
endAt: { $lte: endOfDay(new Date()) },
|
||||||
@@ -22,37 +22,34 @@ scheduledSessionsRouter.get("/", async (_req, res) => {
|
|||||||
res.json(scheduledSessions);
|
res.json(scheduledSessions);
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.get("/:id", async (req, res) => {
|
router.get("/:id", async (req, res) => {
|
||||||
const scheduledSessionId = req.params.id;
|
const scheduledSessionId = req.params.id;
|
||||||
const scheduledSession = await ScheduledSession.findById(scheduledSessionId);
|
const scheduledSession = await ScheduledSession.findById(scheduledSessionId);
|
||||||
|
|
||||||
res.json(scheduledSession);
|
res.json(scheduledSession);
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.get(
|
router.get("/companies/:companyId/builds/:buildId", async (req, res) => {
|
||||||
"/companies/:companyId/builds/:buildId",
|
const { companyId, buildId } = req.params;
|
||||||
async (req, res) => {
|
const { date } = req.query;
|
||||||
const { companyId, buildId } = req.params;
|
|
||||||
const { date } = req.query;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const scheduledSessions = await ScheduledSession.find({
|
const scheduledSessions = await ScheduledSession.find({
|
||||||
companyId,
|
companyId,
|
||||||
buildId,
|
buildId,
|
||||||
startAt: {
|
startAt: {
|
||||||
$gte: startOfDay(parseISO(date as string)),
|
$gte: startOfDay(parseISO(date as string)),
|
||||||
$lt: endOfDay(parseISO(date as string)),
|
$lt: endOfDay(parseISO(date as string)),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
res.json(scheduledSessions);
|
res.json(scheduledSessions);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.json({ error: (error as Error).message });
|
res.json({ error: (error as Error).message });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.get("/:buildId", async (req, res) => {
|
router.get("/:buildId", async (req, res) => {
|
||||||
if (!req.params.buildId) {
|
if (!req.params.buildId) {
|
||||||
res.json({ error: "Parameter `buildId` is required" });
|
res.json({ error: "Parameter `buildId` is required" });
|
||||||
return;
|
return;
|
||||||
@@ -76,9 +73,11 @@ scheduledSessionsRouter.get("/:buildId", async (req, res) => {
|
|||||||
res.json(scheduledSessions);
|
res.json(scheduledSessions);
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.post("/", async (req, res) => {
|
router.post("/", async (req, res) => {
|
||||||
const { buildId, startAt, client, duration } = req.body;
|
const { buildId, startAt, client, duration } = req.body;
|
||||||
|
|
||||||
|
console.log("client", client);
|
||||||
|
|
||||||
if (!buildId || !startAt) {
|
if (!buildId || !startAt) {
|
||||||
return res.json({
|
return res.json({
|
||||||
status: "error",
|
status: "error",
|
||||||
@@ -217,7 +216,7 @@ scheduledSessionsRouter.post("/", async (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.put("/:id", async (req, res) => {
|
router.put("/:id", async (req, res) => {
|
||||||
const scheduledSessionId = req.params.id;
|
const scheduledSessionId = req.params.id;
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -248,7 +247,7 @@ scheduledSessionsRouter.put("/:id", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessionsRouter.delete("/:id", async (req, res) => {
|
router.delete("/:id", async (req, res) => {
|
||||||
const scheduledSessionId = req.params.id;
|
const scheduledSessionId = req.params.id;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -262,4 +261,6 @@ scheduledSessionsRouter.delete("/:id", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default scheduledSessionsRouter;
|
const scheduledSessionsRoute = router;
|
||||||
|
|
||||||
|
export default scheduledSessionsRoute;
|
||||||
|
|||||||
Reference in New Issue
Block a user