Files
graff.estate-nextjs/src/components/Reviews.tsx
T
2024-03-29 11:46:07 +05:00

411 lines
17 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 @next/next/no-img-element */
// import { createRef, useEffect, useLayoutEffect, useRef, useState } from "react";
// import { useSwipeable } from "react-swipeable";
// import { motion } from "framer-motion";
// import { Transition } from "react-transition-group";
// import ArrowLeftIcon from "./icons/ArrowLeftIcon";
// import ArrowRightIcon from "./icons/ArrowRightIcon";
// import { Video } from "../types/Video";
import { createRef, useEffect, useLayoutEffect, useState } from "react";
import { useInView } from "react-intersection-observer";
import { useSwipeable } from "react-swipeable";
import { Video } from "../types/Video";
import ArrowLeftIcon from "./icons/ArrowLeftIcon";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import { Transition } from "react-transition-group";
type Review = {
id: string;
avatar: string;
name: string;
position: string;
desc: string;
video: string;
poster: string;
};
const REVIEWS: Review[] = [
{
id: "1",
avatar: "/images/reviews/avatars/1.png",
name: "Егор бобров",
position: "Коммерческий директор авторского квартала «Машаров»",
desc: "Эффективность инструмента была подтверждена буквально в первый день после его внедрения. Например, один из клиентов, посетив офис и увидев свою будущую квартиру с помощью интерактивной панели, сразу решил купить недвижимость в этом проекте, отказавшись от других вариантов",
poster: "/images/reviews/1.png",
video: "",
},
{
id: "2",
avatar: "/images/reviews/avatars/2.png",
name: "Олег Бондорев",
position: "Ведущий менеджер компании «ЭНКО»",
desc: "Клиенты особенно ценят возможность легко выбрать квартиру с помощью 3D-модель жилого комплекса. Так же инструмент продаж позволяет клиенту увидеть расположение дома, в какое время свет будет попадать в окна, даже зайти в лифт и холл, а также оценить инфраструктуру района и «прочувствовать» его, прогулявшись по двору",
poster: "/images/reviews/1.png",
video: "",
},
{
id: "3",
avatar: "/images/reviews/avatars/3.png",
name: "Алина Веселова",
position: "Ведущий специалист отдела продаж",
desc: "Одним из преимуществ инструмента является возможность посмотреть 3D-модель квартиры с готовым дизайнерским ремонтом и оценить видовые характеристиками, изменяя время суток (день или ночь). Это важно для клиента, так как позволяет реалистично представить, как будет выглядеть будущее жилье.",
poster: "/images/reviews/2.png",
video: "",
},
];
// const REVIEWS: Video[] = [
// {
// id: "1",
// value: "/images/reviews/1.png",
// title: "",
// desc: "Интерактивный комплекс GRAFF.estate для ЖК Upside Towers, Москва",
// poster: "",
// },
// {
// id: "2",
// value: "/images/reviews/2.png",
// title: "",
// desc: "Graff.estate на выставке 100+ TechnoBuild",
// poster: "",
// },
// {
// id: "3",
// value: "/videos/histories/3.mp4",
// title: "",
// desc: "Интерактивная инсталляция graff.estate для ЖК DNS City в г.Владивосток",
// poster: "",
// },
// ];
// const Reviews = () => {
// const [isViewportEntered, setIsViewportEntered] = useState<boolean>(false);
// function handleViewportEnter() {
// if (isViewportEntered) return;
// setIsViewportEntered(true);
// }
// const [cardWidth, setCardWidth] = useState(0);
// const handlers = useSwipeable({
// onSwipedLeft: handleOnRightMove,
// onSwipedRight: handleOnLeftMove,
// trackMouse: true,
// });
// const [selectedVideo, setSelectedVideo] = useState<number>(0);
// const [_document, setDocument] = useState<Document>();
// function handleOnLeftMove(): void {
// if (selectedVideo > 0) {
// setSelectedVideo((prev) => prev - 1);
// }
// }
// function handleOnRightMove(): void {
// if (selectedVideo < 2) {
// setSelectedVideo((prev) => prev + 1);
// }
// }
// useEffect(() => {
// setDocument(document);
// }, []);
// useEffect(() => {
// if (!_document) return;
// const clientWidth = _document.children[0].clientWidth;
// if (clientWidth >= 1600) {
// setCardWidth(1000);
// } else if (clientWidth >= 1280) {
// setCardWidth(805);
// } else if (clientWidth >= 640) {
// setCardWidth(736);
// } else {
// setCardWidth(clientWidth - 16);
// }
// }, [_document]);
// return (
// <motion.div
// onViewportEnter={handleViewportEnter}
// className="container mx-auto 2xl:max-w-screen-2xl flex flex-col justify-center 2xl:mb-[200px] sm:mb-[120px] mb-20"
// >
// <div className="sm:border-b border-b-[#3D425C] 2xl:h-[594px] xl:h-[484px] sm:h-[404px] h-full">
// <div className="flex sm:h-full h-fit sm:flex-row flex-col sm:w-full sm:mx-0 mx-auto">
// <div className=" flex flex-col justify-between 2xl:min-w-[496px] xl:min-w-[395px] sm:min-w-[263px] sm:pb-6 xl:pb-10 sm:h-full">
// <div className="2xl:pr-10 xl:pr-8 sm:pr-[37px]">
// <h2 className="font-medium 2xl:text-[64px] xl:text-5xl text-[40px] leading-10 sm:mb-8 mb-6 font-gilroy">
// <p className="from-[#798FFF] to-[#D375FF] bg-gradient-to-r bg-clip-text text-transparent">
// Отзывы
// </p>
// <p>клиентов</p>
// </h2>
// <div className="flex gap-6 2xl:pb-8 xl:pb-6 ">
// <div className="w-[72px] h-[72px] bg-white rounded-full" />
// <div>
// <h2 className="text-2xl font-semibold">Егор Бобров</h2>
// <p className="w-[272px] opacity-80">
// Коммерческий директор авторского квартала «Машаров»{" "}
// </p>
// </div>
// </div>
// <div
// className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 mb-7`}
// >
// <p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
// Эффективность инструмента была подтверждена буквально в первый
// день после его внедрения. Например, один из клиентов, посетив
// офис и увидев свою будущую квартиру с помощью интерактивной
// панели, сразу решил купить недвижимость в этом проекте,
// отказавшись от других вариантов
// </p>
// </div>
// {/* {VIDEOS.map((item, index) => (
// <Transition
// key={index}
// in={Boolean(index === selectedVideo)}
// timeout={300}
// >
// {(state) => (
// <div
// className={`absolute 2xl:w-[456px] xl:w-[363px] sm:w-[350px] w-[280px] transition-opacity duration-300 ${state} mb-7`}
// >
// <p className="font-normal 2xl:text-[16px] xl:text-[14px] sm:block hidden">
// Эффективность инструмента была подтверждена буквально в
// первый день после его внедрения. Например, один из
// клиентов, посетив офис и увидев свою будущую квартиру с
// помощью интерактивной панели, сразу решил купить
// недвижимость в этом проекте, отказавшись от других
// вариантов
// </p>
// </div>
// )}
// </Transition>
// ))} */}
// </div>
// <div className="gap-2 sm:flex hidden">
// <button
// className="p-4 border border-[#3D425C] rounded-full"
// onClick={handleOnLeftMove}
// >
// <ArrowLeftIcon />
// </button>
// <button
// className="p-4 border border-[#3D425C] rounded-full"
// onClick={handleOnRightMove}
// >
// <ArrowRightIcon />
// </button>
// </div>
// </div>
// <div className="relative sm:border-l border-l-[#3D425C] sm:h-full h-[548px] w-full">
// <div className="absolute overflow-x-clip h-full ">
// <div {...handlers} className="absolute h-full w-full z-10" />
// <div
// className="flex gap-4 w-full h-full transition-all duration-300 ease-in-out 2xl:pl-10 xl:pl-8 sm:pl-3 xl:pb-10 sm:pb-[25px] "
// style={{
// transform: `translateX(${-selectedVideo * cardWidth}px)`,
// }}
// >
// {VIDEOS.map((video, index) => (
// <div
// key={video.id}
// className={`relative 2xl:w-[984px] xl:w-[789px] sm:w-[720px] w-[calc(100vw-32px)] 2xl:h-[554px] xl:h-[444px] sm:h-[404px] h-[206px] transition-opacity duration-300 ${
// selectedVideo === index ? "opacity-100" : "opacity-60"
// }`}
// >
// <img src="/images/posters/integra_crm.jpg" alt="img" />
// </div>
// ))}
// </div>
// </div>
// </div>
// <div className=" p-6 block sm:hidden mb-6">
// <h2 className="font-semibold text-sm leading-[18px] pb-2">
// {VIDEOS[selectedVideo].title}
// </h2>
// <p className="text-[12px] leading-[18px]">
// {VIDEOS[selectedVideo].desc}
// </p>
// </div>
// <div className="mx-auto flex gap-2 h-2 sm:hidden">
// {VIDEOS.map((video, index) => (
// <div
// key={video.id}
// className="h-full w-2 rounded-full transition-all duration-300"
// style={{
// background: `${
// selectedVideo === index ? "white" : "#a1a2a6"
// }`,
// }}
// />
// ))}
// </div>
// </div>
// </div>
// </motion.div>
// );
// };
function Reviews() {
const [selectedVideoIndex, setSelectedVideoIndex] = useState(0);
const videoRefs = REVIEWS.map(() => createRef<HTMLImageElement>());
const [videoWidth, setVideoWidth] = useState<number>(0);
const { ref, inView } = useInView();
const [isEntered, setIsEntered] = useState(false);
const handlers = useSwipeable({
onSwipedLeft: next,
onSwipedRight: prev,
trackMouse: true,
});
useEffect(() => {
if (videoRefs[0].current) {
const width = videoRefs[0].current.clientWidth;
setVideoWidth(width);
}
}, [videoRefs]);
function prev() {
if (selectedVideoIndex === 0) return;
setSelectedVideoIndex((prev) => prev - 1);
}
function next() {
if (selectedVideoIndex === REVIEWS.length - 1) return;
setSelectedVideoIndex((prev) => prev + 1);
}
useEffect(() => {
if (!inView || isEntered) return;
setIsEntered(true);
}, [inView]);
return (
<div
ref={ref}
className="container mx-auto 2xl:max-w-screen-2xl mb-[120px]"
>
<div className="flex 2xl:h-[594px] xl:h-[484px] sm:h-[784px] h-[552px] sm:border-b border-b-[#3D425C] xl:flex-row sm:flex-col-reverse flex-col ">
<div className="left 2xl:min-w-[496px] xl:min-w-[395px] sm:min-w-[354px] flex flex-col sm:pb-10 pb-6">
<h2 className="font-medium 2xl:text-[64px] xl:text-5xl text-[40px] sm:mb-10 mb-6 font-gilroy leading-10">
<p className="from-[#798FFF] to-[#D375FF] bg-gradient-to-r bg-clip-text text-transparent">
Отзывы
</p>
<p>клиентов</p>
</h2>
<div className="relative bg-white sm:block hidden">
{REVIEWS.map((item, index) => (
<Transition
key={index}
in={Boolean(index === selectedVideoIndex)}
timeout={300}
>
{(state) => (
<div
className={`absolute transition-opacity duration-300 pr-10 ${state}`}
>
{item.name ? (
<p className="font-semibold mb-4 2xl:text-xl xl:text-[16px]">
{item.name}
</p>
) : (
<></>
)}
<p className="font-normal 2xl:text-[16px] xl:text-[14px]">
{item.desc}
</p>
</div>
)}
</Transition>
))}
</div>
<div className="gap-2 hidden sm:flex mt-auto">
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={prev}
>
<ArrowLeftIcon />
</button>
<button
className="p-4 border border-[#3D425C] rounded-full"
onClick={next}
>
<ArrowRightIcon />
</button>
</div>
</div>
<div
{...handlers}
className="right relative sm:border-l border-l-[#3D425C] flex gap-4 sm:pb-10 sm:pl-10 select-none"
style={{
clipPath: `rect(auto auto auto 0)`,
}}
>
{REVIEWS.map((video, index) => (
<div
key={video.id}
className="relative sm:aspect-[16/9] aspect-auto bg-black transition-transform duration-300 sm:h-full sm:min-w-0 h-[546px]"
// className="relative sm:aspect-[16/9] aspect-auto bg-black transition-transform duration-300 sm:h-full sm:min-w-0 h-[546px]"
style={{
transform: `translateX(-${
videoWidth * selectedVideoIndex + 16 * selectedVideoIndex
}px)`,
}}
>
<img
src={isEntered ? video.poster : undefined}
alt={video.desc}
ref={videoRefs[index]}
className="aspect-[16/9] object-cover w-full h-full min-w-screen"
/>
</div>
))}
</div>
<div className="relative block sm:hidden h-[100%] bg-[#212431] p-6">
{REVIEWS.map((item, index) => (
<Transition
key={index}
in={Boolean(index === selectedVideoIndex)}
timeout={300}
>
{(state) => (
<div
className={`absolute transition-opacity duration-300 pr-10 ${state}`}
>
{item.name ? (
<p className="font-semibold mb-4 2xl:text-xl xl:text-[16px]">
{item.name}
</p>
) : (
<></>
)}
<p className="font-normal 2xl:text-[16px] xl:text-[14px]">
{item.desc}
</p>
</div>
)}
</Transition>
))}
</div>
<div className="mx-auto flex gap-2 min-h-2 sm:hidden relative mt-6">
{REVIEWS.map((video, index) => (
<div
key={video.id}
className="h-full w-2 rounded-full transition-all duration-300"
style={{
background: `${
selectedVideoIndex === index ? "white" : "#a1a2a6"
}`,
}}
/>
))}
</div>
</div>
</div>
);
}
export default Reviews;