update redesign
This commit is contained in:
@@ -2,8 +2,7 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { MaterialIcon } from "@/components/ui/MaterialIcon";
|
||||
|
||||
const COMPANY = [
|
||||
@@ -27,392 +26,131 @@ const LEGAL = [
|
||||
{ label: "Sitemap", href: "#" },
|
||||
];
|
||||
|
||||
type FooterFormData = {
|
||||
name: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
type FooterFormErrors = {
|
||||
name?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export function Footer() {
|
||||
const pathname = usePathname();
|
||||
const isContactPage = pathname?.startsWith("/contact");
|
||||
|
||||
// Form states
|
||||
const [formData, setFormData] = useState<FooterFormData>({
|
||||
name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
message: "",
|
||||
});
|
||||
const [errors, setErrors] = useState<FooterFormErrors>({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitSuccess, setSubmitSuccess] = useState(false);
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
if (errors[name as keyof FooterFormErrors]) {
|
||||
setErrors((prev) => ({
|
||||
...prev,
|
||||
[name]: undefined,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
const tempErrors: FooterFormErrors = {};
|
||||
let isValid = true;
|
||||
|
||||
if (!formData.name.trim()) {
|
||||
tempErrors.name = "Name is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!formData.phone.trim()) {
|
||||
tempErrors.phone = "Phone is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!formData.email.trim()) {
|
||||
tempErrors.email = "Email is required";
|
||||
isValid = false;
|
||||
} else if (!emailRegex.test(formData.email)) {
|
||||
tempErrors.email = "Please enter a valid email address";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!formData.message.trim()) {
|
||||
tempErrors.message = "Message is required";
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
setErrors(tempErrors);
|
||||
return isValid;
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!validateForm()) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
// Simulate API delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
setIsSubmitting(false);
|
||||
setSubmitSuccess(true);
|
||||
setFormData({ name: "", phone: "", email: "", message: "" });
|
||||
|
||||
// Hide success alert after 5 seconds
|
||||
setTimeout(() => {
|
||||
setSubmitSuccess(false);
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const brandCol = (
|
||||
<div className="footer-brand min-w-0 self-start">
|
||||
<Link href="/" className="mb-4 inline-block">
|
||||
<Image
|
||||
src="/logo-v2.png"
|
||||
alt="Nearle"
|
||||
width={220}
|
||||
height={36}
|
||||
style={{ width: "210px", height: "auto" }}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<p className="footer-desc mb-4 text-white/80">
|
||||
India's leading hyperlocal neighborhood network, empowering
|
||||
communities and verified local businesses within 2km.
|
||||
</p>
|
||||
|
||||
{/* Social Links */}
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="footer-social-link" aria-label="Share">
|
||||
<MaterialIcon icon="share" size={24} />
|
||||
</a>
|
||||
<a href="#" className="footer-social-link" aria-label="Website">
|
||||
<MaterialIcon icon="public" size={24} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<footer className="bg-[#E6D7EA] px-3 sm:px-4 md:px-5 lg:px-6 xl:px-8 pb-0 w-full mt-3 md:mt-4">
|
||||
<div className="mx-auto" style={{ maxWidth: "min(100% - 48px, 1520px)" }}>
|
||||
<div className="bg-[#120217] rounded-[1.5rem] md:rounded-[2rem] lg:rounded-[2.5rem] overflow-hidden border border-white/10 shadow-[0_18px_45px_rgba(20,0,30,0.28)]">
|
||||
{/* Top Helpdesk Bar */}
|
||||
<div className="bg-[#2A0838] border-b border-white/10 px-5 py-4 md:px-8 md:py-5 flex flex-col md:flex-row justify-between items-center gap-6">
|
||||
<div className="flex items-center gap-4 text-white">
|
||||
<div className="w-12 h-12 rounded-full bg-brand-accent text-brand-dark flex items-center justify-center shadow-lg shrink-0">
|
||||
<MaterialIcon icon="headset_mic" size={24} />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<h4 className="text-headline-md font-black text-white">
|
||||
24/7 Neighborhood Helpdesk
|
||||
</h4>
|
||||
<p className="text-sm font-semibold text-white/70 mt-0.5">
|
||||
Need immediate assistance with an order or local service?
|
||||
</p>
|
||||
<footer className="bg-[#E6D7EA] px-3 sm:px-4 md:px-6 lg:px-8 xl:px-10 2xl:px-12 pb-6 md:pb-8 lg:pb-10 w-full mt-4">
|
||||
<div className="mx-auto w-full max-w-[1920px]">
|
||||
<div className="section-card-dark p-8 md:p-12 lg:p-14 text-white relative">
|
||||
{/* Background ambient glowing details */}
|
||||
<div className="absolute right-[-10%] top-[-10%] w-[50%] h-[50%] rounded-full bg-brand-accent/5 blur-[120px] pointer-events-none" />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-10 lg:gap-12 relative z-10 items-start text-left">
|
||||
{/* Col 1: Brand info */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<Link href="/" className="inline-block">
|
||||
<Image
|
||||
src="/logo-light.png"
|
||||
alt="Nearle"
|
||||
width={220}
|
||||
height={36}
|
||||
style={{ width: "160px", height: "auto" }}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<p className="text-sm leading-relaxed text-white/70">
|
||||
India's leading hyperlocal neighborhood network, empowering
|
||||
communities and verified local businesses within 2km.
|
||||
</p>
|
||||
{/* Social Links */}
|
||||
<div className="flex gap-3 mt-2">
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-[#E6D7EA] hover:text-[#17001F] transition-all duration-300" aria-label="Share">
|
||||
<MaterialIcon icon="share" size={20} />
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-[#E6D7EA] hover:text-[#17001F] transition-all duration-300" aria-label="Website">
|
||||
<MaterialIcon icon="public" size={20} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Col 2: Company Links */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Company</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{COMPANY.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 3: Partnerships */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Partnerships</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{PARTNERSHIPS.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 4: Support / Legal */}
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-6">Support & Legal</h5>
|
||||
<ul className="flex flex-col gap-3">
|
||||
{LEGAL.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="text-sm text-white/70 hover:text-[#E6D7EA] hover:translate-x-1 transition-all inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 5: HQ Address & Helpdesk */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h5 className="text-sm font-bold uppercase tracking-wider text-white/50 mb-4">Visit Nearle HQ</h5>
|
||||
<p className="text-xs leading-relaxed text-white/60">
|
||||
424, Diwan Bahadur Rd,<br />
|
||||
Opposite to Sri Krishna Sweets,<br />
|
||||
R.S. Puram, Coimbatore,<br />
|
||||
Tamil Nadu 641002
|
||||
</p>
|
||||
<a
|
||||
href="https://maps.google.com/?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-3 inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-xl border border-white/10 hover:border-[#E6D7EA]/50 text-white/80 hover:text-[#E6D7EA] text-xs font-bold transition-all duration-300"
|
||||
>
|
||||
<MaterialIcon icon="location_on" size={14} />
|
||||
<span>Get Directions</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-white/10 pt-4 flex flex-col gap-2">
|
||||
<p className="text-[10px] font-bold text-white/40 uppercase tracking-widest">Neighborhood Helpdesk</p>
|
||||
<a
|
||||
href="tel:+918049123456"
|
||||
className="flex items-center gap-2 text-white hover:text-[#E6D7EA] transition-all"
|
||||
>
|
||||
<MaterialIcon icon="phone" size={16} className="text-[#E6D7EA] shrink-0" />
|
||||
<span className="text-sm font-black tracking-tight">+91 80 4912 3456</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="tel:+918049123456"
|
||||
className="flex items-center gap-3 bg-brand-accent hover:bg-brand-accent-light text-brand-dark font-black px-6 py-3 rounded-full text-base shadow-lg transition-all duration-300 hover:-translate-y-0.5 shrink-0"
|
||||
>
|
||||
<MaterialIcon
|
||||
icon="phone"
|
||||
size={20}
|
||||
className="animate-pulse-subtle"
|
||||
/>
|
||||
<span>+91 80 4912 3456</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Main Footer Content */}
|
||||
<div className="px-5 pt-10 pb-8 md:px-8 md:pt-12 md:pb-10 lg:px-12 lg:pt-12 lg:pb-10 text-white">
|
||||
<div
|
||||
className={
|
||||
isContactPage
|
||||
? "grid grid-cols-1 sm:grid-cols-3 gap-8 lg:gap-10"
|
||||
: "grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(500px,560px)] gap-10 xl:gap-14 items-start"
|
||||
}
|
||||
>
|
||||
{isContactPage ? (
|
||||
<>
|
||||
{/* Brand Column */}
|
||||
{brandCol}
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="footer-company min-w-0 self-start">
|
||||
<FooterCol title="Company" links={COMPANY} />
|
||||
</div>
|
||||
|
||||
{/* Partnerships Links */}
|
||||
<div className="footer-partnerships min-w-0 self-start">
|
||||
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col self-start w-full">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-8 lg:gap-10">
|
||||
{/* Brand Column */}
|
||||
{brandCol}
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="footer-company min-w-0 self-start">
|
||||
<FooterCol title="Company" links={COMPANY} />
|
||||
</div>
|
||||
|
||||
{/* Partnerships Links */}
|
||||
<div className="footer-partnerships min-w-0 self-start">
|
||||
<FooterCol title="Partnerships" links={PARTNERSHIPS} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* HQ Office Location & Directions block */}
|
||||
<div className="mt-8 border-t border-white/10 pt-7 max-w-[520px] text-left">
|
||||
<p className="text-[11px] font-black uppercase tracking-[0.18em] text-brand-accent">
|
||||
VISIT NEARLE HQ
|
||||
</p>
|
||||
|
||||
<h4 className="mt-2 font-display text-xl md:text-2xl font-black text-white">
|
||||
Meet the team behind your neighbourhood.
|
||||
</h4>
|
||||
|
||||
<p className="mt-3 text-sm leading-6 text-white/60">
|
||||
424, Diwan Bahadur Rd,
|
||||
<br />
|
||||
Opposite to Sri Krishna Sweets,
|
||||
<br />
|
||||
R.S. Puram, Coimbatore,
|
||||
<br />
|
||||
Tamil Nadu 641002
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="https://maps.google.com/?q=424,+Diwan+Bahadur+Rd,+Opposite+To+Sri+Krishna+Sweets,+R.S.+Puram,+Coimbatore,+Tamil+Nadu+641002"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-4 inline-flex items-center gap-2 px-4 py-2 rounded-xl border border-white/15 hover:border-brand-accent/50 text-white hover:text-brand-accent text-xs md:text-sm font-black transition-all duration-300"
|
||||
>
|
||||
<MaterialIcon icon="location_on" size={16} />
|
||||
<span>Get Directions</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contact Form Card */}
|
||||
<div className="footer-contact-wrap w-full self-start">
|
||||
<div className="footer-contact-card bg-white text-brand-dark shadow-2xl border border-outline-variant/15 relative overflow-hidden w-full max-w-[540px] lg:ml-auto p-7 md:p-8 lg:p-9">
|
||||
{/* Background Glow Decors */}
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-primary/5 rounded-full blur-2xl" />
|
||||
<div className="absolute bottom-0 left-0 w-24 h-24 bg-secondary/5 rounded-full blur-2xl" />
|
||||
|
||||
<div className="relative z-10 text-center lg:text-left">
|
||||
<h3 className="footer-contact-title font-display text-2xl md:text-3xl font-black text-brand-dark tracking-tight">
|
||||
Send us a Message
|
||||
</h3>
|
||||
<p className="footer-contact-subtitle text-sm md:text-base mt-1 mb-5">
|
||||
We shall guide you through our Neighbourhood Experts.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-3">
|
||||
{submitSuccess && (
|
||||
<div className="p-3 bg-secondary/10 border border-secondary/20 text-secondary text-body-sm font-bold rounded-xl flex items-center justify-center gap-1.5 animate-bounce-subtle">
|
||||
<MaterialIcon icon="check_circle" size={16} />
|
||||
<span>Message sent successfully!</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="footer-form-row grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-name"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="footer-field-name"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Name..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.name ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.name && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-phone"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Phone
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="footer-field-phone"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Phone..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.phone ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.phone && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.phone}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-email"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="footer-field-email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Email Address..."
|
||||
className={`footer-input h-12 md:h-13 ${errors.email ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.email && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col text-left">
|
||||
<label
|
||||
htmlFor="footer-field-message"
|
||||
className="text-xs font-black text-brand-dark/70 mb-1.5"
|
||||
>
|
||||
Your Message
|
||||
</label>
|
||||
<textarea
|
||||
id="footer-field-message"
|
||||
name="message"
|
||||
value={formData.message}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Your Message..."
|
||||
className={`footer-textarea min-h-[120px] md:min-h-[130px] ${errors.message ? "has-error" : ""}`}
|
||||
/>
|
||||
{errors.message && (
|
||||
<span className="footer-error-text">
|
||||
<MaterialIcon icon="error" size={16} />
|
||||
{errors.message}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="footer-submit-btn h-12 md:h-13"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<span className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||
<span>SUBMITTING...</span>
|
||||
</>
|
||||
) : (
|
||||
<span>SUBMIT</span>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer Bottom Bar */}
|
||||
<div className="mt-8 border-t border-white/10 pt-5 text-xs text-white/45">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
||||
<p>© {new Date().getFullYear()} Nearle. All rights reserved.</p>
|
||||
<div className="flex flex-col md:flex-row gap-2 md:gap-6 text-left">
|
||||
{LEGAL.map((link) => (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className="hover:text-[#e0c8f7] transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* Bottom Copyright Divider & Bar */}
|
||||
<div className="mt-12 pt-6 border-t border-white/10 relative z-10 flex flex-col sm:flex-row justify-between items-center gap-4 text-xs text-white/40">
|
||||
<p>© {new Date().getFullYear()} Nearle. All rights reserved.</p>
|
||||
<div className="flex flex-wrap gap-x-6 gap-y-2 justify-center">
|
||||
{LEGAL.map((link) => (
|
||||
<Link
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
className="hover:text-[#E6D7EA] transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -421,28 +159,4 @@ export function Footer() {
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure default export is also available for Next.js app router client components if needed
|
||||
export default Footer;
|
||||
|
||||
function FooterCol({
|
||||
title,
|
||||
links,
|
||||
}: {
|
||||
title: string;
|
||||
links: { label: string; href: string }[];
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<h5 className="footer-column-title">{title}</h5>
|
||||
<ul className="footer-links-list">
|
||||
{links.map((l) => (
|
||||
<li key={l.label}>
|
||||
<Link href={l.href} className="footer-link inline-block">
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user