-
{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() {
@@ -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")}
-
-
- {t("home.services.learnmore")}
-
-
-
-
-
- {t("home.services.services.suppression.title")}
-
-
- {t("home.services.services.suppression.description")}
-
-
- {t("home.services.learnmore")}
-
-
-
-
-
-
-
-
-
-
- {t("home.services.services.safety.title")}
-
-
- {t("home.services.services.safety.description")}
-
-
- {t("home.services.learnmore")}
-
-
-
-
-
-
- {t("home.services.services.monitoring.title")}
-
-
- {t("home.services.services.monitoring.description")}
-
-
- {t("home.services.learnmore")}
-
-
-
-
-
- {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."}
+
+
+
+ window.location.reload()}
+ className="font-almarai bg-red-600 hover:bg-red-700 text-white font-semibold py-3 px-8 rounded-full transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-red-500/50"
+ >
+ {t("home.services.noData.reload") || "Qayta yuklash"}
+
+
+
+
+ );
+}
\ 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")}
+
+
+ {t("home.services.learnmore")}
+
+
+
+
+
+
+
+
+ {t("home.services.services.suppression.title")}
+
+
+ {t("home.services.services.suppression.description")}
+
+
+ {t("home.services.learnmore")}
+
+
+
+
+
+
+
+
+
+
+
+
+ {t("home.services.services.safety.title")}
+
+
+ {t("home.services.services.safety.description")}
+
+
+ {t("home.services.learnmore")}
+
+
+
+
+
+
+
+
+
+
+ {t("home.services.services.monitoring.title")}
+
+
+ {t("home.services.services.monitoring.description")}
+
+
+ {t("home.services.learnmore")}
+
+
+
+
+
+
+
+
+ {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