diff --git a/app/[locale]/catalog_page/products/[slug]/page.tsx b/app/[locale]/catalog_page/products/[slug]/page.tsx index a48308a..e560189 100644 --- a/app/[locale]/catalog_page/products/[slug]/page.tsx +++ b/app/[locale]/catalog_page/products/[slug]/page.tsx @@ -61,7 +61,7 @@ export default function SlugPage() { const features = product.features.map((item: any) => item.name); return ( -
+
diff --git a/app/[locale]/services/detail/page.tsx b/app/[locale]/services/detail/page.tsx new file mode 100644 index 0000000..5f9bcac --- /dev/null +++ b/app/[locale]/services/detail/page.tsx @@ -0,0 +1,280 @@ +"use client"; + +import Image from "next/image"; +import { motion } from "framer-motion"; +import { useEffect, useState } from "react"; +import { useTranslations } from "next-intl"; +import { + getOperationalSystems, + SystemFeature, +} from "@/lib/api/demoapi/operationalSystems"; +import { Breadcrumb } from "@/components/breadCrumb"; + +export default function OperationalSystemsPage() { + const t = useTranslations("operationalSystems"); + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(false); + + // Demo data - fallback ma'lumotlar + const demoData: SystemFeature[] = [ + { + id: "1", + title: t("systems.sprinkler.title"), + shortDesc:t("systems.sprinkler.short-desc"), + description: t("systems.sprinkler.description"), + features: [ + t("systems.sprinkler.features.0"), + t("systems.sprinkler.features.1"), + t("systems.sprinkler.features.2"), + t("systems.sprinkler.features.3"), + ], + image: "/images/services/sprinkler.jpg", + }, + ]; + + const fetchData = async () => { + try { + setLoading(true); + setError(false); + + const result = await getOperationalSystems(); + + // Agar backend ma'lumot qaytarsa + if (result && result.length > 0) { + setData(result); + } else { + // Backend bo'sh ma'lumot qaytarsa, demo ma'lumotlarni ishlatamiz + setData(demoData); + } + } catch (err) { + setError(true); + // Xatolik bo'lsa, demo ma'lumotlarni ishlatamiz + setData(demoData); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, []); + + // Animation variants + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.15, + }, + }, + }; + + const itemVariants = { + hidden: { opacity: 0, y: 30 }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.6, + ease: [0.22, 1, 0.36, 1] as const, + }, + }, + }; + + const cardVariants = { + hidden: { opacity: 0, scale: 0.95 }, + visible: { + opacity: 1, + scale: 1, + transition: { + duration: 0.5, + ease: [0.22, 1, 0.36, 1] as const, + }, + }, + }; + + // Loading state + if (loading) { + return ( +
+ + +

+ {t("loading")} +

+
+
+ ); + } + + // Error state with retry + if (error && !data) { + return ( +
+ +
⚠️
+

{t("error")}

+ + {t("retry")} + +
+
+ ); + } + + return ( +
+ {/* Header */} + {/* + +

+ {t('title')} +

+

+ {t('subtitle')} +

+
+ + + Fire hose + +
*/} +
+ +
+ + {/* Main Content */} + {!data || data.length === 0 ? ( + +

{t("noData")}

+
+ ) : ( + + {data.map((system, index) => ( + + {/* Image Section */} + + {system.title} +
+ + + {/* Content Section */} +
+ + {system.title} + + + + {system.shortDesc} + + + + {system.description} + + +
+ +
    + {system.features.map((feature, featureIndex) => ( + + + {feature} + + + ))} +
+
+
+ + ))} + + )} +
+ ); +} diff --git a/components/breadCrumb.tsx b/components/breadCrumb.tsx index eaab489..ef886a8 100644 --- a/components/breadCrumb.tsx +++ b/components/breadCrumb.tsx @@ -140,6 +140,7 @@ export function Breadcrumb({ if (segment === "special_product") { return product.name; } + if(segment === 'detail') return ''; return t(`breadcrumb.${segment}`); } catch { // Aks holda, segment nomini formatlash diff --git a/components/layout/footer.tsx b/components/layout/footer.tsx index 91328dd..8bb17fd 100644 --- a/components/layout/footer.tsx +++ b/components/layout/footer.tsx @@ -61,7 +61,10 @@ export function Footer() { const handleSubscribe = (e: React.FormEvent) => { e.preventDefault(); if (email) { - formRequest.mutate({ number: email }); + // Telefon raqamni tozalash (faqat raqamlar) + const cleanPhone = email.replace(/\D/g, ""); + console.log("without 998: ",cleanPhone.slice(3)) + formRequest.mutate({ number: Number(cleanPhone.slice(3))}); } }; @@ -239,7 +242,9 @@ export function Footer() {
- {t("footer.create", { name: "Felix-its.uz" })} + + {t("footer.create", { name: "Felix-its.uz" })} + {/*
Terms & Conditions diff --git a/components/layout/navbar.tsx b/components/layout/navbar.tsx index be53ca4..6df820a 100644 --- a/components/layout/navbar.tsx +++ b/components/layout/navbar.tsx @@ -5,12 +5,10 @@ import { ChevronDown, Phone, Menu, X } from "lucide-react"; import Image from "next/image"; import LanguageSelectRadix from "../languageSwitcher"; import { useLocale, useTranslations } from "next-intl"; -import NavbarLogo from "./navbarLogo/navbarLogo"; export function Navbar() { const locale = useLocale(); const t = useTranslations(); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [scrolled, setScrolled] = useState(false); @@ -42,7 +40,12 @@ export function Navbar() {
- logo image + logo image
@@ -103,8 +106,8 @@ export function Navbar() {
+
+998-55-055-21-21
+998-77-372-21-21
-
+998-98-099-21-21
diff --git a/components/pages/home/index.ts b/components/pages/home/index.ts index 082d0bd..6d5c772 100644 --- a/components/pages/home/index.ts +++ b/components/pages/home/index.ts @@ -2,7 +2,7 @@ export { Banner } from "./banner"; export { Statistics } from "./statistics"; export { AboutUs } from "./about"; export { Video } from "./video"; -export { OurService } from "./ourService"; +export { OurService } from "../services/ourService"; export { Testimonial } from "./testimonal"; export { Line } from "./line"; export { Blog } from "./blog/blog"; diff --git a/components/pages/home/ourService.tsx b/components/pages/home/ourService.tsx deleted file mode 100644 index 203872c..0000000 --- a/components/pages/home/ourService.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import DotAnimatsiya from "@/components/dot/DotAnimatsiya"; -import { ChevronRight } from "lucide-react"; -import { useTranslations } from "next-intl"; -import Image from "next/image"; -import Link from "next/link"; - -export function OurService() { - const t = useTranslations(); - return ( -
-
- {/* Header */} -
-
- - {t("home.services.title")} -
-

- {t("home.services.subtitle")} -

-

- {t("home.services.description")} -

-
- - {/* cards */} -
-
-

- {t("home.services.services.operation.title")} -

-

- {t("home.services.services.operation.description")} -

- - images -
-
-

- {t("home.services.services.suppression.title")} -

-

- {t("home.services.services.suppression.description")} -

- - images -
-
- -
-
- images -
-

- {t("home.services.services.safety.title")} -

-

- {t("home.services.services.safety.description")} -

- -
-
-
-
-

- {t("home.services.services.monitoring.title")} -

-

- {t("home.services.services.monitoring.description")} -

- - images -
-
-

- {t("home.services.viewMoreServices")} -

- - {t("home.services.viewMore")} - -
-
-
-
-
- ); -} diff --git a/components/pages/services/empty.tsx b/components/pages/services/empty.tsx new file mode 100644 index 0000000..a225d0c --- /dev/null +++ b/components/pages/services/empty.tsx @@ -0,0 +1,72 @@ +import { useTranslations } from "next-intl"; +import { motion } from "framer-motion"; + +// Empty State Component +export function EmptyServices() { + const t = useTranslations(); + + return ( + +
+ +
+ + + +
+
+ + + {t("home.services.noData.title") || "Xizmatlar topilmadi"} + + + + {t("home.services.noData.description") || "Hozircha hech qanday xizmat mavjud emas. Tez orada yangi xizmatlar qo'shiladi."} + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/components/pages/services/loading.tsx b/components/pages/services/loading.tsx new file mode 100644 index 0000000..4b40299 --- /dev/null +++ b/components/pages/services/loading.tsx @@ -0,0 +1,46 @@ +import { motion } from "framer-motion"; + + +// Loading Skeleton Component +function ServiceCardSkeleton() { + return ( +
+
+
+
+
+
+ ); +} + +// Loading Component +export function ServicesLoading() { + return ( + + {/* Top Cards Skeleton */} +
+
+ +
+
+ +
+
+ + {/* Bottom Cards Skeleton */} +
+
+ +
+
+ +
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/pages/services/ourService.tsx b/components/pages/services/ourService.tsx new file mode 100644 index 0000000..da67124 --- /dev/null +++ b/components/pages/services/ourService.tsx @@ -0,0 +1,206 @@ +"use client" +import DotAnimatsiya from "@/components/dot/DotAnimatsiya"; +import httpClient from "@/request/api"; +import { endPoints } from "@/request/links"; +import { useQuery } from "@tanstack/react-query"; +import { ChevronRight } from "lucide-react"; +import { useLocale, useTranslations } from "next-intl"; +import Image from "next/image"; +import Link from "next/link"; +import { motion } from "framer-motion"; +import { ServicesLoading } from "./loading"; +import { EmptyServices } from "./empty"; + +export function OurService() { + const t = useTranslations(); + const locale = useLocale(); + + // get request + const { data, isLoading, isError } = useQuery({ + queryKey: ['firesafety'], + queryFn: () => httpClient(endPoints.services.all) + }); + + console.log("service data: ", data); + + // Animation variants + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + }, + }, + }; + + const cardVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.5, + ease: [0.22, 1, 0.36, 1] as const, + }, + }, + }; + + return ( +
+
+ {/* Header */} + +
+ + {t("home.services.title")} +
+

+ {t("home.services.subtitle")} +

+

+ {t("home.services.description")} +

+
+ + {/* Conditional Rendering */} + {isLoading ? ( +
+ +
+ ) : !data || (Array.isArray(data) && data.length === 0) ? ( +
+ +
+ ) : ( + + {/* cards */} +
+ + +

+ {t("home.services.services.operation.title")} +

+

+ {t("home.services.services.operation.description")} +

+ + images + +
+ + +
+

+ {t("home.services.services.suppression.title")} +

+

+ {t("home.services.services.suppression.description")} +

+ + images +
+
+
+ +
+ + + images +
+

+ {t("home.services.services.safety.title")} +

+

+ {t("home.services.services.safety.description")} +

+ +
+ +
+ +
+ + +
+

+ {t("home.services.services.monitoring.title")} +

+

+ {t("home.services.services.monitoring.description")} +

+ + images +
+ +
+ + +

+ {t("home.services.viewMoreServices")} +

+ + {t("home.services.viewMore")} + +
+
+
+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/components/priceContact.tsx b/components/priceContact.tsx index 53a0d05..94ebee6 100644 --- a/components/priceContact.tsx +++ b/components/priceContact.tsx @@ -12,7 +12,7 @@ import { toast } from "react-toastify"; interface FormType { name: string; product: number; - phone: number; // ✅ String bo'lishi kerak + number: number; // ✅ String bo'lishi kerak } export function PriceModal() { @@ -21,12 +21,12 @@ export function PriceModal() { const [formData, setFormData] = useState({ name: "", - phone: "+998 ", + number: "+998 ", }); const [errors, setErrors] = useState({ name: "", - phone: "", + number: "", }); const formRequest = useMutation({ @@ -35,7 +35,7 @@ export function PriceModal() { onSuccess: () => { setFormData({ name: "", - phone: "+998 ", + number: "+998 ", }); toast.success(t("success") || "Muvaffaqiyatli yuborildi!"); closeModal(); @@ -51,11 +51,11 @@ export function PriceModal() { if (!isOpen) { setFormData({ name: "", - phone: "+998 ", + number: "+998 ", }); setErrors({ name: "", - phone: "", + number: '', }); } }, [isOpen]); @@ -90,9 +90,9 @@ export function PriceModal() { const handlePhoneChange = (e: React.ChangeEvent) => { const formatted = formatPhoneNumber(e.target.value); - setFormData({ ...formData, phone: formatted }); - if (errors.phone) { - setErrors({ ...errors, phone: "" }); + setFormData({ ...formData, number: formatted }); + if (errors.number) { + setErrors({ ...errors, number: "" }); } }; @@ -107,7 +107,7 @@ export function PriceModal() { const validateForm = () => { const newErrors = { name: "", - phone: "", + number: "", }; // Name validation @@ -116,17 +116,17 @@ export function PriceModal() { } // Phone validation - const phoneNumbers = formData.phone.replace(/\D/g, ""); + const phoneNumbers = formData.number.replace(/\D/g, ""); if (phoneNumbers.length !== 12) { - newErrors.phone = + newErrors.number = t("validation.phoneRequired") || "To'liq telefon raqam kiriting"; } else if (!phoneNumbers.startsWith("998")) { - newErrors.phone = + newErrors.number = t("validation.phoneInvalid") || "Noto'g'ri telefon raqam"; } setErrors(newErrors); - return !newErrors.name && !newErrors.phone; + return !newErrors.name && !newErrors.number; }; const handleSubmit = async (e: React.FormEvent) => { @@ -137,11 +137,11 @@ export function PriceModal() { } // Telefon raqamni tozalash (faqat raqamlar) - const cleanPhone = formData.phone.replace(/\D/g, ""); + const cleanPhone = formData.number.replace(/\D/g, ""); const sendedData: FormType = { name: formData.name, - phone: Number(cleanPhone), // ✅ String sifatida yuborish + number: Number(cleanPhone.slice(3)), // ✅ String sifatida yuborish product: product?.id || 0, }; @@ -236,16 +236,16 @@ export function PriceModal() { type="tel" id="phone" name="phone" - value={formData.phone} + value={formData.number} onChange={handlePhoneChange} className={`w-full px-4 py-3 bg-[#1e1e1e] border ${ - errors.phone ? "border-red-500" : "border-gray-700" + errors.number ? "border-red-500" : "border-gray-700" } rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-red-700 transition`} placeholder="+998 90 123 45 67" maxLength={17} /> - {errors.phone && ( -

{errors.phone}

+ {errors.number && ( +

{errors.number}

)}
diff --git a/lib/api/demoapi/operationalSystems.ts b/lib/api/demoapi/operationalSystems.ts new file mode 100644 index 0000000..ac60a1a --- /dev/null +++ b/lib/api/demoapi/operationalSystems.ts @@ -0,0 +1,27 @@ +import axios from 'axios'; + +const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://api.example.com'; + +export interface SystemFeature { + id: string; + title: string; + shortDesc?:string; + description: string; + features: string[]; + image: string; +} + +export const getOperationalSystems = async (): Promise => { + try { + const response = await axios.get(`${API_BASE_URL}/operational-systems`, { + timeout: 10000, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (error) { + console.error('Error fetching operational systems:', error); + throw error; + } +}; \ No newline at end of file diff --git a/messages/en.json b/messages/en.json index d7f13ab..9bfa2b3 100644 --- a/messages/en.json +++ b/messages/en.json @@ -225,6 +225,48 @@ "address": "Tashkent city, Yunusabad district, 3rd dead-end of Niyozbek Yoli street, house 39", "create": "Created by {name}" }, + "operationalSystems": { + "title": "Operating Systems", + "subtitle": "Automatic fire detection and extinguishing systems. Latest technological achievements.", + "loading": "Loading...", + "error": "An error occurred. Please try again.", + "noData": "No data found", + "retry": "Retry", + "features": "Features", + "systems": { + "sprinkler": { + "title": "Sprinkler Fire Suppression System", + "short-desc": "Automatic fire detection and extinguishing systems. The latest achievements in technology.", + "description": "The sprinkler fire suppression system controls and extinguishes fires at an early stage through automatic water spraying. The system activates automatically when temperature rises and operates only in the fire detection area.", + "features": [ + "Automatic activation mechanism", + "Covers only the affected area with water", + "Suitable for industrial and commercial buildings", + "Reliable and widely used system" + ] + }, + "gas": { + "title": "Gas Fire Suppression System", + "description": "The gas fire suppression system extinguishes fires using special inert or chemical gases. This system is used in places where water cannot be used — server rooms, data centers, and areas with electrical equipment.", + "features": [ + "Does not damage electrical equipment", + "Fast and effective suppression", + "Leaves no residue", + "Ideal for server and IT rooms" + ] + }, + "foam": { + "title": "Foam Fire Suppression System", + "description": "The foam fire suppression system effectively extinguishes fires involving flammable liquids and petroleum products. The foam covers the combustible material, blocks oxygen access, and quickly suppresses the flames.", + "features": [ + "Effective for flammable liquids", + "Used in oil depots and warehouses", + "Quickly isolates fire", + "High safety level" + ] + } + } + }, "rasmlar": "Images", "fotogalereya": "Photo Gallery", "contactTitle": "Send us your phone number", diff --git a/messages/ru.json b/messages/ru.json index a0132fe..3ba5513 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -225,6 +225,48 @@ "address": "г. Ташкент, Юнусабадский район, 3-й тупик улицы Ниязбек йўли, дом 39", "create": "Разработано {name}" }, + "operationalSystems": { + "title": "Операционные системы", + "subtitle": "Системы автоматического обнаружения и тушения пожаров. Последние достижения технологий.", + "loading": "Загрузка...", + "error": "Произошла ошибка. Пожалуйста, попробуйте снова.", + "noData": "Данные не найдены", + "retry": "Повторить", + "features": "Характеристики", + "systems": { + "sprinkler": { + "title": "Спринклерная система пожаротушения", + "short-desc":"Системы автоматического обнаружения и тушения пожаров. Новейшие достижения технологий.", + "description": "Спринклерная система пожаротушения контролирует и тушит пожар на начальной стадии путем автоматического распыления воды. Система автоматически активируется при повышении температуры и работает только в зоне обнаружения пожара.", + "features": [ + "Автоматический механизм активации", + "Покрывает водой только поврежденную зону", + "Подходит для промышленных и торговых зданий", + "Надежная и широко применяемая система" + ] + }, + "gas": { + "title": "Газовая система пожаротушения", + "description": "Газовая система пожаротушения тушит пожар с помощью специальных инертных или химических газов. Эта система применяется в местах, где нельзя использовать воду — серверные комнаты, дата-центры и помещения с электрооборудованием.", + "features": [ + "Не наносит вреда электрооборудованию", + "Быстрое и эффективное тушение", + "Не оставляет остатков", + "Идеально для серверных и IT помещений" + ] + }, + "foam": { + "title": "Пенная система пожаротушения", + "description": "Пенная система пожаротушения эффективно тушит пожары, связанные с горючими жидкостями и нефтепродуктами. Пена покрывает горючее вещество, перекрывает доступ кислорода и быстро подавляет огонь.", + "features": [ + "Эффективна для горючих жидкостей", + "Применяется на нефтебазах и складах", + "Быстро изолирует пожар", + "Высокий уровень безопасности" + ] + } + } + }, "rasmlar": "Изображения", "fotogalereya": "Фотогалерея", "contactTitle": "Отправьте нам свой номер", diff --git a/messages/uz.json b/messages/uz.json index d343faf..70acbf8 100644 --- a/messages/uz.json +++ b/messages/uz.json @@ -225,6 +225,48 @@ "address": "Toshkent shahri , Yunusabod tumani , Niyozbek yo'li 3 tor ko'chasi , 39 uy", "create": "{name} - Jamoasi tomonidan ishlab chiqilgan" }, + "operationalSystems": { + "title": "Operatsion tizimlar", + "subtitle": "Yong'inni avtomatik aniqlash va o'chirish tizimlari. Texnologiyaning eng so'nggi yutuqlari.", + "loading": "Yuklanmoqda...", + "error": "Xatolik yuz berdi. Iltimos, qaytadan urinib ko'ring.", + "noData": "Ma'lumotlar topilmadi", + "retry": "Qayta urinish", + "features": "Hususiyatlari", + "systems": { + "sprinkler": { + "title": "Sprinklerli yong'in o'chirish tizimi", + "short-desc":"Yong'inni avtomatik aniqlash va o'chirish tizimlari. Texnologiyaning eng so'nggi yutuqlari.", + "description": "Sprinklerli yong'in o'chirish tizimi avtomatik suv purkash orqali yong'inni dastlabki bosqichida nazorat qiladi va o'chiradi. Tizim harorat oshganda avtomatik ishga tushadi va faqat yong'in aniqlangan hududda faoliyat ko'rsatadi.", + "features": [ + "Avtomatik ishga tushish mexanizmi", + "Faqat zararlangan hududni suv bilan qoplaydi", + "Sanoat va savdo binolari uchun mos", + "Ishonchli va keng qo'llaniladigan tizim" + ] + }, + "gas": { + "title": "Gazli yong'in o'chirish tizimi", + "description": "Gazli yong'in o'chirish tizimi maxsus inert yoki kimyoviy gazlar yordamida yong'inni o'chiradi. Bu tizim suv ishlatish mumkin bo'lmagan joylarda — server xonalari, data markazlar va elektr jihozlari mavjud hududlarda qo'llaniladi.", + "features": [ + "Elektr jihozlariga zarar yetkazmaydi", + "Tez va samarali o'chirish", + "Qoldiq modda qoldirmaydi", + "Server va IT xonalari uchun ideal" + ] + }, + "foam": { + "title": "Ko'pikli yong'in o'chirish tizimi", + "description": "Ko'pikli yong'in o'chirish tizimi yonuvchi suyuqliklar va neft mahsulotlari bilan bog'liq yong'inlarni samarali o'chiradi. Ko'pik yonuvchi modda ustini qoplab, kislorod kirishini to'sadi va olovni tezda bostiradi.", + "features": [ + "Yonuvchi suyuqliklar uchun samarali", + "Neft bazalari va omborlarda qo'llaniladi", + "Yong'inni tez izolyatsiya qiladi", + "Yuqori xavfsizlik darajasi" + ] + } + } + }, "rasmlar": "Rasmlar", "fotogalereya": "Fotogalereya", "contactTitle": "Bizga raqamingizni yuboring", @@ -262,7 +304,7 @@ "about": "Biz haqimizda", "services": "Xizmatlar", "catalog_page": "Mahsulotlar", - "subCategory":"{subCategory}", + "subCategory": "{subCategory}", "contact": "Bog'lanish", "blog": "Blog", "fire-safety": "Yong'in xavfsizligi", @@ -271,9 +313,9 @@ "installation": "O'rnatish", "maintenance": "Texnik xizmat" }, - "filter":{ - "category":"Kategoriyalar", - "catalog":"Bo'lim", - "size":"O'lchamlar" + "filter": { + "category": "Kategoriyalar", + "catalog": "Bo'lim", + "size": "O'lchamlar" } } diff --git a/package.json b/package.json index 49cf250..3e1141f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "build": "next build", "dev": "next dev", "lint": "eslint .", - "start": "next start" + "start": "next start -p 3909" }, "dependencies": { "@formatjs/intl-localematcher": "^0.8.0", diff --git a/public/images/services/foam.jpg b/public/images/services/foam.jpg new file mode 100644 index 0000000..44d3bd8 Binary files /dev/null and b/public/images/services/foam.jpg differ diff --git a/public/images/services/gss.webp b/public/images/services/gss.webp new file mode 100644 index 0000000..529febf Binary files /dev/null and b/public/images/services/gss.webp differ diff --git a/public/images/services/sprinkler.jpg b/public/images/services/sprinkler.jpg new file mode 100644 index 0000000..d895cc0 Binary files /dev/null and b/public/images/services/sprinkler.jpg differ diff --git a/request/links.ts b/request/links.ts index 578d171..e69c19a 100644 --- a/request/links.ts +++ b/request/links.ts @@ -5,6 +5,10 @@ export const endPoints = { subCategory: { byId: (id: number) => `subCategory/?category=${id}`, }, + services: { + all: "firesafety/", + detail: (id: number) => `/api/firesafety/${id}`, + }, product: { byCategory: (categoryId: number) => `product/?category=${categoryId}`, bySubCategory: (subCategoryId: number) => @@ -18,10 +22,10 @@ export const endPoints = { filter: { size: "size/", sizePageItems: "size/?page_size=500", - sizeCategoryId:(id:number)=>`size/?category=${id}&page_size=500`, + sizeCategoryId: (id: number) => `size/?category=${id}&page_size=500`, catalog: "catalog/", catalogPageItems: "catalog/?page_size=500", - catalogCategoryId:(id:number)=>`catalog/?category=${id}&page_size=500`, + catalogCategoryId: (id: number) => `catalog/?category=${id}&page_size=500`, }, post: { sendNumber: "callBack/", diff --git a/store/useService.ts b/store/useService.ts new file mode 100644 index 0000000..9ef6b49 --- /dev/null +++ b/store/useService.ts @@ -0,0 +1,14 @@ +import { create } from "zustand"; + +interface ServiceIdZustandType { + serviceId: number; + setServiceId: (serviceId: number) => void; +} + +export const useServiceDetail = create((set) => ({ + serviceId: 0, + setServiceId: (data: number) => + set({ + serviceId: data, + }), +}));