baza , notepp, sertificate pages connected to backend

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-03-05 17:14:58 +05:00
parent dad1070807
commit 9cc151a796
10 changed files with 243 additions and 150 deletions

View File

@@ -1,34 +1,8 @@
"use client";
import Image from "next/image";
import { motion } from "framer-motion";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { Guides } from "@/components/pages/about/aboutDetail/guides"; import { Guides } from "@/components/pages/about/aboutDetail/guides";
const ease = [0.22, 1, 0.36, 1] as [number, number, number, number];
export default function NotePPPage() { export default function NotePPPage() {
const t = useTranslations(); const t = useTranslations();
const guides = [
{
image: "/images/about/pp.avif",
title: t("about.notePPPage.hero.title"),
description: t("about.notePPPage.hero.description"),
eyebrow: t("about.notePPPage.hero.eyebrow"),
titleLine1: t("about.notePPPage.hero.titleLine1"),
titleLine2: t("about.notePPPage.hero.titleLine2"),
},
{
image: "/images/about/pp.avif",
title: t("about.noteTrailerPage.hero.title"),
description: t("about.noteTrailerPage.hero.description"),
eyebrow: t("about.noteTrailerPage.hero.eyebrow"),
titleLine1: t("about.noteTrailerPage.hero.titleLine1"),
titleLine2: t("about.noteTrailerPage.hero.titleLine2"),
},
];
return ( return (
<main className="min-h-[30vh] bg-[#0f0e0d] pt-5 text-white pb-40"> <main className="min-h-[30vh] bg-[#0f0e0d] pt-5 text-white pb-40">
<div className="bg-black sm:w-[95%] w-[98%] mx-auto p-5"> <div className="bg-black sm:w-[95%] w-[98%] mx-auto p-5">

View File

@@ -1,12 +1,30 @@
"use client" "use client";
import { CertCard } from "@/components/pages/about/aboutDetail/sertificateCard"; import { CertCard } from "@/components/pages/about/aboutDetail/sertificateCard";
import PaginationLite from "@/components/paginationUI";
import { certs } from "@/lib/demoData"; import { certs } from "@/lib/demoData";
import httpClient from "@/request/api";
import { endPoints } from "@/request/links";
import { useQuery } from "@tanstack/react-query";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { Award } from "lucide-react"; import { Award } from "lucide-react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useState } from "react";
export default function SertificatePage() { export default function SertificatePage() {
const t = useTranslations(); const t = useTranslations();
const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading } = useQuery({
queryKey: ["sertificate"],
queryFn: () => httpClient(endPoints.sertificate),
select: (res) => ({
results: res.data?.data?.results,
current_page: res.data?.data?.current_page,
total_pages: res.data?.data?.total_pages,
}),
});
console.log(data);
const generallydata = data?.results ?? certs;
return ( return (
<main className="min-h-screen bg-[#0f0e0d] text-white pb-44 overflow-x-hidden"> <main className="min-h-screen bg-[#0f0e0d] text-white pb-44 overflow-x-hidden">
@@ -70,10 +88,19 @@ export default function SertificatePage() {
{/* ── Cards ── */} {/* ── Cards ── */}
<section className="max-w-4xl mx-auto px-6 flex flex-col gap-4"> <section className="max-w-4xl mx-auto px-6 flex flex-col gap-4">
{certs.map((c, i) => ( {generallydata.map((c:any, i:number) => (
<CertCard key={c.id} c={c} i={i} /> <CertCard key={c.id} c={c} i={i} />
))} ))}
</section> </section>
{/*pagination*/}
{data?.total_pages > 1 && (
<PaginationLite
currentPage={currentPage}
totalPages={data?.total_pages}
onChange={setCurrentPage}
/>
)}
</main> </main>
); );
} }

View File

@@ -85,7 +85,7 @@ export function Navbar() {
<div className="hidden h-full lg:flex items-center gap-8"> <div className="hidden h-full lg:flex items-center gap-8">
{navbarItems?.results ? ( {navbarItems?.results ? (
navbarItems.results.map((item: NavbarItem) => ( navbarItems.results.map((item: NavbarItem) => (
<DropdownMenu> <DropdownMenu key={item.id}>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Link <Link
key={item.id} key={item.id}
@@ -200,7 +200,7 @@ export function Navbar() {
<div className="flex flex-col p-6 gap-4"> <div className="flex flex-col p-6 gap-4">
{navbarItems?.results ? ( {navbarItems?.results ? (
navbarItems.results.map((item: NavbarItem) => ( navbarItems.results.map((item: NavbarItem) => (
<DropdownMenu> <DropdownMenu key={item.id}>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Link <Link
key={item.id} key={item.id}

View File

@@ -1,7 +1,7 @@
"use client"; "use client";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { ShieldCheck, BookOpen, Flame } from "lucide-react"; import { ShieldCheck } from "lucide-react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { NormativeCard } from "./normativeCard"; import { NormativeCard } from "./normativeCard";
@@ -21,27 +21,6 @@ const fadeUpView = (delay = 0) => ({
export default function NormativBazaPage() { export default function NormativBazaPage() {
const t = useTranslations(); const t = useTranslations();
const cards = [
{
icon: BookOpen,
title: t("about.normativBaza.cards.card1.title"),
text: t("about.normativBaza.cards.card1.text"),
number: "01",
},
{
icon: Flame,
title: t("about.normativBaza.cards.card2.title"),
text: t("about.normativBaza.cards.card2.text"),
number: "02",
},
{
icon: ShieldCheck,
title: t("about.normativBaza.cards.card3.title"),
text: t("about.normativBaza.cards.card3.text"),
number: "03",
},
];
return ( return (
<div className="bg-[#0f0e0d] text-white min-h-screen pt-10 pb-20"> <div className="bg-[#0f0e0d] text-white min-h-screen pt-10 pb-20">
{/* ── Hero ── */} {/* ── Hero ── */}

View File

@@ -1,40 +1,68 @@
"use client";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import DownloadCard from "./card"; import DownloadCard from "./card";
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import httpClient from "@/request/api";
import { endPoints } from "@/request/links";
import PaginationLite from "@/components/paginationUI";
export function Guides() { export function Guides() {
const t = useTranslations(); const t = useTranslations();
const [currentPage, setCurrentPage] = useState(1);
const guides = [ const guides = [
{ {
fileUrl: "/varnix.pdf", file: "/varnix.pdf",
fileName: t("about.notePPPage.varnix"), name: t("about.notePPPage.varnix"),
fileType: "PDF", file_type: "PDF",
fileSize: "368.51 KB", file_size: "368.51 KB",
}, },
{ {
fileUrl: "/ppFlanes.pdf", file: "/ppFlanes.pdf",
fileName: t("about.notePPPage.ppFlanes"), name: t("about.notePPPage.ppFlanes"),
fileType: "PDF", file_type: "PDF",
fileSize: "368.51 KB", file_size: "368.51 KB",
}, },
{ {
fileUrl: "/ppFiting.pdf", file: "/ppFiting.pdf",
fileName: t("about.notePPPage.ppFiting"), name: t("about.notePPPage.ppFiting"),
fileType: "PDF", file_type: "PDF",
fileSize: "368.51 KB", file_size: "368.51 KB",
}, },
]; ];
const { data } = useQuery({
queryKey: ["guides"],
queryFn: () => httpClient(endPoints.guides),
select: (res) => ({
results: res.data?.data?.results,
current_page: res.data?.data?.current_page,
total_pages: res.data?.data?.total_pages,
}),
});
const guidedata = data?.results ?? guides;
return ( return (
<div className="space-y-4">
<div className="grid lg:grid-cols-3 min-[580px]:grid-cols-2 grid-cols-1 gap-4 max-w-7xl mx-auto py-5"> <div className="grid lg:grid-cols-3 min-[580px]:grid-cols-2 grid-cols-1 gap-4 max-w-7xl mx-auto py-5">
{guides.map((guide, index) => ( {guidedata.map((guide: any, index: number) => (
<DownloadCard <DownloadCard
key={index} key={index}
title={guide.fileName} title={guide.name}
fileType={guide.fileType} fileType={guide.file_ype}
fileSize={guide.fileSize} fileSize={guide.file_size}
fileUrl={guide.fileUrl} fileUrl={guide.file}
/> />
))} ))}
</div> </div>
{data?.total_pages > 1 && (
<PaginationLite
currentPage={currentPage}
totalPages={data?.total_pages}
onChange={setCurrentPage}
/>
)}
</div>
); );
} }

View File

@@ -0,0 +1,44 @@
export function CertCardSkeleton({ count = 6 }: { count?: number }) {
return (
<>
<article className="flex flex-col rounded-2xl overflow-hidden sm:p-5 p-2 bg-[#161514] border border-white/5 w-full">
{/* Badge row */}
<div className="flex flex-col justify-between flex-1 min-w-0 py-1 gap-4">
<div className="space-y-2">
<div className="flex items-center gap-2 flex-wrap">
{/* Award badge */}
<div className="flex items-center gap-1.5">
<div className="w-2.5 h-2.5 rounded-sm bg-red-900/40 animate-pulse" />
<div className="h-2.5 w-20 rounded-full bg-red-900/40 animate-pulse" />
</div>
{/* Category pill */}
<div className="h-4 w-16 rounded-full border border-white/10 bg-white/5 animate-pulse" />
</div>
{/* Title lines */}
<div className="space-y-1.5 pt-1">
<div className="h-3.5 w-full rounded bg-white/8 animate-pulse" />
<div className="h-3.5 w-3/4 rounded bg-white/8 animate-pulse" />
</div>
</div>
</div>
{/* Divider */}
<div className="mx-4 h-px bg-white/5 sm:my-5 my-2" />
{/* Document list */}
<ul className="flex flex-col gap-2.5">
{Array.from({ length: 3 }).map((_, di) => (
<li key={di} className="flex items-start gap-2.5">
<span className="mt-1 flex-none w-1.5 h-1.5 rounded-full bg-red-900/40 animate-pulse" />
<div
className="h-3 rounded bg-white/8 animate-pulse"
style={{ width: `${75 - di * 10}%` }}
/>
</li>
))}
</ul>
</article>
</>
);
}

View File

@@ -4,13 +4,37 @@ import { motion } from "framer-motion";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { Award } from "lucide-react"; import { Award } from "lucide-react";
import { normativeData } from "@/lib/demoData"; import { normativeData } from "@/lib/demoData";
import httpClient from "@/request/api";
import { endPoints } from "@/request/links";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import PaginationLite from "@/components/paginationUI";
import { CertCardSkeleton } from "./loading";
export function NormativeCard() { export function NormativeCard() {
const t = useTranslations(); const t = useTranslations();
const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading } = useQuery({
queryKey: ["normativeData"],
queryFn: () => httpClient(endPoints.normative),
select: (res) => ({
results: res.data?.data?.results,
current_page: res.data?.data?.current_page,
total_pages: res.data?.data?.total_pages,
}),
});
console.log(data);
const generallyData = data?.results ?? normativeData;
if (isLoading) return <CertCardSkeleton />;
return ( return (
<div className="space-y-4">
<div className="flex flex-col gap-8 py-10 max-w-6xl mx-auto px-2"> <div className="flex flex-col gap-8 py-10 max-w-6xl mx-auto px-2">
{normativeData.map((c, i) => ( {generallyData.map((c: any, i: number) => (
<motion.article <motion.article
key={i} key={i}
initial={{ opacity: 0, y: 28 }} initial={{ opacity: 0, y: 28 }}
@@ -31,13 +55,13 @@ export function NormativeCard() {
</span> </span>
</div> </div>
<span className="text-[10px] font-bold uppercase tracking-wider text-white/20 border border-white/10 px-2 py-0.5 rounded-full"> <span className="text-[10px] font-bold uppercase tracking-wider text-white/20 border border-white/10 px-2 py-0.5 rounded-full">
{c.category} {c.artikul}
</span> </span>
</div> </div>
{/* Title */} {/* Title */}
<h3 className="font-bold text-sm md:text-base text-white leading-snug"> <h3 className="font-bold text-sm md:text-base text-white leading-snug">
{t(c.titleKey)} {t(c.title)}
</h3> </h3>
</div> </div>
</div> </div>
@@ -48,11 +72,11 @@ export function NormativeCard() {
{/* Documents list */} {/* Documents list */}
<div className="overflow-hidden"> <div className="overflow-hidden">
<ul className="flex flex-col gap-2.5"> <ul className="flex flex-col gap-2.5">
{c.documents.map((doc, di) => ( {c.features.map((doc: any, di: number) => (
<li key={di} className="flex items-start gap-2.5"> <li key={di} className="flex items-start gap-2.5">
<span className="mt-1 flex-none w-1.5 h-1.5 rounded-full bg-red-600/60" /> <span className="mt-1 flex-none w-1.5 h-1.5 rounded-full bg-red-600/60" />
<p className="text-xs text-gray-400 leading-relaxed"> <p className="text-xs text-gray-400 leading-relaxed">
{t(doc)} {t(doc?.name)}
</p> </p>
</li> </li>
))} ))}
@@ -61,5 +85,13 @@ export function NormativeCard() {
</motion.article> </motion.article>
))} ))}
</div> </div>
{data?.total_pages > 1 && (
<PaginationLite
currentPage={currentPage}
totalPages={data?.total_pages}
onChange={setCurrentPage}
/>
)}
</div>
); );
} }

View File

@@ -28,7 +28,7 @@ export function CertCard({ c, i }: { c: (typeof certs)[0]; i: number }) {
</span> </span>
</div> </div>
<span className="text-[10px] font-bold uppercase tracking-wider text-white/20 border border-white/10 px-2 py-0.5 rounded-full"> <span className="text-[10px] font-bold uppercase tracking-wider text-white/20 border border-white/10 px-2 py-0.5 rounded-full">
{c.category} {c.artikul}
</span> </span>
</div> </div>
@@ -45,12 +45,18 @@ export function CertCard({ c, i }: { c: (typeof certs)[0]; i: number }) {
{/* Collapsible document list */} {/* Collapsible document list */}
<div className="overflow-hidden"> <div className="overflow-hidden">
<ul className="flex flex-col gap-2.5"> <ul className="flex flex-col gap-2.5">
{c.documents.map((doc, di) => ( {c.features.length > 0 &&
c.features.map((doc: any, di: number) => {
const { name } = doc;
return (
<li key={di} className="flex items-start gap-2.5"> <li key={di} className="flex items-start gap-2.5">
<span className="mt-1 flex-none w-1.5 h-1.5 rounded-full bg-red-600/60" /> <span className="mt-1 flex-none w-1.5 h-1.5 rounded-full bg-red-600/60" />
<p className="text-xs text-gray-400 leading-relaxed">{doc}</p> <p className="text-xs text-gray-400 leading-relaxed">
{name || ""}
</p>
</li> </li>
))} );
})}
</ul> </ul>
</div> </div>
</motion.article> </motion.article>

View File

@@ -1,11 +1,13 @@
import { title } from "process";
export const certs = [ export const certs = [
{ {
id: 1, id: 1,
src: "/images/about/sertificate.webp", src: "/images/about/sertificate.webp",
title: "Пожаростойкие армированные трубы SLT BLOCKFIRE PP-R-GF", title: "Пожаростойкие армированные трубы SLT BLOCKFIRE PP-R-GF",
year: "2024", year: "2024",
category: "PP-R-GF", artikul: "PP-R-GF",
documents: [ features: [
"СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.", "СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.",
"СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.", "СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.",
"Протоколы испытаний по ГОСТ Р 58832 ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.", "Протоколы испытаний по ГОСТ Р 58832 ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.",
@@ -17,8 +19,8 @@ export const certs = [
src: "/images/about/sertificate.webp", src: "/images/about/sertificate.webp",
title: "Пожаростойкие однослойные трубы SLT BLOCKFIRE PP-R", title: "Пожаростойкие однослойные трубы SLT BLOCKFIRE PP-R",
year: "2023", year: "2023",
category: "PP-R", artikul: "PP-R",
documents: [ features: [
"СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.", "СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.",
"СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.", "СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.",
"Протоколы испытаний ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.", "Протоколы испытаний ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.",
@@ -30,8 +32,8 @@ export const certs = [
src: "/images/about/sertificate.webp", src: "/images/about/sertificate.webp",
title: "Пожаростойкие фитинги SLT BLOCKFIRE PP-R", title: "Пожаростойкие фитинги SLT BLOCKFIRE PP-R",
year: "2023", year: "2023",
category: "Фитинги", artikul: "Фитинги",
documents: [ features: [
"СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.", "СТО 22.21.29-015-17207509-2022 (версия 2) — согласован МЧС России в качестве нормативного документа по пожарной безопасности.",
"СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.", "СТО 22.21.29-021-17207509-2024 «Автоматическая противопожарная защита многоярусных стеллажных конструкций» — согласован МЧС России №ГУ-исх-66586 от 05.07.2024.",
"Протоколы испытаний по ГОСТ Р 58832 ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.", "Протоколы испытаний по ГОСТ Р 58832 ИЛ НИЦ ПТ и СП ФГБУ ВНИИПО МЧС России № 2249/2.1-2022 от 03.03.2022, №2683/2.1-2023 от 06.10.2023.",
@@ -283,9 +285,9 @@ export const result = [
export const normativeData = [ export const normativeData = [
{ {
titleKey: "certs.slt_blockfire.title", title: "certs.slt_blockfire.title",
category: "SLT BLOCKFIRE", artikul: "SLT BLOCKFIRE",
documents: [ features: [
"certs.slt_blockfire.doc1", "certs.slt_blockfire.doc1",
"certs.slt_blockfire.doc2", "certs.slt_blockfire.doc2",
"certs.slt_blockfire.doc3", "certs.slt_blockfire.doc3",
@@ -293,14 +295,12 @@ export const normativeData = [
"certs.slt_blockfire.doc5", "certs.slt_blockfire.doc5",
"certs.slt_blockfire.doc6", "certs.slt_blockfire.doc6",
"certs.slt_blockfire.doc7", "certs.slt_blockfire.doc7",
"certs.slt_blockfire.doc8" "certs.slt_blockfire.doc8",
] ],
}, },
{ {
titleKey: "certs.slt_aqua.title", title: "certs.slt_aqua.title",
category: "SLT AQUA", artikul: "SLT AQUA",
documents: [ features: ["certs.slt_aqua.doc1"],
"certs.slt_aqua.doc1" },
]
}
]; ];

View File

@@ -37,6 +37,9 @@ export const endPoints = {
statistics: "statistics/", statistics: "statistics/",
banner: "banner/?page_size=500", banner: "banner/?page_size=500",
navbar: "navigationitem/?page_size=500", navbar: "navigationitem/?page_size=500",
sertificate: "document/?type=certificate",
normative: "document/?type=normative",
guides:"guide/",
filter: { filter: {
size: "size/", size: "size/",
sizePageItems: "size/?page_size=500", sizePageItems: "size/?page_size=500",