upd
This commit is contained in:
+107
-332
@@ -1,52 +1,53 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Card from "../components/Card";
|
||||
import EmptyCard from "../components/EmptyCard";
|
||||
import TabButton from "../components/TabButton";
|
||||
import BurgerIcon from "../components/icons/BurgerIcon";
|
||||
import ChevronLeftIcon from "../components/icons/ChevronLeftIcon";
|
||||
import ChevronRightIcon from "../components/icons/ChevronRightIcon";
|
||||
import api from "../utils/api";
|
||||
import useAuthStore from "../stores/useAuthStore";
|
||||
import {
|
||||
eachMinuteOfInterval,
|
||||
format,
|
||||
parse,
|
||||
addDays,
|
||||
subDays,
|
||||
isAfter,
|
||||
isEqual,
|
||||
} from "date-fns";
|
||||
import Button from "../components/Button";
|
||||
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 SpinnerIcon from "../components/icons/SpinnerIcon";
|
||||
import useModalStore from "../stores/useModalStore";
|
||||
import ModalContainer from "../components/ModalContainer";
|
||||
import CreateScheduleModal from "../components/modals/CreateScheduleModal";
|
||||
import MoreIcon from "../components/icons/MoreIcon";
|
||||
import ISchedule from "../types/ISchedule";
|
||||
import Calendar from "../components/Calendar";
|
||||
import ChevronUpIcon from "../components/icons/ChevronUpIcon";
|
||||
import { isEqual } from "lodash";
|
||||
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";
|
||||
|
||||
function DashboardPage() {
|
||||
const [user, setAccessToken] = useAuthStore((state) => [
|
||||
state.user,
|
||||
state.setAccessToken,
|
||||
]);
|
||||
const [company, setCompany] = useState<{ [key: string]: any }>();
|
||||
const [selectedBuildManagers, setSelectedBuildManagers] = useState<any[]>();
|
||||
const [builds, setBuilds] = useState<any[]>();
|
||||
const [selectedBuild, setSelectedBuild] = useState<{ [key: string]: any }>();
|
||||
const [schedules, setSchedules] = useState<ISchedule[]>();
|
||||
const { user } = useAuthStore();
|
||||
const {
|
||||
company,
|
||||
setCompany,
|
||||
selectedBuild,
|
||||
setSelectedBuild,
|
||||
builds,
|
||||
setBuilds,
|
||||
managers,
|
||||
setManagers,
|
||||
schedules,
|
||||
setSchedules,
|
||||
selectedDay,
|
||||
setSelectedDay,
|
||||
} = useStore();
|
||||
const [duration, setDuration] = useState<number>();
|
||||
const [scheduledSessions, setScheduledSessions] = useState<any[]>();
|
||||
const [generatedScheduledSessions, setGeneratedScheduledSessions] =
|
||||
useState<any[]>();
|
||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||
const [dateTimes, setDateTimes] = useState<Date[]>();
|
||||
const [currentTime, setCurrentTime] = useState<string>(
|
||||
format(new Date(), "HH:mm")
|
||||
@@ -54,63 +55,19 @@ function DashboardPage() {
|
||||
const [isLoadingScheduledSessions, setIsLoadingScheduledSessions] =
|
||||
useState(true);
|
||||
const scheduledSessionsRef = useRef<HTMLDivElement>(null);
|
||||
const setModal = useModalStore((state) => state.setModal);
|
||||
|
||||
// const [selectedDate, setSelectedDate] = useState(
|
||||
// format(new Date(), "d MMMM, yyyy", { locale: ru })
|
||||
// );
|
||||
|
||||
function selectNextDay() {
|
||||
setSelectedDate((prev) => addDays(prev, 1));
|
||||
setSelectedDay(addDays(selectedDay, 1));
|
||||
}
|
||||
|
||||
function selectPrevDay() {
|
||||
setSelectedDate((prev) => subDays(prev, 1));
|
||||
setSelectedDay(subDays(selectedDay, 1));
|
||||
}
|
||||
|
||||
function selectCurrentDate() {
|
||||
setSelectedDate(new Date());
|
||||
setSelectedDay(new Date());
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log("schedules", schedules);
|
||||
|
||||
// if (!selectedDate || !selectedBuild || !schedules?.length) return;
|
||||
|
||||
// const foundSchedule = schedules.find(
|
||||
// (schedule) =>
|
||||
// isWithinInterval(selectedDate, {
|
||||
// start: new Date(schedule.startDate),
|
||||
// end: addDays(new Date(schedule.startDate), 14),
|
||||
// }) && selectedBuild.id === schedule.buildId
|
||||
// );
|
||||
|
||||
// console.log("foundSchedule", foundSchedule);
|
||||
|
||||
// if (foundSchedule) {
|
||||
// const startDateTime = parse(
|
||||
// foundSchedule.startTime,
|
||||
// "HH:mm",
|
||||
// selectedDate
|
||||
// );
|
||||
// const endDateTime = parse(foundSchedule.endTime, "HH:mm", selectedDate);
|
||||
// const step = foundSchedule.sessionDuration + foundSchedule.sessionBreak;
|
||||
|
||||
// setDateTimes(
|
||||
// eachMinuteOfInterval(
|
||||
// {
|
||||
// start: startDateTime,
|
||||
// end: endDateTime,
|
||||
// },
|
||||
// { step }
|
||||
// )
|
||||
// );
|
||||
// } else {
|
||||
// setDateTimes(undefined);
|
||||
// setGeneratedScheduledSessions(undefined);
|
||||
// }
|
||||
// }, [selectedDate, selectedBuild, schedules]);
|
||||
|
||||
function findSessionsByTime(time: Date) {
|
||||
if (!scheduledSessions) return [];
|
||||
|
||||
@@ -122,6 +79,8 @@ function DashboardPage() {
|
||||
}
|
||||
|
||||
function generateScheduledSessions() {
|
||||
if (!selectedBuild) return;
|
||||
|
||||
const newGeneratedScheduledSession: any[] = [];
|
||||
|
||||
dateTimes?.forEach((time) => {
|
||||
@@ -134,7 +93,7 @@ function DashboardPage() {
|
||||
|
||||
for (
|
||||
let index = 0;
|
||||
index < selectedBuild?.sessionLimit - foundSessionsByTime.length;
|
||||
index < selectedBuild.sessionLimit - foundSessionsByTime.length;
|
||||
index++
|
||||
) {
|
||||
sessions.push({});
|
||||
@@ -150,36 +109,36 @@ function DashboardPage() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!scheduledSessions) return;
|
||||
if (!scheduledSessions || !selectedBuild || !selectedDay) return;
|
||||
generateScheduledSessions();
|
||||
}, [scheduledSessions]);
|
||||
}, [scheduledSessions, selectedBuild, selectedDay]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!schedules || !selectedDate || !selectedBuild) return;
|
||||
if (!schedules || !selectedDay || !selectedBuild) return;
|
||||
|
||||
const foundSchedule = schedules.find((schedule) =>
|
||||
isAfter(new Date(), new Date(schedule.startDate))
|
||||
console.log("schedules", schedules);
|
||||
|
||||
const foundSchedule = schedules.find(
|
||||
(schedule) => schedule.buildId === selectedBuild.id
|
||||
);
|
||||
|
||||
if (!foundSchedule) return;
|
||||
if (!foundSchedule) {
|
||||
setDateTimes([]);
|
||||
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
|
||||
start: parse(foundSchedule.startTime, "HH:mm", new Date(selectedDay)), // 11:00
|
||||
end: parse(foundSchedule.endTime, "HH:mm", new Date(selectedDay)), // 20:00
|
||||
},
|
||||
{ step }
|
||||
);
|
||||
|
||||
setDateTimes(newTimes);
|
||||
setDuration(foundSchedule.sessionDuration);
|
||||
}, [schedules, selectedDate, selectedBuild]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!schedules) return;
|
||||
// const schedule = schedules.find(schedule => schedule.startDate);
|
||||
}, [selectedDate, selectedBuild, schedules]);
|
||||
}, [schedules, selectedDay, selectedBuild]);
|
||||
|
||||
async function getCompany() {
|
||||
if (!user) {
|
||||
@@ -224,7 +183,7 @@ function DashboardPage() {
|
||||
const result: any = await api
|
||||
.get(`companies/${company.id}/builds/${selectedBuild.id}/users`)
|
||||
.json();
|
||||
setSelectedBuildManagers(result);
|
||||
setManagers(result);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
@@ -250,7 +209,7 @@ function DashboardPage() {
|
||||
.get(
|
||||
`companies/${company.id}/builds/${
|
||||
selectedBuild.id
|
||||
}/scheduled_sessions?date=${selectedDate.toISOString()}`
|
||||
}/scheduled_sessions?date=${selectedDay.toISOString()}`
|
||||
)
|
||||
.json();
|
||||
|
||||
@@ -264,39 +223,9 @@ function DashboardPage() {
|
||||
if (useLoader) setIsLoadingScheduledSessions(false);
|
||||
}
|
||||
|
||||
// function generateScheduledSessions() {
|
||||
// if (!dateTimes || !scheduledSessions || !selectedBuild) return;
|
||||
|
||||
// const arr: any[][] = [];
|
||||
|
||||
// dateTimes.forEach((dateTime) => {
|
||||
// const arr2 = [];
|
||||
|
||||
// const foundSessionsCount = scheduledSessions.filter((session) =>
|
||||
// isEqual(session.startAt, dateTime)
|
||||
// );
|
||||
|
||||
// arr2.push(dateTime);
|
||||
|
||||
// for (let i = 0; i < selectedBuild.sessionLimit; i++) {
|
||||
// if (foundSessionsCount[i]) {
|
||||
// arr2.push(foundSessionsCount[i]);
|
||||
// } else {
|
||||
// arr2.push({});
|
||||
// }
|
||||
// }
|
||||
|
||||
// arr.push(arr2);
|
||||
|
||||
// console.log("arr2", arr2);
|
||||
// });
|
||||
|
||||
// setGeneratedScheduledSessions(arr);
|
||||
// }
|
||||
|
||||
async function updateScheduledSessionManager(
|
||||
scheduledSessionId: string,
|
||||
managerId: string
|
||||
managerId: string | null
|
||||
) {
|
||||
if (!company || !scheduledSessions) return;
|
||||
|
||||
@@ -325,6 +254,8 @@ function DashboardPage() {
|
||||
async function getSchedules() {
|
||||
if (!company || !selectedBuild) return;
|
||||
|
||||
console.log("selectedBuild.id", selectedBuild.id);
|
||||
|
||||
const result: any[] = await api
|
||||
.get(`companies/${company.id}/builds/${selectedBuild.id}/schedules`)
|
||||
.json();
|
||||
@@ -355,33 +286,28 @@ function DashboardPage() {
|
||||
}, [builds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedBuildManagers || !selectedDate || !selectedBuild) return;
|
||||
if (!managers || !selectedDay || !selectedBuild) return;
|
||||
getScheduledSessions(true);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
getScheduledSessions();
|
||||
}, 3000);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [selectedBuildManagers, selectedDate, selectedBuild]);
|
||||
}, [managers, selectedDay, selectedBuild]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!company || !selectedBuild) return;
|
||||
getManagers();
|
||||
console.log("selectedBuild", selectedBuild);
|
||||
getSchedules();
|
||||
getManagers();
|
||||
}, [selectedBuild]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!scheduledSessions) return;
|
||||
// generateScheduledSessions();
|
||||
// }, [scheduledSessions]);
|
||||
|
||||
useEffect(() => {
|
||||
// setIsLoadingScheduledSessions(true);
|
||||
scheduledSessionsRef.current?.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}, [selectedDate, selectedBuild]);
|
||||
}, [selectedDay, selectedBuild]);
|
||||
|
||||
return (
|
||||
<div className="main h-screen flex">
|
||||
@@ -392,7 +318,9 @@ function DashboardPage() {
|
||||
<TabButton
|
||||
key={build.id}
|
||||
handleClick={() => setSelectedBuild(build)}
|
||||
active={selectedBuild && build.id === selectedBuild.id}
|
||||
active={
|
||||
(selectedBuild && build.id === selectedBuild?.id) || false
|
||||
}
|
||||
>
|
||||
{build.name}
|
||||
</TabButton>
|
||||
@@ -403,7 +331,7 @@ function DashboardPage() {
|
||||
<p className="text-sm font-semibold">Расписание</p>
|
||||
<div className="flex items-center gap-4">
|
||||
<p className="text-sm font-semibold">
|
||||
{format(selectedDate, "PPPP", { locale: ru })}
|
||||
{format(selectedDay, "PPPP", { locale: ru })}
|
||||
</p>
|
||||
<div className="flex gap-1">
|
||||
<Button
|
||||
@@ -465,102 +393,50 @@ function DashboardPage() {
|
||||
<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
|
||||
);
|
||||
{company &&
|
||||
managers &&
|
||||
selectedBuild &&
|
||||
generatedScheduledSession.sessions.map(
|
||||
(session: any, index2: number) => {
|
||||
const selectedManager = managers.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!}
|
||||
/>
|
||||
);
|
||||
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={managers}
|
||||
handleSelect={(scheduledSessionId, managerId) =>
|
||||
updateScheduledSessionManager(
|
||||
scheduledSessionId,
|
||||
managerId
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<EmptyCard
|
||||
key={index2}
|
||||
buildId={selectedBuild?.id}
|
||||
startAt={generatedScheduledSession.time}
|
||||
duration={duration!}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* {company &&
|
||||
selectedBuild &&
|
||||
user &&
|
||||
generatedScheduledSessions?.map(
|
||||
(generatedScheduledSession, index) => {
|
||||
return (
|
||||
<div key={index} className="flex">
|
||||
{generatedScheduledSession.map(
|
||||
(scheduledSession, index2) => {
|
||||
if (index2 === 0) {
|
||||
return (
|
||||
<div
|
||||
key={index2}
|
||||
className="w-[84px] h-[164px] flex justify-center items-center text-sm font-semibold bg-[#F0F1F2] border-r border-b border-[#DAE0E5]"
|
||||
>
|
||||
{format(scheduledSession, "HH:mm")}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
if (Object.keys(scheduledSession).length) {
|
||||
const selectedManager = selectedBuildManagers?.find(
|
||||
(manager) => manager.id == scheduledSession.userId
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
key={index2}
|
||||
companyId={company.id}
|
||||
buildId={selectedBuild.id}
|
||||
scheduledSessionId={scheduledSession.id}
|
||||
scheduleSessionStartAt={
|
||||
scheduledSession.startAt
|
||||
}
|
||||
client={scheduledSession.client}
|
||||
manager={selectedManager}
|
||||
managers={selectedBuildManagers || []}
|
||||
handleSelect={(scheduledSessionId, managerId) =>
|
||||
updateScheduledSessionManager(
|
||||
scheduledSessionId,
|
||||
managerId
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <EmptyCard key={index2} />;
|
||||
}
|
||||
}
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -576,110 +452,9 @@ function DashboardPage() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto overflow-x-hidden">
|
||||
<div className="p-4 space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-sm font-semibold">Календарь</p>
|
||||
<Button color="tertiary" icon={<ChevronUpIcon />} onlyIcon />
|
||||
</div>
|
||||
<Calendar
|
||||
defaultValue={selectedDate}
|
||||
onChange={(date) => setSelectedDate(date)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<p className="text-sm font-semibold">Расписание</p>
|
||||
|
||||
{schedules?.map((schedule) => (
|
||||
<div key={schedule.id} className="flex flex-col gap-3 text-xs">
|
||||
<p className="font-semibold flex gap-1">
|
||||
<span>
|
||||
Действует с{" "}
|
||||
{format(new Date(schedule.startDate), "dd.MM.yyyy")}
|
||||
</span>
|
||||
{/* <span>-</span> */}
|
||||
<span>
|
||||
{/* {format(parseISO(schedule.endDate), "dd.MM.yyyy")} */}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="grid grid-cols-3">
|
||||
<p className="col-span-2 text-[#77828C]">Сеансов в день</p>
|
||||
<p>{schedule.sessionsPerDay}</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-3">
|
||||
<p className="col-span-2 text-[#77828C]">
|
||||
Длительность сеанса
|
||||
</p>
|
||||
<p>{schedule.sessionDuration} мин.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-3">
|
||||
<p className="col-span-2 text-[#77828C]">Между сеансами</p>
|
||||
<p>{schedule.sessionBreak} мин.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-3">
|
||||
<p className="col-span-2 text-[#77828C]">Время работы</p>
|
||||
<p>
|
||||
{schedule.startTime} - {schedule.endTime}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
color="secondary"
|
||||
className="w-full"
|
||||
handleClick={() =>
|
||||
setModal(
|
||||
<CreateScheduleModal
|
||||
companyId={company?.id}
|
||||
buildId={selectedBuild?.id}
|
||||
// schedules={schedules}
|
||||
handleCreate={getSchedules}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
Добавить
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="p-4 flex flex-col gap-4">
|
||||
<p className="text-sm font-semibold">Менеджеры</p>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
{selectedBuildManagers?.map((manager) => (
|
||||
<div key={manager.id} className="flex justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<img
|
||||
src={manager.avatar}
|
||||
alt=""
|
||||
className="w-8 h-8 rounded-full"
|
||||
/>
|
||||
<p className="text-sm leading-[140%]">{manager.name}</p>
|
||||
</div>
|
||||
<Button
|
||||
disabled
|
||||
color="tertiary"
|
||||
onlyIcon
|
||||
icon={<MoreIcon />}
|
||||
handleClick={() => {}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
disabled
|
||||
color="secondary"
|
||||
className="w-full"
|
||||
handleClick={() => {}}
|
||||
>
|
||||
Добавить
|
||||
</Button>
|
||||
</div>
|
||||
<Calendar />
|
||||
<Schedules />
|
||||
<Managers />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user