285 lines
13 KiB
TypeScript
285 lines
13 KiB
TypeScript
|
|
import React, { useState, useEffect } from 'react';
|
|||
|
|
import PageHeader from '../components/PageHeader';
|
|||
|
|
import { FileText, X, ChevronLeft, ChevronRight } from 'lucide-react';
|
|||
|
|
|
|||
|
|
interface Certificate {
|
|||
|
|
id: number;
|
|||
|
|
image: string;
|
|||
|
|
title: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface CertificateSection {
|
|||
|
|
title: string;
|
|||
|
|
certificates: Certificate[];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const CertificatesPage: React.FC = () => {
|
|||
|
|
const [selectedImageIndex, setSelectedImageIndex] = useState<number | null>(null);
|
|||
|
|
|
|||
|
|
const sections: CertificateSection[] = [
|
|||
|
|
{
|
|||
|
|
title: 'ПРОГРАММНЫЕ ПРОДУКТЫ КРЕДО',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 1, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Сертификат' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ СРО ПО СТРОИТЕЛЬСТВУ',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 2, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 3, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' },
|
|||
|
|
{ id: 4, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 3' },
|
|||
|
|
{ id: 5, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 4' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ СРО ПО ПРОЕКТИРОВАНИЮ',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 6, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 7, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ СРО ПО ИЗЫСКАНИЯМ',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 8, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 9, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ РЕЕСТРА ЧЛЕНОВ САМОРЕГУЛИРУЕМОЙ ОРГАНИЗАЦИИ, ОСНОВАННОЙ НА ЧЛЕНСТВЕ ЛИЦ, ОСУЩЕСТВЛЯЮЩИХ СТРОИТЕЛЬСТВО',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 10, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 11, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' },
|
|||
|
|
{ id: 12, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 3' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ РЕЕСТРА ЧЛЕНОВ САМОРЕГУЛИРУЕМОЙ ОРГАНИЗАЦИИ, ОСНОВАННОЙ НА ЧЛЕНСТВЕ ЛИЦ, ОСУЩЕСТВЛЯЮЩИХ ИНЖЕНЕРНЫЕ ИЗЫСКАНИЯ',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 13, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 14, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'ВЫПИСКА ИЗ РЕЕСТРА ЧЛЕНОВ САМОРЕГУЛИРУЕМОЙ ОРГАНИЗАЦИИ, ОСНОВАННОЙ НА ЧЛЕНСТВЕ ЛИЦ, ОСУЩЕСТВЛЯЮЩИХ ПРОЕКТНЫЕ РАБОТЫ',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 15, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 16, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'СВЕДЕНИЕ НА ОСУЩЕСТВЛЕНИЕ ГЕОДЕЗИЧЕСКОЙ И КАРТОГРАФИЧЕСКОЙ ДЕЯТЕЛЬНОСТИ ФЕДЕРАЛЬНАЯ СЛУЖБА ГОСУДАРСТВА',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 17, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 18, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: 'СВИДЕТЕЛЬСТВО О ПРОХОЖДЕНИИ ИСПЫТАНИЙ И КОНТРОЛЯ ПО ISO 9001',
|
|||
|
|
certificates: [
|
|||
|
|
{ id: 19, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 1' },
|
|||
|
|
{ id: 20, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 2' },
|
|||
|
|
{ id: 21, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 3' },
|
|||
|
|
{ id: 22, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 4' },
|
|||
|
|
{ id: 23, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 5' },
|
|||
|
|
{ id: 24, image: 'https://placehold.co/400x600/94a3b8/white', title: 'Документ 6' }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Создаем плоский массив всех изображений для навигации
|
|||
|
|
const allImages = sections.flatMap(section => section.certificates.map(cert => cert.image));
|
|||
|
|
|
|||
|
|
const openModal = (image: string) => {
|
|||
|
|
const index = allImages.indexOf(image);
|
|||
|
|
setSelectedImageIndex(index);
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const closeModal = () => {
|
|||
|
|
setSelectedImageIndex(null);
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const nextImage = () => {
|
|||
|
|
if (selectedImageIndex !== null) {
|
|||
|
|
setSelectedImageIndex((selectedImageIndex + 1) % allImages.length);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const prevImage = () => {
|
|||
|
|
if (selectedImageIndex !== null) {
|
|||
|
|
setSelectedImageIndex((selectedImageIndex - 1 + allImages.length) % allImages.length);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Обработка клавиатуры
|
|||
|
|
useEffect(() => {
|
|||
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|||
|
|
if (selectedImageIndex === null) return;
|
|||
|
|
|
|||
|
|
if (e.key === 'Escape') {
|
|||
|
|
closeModal();
|
|||
|
|
} else if (e.key === 'ArrowRight') {
|
|||
|
|
nextImage();
|
|||
|
|
} else if (e.key === 'ArrowLeft') {
|
|||
|
|
prevImage();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.addEventListener('keydown', handleKeyDown);
|
|||
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|||
|
|
}, [selectedImageIndex]);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="bg-white pb-20">
|
|||
|
|
<PageHeader
|
|||
|
|
title="Сертификаты"
|
|||
|
|
description="Документы, подтверждающие нашу квалификацию и соответствие стандартам качества"
|
|||
|
|
image="/media/images/headers/header-certificates.png"
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<div className="container mx-auto px-6 py-20">
|
|||
|
|
<div className="max-w-7xl mx-auto">
|
|||
|
|
<h2 className="text-3xl font-bold text-gray-900 mb-12 text-center">
|
|||
|
|
СВИДЕТЕЛЬСТВА
|
|||
|
|
</h2>
|
|||
|
|
|
|||
|
|
{/* Секции с сертификатами */}
|
|||
|
|
<div className="space-y-16">
|
|||
|
|
{sections.map((section, sectionIndex) => (
|
|||
|
|
<div key={sectionIndex} className="space-y-6">
|
|||
|
|
{/* Заголовок секции */}
|
|||
|
|
<div className="flex items-center gap-3 mb-8">
|
|||
|
|
<FileText className="text-brand-orange" size={28} />
|
|||
|
|
<h3 className="text-lg font-bold text-gray-900 uppercase leading-tight">
|
|||
|
|
{section.title}
|
|||
|
|
</h3>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Сетка документов */}
|
|||
|
|
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
|
|||
|
|
{section.certificates.map((cert) => (
|
|||
|
|
<div
|
|||
|
|
key={cert.id}
|
|||
|
|
onClick={() => openModal(cert.image)}
|
|||
|
|
className="group cursor-pointer"
|
|||
|
|
>
|
|||
|
|
<div className="relative aspect-[3/4] rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-all duration-300 bg-gray-100">
|
|||
|
|
<img
|
|||
|
|
src={cert.image}
|
|||
|
|
alt={cert.title}
|
|||
|
|
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
|
|||
|
|
/>
|
|||
|
|
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-colors" />
|
|||
|
|
|
|||
|
|
{/* Overlay при наведении */}
|
|||
|
|
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
|||
|
|
<div className="bg-brand-orange text-white px-4 py-2 rounded-lg font-semibold text-sm">
|
|||
|
|
Увеличить
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Информационный блок */}
|
|||
|
|
<div className="mt-20 bg-gray-50 rounded-2xl p-8 md:p-12">
|
|||
|
|
<div className="max-w-3xl mx-auto text-center">
|
|||
|
|
<h3 className="text-2xl font-bold text-gray-900 mb-4">
|
|||
|
|
Гарантия качества
|
|||
|
|
</h3>
|
|||
|
|
<p className="text-gray-600 leading-relaxed mb-6">
|
|||
|
|
ООО «ГЕОВЕКТОР» имеет все необходимые лицензии и сертификаты для осуществления
|
|||
|
|
деятельности в области проектирования, строительства и инженерных изысканий.
|
|||
|
|
Наша компания является членом саморегулируемых организаций и соответствует
|
|||
|
|
международным стандартам качества ISO 9001.
|
|||
|
|
</p>
|
|||
|
|
<div className="flex flex-wrap justify-center gap-4 mt-8">
|
|||
|
|
<div className="bg-white px-6 py-3 rounded-lg shadow-sm">
|
|||
|
|
<div className="text-2xl font-bold text-brand-orange mb-1">СРО</div>
|
|||
|
|
<div className="text-sm text-gray-600">Член организации</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="bg-white px-6 py-3 rounded-lg shadow-sm">
|
|||
|
|
<div className="text-2xl font-bold text-brand-orange mb-1">ISO 9001</div>
|
|||
|
|
<div className="text-sm text-gray-600">Сертифицирован</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="bg-white px-6 py-3 rounded-lg shadow-sm">
|
|||
|
|
<div className="text-2xl font-bold text-brand-orange mb-1">10+ лет</div>
|
|||
|
|
<div className="text-sm text-gray-600">На рынке</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Модальное окно для просмотра изображения */}
|
|||
|
|
{selectedImageIndex !== null && (
|
|||
|
|
<div
|
|||
|
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/95 p-4"
|
|||
|
|
onClick={closeModal}
|
|||
|
|
>
|
|||
|
|
{/* Кнопка закрытия */}
|
|||
|
|
<button
|
|||
|
|
onClick={closeModal}
|
|||
|
|
className="absolute top-4 right-4 bg-white/10 hover:bg-white/20 text-white p-3 rounded-full transition-colors z-10"
|
|||
|
|
aria-label="Закрыть"
|
|||
|
|
>
|
|||
|
|
<X size={28} />
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
{/* Кнопка "Назад" */}
|
|||
|
|
<button
|
|||
|
|
onClick={(e) => {
|
|||
|
|
e.stopPropagation();
|
|||
|
|
prevImage();
|
|||
|
|
}}
|
|||
|
|
className="absolute left-4 top-1/2 -translate-y-1/2 bg-white/10 hover:bg-white/20 text-white p-3 rounded-full transition-colors z-10"
|
|||
|
|
aria-label="Предыдущее изображение"
|
|||
|
|
>
|
|||
|
|
<ChevronLeft size={32} />
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
{/* Кнопка "Вперед" */}
|
|||
|
|
<button
|
|||
|
|
onClick={(e) => {
|
|||
|
|
e.stopPropagation();
|
|||
|
|
nextImage();
|
|||
|
|
}}
|
|||
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 bg-white/10 hover:bg-white/20 text-white p-3 rounded-full transition-colors z-10"
|
|||
|
|
aria-label="Следующее изображение"
|
|||
|
|
>
|
|||
|
|
<ChevronRight size={32} />
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
{/* Индикатор */}
|
|||
|
|
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 bg-black/50 text-white px-4 py-2 rounded-full text-sm font-semibold z-10">
|
|||
|
|
{selectedImageIndex + 1} / {allImages.length}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Изображение */}
|
|||
|
|
<div
|
|||
|
|
className="relative w-full h-full flex items-center justify-center"
|
|||
|
|
onClick={(e) => e.stopPropagation()}
|
|||
|
|
>
|
|||
|
|
<img
|
|||
|
|
src={allImages[selectedImageIndex]}
|
|||
|
|
alt={`Документ ${selectedImageIndex + 1}`}
|
|||
|
|
className="max-w-full max-h-[90vh] object-contain rounded-lg shadow-2xl"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default CertificatesPage;
|
|||
|
|
|