contact form updated , added telegram instagram icon buttons

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-02-09 19:21:22 +05:00
parent 625e21394f
commit dcdfce4d79
7 changed files with 118 additions and 57 deletions

View File

@@ -3,18 +3,18 @@
import React from "react"; import React from "react";
import { useState } from "react"; import { useState } from "react";
import { Mail, Phone, MapPin } from "lucide-react"; import { Mail, Phone, MapPin, Instagram, Send } 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 { useMutation } from "@tanstack/react-query";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import axios from "axios";
import httpClient from "@/request/api"; import httpClient from "@/request/api";
import { endPoints } from "@/request/links"; import { endPoints } from "@/request/links";
export function Footer() { export function Footer() {
const locale = useLocale(); const locale = useLocale();
const [errors, setErrors] = useState<any>({});
const t = useTranslations(); const t = useTranslations();
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [subscribed, setSubscribed] = useState(false); const [subscribed, setSubscribed] = useState(false);
@@ -34,6 +34,30 @@ export function Footer() {
}, },
}); });
const formatPhoneNumber = (value: string) => {
const numbers = value.replace(/\D/g, "");
if (!numbers.startsWith("998")) {
return "+998 ";
}
let formatted = "+998 ";
const rest = numbers.slice(3);
if (rest.length > 0) formatted += rest.slice(0, 2);
if (rest.length > 2) formatted += " " + rest.slice(2, 5);
if (rest.length > 5) formatted += " " + rest.slice(5, 7);
if (rest.length > 7) formatted += " " + rest.slice(7, 9);
return formatted;
};
const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const formatted = formatPhoneNumber(e.target.value);
setEmail(formatted);
if (errors.address) {
setErrors({ ...errors, address: "" });
}
};
const handleSubscribe = (e: React.FormEvent) => { const handleSubscribe = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (email) { if (email) {
@@ -67,14 +91,16 @@ 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="text" type="tel"
placeholder={t("enterPhone")} id="phone"
name="phone"
value={email} value={email}
minLength={9} onChange={handlePhoneChange}
maxLength={13} 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 ${
onChange={(e) => setEmail(e.target.value)} errors.email ? "border-red-500" : "border-transparent"
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 placeholder="+998 90 123 45 67"
maxLength={17}
/> />
<button <button
type="submit" type="submit"
@@ -107,6 +133,20 @@ export function Footer() {
<p className="font-almarai text-sm leading-relaxed text-gray-300"> <p className="font-almarai text-sm leading-relaxed text-gray-300">
{t("footer.description")} {t("footer.description")}
</p> </p>
<div className="flex items-center gap-5 mt-5">
<a
href=""
className="p-2 rounded-md bg-gray-700 hover:bg-red-500"
>
<Instagram />
</a>
<a
href=""
className="p-2 rounded-md bg-gray-700 hover:bg-red-500"
>
<Send />
</a>
</div>
</div> </div>
{/* Quick Links */} {/* Quick Links */}
@@ -187,9 +227,7 @@ export function Footer() {
</li> </li>
<li className="flex items-start gap-3"> <li className="flex items-start gap-3">
<MapPin className="mt-1 h-5 w-5 shrink-0 text-white" /> <MapPin className="mt-1 h-5 w-5 shrink-0 text-white" />
<span> <span>{t("footer.address")}</span>
{t("footer.address")}
</span>
</li> </li>
</ul> </ul>
</div> </div>

View File

@@ -45,7 +45,8 @@ export default function Form() {
const formRequest = useMutation({ const formRequest = useMutation({
mutationKey: [], mutationKey: [],
mutationFn: (data: FormData) => httpClient.post(endPoints.post.contact, data), mutationFn: (data: FormData) =>
httpClient.post(endPoints.post.contact, data),
onSuccess: () => { onSuccess: () => {
setSubmitStatus("success"); setSubmitStatus("success");
setFormData({ setFormData({
@@ -78,10 +79,13 @@ export default function Form() {
if (!formData.surname.trim()) { if (!formData.surname.trim()) {
newErrors.surname = "Last name is required"; newErrors.surname = "Last name is required";
} }
if (!formData.address.trim()) { const phoneNumbers = formData.address.replace(/\D/g, "");
newErrors.address = "address is required"; if (phoneNumbers.length !== 12) {
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.address)) { newErrors.address =
newErrors.address = "Please enter a valid address"; t("validation.phoneRequired") || "To'liq telefon raqam kiriting";
} else if (!phoneNumbers.startsWith("998")) {
newErrors.address =
t("validation.phoneInvalid") || "Noto'g'ri telefon raqam";
} }
if (!formData.theme.trim()) { if (!formData.theme.trim()) {
newErrors.theme = "theme is required"; newErrors.theme = "theme is required";
@@ -97,6 +101,30 @@ export default function Form() {
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0;
}; };
const formatPhoneNumber = (value: string) => {
const numbers = value.replace(/\D/g, "");
if (!numbers.startsWith("998")) {
return "+998 ";
}
let formatted = "+998 ";
const rest = numbers.slice(3);
if (rest.length > 0) formatted += rest.slice(0, 2);
if (rest.length > 2) formatted += " " + rest.slice(2, 5);
if (rest.length > 5) formatted += " " + rest.slice(5, 7);
if (rest.length > 7) formatted += " " + rest.slice(7, 9);
return formatted;
};
const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const formatted = formatPhoneNumber(e.target.value);
setFormData({ ...formData, address: formatted });
if (errors.address) {
setErrors({ ...errors, address: "" });
}
};
const handleChange = ( const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => { ) => {
@@ -169,19 +197,19 @@ export default function Form() {
<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="address" type="tel"
name="address" id="phone"
placeholder={t("contact.form.placeholders.email")} name="phone"
value={formData.address} value={formData.address}
onChange={handleChange} onChange={handlePhoneChange}
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.address ? "border-red-500" : "border-transparent" errors.address ? "border-red-500" : "border-transparent"
}`} }`}
placeholder="+998 90 123 45 67"
maxLength={17}
/> />
{errors.address && ( {errors.address && (
<p className="font-almarai mt-1 text-xs text-red-500"> <p className="mt-1 text-sm text-red-500">{errors.address}</p>
{errors.address}
</p>
)} )}
</div> </div>
<div> <div>

View File

@@ -42,7 +42,7 @@ export function Contact() {
className="absolute inset-0" className="absolute inset-0"
style={{ style={{
background: background:
"radial-gradient(ellipse at bottom center, #d2610a 0%, #1e1d1ce9 70% , #1e1d1ce9 70%)", "radial-gradient(at center bottom, rgb(144 74 20) 0%, rgba(30, 29, 28, 0.914) 70%, rgba(30, 29, 28, 0.914) 70%)",
}} }}
/> />
</div> </div>

View File

@@ -1,12 +1,11 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { Button } from "@/components/ui/button";
import Image from "next/image"; import Image from "next/image";
import { Flame, Building2, Ambulance } from "lucide-react"; import { Flame, Building2, Ambulance } from "lucide-react";
import DotAnimatsiya from "@/components/dot/DotAnimatsiya"; import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
import { useTranslations } from "next-intl"; import { useLocale, useTranslations } from "next-intl";
import Link from "next/link";
interface ServiceItem { interface ServiceItem {
icon: React.ReactNode; icon: React.ReactNode;
@@ -16,6 +15,7 @@ interface ServiceItem {
export function AboutUs() { export function AboutUs() {
const t = useTranslations(); const t = useTranslations();
const locale = useLocale();
const services: ServiceItem[] = [ const services: ServiceItem[] = [
{ {
icon: <Flame width={40} height={40} className="text-red-500" />, icon: <Flame width={40} height={40} className="text-red-500" />,
@@ -76,9 +76,9 @@ export function AboutUs() {
{/* Button */} {/* Button */}
<div> <div>
<Button className="font-almarai bg-red-600 hover:bg-red-700 text-white font-bold px-8 py-3 rounded-full transition-colors duration-300 shadow-[0px_0px_2px_8px_#ff01015c]"> <Link href={`/${locale}/about`} className="font-almarai bg-red-600 hover:bg-red-700 text-white font-bold px-8 py-3 rounded-full transition-colors duration-300 shadow-[0px_0px_2px_8px_#ff01015c]">
{t("home.about.title")} {t("home.about.title")}
</Button> </Link>
</div> </div>
</div> </div>

View File

@@ -1,8 +1,10 @@
import { useTranslations } from "next-intl"; import { useLocale, useTranslations } from "next-intl";
import DotAnimatsiya from "../../dot/DotAnimatsiya"; import DotAnimatsiya from "../../dot/DotAnimatsiya";
import Link from "next/link";
export function Banner() { export function Banner() {
const t = useTranslations(); const t = useTranslations();
const locale = useLocale();
return ( return (
<section className="relative w-full lg:h-[86vh] h-screen min-h-150 overflow-hidden pt-20"> <section className="relative w-full lg:h-[86vh] h-screen min-h-150 overflow-hidden pt-20">
{/* Background Image */} {/* Background Image */}
@@ -77,8 +79,10 @@ export function Banner() {
</div> </div>
{/* Main Heading */} {/* Main Heading */}
<h1 className="font-unbounded uppercase text-4xl bg-linear-to-br from-white via-white to-black <h1
text-transparent bg-clip-text sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"> className="font-unbounded uppercase text-4xl bg-linear-to-br from-white via-white to-black
text-transparent bg-clip-text sm:text-5xl lg:text-6xl font-bold leading-tight text-pretty"
>
{t("home.banner.title2")} {t("home.banner.title2")}
</h1> </h1>
@@ -88,9 +92,12 @@ export function Banner() {
</p> </p>
{/* CTA Button */} {/* CTA Button */}
<button className="font-almarai shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit"> <Link
href={`/${locale}/contact`}
className="font-almarai shadow-[0px_0px_2px_8px_#ff01015c] bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-8 rounded-full transition duration-300 transform hover:scale-105 w-fit"
>
{t("home.banner.cta")} {t("home.banner.cta")}
</button> </Link>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,12 +1,5 @@
import { usePriceModalStore } from "@/store/useProceModalStore"; import { usePriceModalStore } from "@/store/useProceModalStore";
import { Facebook, Share2 } from "lucide-react"; import { Instagram, Send, Share2 } from "lucide-react";
const socialLinks = [
{ name: "telegram", icon: "✈️", color: "#0088cc" },
{ name: "facebook", icon: <Facebook size={18} />, color: "#1877F2" },
{ name: "whatsapp", icon: "💬", color: "#25D366" },
{ name: "twitter", icon: "𝕏", color: "#1DA1F2" },
];
interface RightSideProps { interface RightSideProps {
id: number; id: number;
@@ -95,18 +88,13 @@ export function RightSide({
<Share2 className="w-5 h-5 text-gray-400" /> <Share2 className="w-5 h-5 text-gray-400" />
<span className="text-sm text-gray-400">Ulashish:</span> <span className="text-sm text-gray-400">Ulashish:</span>
</div> </div>
<div className="flex flex-wrap gap-2"> <div className="flex items-center gap-5 mt-5">
{socialLinks.map((social) => ( <a href="" className="p-2 rounded-md bg-white text-red-500 hover:text-white hover:bg-red-500">
<a <Instagram />
key={social.name} </a>
href="#" <a href="" className="p-2 rounded-md bg-white text-red-500 hover:text-white hover:bg-red-500">
className="w-10 h-10 rounded-lg flex items-center justify-center text-white text-sm font-bold transition-all duration-300 hover:scale-110 hover:shadow-lg" <Send />
style={{ backgroundColor: social.color }}
title={social.name}
>
{social.icon}
</a> </a>
))}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -14,7 +14,7 @@ export function Providers({ children }: { children: ReactNode }) {
return ( return (
<div> <div>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<BackAnimatsiya /> {/* <BackAnimatsiya /> */}
<Navbar /> <Navbar />
{children} {children}
<Footer /> <Footer />