upd
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
NEXT_PUBLIC_API=http://192.168.1.250:3001/
|
||||
NEXT_PUBLIC_OLD_API=https://graff.estate/api
|
||||
NEXT_PUBLIC_S3_BUCKET=https://storage.yandexcloud.net/dult-faib-knac-fint
|
||||
NEXT_PUBLIC_TINYMCE_API_KEY=2vf68779upg45y46o6g5gaxldy9gzr399eyaaqa0ki3mj2h2
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 356 KiB After Width: | Height: | Size: 216 KiB |
+5
-1
@@ -1,6 +1,10 @@
|
||||
import ky from 'ky';
|
||||
|
||||
export const oldApi = ky.extend({
|
||||
prefixUrl: process.env.NEXT_PUBLIC_OLD_API,
|
||||
});
|
||||
|
||||
export const api = ky.extend({
|
||||
prefixUrl: process.env.NEXT_PUBLIC_API,
|
||||
prefixUrl: process.env.NEXT_PUBLIC_OLD_API,
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AvailablesSlider } from '@/components/pages/MainPage/Availables/AvailablesSlider';
|
||||
import { Calculator } from '@/components/pages/MainPage/Calculator/Calculator';
|
||||
import { Clients } from '@/components/pages/MainPage/Clients';
|
||||
import { Datamining } from '@/components/pages/MainPage/Datamining';
|
||||
import { IntegrationsSlider } from '@/components/pages/MainPage/Integrations/IntegrationsSlider';
|
||||
@@ -6,6 +7,7 @@ import { Motivation } from '@/components/pages/MainPage/Motivation';
|
||||
import { Projects } from '@/components/pages/MainPage/Projects';
|
||||
import { Reviews } from '@/components/pages/MainPage/Reviews';
|
||||
import { Showreel } from '@/components/pages/MainPage/Showreel';
|
||||
import { Statistics } from '@/components/pages/MainPage/Statistics';
|
||||
import { Streaming } from '@/components/pages/MainPage/Streaming';
|
||||
import { Winners } from '@/components/pages/MainPage/Winners';
|
||||
import { integrations } from '@/consts/integrations';
|
||||
@@ -24,7 +26,7 @@ export default function HomePage() {
|
||||
<DynamicEllipse />
|
||||
<Motivation />
|
||||
<Showreel />
|
||||
{/* <Statistics /> */}
|
||||
<Statistics />
|
||||
<IntegrationsSlider integrations={integrations} />
|
||||
<AvailablesSlider
|
||||
availables={[
|
||||
@@ -47,7 +49,7 @@ export default function HomePage() {
|
||||
/>
|
||||
<Streaming />
|
||||
<Datamining />
|
||||
{/* <Calculator /> */}
|
||||
<Calculator />
|
||||
<Reviews />
|
||||
<Winners />
|
||||
<Projects />
|
||||
|
||||
@@ -20,8 +20,7 @@ export function Feedback() {
|
||||
className="lg:px-6 px-4 sm:grid lg:grid-cols-12 sm:grid-cols-2 lg:gap-x-4 sm:gap-x-14 lg:gap-y-[68px] pb-20 pt-[70px]"
|
||||
>
|
||||
<h2 className="font-medium lg:col-span-7 sm:col-span-full h2 max-lg:mb-6">
|
||||
Хотите использовать интерактивные тренажеры в обучении?
|
||||
<br />
|
||||
Хотите увеличить конверсию? <br />
|
||||
<span className="text-gradient">Давайте обсудим детали.</span>
|
||||
</h2>
|
||||
<Button
|
||||
|
||||
@@ -64,7 +64,10 @@ export function Header() {
|
||||
</Button>
|
||||
<button
|
||||
ref={menuBtnRef}
|
||||
className="h-full p-3 mr-0 aspect-square lg:hidden"
|
||||
className={
|
||||
'h-full p-3 mr-0 aspect-square lg:hidden' +
|
||||
(menuOpen ? ' bg-[#798FFF]' : '')
|
||||
}
|
||||
onClick={() => setMenuOpen(prev => !prev)}
|
||||
>
|
||||
<ClassNameWrapper
|
||||
@@ -89,22 +92,9 @@ export function Header() {
|
||||
(menuOpen ? ' shadow-[0_0_0_9999px_rgba(0,0,0,.4)]' : '')
|
||||
}
|
||||
>
|
||||
<ProductsList inBurger />
|
||||
<BurgerLink href="/about">О нас</BurgerLink>
|
||||
<BurgerLink href="/blog">Блог</BurgerLink>
|
||||
<BurgerLink href="/projects">Проекты</BurgerLink>
|
||||
{/* <div className="grid grid-cols-[2fr_1fr_1fr] sm:grid-cols-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setMenuOpen(false);
|
||||
setModal(<ModalWithForm />, 'form');
|
||||
}}
|
||||
width="full"
|
||||
className="font-semibold rounded-none sm:hidden btn-text"
|
||||
>
|
||||
Оставить заявку
|
||||
</Button>
|
||||
</div> */}
|
||||
</motion.div>
|
||||
)}
|
||||
</header>
|
||||
|
||||
@@ -16,7 +16,9 @@ export function TagFilterItem({
|
||||
multiple?: boolean;
|
||||
}) {
|
||||
const { push } = useRouter();
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
const params = new URLSearchParams(useSearchParams());
|
||||
|
||||
function clickHandler() {
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
export function PhoneIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
width={28}
|
||||
height={28}
|
||||
viewBox="0 0 28 28"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
color="currentColor"
|
||||
>
|
||||
<g id="Icon/Phone" opacity="0.8">
|
||||
<path
|
||||
id="phone"
|
||||
d="M13.2467 8.50638L10.4411 5.70883C9.93919 5.20838 9.12547 5.20839 8.62358 5.70883L6.29613 8.02957C3.39974 10.9176 7.6513 17.8 10.9553 21.0945C14.2395 24.3692 21.0664 28.5923 23.9628 25.7043L26.2902 23.3835C26.7921 22.8831 26.7921 22.0717 26.2902 21.5713L23.4846 18.7737C22.9827 18.2733 22.169 18.2733 21.6671 18.7737L19.5362 20.8984C19.4067 21.0276 19.2417 21.1047 19.0714 21.0372C18.6101 20.8542 17.4325 20.137 14.6538 17.4066C11.8643 14.6655 11.1485 13.4312 10.9713 12.9337C10.9044 12.7461 10.992 12.5669 11.1332 12.4261L13.2473 10.318C13.7492 9.8176 13.7486 9.00683 13.2467 8.50638Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M22.1325 24.6073L3.9834 6.45825V9.75808L18.8326 24.6073L22.1325 24.6073Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M10.5825 11.4078L13.8824 8.10802L9.75758 3.98323H6.45775L4.80783 5.63314L10.5825 11.4078Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M17.1809 18.0074L22.9556 23.7821L24.6055 22.1321L24.6055 18.8323L20.4807 14.7075L17.1809 18.0074Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/api';
|
||||
import { oldApi } from '@/api';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useModalStore } from '@/stores/useModalStore';
|
||||
import { Button } from '@/ui/Button';
|
||||
@@ -47,7 +47,7 @@ export function ModalWithForm() {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
await api
|
||||
await oldApi
|
||||
.post('mail', {
|
||||
json: {
|
||||
fullname: name,
|
||||
@@ -89,9 +89,9 @@ export function ModalWithForm() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6">
|
||||
<div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6 z-40">
|
||||
{!isSend ? (
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-8 z-40 relative">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="font-medium accent">Оставьте заявку</p>
|
||||
<button
|
||||
@@ -113,7 +113,6 @@ export function ModalWithForm() {
|
||||
Имя
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
id="name"
|
||||
type="text"
|
||||
value={name}
|
||||
@@ -137,7 +136,6 @@ export function ModalWithForm() {
|
||||
/>
|
||||
<div className="border-l border-[#3D425C]" />
|
||||
<ReactInputMask
|
||||
required
|
||||
type="tel"
|
||||
id={'tel'}
|
||||
mask={placeholder?.replace(/\d/g, '9') ?? ''}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { AnimatePresence, motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import { RefObject, useEffect, useRef, useState } from 'react';
|
||||
import { useOnClickOutside } from 'usehooks-ts';
|
||||
import { CloseIcon } from '../icons/CloseIcon';
|
||||
|
||||
interface IProduct {
|
||||
id: number;
|
||||
@@ -51,7 +50,7 @@ export function ModalWithProducts({
|
||||
exit={{
|
||||
opacity: 0,
|
||||
}}
|
||||
className="pt-10 p-6 bg-[#14161F] bg-opacity-90 z-100 aspect-[1600/720] lg:top-16 top-12 relative space-y-6 backdrop-blur-3xl"
|
||||
className="pt-10 p-6 bg-[#14161F] bg-opacity-90 z-100 lg:top-16 top-4 relative grid grid-cols-4 gap-y-4 backdrop-blur-3xl"
|
||||
>
|
||||
<motion.h4
|
||||
initial={{ y: -76 }}
|
||||
@@ -59,31 +58,34 @@ export function ModalWithProducts({
|
||||
exit={{ y: -76 }}
|
||||
key={'title'}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="flex items-center justify-between font-medium h4"
|
||||
className="font-medium h4 col-span-1"
|
||||
>
|
||||
GRAFF.estate
|
||||
<button
|
||||
onClick={() => setShow(false)}
|
||||
className="hover:bg-[#3D425C] rounded-full p-2"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
Продукты
|
||||
</motion.h4>
|
||||
<motion.div
|
||||
initial={{ y: -76 }}
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: -76 }}
|
||||
key={'title'}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="border-y border-[#3D425C] row-start-2"
|
||||
/>
|
||||
<motion.div
|
||||
initial={{ y: -76 }}
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: -76 }}
|
||||
key={'products'}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="grid grid-rows-2 mt-px ml-px grid-col-3"
|
||||
className="grid grid-rows-3 mt-px ml-px grid-cols-2 col-start-2 col-span-3 row-start-2"
|
||||
>
|
||||
{Products.map((product, index) => (
|
||||
<ProductItem
|
||||
key={product.id}
|
||||
{...product}
|
||||
className={`col-start-${(index % 3) + 1} row-start-${index < 3 ? 1 : 2}`}
|
||||
className={`row-start-${(index % 3) + 1} col-start-${index < 3 ? 1 : 2}`}
|
||||
/>
|
||||
))}
|
||||
<motion.div className="border-b border-r border-[#3D425C]" />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
@@ -105,7 +107,7 @@ function ProductItem({
|
||||
}}
|
||||
transition={{ duration: 0.2, type: 'just', delay: 0.1 }}
|
||||
className={
|
||||
'border border-[#3D425C] -mt-px -ml-px p-6 flex col-span-1 row-span-1 aspect-[517/304] bg-[url(/img/components/products/highlight.svg)] bg-[length:0px_0px] bg-left-top bg-no-repeat cursor-pointer ' +
|
||||
'border border-[#3D425C] -mt-px -ml-px p-6 aspect-[588/207] flex bg-[url(/img/components/products/highlight.svg)] bg-[length:0px_0px] bg-left-top bg-no-repeat cursor-pointer ' +
|
||||
className
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/api';
|
||||
import { oldApi } from '@/api';
|
||||
import regionsData from '@/consts/regionsData.json';
|
||||
import { useWindowWidth } from '@/hooks/useWindowWidth';
|
||||
import { Descriptor } from '@/ui/Descriptor';
|
||||
@@ -41,7 +41,7 @@ export function Calculator() {
|
||||
const [calculated, setCalculated] = useState(true);
|
||||
|
||||
async function getRegionName() {
|
||||
const result: any = await api.get('getRegionName').json();
|
||||
const result: any = await oldApi.get('getRegionName').json();
|
||||
|
||||
if (result.error) {
|
||||
setSelectedRegion(regionsData.find(region => region.id === 11));
|
||||
@@ -55,6 +55,20 @@ export function Calculator() {
|
||||
setSelectedRegion(foundRegion);
|
||||
}
|
||||
|
||||
// useGetRegionNameQuery({
|
||||
// onCompleted: data => {
|
||||
// if (data.regionName.__typename === 'Region') {
|
||||
// const { regionName } = data.regionName;
|
||||
// setSelectedRegion(
|
||||
// regionsData.find(region => region.name === regionName) ||
|
||||
// regionsData.find(region => region.id === 11),
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
// setSelectedRegion(regionsData.find(region => region.id === 11));
|
||||
// },
|
||||
// });
|
||||
|
||||
useEffect(() => {
|
||||
getRegionName();
|
||||
}, []);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ClientIcon } from '@/components/icons/ClientIcon';
|
||||
import { ListIcon } from '@/components/icons/ListIcon';
|
||||
import { MailIcon } from '@/components/icons/MailIcon';
|
||||
import { PhoneIcon } from '@/components/icons/PhoneIcon';
|
||||
import { Title } from '@/ui/Title';
|
||||
import Image from 'next/image';
|
||||
|
||||
@@ -19,7 +19,30 @@ export function Datamining() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 my-4 w-full bg-[url(/img/pages/home/projectmanagment/Ellipse.png)] lg:flex flex-col justify-between sm:max-lg:col-start-1 col-span-1 space-y-[140px]">
|
||||
<ListIcon />
|
||||
{/* <ListIcon /> */}
|
||||
<div className="flex max-w-16 relative">
|
||||
<Image
|
||||
src={'/img/components/datamining/2k.png'}
|
||||
alt="room2"
|
||||
width={64}
|
||||
height={64}
|
||||
className="!relative z-[2]"
|
||||
/>
|
||||
<Image
|
||||
src={'/img/components/datamining/room1.png'}
|
||||
alt="room1"
|
||||
width={64}
|
||||
height={64}
|
||||
className="!relative -left-4 z-[1]"
|
||||
/>
|
||||
<Image
|
||||
src={'/img/components/datamining/room2.png'}
|
||||
alt="room1"
|
||||
width={64}
|
||||
height={64}
|
||||
className="!relative -left-8"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="font-medium sm:max-lg:h3 h4">
|
||||
Актуальная информация о квартирах
|
||||
@@ -31,7 +54,21 @@ export function Datamining() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 sm:my-4 max-sm:mb-4 w-full bg-[url(/img/pages/home/projectmanagment/Ellipse.png)] flex flex-col justify-between sm:max-lg:col-start-2 col-span-1 space-y-[140px]">
|
||||
<ClientIcon />
|
||||
<div className="flex max-h-16">
|
||||
<Image
|
||||
src={'/img/components/datamining/vova.png'}
|
||||
alt="vova"
|
||||
width={64}
|
||||
height={64}
|
||||
className="!relative z-[2]"
|
||||
/>
|
||||
<div className="p-[18px] rounded-full bg-[#33353E] max-h-[60px] relative -left-4 z-[1] drop-shadow-[0_4px_4px_rgba(0,0,0,0.25)]">
|
||||
<MailIcon />
|
||||
</div>
|
||||
<div className="p-[18px] rounded-full bg-[#33353E] max-h-[60px] relative -left-8">
|
||||
<PhoneIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="font-medium sm:max-lg:h3 h4">
|
||||
Создание карточки клиента
|
||||
|
||||
@@ -4,7 +4,6 @@ import { ArrowMoreIcon } from '@/components/icons/ArrowMoreIcon';
|
||||
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
|
||||
import { useGetProjectsQuery } from '@/queries/projects/getProjects';
|
||||
import { IProject } from '@/types/IProject';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Descriptor } from '@/ui/Descriptor';
|
||||
import { getProjectsCount } from '@/utils/getProjectsCount';
|
||||
import { getSortedProjects } from '@/utils/getSortedProjects';
|
||||
@@ -48,9 +47,8 @@ export function Projects() {
|
||||
<Descriptor title="Проекты" />
|
||||
<p className="accent font-medium">
|
||||
За <span className="text-gradient">13 лет</span> работы мы
|
||||
реализовали
|
||||
реализовали{' '}
|
||||
<span className="text-gradient">
|
||||
{' '}
|
||||
{getProjectsCount(
|
||||
Array.from(sortedProjects?.values() ?? [])?.flat().length,
|
||||
)}
|
||||
@@ -58,20 +56,16 @@ export function Projects() {
|
||||
в разных городах России и мира
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
color="secondary"
|
||||
className="lg:col-start-4 self-end w-full py-4 bg-[#14161F]"
|
||||
icon={
|
||||
<ClassNameWrapper
|
||||
className="lg:w-8 lg:h-8 sm:w-6 sm:h-6"
|
||||
element={<ArrowMoreIcon />}
|
||||
/>
|
||||
}
|
||||
<Link
|
||||
href={'/projects'}
|
||||
className="lg:col-start-4 self-end w-full bg-[#14161F] btn-text flex justify-between items-center rounded-full border border-[#3D425C] py-5 px-6"
|
||||
>
|
||||
<Link href={'/projects'} className="btn-text">
|
||||
Все проекты{' '}
|
||||
</Link>
|
||||
</Button>
|
||||
Все проекты
|
||||
<ClassNameWrapper
|
||||
className="lg:w-8 lg:h-8 sm:w-6 sm:h-6"
|
||||
element={<ArrowMoreIcon />}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
<ProjectsSection
|
||||
showMore={!all}
|
||||
|
||||
@@ -20,7 +20,7 @@ export function Reviews() {
|
||||
</Title>
|
||||
<Descriptor title="отзывы клиентов" className="lg:hidden sm:mb-8 mb-6" />
|
||||
<div className="relative w-full xl:aspect-[1552/616] sm:aspect-[720/412]">
|
||||
<div className="lg:absolute flex flex-wrap bottom-10 left-10 gap-2 z-10 sm:max-lg:mb-6 max-sm:mb-4">
|
||||
<div className="lg:absolute flex flex-wrap bottom-10 left-10 gap-2 z-[1] sm:max-lg:mb-6 max-sm:mb-4">
|
||||
<ReviewTab
|
||||
onClick={() => setTab(0)}
|
||||
active={tab === 0}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/api';
|
||||
import { useGetProjectsQuery } from '@/queries/projects/getProjects';
|
||||
import { IProject } from '@/types/IProject';
|
||||
import { Descriptor } from '@/ui/Descriptor';
|
||||
import { Title } from '@/ui/Title';
|
||||
import { getProjectsCount } from '@/utils/getProjectsCount';
|
||||
import { motion, useInView, useMotionValue, useSpring } from 'framer-motion';
|
||||
import { Manrope } from 'next/font/google';
|
||||
import Image from 'next/image';
|
||||
@@ -15,20 +16,16 @@ const manrope = Manrope({ subsets: ['latin'] });
|
||||
export function Statistics() {
|
||||
const [projects, setProjects] = useState<IProject[]>([]);
|
||||
|
||||
async function getProjects() {
|
||||
try {
|
||||
const projects: IProject[] = await api.get('projects').json();
|
||||
return projects;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(`Error: ${error.message}`);
|
||||
useGetProjectsQuery({
|
||||
variables: { devices: [] },
|
||||
onCompleted(data) {
|
||||
if (data.projects.__typename === 'Error') {
|
||||
alert(data.projects.message);
|
||||
} else if (data.projects.__typename === 'Projects') {
|
||||
setProjects(data.projects.projects as IProject[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getProjects().then(projects => setProjects(projects!));
|
||||
}, []);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<section className="lg:space-y-20 sm:space-y-12 space-y-8">
|
||||
@@ -44,8 +41,7 @@ export function Statistics() {
|
||||
<div className="grid lg:grid-cols-12 grid-cols-2 border-t border-[#3D425C]">
|
||||
<div className="lg:col-span-3 col-span-2 lg:pt-10 sm:py-8 py-4 lg:border-r border-b border-[#3D425C] accent font-medium">
|
||||
Мы собрали статистику за 13 лет работы c застройщиками,
|
||||
реализовав
|
||||
{/* {getProjectsCount(projects.length)} */}
|
||||
реализовав {getProjectsCount(projects.length)}
|
||||
</div>
|
||||
<div className="lg:col-start-4 lg:col-span-full sm:col-span-2 lg:py-10 lg:pl-4 border-b border-[#3D425C] aspect-[1176/570] max-md:hidden">
|
||||
<ProjectsMap />
|
||||
|
||||
@@ -25,7 +25,7 @@ export function Streaming() {
|
||||
выбора квартиры
|
||||
</p>
|
||||
</div>
|
||||
<div className="lg:py-4 py-8 lg:pl-4 w-full lg:col-start-4 lg:col-span-full sm:col-span-2 lg:border-t sm:max-lg:border-b border-[#3D425C]">
|
||||
<div className="lg:pt-4 py-8 lg:pl-4 w-full lg:col-start-4 lg:col-span-full sm:col-span-2 lg:border-t sm:max-lg:border-b border-[#3D425C]">
|
||||
<video
|
||||
src="/videos/pages/home/technology.mp4"
|
||||
autoPlay
|
||||
@@ -34,13 +34,13 @@ export function Streaming() {
|
||||
className="lg:aspect-[1160/652]"
|
||||
/>
|
||||
</div>
|
||||
<div className="lg:pt-10 sm:max-lg:py-8 max-sm:py-6 lg:flex flex-col justify-between lg:row-start-2 lg:col-span-3 sm:col-span-1 lg:border-y sm:max-lg:space-y-5 max-sm:space-y-3 max-sm:border-t lg:border-r border-[#3D425C]">
|
||||
<div className="lg:pt-10 lg:pb-8 sm:max-lg:py-8 max-sm:py-6 lg:flex flex-col justify-between lg:row-start-2 lg:col-span-3 sm:col-span-1 lg:border-y sm:max-lg:space-y-5 max-sm:space-y-3 max-sm:border-t lg:border-r border-[#3D425C]">
|
||||
<Descriptor title="Демоверсии" />
|
||||
<p className="l-text">
|
||||
Местоположение и устройство не имеют значения. Нужен только интернет
|
||||
</p>
|
||||
</div>
|
||||
<div className="lg:p-4 sm:pb-8 min-[480px]:grid space-y-4 grid-cols-2 xl:grid-cols-3 gap-4 lg:col-start-4 col-span-full lg:border-y sm:max-lg:border-b border-[#3D425C]">
|
||||
<div className="lg:p-4 sm:pb-8 min-[480px]:grid max-sm:space-y-4 grid-cols-2 xl:grid-cols-3 gap-4 lg:col-start-4 col-span-full lg:border-y sm:max-lg:border-b border-[#3D425C]">
|
||||
<StreamingProject
|
||||
city="Екатеринбург"
|
||||
name="Re:volution Towers"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DeleteProjectModal } from '@/components/modals/DeleteProjectModal';
|
||||
import {
|
||||
IAddProjectFormInput,
|
||||
ProjectFormModal,
|
||||
@@ -8,6 +9,7 @@ import { useModalStore } from '@/stores/useModalStore';
|
||||
import { IProject } from '@/types/IProject';
|
||||
import { DeviceBadge } from '@/ui/DeviceBadge';
|
||||
import { ProgressPie } from '@/ui/ProgressPie';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
@@ -19,12 +21,22 @@ export function ProjectCard({
|
||||
stage = 6,
|
||||
devices,
|
||||
id,
|
||||
releaseDate,
|
||||
}: IProject) {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
const client = useApolloClient();
|
||||
|
||||
const { data } = useCheckAuthQuery();
|
||||
|
||||
const [editProject] = useEditProjectMutation();
|
||||
const [editProject] = useEditProjectMutation({
|
||||
onCompleted() {
|
||||
setModal(null, '');
|
||||
client.refetchQueries({
|
||||
include: ['GetProjects'],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const stagePercentage = Math.round((100 / 6) * stage);
|
||||
const params = useSearchParams();
|
||||
@@ -38,69 +50,76 @@ export function ProjectCard({
|
||||
transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }}
|
||||
className="group relative aspect-square p-4 flex items-end overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 right-0 p-4 flex gap-2">
|
||||
<button
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<ProjectFormModal
|
||||
action="edit"
|
||||
onSubmit={(data: IAddProjectFormInput) => {
|
||||
console.log(data);
|
||||
editProject({
|
||||
variables: { id, input: data },
|
||||
});
|
||||
}}
|
||||
defaultValues={{
|
||||
...project,
|
||||
devices: project.devices as Device[],
|
||||
}}
|
||||
/>,
|
||||
'editProject',
|
||||
)
|
||||
}
|
||||
className="group relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
|
||||
/>
|
||||
</svg>
|
||||
<span className="pointer-events-none group-hover:opacity-100 opacity-0 transition-opacity absolute -bottom-[90%] left-[50%] -translate-x-[50%] bg-neutral-900 px-2 py-1 text-sm rounded-lg">
|
||||
Редактировать
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setModal(<DeleteProjectModal id={id} />, '')}
|
||||
className="group relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
<span className="pointer-events-none group-hover:opacity-100 opacity-0 transition-opacity absolute -bottom-[90%] left-[50%] -translate-x-[50%] bg-neutral-900 px-2 py-1 text-sm rounded-lg">
|
||||
Удалить
|
||||
</span>
|
||||
</button>
|
||||
</div>{' '}
|
||||
{data?.checkAuth.__typename === 'CheckAuthResponse' &&
|
||||
data.checkAuth.isAuth && (
|
||||
<div className="absolute top-0 right-0 p-4 flex gap-2 z-10">
|
||||
<button
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<ProjectFormModal
|
||||
action="edit"
|
||||
onSubmit={(data: IAddProjectFormInput) => {
|
||||
editProject({
|
||||
variables: { id, input: data },
|
||||
});
|
||||
}}
|
||||
defaultValues={{
|
||||
image,
|
||||
name,
|
||||
company,
|
||||
city,
|
||||
stage,
|
||||
releaseDate,
|
||||
devices,
|
||||
}}
|
||||
/>,
|
||||
'editProject',
|
||||
)
|
||||
}
|
||||
className="group relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
|
||||
/>
|
||||
</svg>
|
||||
<span className="pointer-events-none group-hover:opacity-100 opacity-0 transition-opacity absolute -bottom-[90%] left-[50%] -translate-x-[50%] bg-neutral-900 px-2 py-1 text-sm rounded-lg">
|
||||
Редактировать
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setModal(<DeleteProjectModal id={id} />, '')}
|
||||
className="group relative p-2 bg-black bg-opacity-60 hover:bg-opacity-70 transition-opacity rounded-full"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
<span className="pointer-events-none group-hover:opacity-100 opacity-0 transition-opacity absolute -bottom-[90%] left-[50%] -translate-x-[50%] bg-neutral-900 px-2 py-1 text-sm rounded-lg">
|
||||
Удалить
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="group-hover:scale-110 transition-transform duration-500 absolute top-0 left-0 w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { TagFilterItem } from '@/components/TagFilterItem';
|
||||
import { YearFilterDropdown } from '@/components/YearFilterDropdown';
|
||||
import { YearFilterItem } from '@/components/YearFilterItem';
|
||||
import { ProjectTags } from '@/consts/ProjectTags';
|
||||
import { ProjectYears } from '@/consts/ProjectYears';
|
||||
import { Vertical } from '@/ui/Vertical';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
@@ -27,14 +24,14 @@ export function ProjectsFilters() {
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-4 h-fit max-sm:hidden">
|
||||
{/* <div className="flex flex-wrap gap-4 h-fit max-sm:hidden">
|
||||
{ProjectYears.map(year => (
|
||||
<YearFilterItem key={year} text={year} chosen={year === chosenYear} />
|
||||
))}
|
||||
<Vertical />
|
||||
<YearFilterItem text="Все время" isAll chosen={!params.has('year')} />
|
||||
</div>
|
||||
<YearFilterDropdown years={ProjectYears} />
|
||||
<YearFilterDropdown years={ProjectYears} /> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,15 +22,16 @@ export function ProjectsSection({
|
||||
const [filteredProjects, setFilteredProjects] = useState(projects);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(projects);
|
||||
setFilteredProjects(
|
||||
projects.filter(
|
||||
project =>
|
||||
(!params.has('tags') ||
|
||||
(params.getAll('tags') as Device[]).every(tag =>
|
||||
project.devices.includes(tag),
|
||||
)) &&
|
||||
(!params.has('year') ||
|
||||
params.get('year') === project.releaseDate.split('-')[0]),
|
||||
!params.has('tags') ||
|
||||
(params.getAll('tags') as Device[]).every(tag =>
|
||||
project.devices.includes(tag),
|
||||
),
|
||||
// &&(!params.has('year') ||
|
||||
// params.get('year') === project.releaseDate.split('-')[0]),
|
||||
),
|
||||
);
|
||||
}, [projects, params]);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { Device } from '@/types/IProject';
|
||||
|
||||
export const ProjectTags: Device[] = ['mobile', 'stream', 'touch', 'vr'];
|
||||
export const ProjectTags: Device[] = ['Mobile', 'Stream', 'Touch', 'VR'];
|
||||
|
||||
@@ -13,24 +13,18 @@
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "View",
|
||||
"text": "Интерактивное окно",
|
||||
"image": "/img/components/products/view.png"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Web",
|
||||
"text": "Создание сайтов",
|
||||
"image": "/img/components/products/web.png"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"id": 3,
|
||||
"title": "360",
|
||||
"text": "Сферы для сайта",
|
||||
"image": "/img/components/products/360.png"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"id": 4,
|
||||
"title": "Picture",
|
||||
"text": "Архитектурная визуализация",
|
||||
"image": "/img/components/products/picture.png"
|
||||
|
||||
@@ -186,6 +186,7 @@ export type Query = {
|
||||
logout: LogoutResult;
|
||||
project: ProjectResult;
|
||||
projects: ProjectsResult;
|
||||
regionName: RegionResult;
|
||||
};
|
||||
|
||||
|
||||
@@ -219,6 +220,13 @@ export type Quote = {
|
||||
type: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type Region = {
|
||||
__typename?: 'Region';
|
||||
regionName: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type RegionResult = Error | Region;
|
||||
|
||||
export type Slider = {
|
||||
__typename?: 'Slider';
|
||||
images: Array<Image>;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import * as Types from '../../generated/graphql';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type GetRegionNameQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetRegionNameQuery = { __typename?: 'Query', regionName: { __typename?: 'Error', message: string } | { __typename?: 'Region', regionName: string } };
|
||||
|
||||
|
||||
export const GetRegionNameDocument = gql`
|
||||
query GetRegionName {
|
||||
regionName {
|
||||
... on Region {
|
||||
regionName
|
||||
}
|
||||
... on Error {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetRegionNameQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetRegionNameQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetRegionNameQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetRegionNameQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetRegionNameQuery(baseOptions?: Apollo.QueryHookOptions<GetRegionNameQuery, GetRegionNameQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetRegionNameQuery, GetRegionNameQueryVariables>(GetRegionNameDocument, options);
|
||||
}
|
||||
export function useGetRegionNameLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetRegionNameQuery, GetRegionNameQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetRegionNameQuery, GetRegionNameQueryVariables>(GetRegionNameDocument, options);
|
||||
}
|
||||
export function useGetRegionNameSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetRegionNameQuery, GetRegionNameQueryVariables>) {
|
||||
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useSuspenseQuery<GetRegionNameQuery, GetRegionNameQueryVariables>(GetRegionNameDocument, options);
|
||||
}
|
||||
export type GetRegionNameQueryHookResult = ReturnType<typeof useGetRegionNameQuery>;
|
||||
export type GetRegionNameLazyQueryHookResult = ReturnType<typeof useGetRegionNameLazyQuery>;
|
||||
export type GetRegionNameSuspenseQueryHookResult = ReturnType<typeof useGetRegionNameSuspenseQuery>;
|
||||
export type GetRegionNameQueryResult = Apollo.QueryResult<GetRegionNameQuery, GetRegionNameQueryVariables>;
|
||||
@@ -0,0 +1,10 @@
|
||||
query GetRegionName {
|
||||
regionName {
|
||||
... on Region {
|
||||
regionName
|
||||
}
|
||||
... on Error {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './getRegionName.generated';
|
||||
@@ -1,4 +1,4 @@
|
||||
export type Device = 'stream' | 'touch' | 'mobile' | 'vr';
|
||||
export type Device = 'Stream' | 'Touch' | 'Mobile' | 'VR';
|
||||
|
||||
export interface IProject {
|
||||
id: number;
|
||||
|
||||
Reference in New Issue
Block a user