Files
graff.estate/client/src/components/Calc.tsx
T
2023-12-28 15:35:58 +05:00

421 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable @typescript-eslint/no-explicit-any */
import Slider from "react-rangeslider";
import Button from "./Button";
import CalcSelect from "./CalcSelect";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import regionsData from "../assets/regionsData.json";
import { useEffect, useState } from "react";
import CloseIcon from "./icons/CloseIcon";
interface Region {
id: number;
name: string;
areaInComplex: number;
areaApartment: number;
costPerSquare: number;
}
function Calc() {
const [consultations, setConsultations] = useState<number>(100);
const [selectedRegion, setSelectedRegion] = useState<Region>();
const [implementationPeriod, setImplementationPeriod] = useState<number>();
const [oldImplementationPeriod, setOldImplementationPeriod] =
useState<number>();
const [monthlyIncome, setMonthlyIncome] = useState<number>();
const [oldMonthlyIncome, setOldMonthlyIncome] = useState<number>();
const [isToolEnabled, setIsToolEnabled] = useState<boolean>(false);
const [reservation, setReservation] = useState<number>();
const [oldReservation, setOldReservation] = useState<number>();
const [sales, setSales] = useState<number>();
const [oldSales, setOldSales] = useState<number>();
const [diffImplementationPeriod, setDiffImplementationPeriod] =
useState<number>();
const [diffMonthlyIncome, setDiffMonthlyIncome] = useState<number>();
const [implementationPeriodEnding, setImplementationPeriodEnding] =
useState<string>();
const [oldImplementationPeriodEnding, setOldImplementationPeriodEnding] =
useState<string>();
const [diffImplementationPeriodEnding, setDiffImplementationPeriodEnding] =
useState<string>();
useEffect(() => {
setSelectedRegion(regionsData.find((region) => region.id === 11));
}, []);
useEffect(() => {
if (!consultations || !selectedRegion || !sales || !oldSales) return;
setOldImplementationPeriod(
Math.round(
selectedRegion.areaInComplex / selectedRegion.areaApartment / oldSales
)
);
setImplementationPeriod(
Math.round(
selectedRegion.areaInComplex / selectedRegion.areaApartment / sales
)
);
setOldMonthlyIncome(
Math.round(
(selectedRegion.areaApartment *
selectedRegion.costPerSquare *
oldSales) /
1000
)
);
setMonthlyIncome(
Math.round(
(selectedRegion.areaApartment * selectedRegion.costPerSquare * sales) /
1000
)
);
}, [consultations, selectedRegion, isToolEnabled, sales]);
useEffect(() => {
setOldReservation(Math.round((30 * consultations) / 100));
setReservation(Math.round((48 * consultations) / 100));
setOldSales(Math.round((((30 * consultations) / 100) * 30) / 100));
setSales(Math.round((((48 * consultations) / 100) * 42) / 100));
}, [consultations]);
useEffect(() => {
if (!implementationPeriod || !oldImplementationPeriod) return;
setDiffImplementationPeriod(oldImplementationPeriod - implementationPeriod);
}, [implementationPeriod, oldImplementationPeriod]);
useEffect(() => {
if (!monthlyIncome || !oldMonthlyIncome) return;
setDiffMonthlyIncome(monthlyIncome - oldMonthlyIncome);
}, [monthlyIncome, oldMonthlyIncome]);
useEffect(() => {
if (!implementationPeriod) return;
if (implementationPeriod > 10 && implementationPeriod < 15) {
setOldImplementationPeriodEnding("месяцев");
return;
}
if (implementationPeriod % 10 === 1) {
setImplementationPeriodEnding("месяц");
} else if (
implementationPeriod % 10 === 2 ||
implementationPeriod % 10 === 3 ||
implementationPeriod % 10 === 4
) {
setImplementationPeriodEnding("месяца");
} else {
setImplementationPeriodEnding("месяцев");
}
}, [implementationPeriod]);
useEffect(() => {
if (!oldImplementationPeriod) return;
if (oldImplementationPeriod > 10 && oldImplementationPeriod < 15) {
setOldImplementationPeriodEnding("месяцев");
return;
}
if (oldImplementationPeriod % 10 === 1) {
setOldImplementationPeriodEnding("месяц");
} else if (
oldImplementationPeriod % 10 === 2 ||
oldImplementationPeriod % 10 === 3 ||
oldImplementationPeriod % 10 === 4
) {
setOldImplementationPeriodEnding("месяца");
} else {
setOldImplementationPeriodEnding("месяцев");
}
}, [oldImplementationPeriod]);
useEffect(() => {
if (!diffImplementationPeriod) return;
if (diffImplementationPeriod > 10 && diffImplementationPeriod < 15) {
setDiffImplementationPeriodEnding("месяцев");
return;
}
if (diffImplementationPeriod % 10 === 1) {
setDiffImplementationPeriodEnding("месяц");
} else if (
diffImplementationPeriod % 10 === 2 ||
diffImplementationPeriod % 10 === 3 ||
diffImplementationPeriod % 10 === 4
) {
setDiffImplementationPeriodEnding("месяца");
} else {
setDiffImplementationPeriodEnding("месяцев");
}
}, [diffImplementationPeriod]);
return (
<div className="relative flex flex-col sm:gap-16 gap-8">
<div className="grid xl:grid-cols-4 sm:grid-cols-3">
<div className="xl:col-auto sm:col-span-full xl:block sm:grid grid-cols-2">
<CalcSelect
label="Регион"
placeholder="Выберите регион"
defaultOption={regionsData.find((region) => region.id === 11)?.name}
options={regionsData.map((regionItem) => regionItem.name)}
handleSelect={(option) => {
const foundRegion = regionsData.find(
(region) => region.name === option
);
if (foundRegion) {
setSelectedRegion(foundRegion);
}
}}
/>
<div className="border xl:border-t-0 xl:border-l sm:border-l-0 sm:border-t border-t-0 border-[#3D425C] 2xl:p-6 p-4 flex items-center">
<p className="text-[#52587A] text-xs leading-[120%]">
Установлены усредненные показатели по региону.
<br className="2xl:block xl:hidden sm:block hidden" /> Источник:{" "}
<a
href="https://наш.дом.рф"
target="_blank"
className="text-[#798FFF]"
>
наш.дом.рф
</a>
</p>
</div>
</div>
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between gap-6 border xl:border-l-0 xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя площадь
<br />
жилья в комплексе, м²
</p>
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.areaInComplex || 1500).toLocaleString()}
</p>
</div>
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between gap-6 border sm:border-l-0 border-l xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя площадь
<br />
квартиры, м²
</p>
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.areaApartment || 100).toLocaleString()}
</p>
</div>
<div className="2xl:px-8 2xl:py-6 px-6 py-4 flex flex-col justify-between gap-6 border sm:border-l-0 border-l xl:border-t border-t-0 border-[#3D425C]">
<p className="text-sm">
Средняя стоимость
<br />
одного м², тыс. руб.
</p>
<p className="2xl:text-5xl text-[32px] font-gilroy font-medium leading-none">
{(selectedRegion?.costPerSquare || 100).toLocaleString()}
</p>
</div>
</div>
<div className="grid xl:grid-cols-4 grid-cols-2">
<div className="xl:flex flex-col xl:gap-6 xl:mr-8 xl:border-b border-[#3D425C] xl:col-auto col-span-full sm:grid grid-cols-2 gap-12 xl:mb-0 sm:mb-6 mb-8">
<div className="flex flex-col gap-6">
<div className="flex justify-between">
<p className="font-gilroy font-medium 2xl:text-base text-sm leading-none">
Очных консультаций в месяц
</p>
<p className="font-gilroy font-medium text-[#798FFF] 2xl:text-base text-sm leading-none">
{consultations}
</p>
</div>
<div className="py-[9px]">
<Slider
min={10}
max={1000}
step={10}
value={consultations}
onChange={(value) => setConsultations(value)}
tooltip={false}
/>
</div>
</div>
<Button
icon={
isToolEnabled ? (
<CloseIcon className="2xl:w-8 w-6 2xl:h-8 h-6" />
) : (
<ArrowRightIcon className="2xl:w-8 2xl:h-8" />
)
}
color={isToolEnabled ? "secondary" : "primary"}
onClick={() => setIsToolEnabled((prev) => !prev)}
className="px-6 py-4 w-full h-fit self-center sm:flex hidden"
>
{isToolEnabled ? "Отключить" : "Включить"} инструмент
</Button>
</div>
<div className="col-span-3 grid xl:grid-cols-2">
<div className="xl:block sm:grid grid-cols-2">
<div className="2xl:px-8 2xl:py-6 p-4 border border-[#3D425C] grid grid-cols-2 gap-4 items-center">
<div className="flex flex-col gap-4">
<p className="text-sm">Срок реализации</p>
<p
className={`2xl:text-5xl text-[32px] font-gilroy font-medium flex items-end gap-1.5 w-fit ${
isToolEnabled ? "text-gradient" : ""
}`}
>
<span className="2xl:leading-none leading-[115%]">
{isToolEnabled
? implementationPeriod
: oldImplementationPeriod}
</span>
<span className="2xl:text-2xl xl:text-xl text-base">
{isToolEnabled
? implementationPeriodEnding
: oldImplementationPeriodEnding}
</span>
</p>
</div>
<p
className={`text-xs transition-opacity ${
isToolEnabled ? `opacity-100` : `opacity-0`
}`}
>
На{" "}
<span className="text-[#798FFF]">
{diffImplementationPeriod} {diffImplementationPeriodEnding}
</span>{" "}
вы сократили
<br />
срок реализации проекта
</p>
</div>
<div className="2xl:px-8 2xl:py-6 p-4 border xl:border-t-0 sm:border-t border-t-0 xl:border-l sm:border-l-0 border-l border-[#3D425C] grid grid-cols-2 gap-4 items-center">
<div className="flex flex-col gap-4">
<p className="text-sm">Месячный доход</p>
<p
className={`2xl:text-5xl text-[32px] font-gilroy font-medium flex items-end gap-1.5 w-fit ${
isToolEnabled ? "text-gradient" : ""
}`}
>
<span className="2xl:leading-none leading-[115%]">
{isToolEnabled ? monthlyIncome : oldMonthlyIncome}
</span>
<span className="2xl:text-2xl xl:text-xl text-base">
млн руб.
</span>
</p>
</div>
<p
className={`text-xs transition-opacity ${
isToolEnabled ? `opacity-100` : `opacity-0`
}`}
>
На{" "}
<span className="text-[#798FFF]">
{diffMonthlyIncome} млн руб.
</span>{" "}
в месяц
<br />
вы заработали больше
</p>
</div>
</div>
<div className="2xl:px-8 2xl:py-6 sm:px-6 sm:py-4 p-4 border xl:border-l-0 xl:border-t border-t-0 border-[#3D425C] flex flex-col gap-4">
<p className="text-sm">Статистика продаж</p>
<div className="flex flex-col 2xl:gap-3 sm:gap-1.5 gap-2">
<div className="flex sm:gap-4 gap-2">
<div className="flex flex-col 2xl:gap-3 sm:gap-1.5 gap-2 justify-around">
<p className="2xl:text-sm text-xs">100%</p>
<p className="2xl:text-sm text-xs">
{isToolEnabled ? 48 : 30}%
</p>
<p className="2xl:text-sm text-xs">
{isToolEnabled ? 42 : 30}%
</p>
</div>
<div className="w-full flex flex-col 2xl:gap-3 sm:gap-1.5 gap-2 justify-around">
<div className="bg-[#212431] rounded-full flex justify-center">
<div
className={`2xl:py-3.5 py-2 rounded-full w-full transition-all ${
isToolEnabled ? "bg-gradient" : "bg-[#52587A]"
}`}
>
<p className="text-center">{consultations}</p>
</div>
</div>
<div className="bg-[#212431] rounded-full flex justify-center">
<div
className={`2xl:py-3.5 py-2 rounded-full transition-all ${
isToolEnabled
? "w-[60%] bg-gradient"
: "w-[50%] bg-[#52587A]"
}`}
>
<p className="text-center">
{isToolEnabled ? reservation : oldReservation}
</p>
</div>
</div>
<div className="bg-[#212431] rounded-full flex justify-center">
<div
className={`2xl:py-3.5 py-2 rounded-full transition-all ${
isToolEnabled
? "w-[32%] bg-gradient"
: "w-[22%] bg-[#52587A]"
}`}
>
<p className="text-center">
{isToolEnabled ? sales : oldSales}
</p>
</div>
</div>
</div>
<div className="flex flex-col 2xl:gap-3 sm:gap-1.5 gap-2 justify-around">
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
<span className="sm:inline hidden">
Консультаций в офисе
</span>
<span className="sm:hidden inline">Консультации</span>
</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Бронь<span className="sm:inline hidden"> квартиры</span>
</p>
<p className="2xl:text-sm text-xs text-[#8088A7] whitespace-nowrap">
Продажа
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<Button
icon={
isToolEnabled ? (
<CloseIcon className="2xl:w-8 w-6 2xl:h-8 h-6" />
) : (
<ArrowRightIcon className="2xl:w-8 2xl:h-8" />
)
}
color={isToolEnabled ? "secondary" : "primary"}
onClick={() => setIsToolEnabled((prev) => !prev)}
className="px-6 py-4 w-full h-fit self-center sm:hidden flex"
>
{isToolEnabled ? "Отключить" : "Включить"} инструмент
</Button>
</div>
);
}
export default Calc;