287 lines
13 KiB
TypeScript
287 lines
13 KiB
TypeScript
'use client';
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import Link from 'next/link';
|
|
import {
|
|
storefrontService,
|
|
FooterInfo,
|
|
MOCK_FOOTER_INFO,
|
|
} from '@/services/api/storefrontService';
|
|
import { PaymentMethodBadges } from '@/components/PaymentMethodBadges';
|
|
|
|
function SocialIcon({ name }: { name?: string }) {
|
|
const key = (name || '').toLowerCase();
|
|
const className = 'w-5 h-5 fill-current';
|
|
|
|
if (key.includes('facebook')) {
|
|
return (
|
|
<svg className={className} viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('twitter') || key === 'x') {
|
|
return (
|
|
<svg className="w-4.5 h-4.5 fill-current" viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('instagram')) {
|
|
return (
|
|
<svg className={className} viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('tiktok')) {
|
|
return (
|
|
<svg className="w-4.5 h-4.5 fill-current" viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.17-2.86-.74-3.99-1.72-.08-.07-.17-.17-.24-.25v5.13c-.02 3.42-1.92 6.78-5.26 7.82-3.34 1.04-7.25-.33-8.81-3.41-1.57-3.07-.48-7.3 2.5-8.88 1.4-.74 3.01-.93 4.55-.58v4.01c-.88-.23-1.84-.13-2.63.34-.8.47-1.34 1.34-1.37 2.27-.02 1.32.96 2.55 2.27 2.76 1.3.2 2.6-.62 2.97-1.87.12-.41.15-.85.15-1.28V.02z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('pinterest')) {
|
|
return (
|
|
<svg className="w-4.5 h-4.5 fill-current" viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M12 0c-6.627 0-12 5.372-12 12 0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.993 3.994-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345-.091.377-.294 1.197-.333 1.36-.053.218-.173.264-.399.158-1.492-.695-2.424-2.876-2.424-4.629 0-3.769 2.739-7.229 7.892-7.229 4.144 0 7.365 2.953 7.365 6.899 0 4.117-2.595 7.431-6.199 7.431-1.21 0-2.348-.628-2.738-1.373 0 0-.599 2.282-.744 2.84-.282 1.084-1.047 2.443-1.558 3.272 1.124.348 2.316.537 3.551.537 6.628 0 12-5.373 12-12 0-6.628-5.372-12-12-12z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('youtube')) {
|
|
return (
|
|
<svg className={className} viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186 31.59 31.59 0 0 0 0 12a31.59 31.59 0 0 0 .502 5.814 3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136A31.59 31.59 0 0 0 24 12a31.59 31.59 0 0 0-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
|
|
</svg>
|
|
);
|
|
}
|
|
if (key.includes('linkedin')) {
|
|
return (
|
|
<svg className={className} viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M4.98 3.5C4.98 4.88 3.88 6 2.5 6S0 4.88 0 3.5 1.12 1 2.5 1s2.48 1.12 2.48 2.5zM.5 8.5h4V24h-4V8.5zM8.5 8.5h3.8v2.1h.05c.53-1 1.83-2.1 3.77-2.1 4.03 0 4.78 2.65 4.78 6.1V24h-4v-7.7c0-1.84-.03-4.2-2.56-4.2-2.56 0-2.95 2-2.95 4.06V24h-4V8.5z" />
|
|
</svg>
|
|
);
|
|
}
|
|
return (
|
|
<svg className={className} viewBox="0 0 24 24" aria-hidden>
|
|
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function FooterLink({ href, label }: { href: string; label: string }) {
|
|
const to = href?.trim() || '#';
|
|
const className =
|
|
'hover:text-[#0073EC] transition-colors';
|
|
const isExternal = /^https?:\/\//i.test(to);
|
|
if (isExternal) {
|
|
return (
|
|
<a href={to} target="_blank" rel="noopener noreferrer" className={className}>
|
|
{label}
|
|
</a>
|
|
);
|
|
}
|
|
return (
|
|
<Link href={to.startsWith('/') || to === '#' ? to : `/${to}`} className={className}>
|
|
{label}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
function isFeedbackFooterLink(label?: string, href?: string): boolean {
|
|
const text = String(label || '').toLowerCase();
|
|
const path = String(href || '').split('?')[0];
|
|
return text.includes('feedback') || /^\/feedback\/?$/i.test(path);
|
|
}
|
|
|
|
function isHelpCenterFooterLink(label?: string, href?: string): boolean {
|
|
const text = String(label || '').toLowerCase();
|
|
const path = String(href || '').split('?')[0];
|
|
return text.includes('help') || /^\/help\/?$/i.test(path);
|
|
}
|
|
|
|
function isPaymentsFooterLink(label?: string, href?: string): boolean {
|
|
const text = String(label || '').toLowerCase();
|
|
const path = String(href || '').split('?')[0];
|
|
return text.includes('payment') || /^\/payments\/?$/i.test(path);
|
|
}
|
|
|
|
function isReturnsFooterLink(label?: string, href?: string): boolean {
|
|
const text = String(label || '').toLowerCase();
|
|
const path = String(href || '').split('?')[0];
|
|
return text.includes('return') || /^\/returns?\/?$/i.test(path);
|
|
}
|
|
|
|
type FooterColumn = { title?: string; links?: { label: string; href: string }[] };
|
|
|
|
function withRequiredFooterLinks(columns: FooterColumn[]): FooterColumn[] {
|
|
let hasInformation = false;
|
|
let hasOrders = false;
|
|
|
|
const next = columns.map((col) => {
|
|
const title = String(col.title || '');
|
|
let links = [...(col.links || [])];
|
|
|
|
if (/information/i.test(title)) {
|
|
hasInformation = true;
|
|
links = links.map((l) => {
|
|
if (isHelpCenterFooterLink(l.label, l.href)) return { ...l, href: '/help' };
|
|
if (isFeedbackFooterLink(l.label, l.href)) return { ...l, href: '/feedback' };
|
|
return l;
|
|
});
|
|
if (!links.some((l) => isHelpCenterFooterLink(l.label, l.href))) {
|
|
links.unshift({ label: 'Help Center', href: '/help' });
|
|
}
|
|
if (!links.some((l) => isFeedbackFooterLink(l.label, l.href))) {
|
|
links.push({ label: 'Feedback', href: '/feedback' });
|
|
}
|
|
if (!links.some((l) => isPaymentsFooterLink(l.label, l.href))) {
|
|
links.push({ label: 'Payments', href: '/payments' });
|
|
}
|
|
}
|
|
|
|
if (/order/i.test(title) || /return/i.test(title)) {
|
|
hasOrders = true;
|
|
links = links.map((l) =>
|
|
isReturnsFooterLink(l.label, l.href) ? { ...l, href: '/returns' } : l
|
|
);
|
|
if (!links.some((l) => isReturnsFooterLink(l.label, l.href))) {
|
|
links.push({ label: 'Returns', href: '/returns' });
|
|
}
|
|
}
|
|
|
|
return { ...col, links };
|
|
});
|
|
|
|
if (!hasInformation) {
|
|
next.push({
|
|
title: 'Information',
|
|
links: [
|
|
{ label: 'Help Center', href: '/help' },
|
|
{ label: 'Feedback', href: '/feedback' },
|
|
{ label: 'Payments', href: '/payments' },
|
|
],
|
|
});
|
|
}
|
|
if (!hasOrders) {
|
|
next.push({ title: 'Orders & Returns', links: [{ label: 'Returns', href: '/returns' }] });
|
|
}
|
|
return next;
|
|
}
|
|
|
|
export const Footer: React.FC = () => {
|
|
const [info, setInfo] = useState<FooterInfo>(MOCK_FOOTER_INFO);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
storefrontService.getFooterInfo().then((data) => {
|
|
if (!cancelled && data) setInfo(data);
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, []);
|
|
|
|
const columns = withRequiredFooterLinks(
|
|
info.columns && info.columns.length > 0
|
|
? info.columns.filter((c) => c?.title || (c.links || []).length > 0)
|
|
: [
|
|
{ title: 'Get to know Us', links: info.get_to_know_us || [] },
|
|
{ title: 'Information', links: info.information || [] },
|
|
{ title: 'Orders & Returns', links: info.orders_returns || [] },
|
|
{ title: 'Our Store', links: info.our_store || [] },
|
|
].filter((c) => c.links.length > 0)
|
|
);
|
|
|
|
const socials = (info.social_links || []).filter((s) => s?.url);
|
|
const payments = (info.payment_methods || []).filter((p) => p?.name || p?.icon_url);
|
|
|
|
return (
|
|
<footer className="bg-white border-t border-gray-200 font-sans">
|
|
<div className="py-16 bg-[#F8F9FB] border-b border-gray-150">
|
|
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[1400px]">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-8">
|
|
<div className="flex flex-col gap-4 text-left">
|
|
<h4 className="text-[12.5px] font-bold text-[#1E293B] tracking-[0.05em] uppercase font-sans">
|
|
Contact Us
|
|
</h4>
|
|
|
|
{info.phone ? (
|
|
<a
|
|
href={`tel:${info.phone.replace(/[^\d+]/g, '')}`}
|
|
className="text-[17px] font-bold text-gray-900 font-sans tracking-tight leading-tight hover:text-[#0073EC] transition-colors"
|
|
>
|
|
{info.phone}
|
|
</a>
|
|
) : null}
|
|
|
|
{info.address ? (
|
|
<p className="text-[13px] text-gray-500 font-semibold font-sans leading-relaxed max-w-[220px]">
|
|
{info.address}
|
|
</p>
|
|
) : null}
|
|
|
|
{info.email ? (
|
|
<a
|
|
href={`mailto:${info.email}`}
|
|
className="text-[13px] text-gray-500 font-semibold underline hover:text-[#0073EC] transition-colors font-sans"
|
|
>
|
|
{info.email}
|
|
</a>
|
|
) : null}
|
|
|
|
{socials.length > 0 ? (
|
|
<div className="flex items-center gap-4 mt-4">
|
|
{socials.map((s, i) => (
|
|
<a
|
|
key={`${s.platform}-${i}`}
|
|
href={s.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-gray-600 hover:text-[#0073EC] transition-colors"
|
|
title={s.platform}
|
|
>
|
|
<SocialIcon name={s.icon || s.platform} />
|
|
</a>
|
|
))}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
|
|
{columns.map((col, ci) => (
|
|
<div key={`${col.title}-${ci}`} className="text-left">
|
|
{col.title ? (
|
|
<h4 className="text-[12.5px] font-bold text-[#1E293B] tracking-[0.05em] uppercase mb-5 font-sans">
|
|
{col.title}
|
|
</h4>
|
|
) : null}
|
|
<ul className="space-y-3.5 text-[13px] font-semibold text-gray-500 font-sans">
|
|
{(col.links || [])
|
|
.filter((item) => item?.label)
|
|
.map((item, li) => (
|
|
<li key={`${item.label}-${li}`}>
|
|
<FooterLink href={item.href} label={item.label} />
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="py-8 bg-[#F0F2F5]">
|
|
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[1400px] flex flex-col md:flex-row justify-between items-center gap-4">
|
|
<p className="text-[12.5px] text-gray-500 font-medium text-center md:text-left">
|
|
{info.copyright || '© 2026 iFixKart'}
|
|
</p>
|
|
|
|
<PaymentMethodBadges
|
|
methods={payments}
|
|
className="justify-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
);
|
|
};
|