connetcted to backend: form request
This commit is contained in:
@@ -10,6 +10,9 @@ import BackAnimatsiya from "@/components/backAnimatsiya/backAnimatsiya";
|
|||||||
import { PriceModal } from "@/components/priceContact";
|
import { PriceModal } from "@/components/priceContact";
|
||||||
import PageTransition from "@/components/pageTransition/pageTransition";
|
import PageTransition from "@/components/pageTransition/pageTransition";
|
||||||
import { InitialLoading } from "@/components/initialLoading/initialLoading";
|
import { InitialLoading } from "@/components/initialLoading/initialLoading";
|
||||||
|
import { Providers } from "@/components/provider";
|
||||||
|
|
||||||
|
("info@ignum-tech.com");
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@@ -61,12 +64,7 @@ export default async function RootLayout({
|
|||||||
>
|
>
|
||||||
<InitialLoading />
|
<InitialLoading />
|
||||||
<NextIntlClientProvider messages={messages} locale={locale}>
|
<NextIntlClientProvider messages={messages} locale={locale}>
|
||||||
<BackAnimatsiya />
|
<Providers>{children}</Providers>
|
||||||
<Navbar />
|
|
||||||
{children}
|
|
||||||
<Footer />
|
|
||||||
<PriceModal />
|
|
||||||
<Analytics />
|
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ import { Mail, Phone, MapPin } from "lucide-react";
|
|||||||
import { useLocale, useTranslations } from "next-intl";
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import axios from "axios";
|
||||||
|
import httpClient from "@/request/api";
|
||||||
|
import { endPoints } from "@/request/links";
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
@@ -14,12 +19,25 @@ export function Footer() {
|
|||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [subscribed, setSubscribed] = useState(false);
|
const [subscribed, setSubscribed] = useState(false);
|
||||||
|
|
||||||
const handleSubscribe = (e: React.FormEvent) => {
|
const formRequest = useMutation({
|
||||||
e.preventDefault();
|
mutationKey: [],
|
||||||
if (email) {
|
mutationFn: (data: any) => httpClient.post(endPoints.post.sendNumber, data),
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success(t("succes"));
|
||||||
setSubscribed(true);
|
setSubscribed(true);
|
||||||
setEmail("");
|
setEmail("");
|
||||||
setTimeout(() => setSubscribed(false), 3000);
|
setTimeout(() => setSubscribed(false), 3000);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.log("error: ", error);
|
||||||
|
toast.error(t("error"));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubscribe = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (email) {
|
||||||
|
formRequest.mutate({ number: email });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,9 +67,11 @@ export function Footer() {
|
|||||||
className="flex sm:flex-row flex-col w-full gap-2 md:w-auto"
|
className="flex sm:flex-row flex-col w-full gap-2 md:w-auto"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="text"
|
||||||
placeholder={t("enterPhone")}
|
placeholder={t("enterPhone")}
|
||||||
value={email}
|
value={email}
|
||||||
|
minLength={9}
|
||||||
|
maxLength={13}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
className="font-almarai flex-1 rounded-full bg-white px-6 py-3 text-gray-800 placeholder-gray-400 focus:outline-none md:w-64"
|
className="font-almarai flex-1 rounded-full bg-white px-6 py-3 text-gray-800 placeholder-gray-400 focus:outline-none md:w-64"
|
||||||
required
|
required
|
||||||
@@ -179,9 +199,7 @@ export function Footer() {
|
|||||||
<div className="border-t border-gray-800 px-4 py-8">
|
<div className="border-t border-gray-800 px-4 py-8">
|
||||||
<div className="mx-auto max-w-6xl">
|
<div className="mx-auto max-w-6xl">
|
||||||
<div className="font-almarai flex flex-col justify-between gap-4 text-sm text-gray-400 md:flex-row md:items-center">
|
<div className="font-almarai flex flex-col justify-between gap-4 text-sm text-gray-400 md:flex-row md:items-center">
|
||||||
<div>
|
<div>Copyright © 2025 Ignum Company.</div>
|
||||||
Copyright © 2025 Ignum Company.
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-6">
|
<div className="flex gap-6">
|
||||||
<a href="#terms" className="hover:text-white">
|
<a href="#terms" className="hover:text-white">
|
||||||
Terms & Conditions
|
Terms & Conditions
|
||||||
|
|||||||
@@ -3,21 +3,26 @@
|
|||||||
import { Check } from "lucide-react";
|
import { Check } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import httpClient from "@/request/api";
|
||||||
|
import { endPoints } from "@/request/links";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
firstName: string;
|
name: string;
|
||||||
lastName: string;
|
surname: string;
|
||||||
email: string;
|
address: string;
|
||||||
subject: string;
|
theme: string;
|
||||||
message: string;
|
message: string;
|
||||||
agreeToPolicy: boolean;
|
agreeToPolicy: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FormErrors {
|
interface FormErrors {
|
||||||
firstName?: string;
|
name?: string;
|
||||||
lastName?: string;
|
surname?: string;
|
||||||
email?: string;
|
address?: string;
|
||||||
subject?: string;
|
theme?: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
agreeToPolicy?: string;
|
agreeToPolicy?: string;
|
||||||
}
|
}
|
||||||
@@ -25,10 +30,10 @@ interface FormErrors {
|
|||||||
export default function Form() {
|
export default function Form() {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const [formData, setFormData] = useState<FormData>({
|
const [formData, setFormData] = useState<FormData>({
|
||||||
firstName: "",
|
name: "",
|
||||||
lastName: "",
|
surname: "",
|
||||||
email: "",
|
address: "",
|
||||||
subject: "",
|
theme: "",
|
||||||
message: "",
|
message: "",
|
||||||
agreeToPolicy: false,
|
agreeToPolicy: false,
|
||||||
});
|
});
|
||||||
@@ -38,22 +43,48 @@ export default function Form() {
|
|||||||
"idle" | "success" | "error"
|
"idle" | "success" | "error"
|
||||||
>("idle");
|
>("idle");
|
||||||
|
|
||||||
|
const formRequest = useMutation({
|
||||||
|
mutationKey: [],
|
||||||
|
mutationFn: (data: FormData) => httpClient.post(endPoints.post.contact, data),
|
||||||
|
onSuccess: () => {
|
||||||
|
setSubmitStatus("success");
|
||||||
|
setFormData({
|
||||||
|
name: "",
|
||||||
|
surname: "",
|
||||||
|
address: "",
|
||||||
|
theme: "",
|
||||||
|
message: "",
|
||||||
|
agreeToPolicy: false,
|
||||||
|
});
|
||||||
|
setIsSubmitting(false);
|
||||||
|
toast.success(t("succes"));
|
||||||
|
setTimeout(() => setSubmitStatus("idle"), 3000);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.log("error: ", error);
|
||||||
|
setIsSubmitting(false);
|
||||||
|
setSubmitStatus("error");
|
||||||
|
toast.error(t("error"));
|
||||||
|
setTimeout(() => setSubmitStatus("idle"), 3000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const validateForm = (): boolean => {
|
const validateForm = (): boolean => {
|
||||||
const newErrors: FormErrors = {};
|
const newErrors: FormErrors = {};
|
||||||
|
|
||||||
if (!formData.firstName.trim()) {
|
if (!formData.name.trim()) {
|
||||||
newErrors.firstName = "First name is required";
|
newErrors.name = "First name is required";
|
||||||
}
|
}
|
||||||
if (!formData.lastName.trim()) {
|
if (!formData.surname.trim()) {
|
||||||
newErrors.lastName = "Last name is required";
|
newErrors.surname = "Last name is required";
|
||||||
}
|
}
|
||||||
if (!formData.email.trim()) {
|
if (!formData.address.trim()) {
|
||||||
newErrors.email = "Email is required";
|
newErrors.address = "address is required";
|
||||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.address)) {
|
||||||
newErrors.email = "Please enter a valid email";
|
newErrors.address = "Please enter a valid address";
|
||||||
}
|
}
|
||||||
if (!formData.subject.trim()) {
|
if (!formData.theme.trim()) {
|
||||||
newErrors.subject = "Subject is required";
|
newErrors.theme = "theme is required";
|
||||||
}
|
}
|
||||||
if (!formData.message.trim()) {
|
if (!formData.message.trim()) {
|
||||||
newErrors.message = "Message is required";
|
newErrors.message = "Message is required";
|
||||||
@@ -90,32 +121,7 @@ export default function Form() {
|
|||||||
|
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
setSubmitStatus("idle");
|
setSubmitStatus("idle");
|
||||||
|
formRequest.mutate(formData);
|
||||||
try {
|
|
||||||
const response = await fetch("/api/contact", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(formData),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
setSubmitStatus("success");
|
|
||||||
setFormData({
|
|
||||||
firstName: "",
|
|
||||||
lastName: "",
|
|
||||||
email: "",
|
|
||||||
subject: "",
|
|
||||||
message: "",
|
|
||||||
agreeToPolicy: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setSubmitStatus("error");
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setSubmitStatus("error");
|
|
||||||
} finally {
|
|
||||||
setIsSubmitting(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -125,66 +131,74 @@ export default function Form() {
|
|||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="firstName"
|
name="name"
|
||||||
placeholder={t("contact.form.placeholders.firstName")}
|
placeholder={t("contact.form.placeholders.firstName")}
|
||||||
value={formData.firstName}
|
value={formData.name}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm
|
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm
|
||||||
text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||||
errors.firstName ? "border-red-500" : "border-transparent"
|
errors.name ? "border-red-500" : "border-transparent"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.firstName && (
|
{errors.name && (
|
||||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.firstName}</p>
|
<p className="font-almarai mt-1 text-xs text-red-500">
|
||||||
|
{errors.name}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="lastName"
|
name="surname"
|
||||||
placeholder={t("contact.form.placeholders.lastName")}
|
placeholder={t("contact.form.placeholders.lastName")}
|
||||||
value={formData.lastName}
|
value={formData.surname}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||||
errors.lastName ? "border-red-500" : "border-transparent"
|
errors.surname ? "border-red-500" : "border-transparent"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.lastName && (
|
{errors.surname && (
|
||||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.lastName}</p>
|
<p className="font-almarai mt-1 text-xs text-red-500">
|
||||||
|
{errors.surname}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Second Row - Email & Subject */}
|
{/* Second Row - address & theme */}
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="address"
|
||||||
name="email"
|
name="address"
|
||||||
placeholder={t("contact.form.placeholders.email")}
|
placeholder={t("contact.form.placeholders.email")}
|
||||||
value={formData.email}
|
value={formData.address}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||||
errors.email ? "border-red-500" : "border-transparent"
|
errors.address ? "border-red-500" : "border-transparent"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.email && (
|
{errors.address && (
|
||||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.email}</p>
|
<p className="font-almarai mt-1 text-xs text-red-500">
|
||||||
|
{errors.address}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="subject"
|
name="theme"
|
||||||
placeholder={t("contact.form.placeholders.subject")}
|
placeholder={t("contact.form.placeholders.subject")}
|
||||||
value={formData.subject}
|
value={formData.theme}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
className={`font-almarai w-full rounded-3xl border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
|
||||||
errors.subject ? "border-red-500" : "border-transparent"
|
errors.theme ? "border-red-500" : "border-transparent"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.subject && (
|
{errors.theme && (
|
||||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.subject}</p>
|
<p className="font-almarai mt-1 text-xs text-red-500">
|
||||||
|
{errors.theme}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -202,7 +216,9 @@ export default function Form() {
|
|||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
{errors.message && (
|
{errors.message && (
|
||||||
<p className="font-almarai mt-1 text-xs text-red-500">{errors.message}</p>
|
<p className="font-almarai mt-1 text-xs text-red-500">
|
||||||
|
{errors.message}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -236,7 +252,9 @@ export default function Form() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{errors.agreeToPolicy && (
|
{errors.agreeToPolicy && (
|
||||||
<p className="font-almarai text-xs text-red-500">{errors.agreeToPolicy}</p>
|
<p className="font-almarai text-xs text-red-500">
|
||||||
|
{errors.agreeToPolicy}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Status Messages */}
|
{/* Status Messages */}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Mail, MapPin, Phone, Check } from "lucide-react";
|
import { Mail, MapPin, Phone } from "lucide-react";
|
||||||
import ContactHeader from "./contactHeader";
|
import ContactHeader from "./contactHeader";
|
||||||
import Form from "./form";
|
import Form from "./form";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -25,7 +25,7 @@ export function Contact() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative min-h-175 w-full py-16 md:py-40">
|
<section className="relative min-h-175 w-full py-30 md:py-40">
|
||||||
{/* Background Image */}
|
{/* Background Image */}
|
||||||
<div className="absolute inset-0 z-0">
|
<div className="absolute inset-0 z-0">
|
||||||
<Image
|
<Image
|
||||||
|
|||||||
27
components/provider/index.tsx
Normal file
27
components/provider/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import BackAnimatsiya from "../backAnimatsiya/backAnimatsiya";
|
||||||
|
import { Footer, Navbar } from "../layout";
|
||||||
|
import { PriceModal } from "../priceContact";
|
||||||
|
import { Analytics } from "@vercel/analytics/next";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { ToastContainer } from 'react-toastify';
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
export function Providers({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<BackAnimatsiya />
|
||||||
|
<Navbar />
|
||||||
|
{children}
|
||||||
|
<Footer />
|
||||||
|
<PriceModal />
|
||||||
|
<Analytics />
|
||||||
|
<ToastContainer/>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -228,7 +228,9 @@
|
|||||||
"contactTitle": "Send us your phone number",
|
"contactTitle": "Send us your phone number",
|
||||||
"contactSubTitle": "Our staff will contact you",
|
"contactSubTitle": "Our staff will contact you",
|
||||||
"enterPhone": "Enter your phone number",
|
"enterPhone": "Enter your phone number",
|
||||||
"send": "Send",
|
"send": "Sent",
|
||||||
|
"error":"Error!",
|
||||||
|
"succes":"sent!",
|
||||||
"priceModal": {
|
"priceModal": {
|
||||||
"title": "Get Price",
|
"title": "Get Price",
|
||||||
"product": {
|
"product": {
|
||||||
|
|||||||
@@ -229,6 +229,8 @@
|
|||||||
"contactSubTitle": "Наши сотрудники свяжутся с вами",
|
"contactSubTitle": "Наши сотрудники свяжутся с вами",
|
||||||
"enterPhone": "Введите ваш номер телефона",
|
"enterPhone": "Введите ваш номер телефона",
|
||||||
"send": "Отправить",
|
"send": "Отправить",
|
||||||
|
"error": "Ошибка!",
|
||||||
|
"succes": "Отправлено!",
|
||||||
"priceModal": {
|
"priceModal": {
|
||||||
"title": "Узнать цену",
|
"title": "Узнать цену",
|
||||||
"product": {
|
"product": {
|
||||||
|
|||||||
@@ -229,7 +229,8 @@
|
|||||||
"contactSubTitle": "Xodimlarimiz siz bilan bog'lanishadi",
|
"contactSubTitle": "Xodimlarimiz siz bilan bog'lanishadi",
|
||||||
"enterPhone": "Telefon raqamingiz kiriting",
|
"enterPhone": "Telefon raqamingiz kiriting",
|
||||||
"send": "Yuborish",
|
"send": "Yuborish",
|
||||||
|
"error":"Xatolik!",
|
||||||
|
"succes":"Yuborildi!",
|
||||||
"priceModal": {
|
"priceModal": {
|
||||||
"title": "Narxni bilish",
|
"title": "Narxni bilish",
|
||||||
"product": {
|
"product": {
|
||||||
|
|||||||
@@ -38,8 +38,10 @@
|
|||||||
"@radix-ui/react-toggle": "1.1.1",
|
"@radix-ui/react-toggle": "1.1.1",
|
||||||
"@radix-ui/react-toggle-group": "1.1.1",
|
"@radix-ui/react-toggle-group": "1.1.1",
|
||||||
"@radix-ui/react-tooltip": "1.1.6",
|
"@radix-ui/react-tooltip": "1.1.6",
|
||||||
|
"@tanstack/react-query": "^5.90.20",
|
||||||
"@vercel/analytics": "1.3.1",
|
"@vercel/analytics": "1.3.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
"axios": "^1.13.4",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "1.0.4",
|
"cmdk": "1.0.4",
|
||||||
@@ -58,6 +60,7 @@
|
|||||||
"react-fast-marquee": "^1.6.5",
|
"react-fast-marquee": "^1.6.5",
|
||||||
"react-hook-form": "^7.60.0",
|
"react-hook-form": "^7.60.0",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
|
"react-toastify": "^11.0.5",
|
||||||
"recharts": "2.15.4",
|
"recharts": "2.15.4",
|
||||||
"sonner": "^1.7.4",
|
"sonner": "^1.7.4",
|
||||||
"swiper": "^12.0.3",
|
"swiper": "^12.0.3",
|
||||||
|
|||||||
223
pnpm-lock.yaml
generated
223
pnpm-lock.yaml
generated
@@ -95,12 +95,18 @@ importers:
|
|||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: 1.1.6
|
specifier: 1.1.6
|
||||||
version: 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.9))(@types/react@19.2.9)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.9))(@types/react@19.2.9)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
|
'@tanstack/react-query':
|
||||||
|
specifier: ^5.90.20
|
||||||
|
version: 5.90.20(react@19.2.0)
|
||||||
'@vercel/analytics':
|
'@vercel/analytics':
|
||||||
specifier: 1.3.1
|
specifier: 1.3.1
|
||||||
version: 1.3.1(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)
|
version: 1.3.1(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.20
|
specifier: ^10.4.20
|
||||||
version: 10.4.23(postcss@8.5.6)
|
version: 10.4.23(postcss@8.5.6)
|
||||||
|
axios:
|
||||||
|
specifier: ^1.13.4
|
||||||
|
version: 1.13.4
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.1
|
specifier: ^0.7.1
|
||||||
version: 0.7.1
|
version: 0.7.1
|
||||||
@@ -155,6 +161,9 @@ importers:
|
|||||||
react-resizable-panels:
|
react-resizable-panels:
|
||||||
specifier: ^2.1.7
|
specifier: ^2.1.7
|
||||||
version: 2.1.9(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 2.1.9(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
|
react-toastify:
|
||||||
|
specifier: ^11.0.5
|
||||||
|
version: 11.0.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
recharts:
|
recharts:
|
||||||
specifier: 2.15.4
|
specifier: 2.15.4
|
||||||
version: 2.15.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 2.15.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
@@ -1379,6 +1388,14 @@ packages:
|
|||||||
'@tailwindcss/postcss@4.1.18':
|
'@tailwindcss/postcss@4.1.18':
|
||||||
resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
|
resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.90.20':
|
||||||
|
resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.90.20':
|
||||||
|
resolution: {integrity: sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18 || ^19
|
||||||
|
|
||||||
'@types/d3-array@3.2.2':
|
'@types/d3-array@3.2.2':
|
||||||
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
|
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
|
||||||
|
|
||||||
@@ -1435,6 +1452,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
asynckit@0.4.0:
|
||||||
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
autoprefixer@10.4.23:
|
autoprefixer@10.4.23:
|
||||||
resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==}
|
resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
@@ -1442,6 +1462,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.1.0
|
postcss: ^8.1.0
|
||||||
|
|
||||||
|
axios@1.13.4:
|
||||||
|
resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==}
|
||||||
|
|
||||||
baseline-browser-mapping@2.9.17:
|
baseline-browser-mapping@2.9.17:
|
||||||
resolution: {integrity: sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==}
|
resolution: {integrity: sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1451,6 +1474,10 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
call-bind-apply-helpers@1.0.2:
|
||||||
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001765:
|
caniuse-lite@1.0.30001765:
|
||||||
resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==}
|
resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==}
|
||||||
|
|
||||||
@@ -1470,6 +1497,10 @@ packages:
|
|||||||
react: ^18 || ^19 || ^19.0.0-rc
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
react-dom: ^18 || ^19 || ^19.0.0-rc
|
react-dom: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
csstype@3.2.3:
|
csstype@3.2.3:
|
||||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||||
|
|
||||||
@@ -1529,6 +1560,10 @@ packages:
|
|||||||
decimal.js@10.6.0:
|
decimal.js@10.6.0:
|
||||||
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
detect-libc@2.1.2:
|
detect-libc@2.1.2:
|
||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1539,6 +1574,10 @@ packages:
|
|||||||
dom-helpers@5.2.1:
|
dom-helpers@5.2.1:
|
||||||
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||||
|
|
||||||
|
dunder-proto@1.0.1:
|
||||||
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
electron-to-chromium@1.5.267:
|
electron-to-chromium@1.5.267:
|
||||||
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
|
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
|
||||||
|
|
||||||
@@ -1559,6 +1598,22 @@ packages:
|
|||||||
resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
|
resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
es-define-property@1.0.1:
|
||||||
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es-errors@1.3.0:
|
||||||
|
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es-object-atoms@1.1.1:
|
||||||
|
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0:
|
||||||
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
escalade@3.2.0:
|
escalade@3.2.0:
|
||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -1570,6 +1625,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==}
|
resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
follow-redirects@1.15.11:
|
||||||
|
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
form-data@4.0.5:
|
||||||
|
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
fraction.js@5.3.4:
|
fraction.js@5.3.4:
|
||||||
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
||||||
|
|
||||||
@@ -1587,13 +1655,40 @@ packages:
|
|||||||
react-dom:
|
react-dom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
function-bind@1.1.2:
|
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
|
get-intrinsic@1.3.0:
|
||||||
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
get-nonce@1.0.1:
|
get-nonce@1.0.1:
|
||||||
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
get-proto@1.0.1:
|
||||||
|
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
gopd@1.2.0:
|
||||||
|
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
graceful-fs@4.2.11:
|
graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
|
has-symbols@1.1.0:
|
||||||
|
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
has-tostringtag@1.0.2:
|
||||||
|
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
input-otp@1.4.1:
|
input-otp@1.4.1:
|
||||||
resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==}
|
resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1707,6 +1802,18 @@ packages:
|
|||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
|
math-intrinsics@1.1.0:
|
||||||
|
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
mime-db@1.52.0:
|
||||||
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
mime-types@2.1.35:
|
||||||
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
motion-dom@12.29.2:
|
motion-dom@12.29.2:
|
||||||
resolution: {integrity: sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA==}
|
resolution: {integrity: sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA==}
|
||||||
|
|
||||||
@@ -1796,6 +1903,9 @@ packages:
|
|||||||
prop-types@15.8.1:
|
prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0:
|
||||||
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
|
||||||
react-day-picker@9.8.0:
|
react-day-picker@9.8.0:
|
||||||
resolution: {integrity: sha512-E0yhhg7R+pdgbl/2toTb0xBhsEAtmAx1l7qjIWYfcxOy8w4rTSVfbtBoSzVVhPwKP/5E9iL38LivzoE3AQDhCQ==}
|
resolution: {integrity: sha512-E0yhhg7R+pdgbl/2toTb0xBhsEAtmAx1l7qjIWYfcxOy8w4rTSVfbtBoSzVVhPwKP/5E9iL38LivzoE3AQDhCQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -1867,6 +1977,12 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
react-toastify@11.0.5:
|
||||||
|
resolution: {integrity: sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18 || ^19
|
||||||
|
react-dom: ^18 || ^19
|
||||||
|
|
||||||
react-transition-group@4.4.5:
|
react-transition-group@4.4.5:
|
||||||
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3121,6 +3237,13 @@ snapshots:
|
|||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
tailwindcss: 4.1.18
|
tailwindcss: 4.1.18
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.90.20': {}
|
||||||
|
|
||||||
|
'@tanstack/react-query@5.90.20(react@19.2.0)':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/query-core': 5.90.20
|
||||||
|
react: 19.2.0
|
||||||
|
|
||||||
'@types/d3-array@3.2.2': {}
|
'@types/d3-array@3.2.2': {}
|
||||||
|
|
||||||
'@types/d3-color@3.1.3': {}
|
'@types/d3-color@3.1.3': {}
|
||||||
@@ -3170,6 +3293,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
autoprefixer@10.4.23(postcss@8.5.6):
|
autoprefixer@10.4.23(postcss@8.5.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.28.1
|
browserslist: 4.28.1
|
||||||
@@ -3179,6 +3304,14 @@ snapshots:
|
|||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
|
|
||||||
|
axios@1.13.4:
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.15.11
|
||||||
|
form-data: 4.0.5
|
||||||
|
proxy-from-env: 1.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
|
||||||
baseline-browser-mapping@2.9.17: {}
|
baseline-browser-mapping@2.9.17: {}
|
||||||
|
|
||||||
browserslist@4.28.1:
|
browserslist@4.28.1:
|
||||||
@@ -3189,6 +3322,11 @@ snapshots:
|
|||||||
node-releases: 2.0.27
|
node-releases: 2.0.27
|
||||||
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||||
|
|
||||||
|
call-bind-apply-helpers@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
es-errors: 1.3.0
|
||||||
|
function-bind: 1.1.2
|
||||||
|
|
||||||
caniuse-lite@1.0.30001765: {}
|
caniuse-lite@1.0.30001765: {}
|
||||||
|
|
||||||
class-variance-authority@0.7.1:
|
class-variance-authority@0.7.1:
|
||||||
@@ -3211,6 +3349,10 @@ snapshots:
|
|||||||
- '@types/react'
|
- '@types/react'
|
||||||
- '@types/react-dom'
|
- '@types/react-dom'
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
dependencies:
|
||||||
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
csstype@3.2.3: {}
|
csstype@3.2.3: {}
|
||||||
|
|
||||||
d3-array@3.2.4:
|
d3-array@3.2.4:
|
||||||
@@ -3259,6 +3401,8 @@ snapshots:
|
|||||||
|
|
||||||
decimal.js@10.6.0: {}
|
decimal.js@10.6.0: {}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
detect-node-es@1.1.0: {}
|
detect-node-es@1.1.0: {}
|
||||||
@@ -3268,6 +3412,12 @@ snapshots:
|
|||||||
'@babel/runtime': 7.28.6
|
'@babel/runtime': 7.28.6
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
|
dunder-proto@1.0.1:
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers: 1.0.2
|
||||||
|
es-errors: 1.3.0
|
||||||
|
gopd: 1.2.0
|
||||||
|
|
||||||
electron-to-chromium@1.5.267: {}
|
electron-to-chromium@1.5.267: {}
|
||||||
|
|
||||||
embla-carousel-react@8.5.1(react@19.2.0):
|
embla-carousel-react@8.5.1(react@19.2.0):
|
||||||
@@ -3287,12 +3437,37 @@ snapshots:
|
|||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
|
|
||||||
|
es-define-property@1.0.1: {}
|
||||||
|
|
||||||
|
es-errors@1.3.0: {}
|
||||||
|
|
||||||
|
es-object-atoms@1.1.1:
|
||||||
|
dependencies:
|
||||||
|
es-errors: 1.3.0
|
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0:
|
||||||
|
dependencies:
|
||||||
|
es-errors: 1.3.0
|
||||||
|
get-intrinsic: 1.3.0
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
hasown: 2.0.2
|
||||||
|
|
||||||
escalade@3.2.0: {}
|
escalade@3.2.0: {}
|
||||||
|
|
||||||
eventemitter3@4.0.7: {}
|
eventemitter3@4.0.7: {}
|
||||||
|
|
||||||
fast-equals@5.4.0: {}
|
fast-equals@5.4.0: {}
|
||||||
|
|
||||||
|
follow-redirects@1.15.11: {}
|
||||||
|
|
||||||
|
form-data@4.0.5:
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
es-set-tostringtag: 2.1.0
|
||||||
|
hasown: 2.0.2
|
||||||
|
mime-types: 2.1.35
|
||||||
|
|
||||||
fraction.js@5.3.4: {}
|
fraction.js@5.3.4: {}
|
||||||
|
|
||||||
framer-motion@12.29.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
framer-motion@12.29.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||||
@@ -3304,10 +3479,42 @@ snapshots:
|
|||||||
react: 19.2.0
|
react: 19.2.0
|
||||||
react-dom: 19.2.0(react@19.2.0)
|
react-dom: 19.2.0(react@19.2.0)
|
||||||
|
|
||||||
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
|
get-intrinsic@1.3.0:
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers: 1.0.2
|
||||||
|
es-define-property: 1.0.1
|
||||||
|
es-errors: 1.3.0
|
||||||
|
es-object-atoms: 1.1.1
|
||||||
|
function-bind: 1.1.2
|
||||||
|
get-proto: 1.0.1
|
||||||
|
gopd: 1.2.0
|
||||||
|
has-symbols: 1.1.0
|
||||||
|
hasown: 2.0.2
|
||||||
|
math-intrinsics: 1.1.0
|
||||||
|
|
||||||
get-nonce@1.0.1: {}
|
get-nonce@1.0.1: {}
|
||||||
|
|
||||||
|
get-proto@1.0.1:
|
||||||
|
dependencies:
|
||||||
|
dunder-proto: 1.0.1
|
||||||
|
es-object-atoms: 1.1.1
|
||||||
|
|
||||||
|
gopd@1.2.0: {}
|
||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
|
has-symbols@1.1.0: {}
|
||||||
|
|
||||||
|
has-tostringtag@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
has-symbols: 1.1.0
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
function-bind: 1.1.2
|
||||||
|
|
||||||
input-otp@1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
input-otp@1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.0
|
react: 19.2.0
|
||||||
@@ -3395,6 +3602,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
math-intrinsics@1.1.0: {}
|
||||||
|
|
||||||
|
mime-db@1.52.0: {}
|
||||||
|
|
||||||
|
mime-types@2.1.35:
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.52.0
|
||||||
|
|
||||||
motion-dom@12.29.2:
|
motion-dom@12.29.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
motion-utils: 12.29.2
|
motion-utils: 12.29.2
|
||||||
@@ -3483,6 +3698,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0: {}
|
||||||
|
|
||||||
react-day-picker@9.8.0(react@19.2.0):
|
react-day-picker@9.8.0(react@19.2.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@date-fns/tz': 1.2.0
|
'@date-fns/tz': 1.2.0
|
||||||
@@ -3548,6 +3765,12 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.2.9
|
'@types/react': 19.2.9
|
||||||
|
|
||||||
|
react-toastify@11.0.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||||
|
dependencies:
|
||||||
|
clsx: 2.1.1
|
||||||
|
react: 19.2.0
|
||||||
|
react-dom: 19.2.0(react@19.2.0)
|
||||||
|
|
||||||
react-transition-group@4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
react-transition-group@4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.6
|
'@babel/runtime': 7.28.6
|
||||||
|
|||||||
35
request/api.ts
Normal file
35
request/api.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import axios, { InternalAxiosRequestConfig } from "axios";
|
||||||
|
import { getRouteLang } from "./getLang";
|
||||||
|
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
|
||||||
|
|
||||||
|
const httpClient = axios.create({
|
||||||
|
baseURL: baseUrl,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Request interceptor
|
||||||
|
httpClient.interceptors.request.use(
|
||||||
|
(config: InternalAxiosRequestConfig) => {
|
||||||
|
const language = getRouteLang();
|
||||||
|
config.headers["Accept-Language"] = language;
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Response interceptor (xatoliklarni boshqarish uchun)
|
||||||
|
httpClient.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
// Xatolikni formatlash
|
||||||
|
const message = error.response?.data?.message || error.message;
|
||||||
|
return Promise.reject(message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default httpClient;
|
||||||
18
request/getLang.ts
Normal file
18
request/getLang.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// utils/getRouteLang.ts
|
||||||
|
import { locales, defaultLocale } from "@/i18n/config";
|
||||||
|
|
||||||
|
export function getRouteLang(): string {
|
||||||
|
if (typeof window === "undefined") return defaultLocale;
|
||||||
|
|
||||||
|
// 1)Fall back to the first non-empty pathname segment
|
||||||
|
const rawSegments = window.location.pathname.split("/"); // e.g. ['', 'uz', 'path', ...]
|
||||||
|
const segments = rawSegments.filter(Boolean); // removes empty strings
|
||||||
|
if (segments.length > 0) {
|
||||||
|
const candidate = segments[0]; // first segment after root
|
||||||
|
if (locales.includes(candidate as (typeof locales)[number]))
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) final fallback
|
||||||
|
return defaultLocale;
|
||||||
|
}
|
||||||
23
request/links.ts
Normal file
23
request/links.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export const endPoints = {
|
||||||
|
category: {
|
||||||
|
all: "category/",
|
||||||
|
},
|
||||||
|
subCategory: {
|
||||||
|
byId: (id: number) => `subCategory/?category=${id}`,
|
||||||
|
},
|
||||||
|
product: {
|
||||||
|
byCategory: (categoryId: number) => `product/?category=${categoryId}`,
|
||||||
|
bySubCategory: (subCategoryId: number) =>
|
||||||
|
`product/?subCategory=${subCategoryId}`,
|
||||||
|
detail: (id: number) => `product/${id}/`,
|
||||||
|
},
|
||||||
|
faq: "faq/",
|
||||||
|
gallery: "gallery/",
|
||||||
|
contact: "contact/",
|
||||||
|
statistics: "statistics/",
|
||||||
|
post: {
|
||||||
|
sendNumber: "callBack/",
|
||||||
|
productContact: "customer/",
|
||||||
|
contact: "question/",
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user