diff --git a/client/src/components/Input.tsx b/client/src/components/Input.tsx
index 7089d50..b7b0752 100644
--- a/client/src/components/Input.tsx
+++ b/client/src/components/Input.tsx
@@ -43,7 +43,7 @@ function Input({
value={value}
onChange={(e) => handleChange && handleChange(e.target.value)}
onFocus={handleFocus}
- className={`px-3 py-2.5 outline-none rounded-lg ring-1 ring-[#DAE0E5] focus:ring-[#49A1F5] ring-inset transition-all text-sm ${className}`}
+ className={`px-3 py-[9px] outline-none rounded-lg ring-1 ring-[#DAE0E5] focus:ring-[#49A1F5] ring-inset transition-all text-sm ${className}`}
/>
);
}
diff --git a/client/src/components/Schedule.tsx b/client/src/components/Schedule.tsx
index 99026e4..9866321 100644
--- a/client/src/components/Schedule.tsx
+++ b/client/src/components/Schedule.tsx
@@ -5,7 +5,9 @@ import Timeline from "./Timeline";
import {
format,
getDate,
+ getHours,
getMonth,
+ parseISO,
setDate,
setHours,
setMonth,
@@ -119,6 +121,15 @@ function Schedule({ selectedDay, slots, events }: Props) {
// setModal(null);
}
+ function countWorkingHours() {
+ if (!company?.startTime || !company?.endTime) return 24;
+
+ const startHour = getHours(parseISO(company.startTime));
+ const endHour = getHours(parseISO(company.endTime));
+
+ return endHour - startHour;
+ }
+
useEffect(() => {
if (!builds) return;
@@ -169,13 +180,21 @@ function Schedule({ selectedDay, slots, events }: Props) {
- {Array.from({ length: 24 }).map((_, index) => (
+ {Array.from({ length: countWorkingHours() }).map((_, index) => (
- {format(setHours(startOfDay(new Date()), index), "HH:mm")}
+ {format(
+ setHours(
+ startOfDay(new Date()),
+ company?.startTime && company.endTime
+ ? getHours(parseISO(company.startTime)) + index
+ : index
+ ),
+ "HH:mm"
+ )}
))}
@@ -194,6 +213,8 @@ function Schedule({ selectedDay, slots, events }: Props) {
onChangeDraftMode={handleChangeDraftMode}
onChangeStartAt={handleChangeStartAt}
onChangeDuration={handleChangeDuration}
+ startTime={company?.startTime}
+ endTime={company?.endTime}
/>
))}
diff --git a/client/src/components/Timeline.tsx b/client/src/components/Timeline.tsx
index 42c49bb..7b887a0 100644
--- a/client/src/components/Timeline.tsx
+++ b/client/src/components/Timeline.tsx
@@ -2,7 +2,15 @@
/* 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 {
+ addHours,
+ addMinutes,
+ differenceInMinutes,
+ format,
+ getHours,
+ parseISO,
+ startOfDay,
+} from "date-fns";
import Button from "./Button";
import IScheduledSession from "../types/IScheduledSession";
import useStore from "../stores/useStore";
@@ -14,6 +22,8 @@ interface Props {
timelineEvents: IScheduledSession[];
slot: number;
draftMode: boolean;
+ startTime?: string; // 10:00
+ endTime?: string;
onChangeDraftMode: (draftMode: boolean) => void;
onChangeStartAt: (startAt: Date) => void;
onChangeDuration: (duration: number) => void;
@@ -27,6 +37,8 @@ function Timeline({
timelineEvents,
slot,
draftMode,
+ startTime,
+ endTime,
onChangeDraftMode,
onChangeStartAt,
onChangeDuration,
@@ -57,9 +69,14 @@ function Timeline({
setDuration(30);
}
- setStartAt(
- addMinutes(startOfDay(new Date()), roundedY / minutePx).toISOString()
- );
+ if (startTime) {
+ const newStartOfDay = parseISO(startTime);
+ setStartAt(addMinutes(newStartOfDay, roundedY / minutePx).toISOString());
+ } else {
+ setStartAt(
+ addMinutes(startOfDay(new Date()), roundedY / minutePx).toISOString()
+ );
+ }
onChangeSlot(slot);
}
@@ -70,10 +87,6 @@ function Timeline({
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 {
@@ -117,6 +130,15 @@ function Timeline({
// );
// }, [timelineEvents]);
+ function countWorkingHours() {
+ if (!startTime || !endTime) return 24;
+
+ const startHour = getHours(parseISO(startTime));
+ const endHour = getHours(parseISO(endTime));
+
+ return endHour - startHour;
+ }
+
useEffect(() => {
if (!startAt) return;
@@ -150,7 +172,7 @@ function Timeline({
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
>
- {Array.from({ length: 24 }).map((_, index) => (
+ {Array.from({ length: countWorkingHours() }).map((_, index) => (
(
@@ -16,6 +20,45 @@ function CompanyModal() {
const { user } = useAuthStore();
const { setModal } = useModalStore();
const { company, managers } = useStore();
+ const [startTime, setStartTime] = useState(
+ company?.startTime ? format(parseISO(company.startTime), "HH:mm") : ""
+ );
+ const [endTime, setEndTime] = useState(
+ company?.endTime ? format(parseISO(company.endTime), "HH:mm") : ""
+ );
+
+ async function handleClickSaveWorkingHours() {
+ if (!startTime || !endTime) return;
+
+ try {
+ await api
+ .put(`companies/${company?.id}`, {
+ json: {
+ startTime: parse(startTime, "HH:mm", new Date()),
+ endTime: parse(endTime, "HH:mm", new Date()),
+ },
+ })
+ .json();
+
+ toast.success("Изменения сохранены");
+ setModal(null);
+ setTimeout(() => {
+ window.location.reload();
+ }, 2000);
+ } catch (error) {
+ toast.error("Что-то пошло не так");
+ }
+ }
+
+ useEffect(() => {
+ if (startTime) {
+ setStartTime((prev) => `${prev.split(":")[0]}:00`);
+ }
+
+ if (endTime) {
+ setEndTime((prev) => `${prev.split(":")[0]}:00`);
+ }
+ }, [startTime, endTime]);
return (
@@ -44,9 +87,34 @@ function CompanyModal() {
{selectedTab === "company" && (
-
-
-
+ //
+ //
+ //
+ // {company?.avatar && (
+ //

+ // )}
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+
+
+
{company?.avatar && (

)}
-
+
+
+
@@ -66,25 +136,35 @@ function CompanyModal() {
- {/*
*/}
+
+
+
Рабочее время
+
+
+
+
Начало
+
setStartTime(value)}
+ />
+
+
-
+
+
Конец
+
setEndTime(value)}
+ />
+
+
+
+
- {/*
-
-
Проекты
- {Array.from({ length: 3 }).map((_, index) => (
-
- ))}
-
-
-
*/}
)}
{selectedTab === "employees" && (
@@ -125,7 +205,7 @@ function CompanyModal() {
-
+ {/*
{user?.role === "admin" && (
)}
-
+
*/}
))}
diff --git a/client/src/types/ICompany.ts b/client/src/types/ICompany.ts
index 93c0095..3b6e3fd 100644
--- a/client/src/types/ICompany.ts
+++ b/client/src/types/ICompany.ts
@@ -7,6 +7,8 @@ interface ICompany {
phone?: string;
address?: string;
avatar?: string;
+ startTime?: string;
+ endTime?: string;
}
export default ICompany;
diff --git a/server/src/models/Company.ts b/server/src/models/Company.ts
index 2baf423..afa4abe 100644
--- a/server/src/models/Company.ts
+++ b/server/src/models/Company.ts
@@ -26,6 +26,12 @@ const companySchema = new Schema(
address: {
type: String,
},
+ startTime: {
+ type: String,
+ },
+ endTime: {
+ type: String,
+ },
},
{
timestamps: true,
diff --git a/server/src/routes/companies.ts b/server/src/routes/companies.ts
index 585902c..b462e03 100644
--- a/server/src/routes/companies.ts
+++ b/server/src/routes/companies.ts
@@ -24,6 +24,23 @@ router.get("/:companyId", async (req, res) => {
res.json(company);
});
+router.put("/:companyId", async (req, res) => {
+ if (req.params.companyId != res.locals.user.companyId) {
+ res.json({ error: "Access denied" });
+ return;
+ }
+
+ const company = await Company.findByIdAndUpdate(
+ req.params.companyId,
+ req.body,
+ {
+ new: true,
+ }
+ );
+
+ res.json(company);
+});
+
router.get("/:companyId/builds", async (req, res) => {
if (req.params.companyId != res.locals.user.companyId) {
res.json({ error: "Access denied" });