This commit is contained in:
2024-02-01 16:20:40 +05:00
parent 42c7f15cdd
commit 7709cc6119
9 changed files with 180 additions and 83 deletions
+44
View File
@@ -9,5 +9,49 @@
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (m, e, t, r, i, k, a) {
m[i] =
m[i] ||
function () {
(m[i].a = m[i].a || []).push(arguments);
};
m[i].l = 1 * new Date();
for (var j = 0; j < document.scripts.length; j++) {
if (document.scripts[j].src === r) {
return;
}
}
(k = e.createElement(t)),
(a = e.getElementsByTagName(t)[0]),
(k.async = 1),
(k.src = r),
a.parentNode.insertBefore(k, a);
})(
window,
document,
"script",
"https://mc.yandex.ru/metrika/tag.js",
"ym"
);
ym(93606080, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true,
});
</script>
<noscript
><div>
<img
src="https://mc.yandex.ru/watch/93606080"
style="position: absolute; left: -9999px"
alt=""
/></div
></noscript>
<!-- /Yandex.Metrika counter -->
</body>
</html>
-1
View File
@@ -22,7 +22,6 @@
"react-rangeslider": "^2.2.0",
"react-router-dom": "^6.18.0",
"react-swipeable": "^7.0.1",
"react-yandex-metrika": "^2.6.0",
"usehooks-ts": "^2.9.1",
"zustand": "^4.4.6"
},
Binary file not shown.
+65 -57
View File
@@ -2,7 +2,6 @@
import "./App.css";
import "react-rangeslider/lib/index.css";
import "./components/RangeSlider.css";
import { YMInitializer } from "react-yandex-metrika";
import IProject from "./types/IProject";
import api from "./utils/api";
import { useEffect, useState } from "react";
@@ -34,6 +33,7 @@ function App() {
const [projects, setProjects] = useState<IProject[]>([]);
const [setModal] = useModalStore((state) => [state.setModal]);
const [isShownAllProjects, setIsShownAllProjects] = useState<boolean>(false);
const [isBuffering, setIsBuffering] = useState(true);
async function getProjects() {
try {
@@ -52,7 +52,7 @@ function App() {
}, []);
return (
<>
<div>
<div className="min-h-screen 2xl:px-10 xl:px-8 sm:px-6 px-4 overflow-x-clip">
<div className="relative conatiner mx-auto 2xl:max-w-screen-2xl">
<div className="flex justify-between py-6 2xl:mb-28 xl:mb-[88px] sm:mb-12 mb-14">
@@ -104,66 +104,86 @@ function App() {
</div>
</div>
<div className="2xl:mb-[200px] sm:mb-[120px] mb-20">
<div className="relative aspect-video w-full 2xl:mb-[200px] sm:mb-[120px] mb-20">
<video
src="/videos/showreel_1080p_4000k_h264.mp4"
muted
autoPlay
loop
playsInline
preload="metadata"
className="aspect-video w-full"
className="absolute aspect-video w-full"
onPlaying={() => setIsBuffering(false)}
onWaiting={() => setIsBuffering(true)}
/>
<div
className={`absolute aspect-video w-full h-full flex justify-center items-center bg-black bg-opacity-50 transition-opacity ${
isBuffering ? "opacity-100" : "opacity-0"
}`}
>
<div className="flex gap-4 items-center">
<span>
<svg
className="animate-spin h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
</span>
<span className="font-gilroy">Загружаем шоурил...</span>
</div>
</div>
</div>
<div className="relative conatiner mx-auto 2xl:max-w-screen-2xl">
<div className="flex flex-col 2xl:gap-16 xl:gap-10 gap-8 2xl:mb-[200px] sm:mb-[120px] mb-20">
<div className="xl:grid flex flex-col xl:grid-cols-4 xl:gap-0 sm:gap-6 gap-4">
<Heading2 className="2xl:col-span-full col-span-3">
Помогаем <br className="sm:hidden" /> продавать{" "}
<br className="2xl:hidden" />{" "}
<span style={{ WebkitTextFillColor: "#fff" }}>
проще <br className="sm:hidden" /> и{" "}
<span
style={{ WebkitTextFillColor: "#52587A" }}
className="relative custom-line-through"
>
<Heading2>
Продавайте недвижимость
<br />
<span style={{ WebkitTextFillColor: "#fff" }}>
проще и{" "}
<span className="relative">
<span style={{ WebkitTextFillColor: "#52587A" }}>
быстрее
</span>{" "}
<br className="sm:hidden" />
дороже
</span>
</Heading2>
</span>
<span className="absolute top-[55%] -left-[2.5%] 2xl:h-1.5 h-1 w-[105%] bg-white"></span>
</span>{" "}
дороже
</span>
</Heading2>
<p className="2xl:hidden 2xl:text-2xl text-sm">
Мы собрали статистику за 13 лет работы
<div className="relative xl:flex items-center gap-4 xl:max-h-[400px]">
<p className="2xl:text-2xl sm:text-xl font-gilroy min-w-fit">
Мы собрали статистику{" "}
<span className="text-gradient font-semibold">за 13 лет</span>{" "}
работы
<br />
с застройщиками, реализовав 31 проект
с застройщиками,{" "}
<span className="text-gradient font-semibold">
реализовав 31 проект
</span>
</p>
<div className="2xl:flex hidden relative items-center gap-4 col-span-full h-[400px]">
<p className="2xl:text-2xl text-sm font-gilroy font-medium min-w-[496px] ">
Мы собрали статистику{" "}
<span className="text-gradient font-semibold">за 13 лет</span>{" "}
работы
<br />
с застройщиками,{" "}
<span className="text-gradient font-semibold">
реализовав 31 проект
</span>
</p>
<div className="2xl:block hidden">
<img
src="/images/Map.png"
alt=""
className="relative top-8 -z-10"
/>
</div>
<div className="2xl:ml-6 xl:ml-[14px] relative 2xl:-top-8 xl:-top-4 -z-10">
<img src="/images/Map.png" alt="" />
</div>
</div>
<p className="2xl:block hidden text-gradient font-gilroy font-medium text-5xl w-fit">
<p className="2xl:text-[64px] xl:text-5xl text-[40px] text-gradient font-gilroy font-medium w-fit leading-none">
Graff.estate
</p>
@@ -409,7 +429,7 @@ function App() {
title="ЖК «Айвазовский City»"
location="Россия, Тюмень"
background="/images/stream/aivaz.jpg"
link="https://stream.graff.tech/?build=Ivazowsky&location=a1"
link="https://stream.graff.tech/?build=IvazowskyDev&location=a1"
/>
</div>
@@ -754,19 +774,7 @@ function App() {
</div>
<ModalContainer />
<YMInitializer
accounts={[93606080]}
options={{
defer: true,
webvisor: true,
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
}}
version="2"
/>
</>
</div>
);
}
+37 -19
View File
@@ -7,6 +7,7 @@ import ArrowRightIcon from "./icons/ArrowRightIcon";
import regionsData from "../assets/regionsData.json";
import { useEffect, useState } from "react";
import CloseIcon from "./icons/CloseIcon";
import api from "../utils/api";
interface Region {
id: number;
@@ -17,9 +18,11 @@ interface Region {
}
function Calc() {
const [consultations, setConsultations] = useState<number>(100);
const [selectedRegion, setSelectedRegion] = useState<Region>();
const [implementationPeriod, setImplementationPeriod] = useState<number>();
const [consultations, setConsultations] = useState<number>(100);
const [implementationPeriod, setImplementationPeriod] = useState<number>(
null!
);
const [oldImplementationPeriod, setOldImplementationPeriod] =
useState<number>();
const [monthlyIncome, setMonthlyIncome] = useState<number>();
@@ -39,8 +42,23 @@ function Calc() {
const [diffImplementationPeriodEnding, setDiffImplementationPeriodEnding] =
useState<string>();
async function getRegionName() {
const result: any = await api.get("getRegionName").json();
if (result.error) {
setSelectedRegion(regionsData.find((region) => region.id === 11));
return;
}
const foundRegion =
regionsData.find((region) => region.name === result.regionName) ||
regionsData.find((region) => region.id === 11);
setSelectedRegion(foundRegion);
}
useEffect(() => {
setSelectedRegion(regionsData.find((region) => region.id === 11));
getRegionName();
}, []);
useEffect(() => {
@@ -94,8 +112,6 @@ function Calc() {
}, [monthlyIncome, oldMonthlyIncome]);
useEffect(() => {
if (!implementationPeriod) return;
if (implementationPeriod > 10 && implementationPeriod < 15) {
setOldImplementationPeriodEnding("месяцев");
return;
@@ -160,21 +176,23 @@ function Calc() {
<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
);
{selectedRegion && (
<CalcSelect
label="Регион"
placeholder="Выберите регион"
defaultOption={selectedRegion.name}
options={regionsData.map((regionItem) => regionItem.name)}
handleSelect={(option) => {
const foundRegion = regionsData.find(
(region) => region.name === option
);
if (foundRegion) {
setSelectedRegion(foundRegion);
}
}}
/>
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%]">
Установлены усредненные показатели по региону.
+1 -1
View File
@@ -6,7 +6,7 @@ import { useOnClickOutside } from "usehooks-ts";
interface CalcSelectProps {
label: string;
placeholder: string;
defaultOption?: string;
defaultOption: string;
options: string[];
handleSelect: (option: string) => void;
}
-5
View File
@@ -1491,11 +1491,6 @@ react-swipeable@^7.0.1:
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-7.0.1.tgz#cd299f5986c5e4a7ee979839658c228f660e1e0c"
integrity sha512-RKB17JdQzvECfnVj9yDZsiYn3vH0eyva/ZbrCZXZR0qp66PBRhtg4F9yJcJTWYT5Adadi+x4NoG53BxKHwIYLQ==
react-yandex-metrika@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/react-yandex-metrika/-/react-yandex-metrika-2.6.0.tgz#9c935c8c7ea5505e34391b9b3e86deb6d50053c9"
integrity sha512-8K4wExsNZtY3DTxh1G8a+zWH9Pg8fw23MJcoJ4I/562qrHRnh7L5nteq3lnNL58dnNQbuuHIRoGgMjIo+r1GjA==
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+2
View File
@@ -5,6 +5,7 @@ import cors from "cors";
import mailRoute from "./routes/mail";
import projectRoute from "./routes/projects";
import uploadRoute from "./routes/upload";
import getRegionNameRoute from "./routes/getRegionName";
connectDB();
@@ -17,6 +18,7 @@ app.use(cors({ origin: "*" }));
app.use("/mail", mailRoute);
app.use("/projects", projectRoute);
app.use("/upload", uploadRoute);
app.use("/getRegionName", getRegionNameRoute);
app.listen(port, () => {
console.log(`Server is listening on port ${port}`);
+31
View File
@@ -0,0 +1,31 @@
import { Router } from "express";
import fs from "fs";
const router = Router();
router.get("/", async (req, res) => {
const ip = req.headers["x-forwarded-for"];
try {
const { countryCode, region, regionName }: any = await (
await fetch(`http://ip-api.com/json/${ip}?lang=ru`)
).json();
if (countryCode === "RU") {
fs.appendFileSync(
"./log.txt",
`${countryCode}-${region} (${regionName})\n`
);
}
res.json({ regionName });
} catch (error) {
if (error instanceof Error) {
res.json({ error: error.message });
}
}
});
const getRegionNameRoute = router;
export default getRegionNameRoute;