contact form updated , added telegram instagram icon buttons
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,19 +88,14 @@ 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 }}
|
</a>
|
||||||
title={social.name}
|
</div>
|
||||||
>
|
|
||||||
{social.icon}
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
Reference in New Issue
Block a user