358 lines
11 KiB
TypeScript
358 lines
11 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||
import { FormEvent, useEffect, useState } from "react";
|
||
import Calendar from "react-calendar";
|
||
import "react-calendar/dist/Calendar.css";
|
||
import "./CalendarPage.css";
|
||
import {
|
||
format,
|
||
isBefore,
|
||
differenceInBusinessDays,
|
||
setHours,
|
||
getHours,
|
||
setMinutes,
|
||
getMinutes,
|
||
setSeconds,
|
||
setMilliseconds,
|
||
} from "date-fns";
|
||
import ru from "date-fns/locale/ru";
|
||
import ky from "ky";
|
||
import { useParams } from "react-router-dom";
|
||
import InputMask from "react-input-mask";
|
||
|
||
function CalendarPage() {
|
||
const params = useParams();
|
||
const [step, setStep] = useState<number>(1);
|
||
const [date, setDate] = useState<Date>(new Date());
|
||
const [name, setName] = useState<string>("");
|
||
const [email, setEmail] = useState<string>("");
|
||
const [phone, setPhone] = useState<string>("");
|
||
const [link, setLink] = useState<string>("");
|
||
const [datesAndTimes, setDatesAndTimes] = useState<any[]>([]);
|
||
const [scheduledSessions, setScheduledSessions] = useState<any[]>([]);
|
||
|
||
async function selectDate(value: any) {
|
||
await getScheduledSessions("653675f420af0dadee9003ec", value);
|
||
|
||
setDate(value);
|
||
setStep((prev) => prev + 1);
|
||
}
|
||
|
||
async function getScheduledSessions(buildId: string, date: Date) {
|
||
const result: any[] = await ky
|
||
.get(
|
||
`https://crm.stream.graff.tech/api/scheduled_sessions/${buildId}?date=${date.toISOString()}`
|
||
)
|
||
.json();
|
||
|
||
console.log(result);
|
||
|
||
setScheduledSessions(result);
|
||
}
|
||
|
||
function selectTime(value: any) {
|
||
let newDate = date;
|
||
newDate = setHours(date, getHours(value));
|
||
newDate = setMinutes(newDate, getMinutes(value));
|
||
newDate = setSeconds(newDate, 0);
|
||
newDate = setMilliseconds(newDate, 0);
|
||
|
||
setDate(newDate);
|
||
setStep((prev) => prev + 1);
|
||
}
|
||
|
||
async function addSchedule(e: FormEvent) {
|
||
e.preventDefault();
|
||
|
||
const username = params.username;
|
||
const title = "nksJukovaDev";
|
||
const startAt = date;
|
||
|
||
try {
|
||
const result: any = await ky
|
||
.post(`${import.meta.env.VITE_COORD_URL}/scheduled_sessions`, {
|
||
json: {
|
||
username,
|
||
name,
|
||
email,
|
||
phone,
|
||
title,
|
||
startAt,
|
||
},
|
||
})
|
||
.json();
|
||
|
||
if (!result.userInviteLink) {
|
||
alert(result.error);
|
||
return;
|
||
}
|
||
|
||
setLink(result.userInviteLink);
|
||
setName("");
|
||
setEmail("");
|
||
setPhone("");
|
||
setStep(4);
|
||
} catch (error: any) {
|
||
alert(error.message);
|
||
}
|
||
}
|
||
|
||
async function getSessionScheduleSettings() {
|
||
const username = params.username;
|
||
|
||
try {
|
||
const result: any = await ky
|
||
.get(
|
||
`${
|
||
import.meta.env.VITE_COORD_URL
|
||
}/session_schedule_settings/${username}`
|
||
)
|
||
.json();
|
||
|
||
if (result.error) {
|
||
console.log("Error: ", result.error);
|
||
return;
|
||
}
|
||
|
||
const { datesAndTimes } = result;
|
||
|
||
console.log(datesAndTimes);
|
||
|
||
setDatesAndTimes(datesAndTimes);
|
||
} catch (error) {
|
||
if (error instanceof Error) {
|
||
console.log(error.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
getSessionScheduleSettings();
|
||
}, []);
|
||
|
||
return (
|
||
<div className="min-h-screen flex justify-center items-center p-8 rounded-lg text-white">
|
||
{step === 1 && (
|
||
<div className="space-y-8 w-80">
|
||
<p className="text-4xl font-gilroy">
|
||
Выберите
|
||
<br />
|
||
дату
|
||
</p>
|
||
<Calendar onChange={selectDate} value={date} minDate={new Date()} />
|
||
</div>
|
||
)}
|
||
|
||
{step === 2 && (
|
||
<div className="space-y-8">
|
||
<p className="text-4xl font-gilroy">
|
||
Выберите
|
||
<br />
|
||
время
|
||
</p>
|
||
|
||
<div className="space-y-4">
|
||
<button
|
||
onClick={() => setStep((prev) => prev - 1)}
|
||
className="text-[#C5C7CE] flex items-center gap-1 bg-[#1C1D21] p-1 pr-4 text-xs rounded"
|
||
>
|
||
<svg
|
||
width="24"
|
||
height="24"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
>
|
||
<path
|
||
d="M15 19L8 12L15 5"
|
||
stroke="#C5C7CE"
|
||
strokeWidth="2"
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
/>
|
||
</svg>
|
||
<span>Выбор даты</span>
|
||
</button>
|
||
|
||
<p className="text-xl font-gilroy">
|
||
{format(date, "dd MMMM", { locale: ru })}
|
||
</p>
|
||
|
||
<div className="grid grid-cols-4">
|
||
{datesAndTimes.map(
|
||
(dateAndTime: { value: Date; active: true }, index: number) =>
|
||
!differenceInBusinessDays(date, new Date()) ? (
|
||
isBefore(new Date(), new Date(dateAndTime.value)) && (
|
||
<button
|
||
key={index}
|
||
onClick={() => selectTime(new Date(dateAndTime.value))}
|
||
className="px-3 py-2 text-center rounded hover:bg-[#23242A] disabled:hover:bg-inherit disabled:opacity-25"
|
||
disabled={
|
||
scheduledSessions.filter(
|
||
(session) => session.startAt === dateAndTime.value
|
||
).length >= 3
|
||
}
|
||
>
|
||
{format(new Date(dateAndTime.value), "HH:mm")}
|
||
</button>
|
||
)
|
||
) : (
|
||
<button
|
||
key={index}
|
||
onClick={() => selectTime(new Date(dateAndTime.value))}
|
||
className="px-3 py-2 text-center rounded hover:bg-[#23242A] disabled:hover:bg-inherit disabled:opacity-25"
|
||
disabled={
|
||
scheduledSessions.filter(
|
||
(session) => session.startAt === dateAndTime.value
|
||
).length >= 3
|
||
}
|
||
>
|
||
{format(new Date(dateAndTime.value), "HH:mm")}
|
||
</button>
|
||
)
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{step === 3 && (
|
||
<div className="space-y-8 w-80">
|
||
<p className="text-4xl font-gilroy">
|
||
Расскажите
|
||
<br />о себе
|
||
</p>
|
||
|
||
<div className="space-y-4">
|
||
<button
|
||
onClick={() => setStep((prev) => prev - 1)}
|
||
className="text-[#C5C7CE] flex items-center gap-1 bg-[#1C1D21] p-1 pr-4 text-xs rounded"
|
||
>
|
||
<svg
|
||
width="24"
|
||
height="24"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
>
|
||
<path
|
||
d="M15 19L8 12L15 5"
|
||
stroke="#C5C7CE"
|
||
strokeWidth="2"
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
/>
|
||
</svg>
|
||
<span>Выбор времени</span>
|
||
</button>
|
||
|
||
<p className="text-xl font-gilroy">
|
||
{format(date, "dd MMMM HH:mm", { locale: ru })}
|
||
</p>
|
||
|
||
<form onSubmit={addSchedule} className="space-y-12">
|
||
<div className="space-y-4">
|
||
<div className="space-y-1">
|
||
<p className="text-[#C5C7CE]">Имя</p>
|
||
<input
|
||
required
|
||
type="text"
|
||
className="px-4 py-3 bg-[#23242A] rounded outline-none w-full"
|
||
placeholder="Константин"
|
||
value={name}
|
||
onChange={(e) => setName(e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<p className="text-[#C5C7CE]">Email</p>
|
||
<input
|
||
required
|
||
type="email"
|
||
className="px-4 py-3 bg-[#23242A] rounded outline-none w-full"
|
||
placeholder="example@mail.ru"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<p className="text-[#C5C7CE]">Телефон</p>
|
||
<InputMask
|
||
mask={"+999999999999999"}
|
||
maskChar={null}
|
||
required
|
||
type="tel"
|
||
className="px-4 py-3 bg-[#23242A] rounded outline-none w-full"
|
||
placeholder="+79009998877"
|
||
value={phone}
|
||
onChange={(e) => setPhone(e.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
type="submit"
|
||
className="px-4 py-2 bg-gradient w-full rounded"
|
||
>
|
||
Запланировать
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{step === 4 && (
|
||
<div className="space-y-8 w-80">
|
||
<p className="text-4xl font-gilroy">
|
||
Просмотр
|
||
<br />
|
||
запланирован
|
||
</p>
|
||
|
||
<div className="space-y-12">
|
||
<p className="text-[#C5C7CE]">
|
||
Ссылка для подключения и другая дополнительная информация будут
|
||
отправлены на ваш почтовый адрес.
|
||
</p>
|
||
|
||
<div className="space-y-4">
|
||
<div className="space-y-1">
|
||
<p>Скопируйте ссылку для поключения</p>
|
||
<input
|
||
type="text"
|
||
className="px-4 py-3 bg-[#23242A] rounded outline-none w-full"
|
||
defaultValue={link}
|
||
/>
|
||
</div>
|
||
|
||
<p className="text-center">или</p>
|
||
|
||
<a
|
||
href={link}
|
||
target="_blank"
|
||
className="inline-block px-4 py-2 bg-gradient w-full rounded text-center"
|
||
>
|
||
Подключиться
|
||
</a>
|
||
|
||
<div className="h-0.5 bg-[#23242A]"></div>
|
||
|
||
<a
|
||
onClick={() => setStep(1)}
|
||
href="#"
|
||
className="inline-block px-4 py-2 w-full rounded text-center bg-[#1C1D21] text-[#C5C7CE]"
|
||
>
|
||
На сайт жилого комплекса
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default CalendarPage;
|