399 lines
9.9 KiB
TypeScript
399 lines
9.9 KiB
TypeScript
"use client";
|
|
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { ArrowRight, Plus } from "lucide-react";
|
|
import { Fragment, useState } from "react";
|
|
import { Controller, useForm } from "react-hook-form";
|
|
import z from "zod";
|
|
|
|
import {
|
|
Accordion,
|
|
AccordionContent,
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
} from "@/components/ui/accordion";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Field,
|
|
FieldDescription,
|
|
FieldError,
|
|
FieldTitle,
|
|
} from "@/components/ui/field";
|
|
import {
|
|
InputGroup,
|
|
InputGroupAddon,
|
|
InputGroupButton,
|
|
InputGroupInput,
|
|
} from "@/components/ui/input-group";
|
|
import { useMediaQuery } from "@/hooks/useMediaQuery";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
type NewsletterData = {
|
|
title?: string;
|
|
description?: string;
|
|
};
|
|
|
|
type NewsletterFormProps = NewsletterData;
|
|
|
|
type FooterLink = {
|
|
text: string;
|
|
type?: string;
|
|
link?: string;
|
|
email?: string;
|
|
};
|
|
|
|
type FooterLinksSection = {
|
|
title: string;
|
|
id: string;
|
|
items: FooterLink[];
|
|
};
|
|
|
|
type SocialIcon = {
|
|
title: string;
|
|
light: string;
|
|
dark: string;
|
|
};
|
|
|
|
type SocialLink = {
|
|
link: string;
|
|
icon: SocialIcon;
|
|
};
|
|
|
|
interface EcommerceFooter2Props {
|
|
newsletter: NewsletterData;
|
|
footerLinks: FooterLinksSection[];
|
|
socialLinks: SocialLink[];
|
|
description: string;
|
|
className?: string;
|
|
}
|
|
|
|
interface FooterLinksSectionProps {
|
|
sections: FooterLinksSection[];
|
|
}
|
|
|
|
interface SocialMediaSectionProps {
|
|
links: SocialLink[];
|
|
}
|
|
|
|
const NEWSLETTER_DATA = {
|
|
title: "عضویت در خبرنامه و ۱۰٪ تخفیف برای اولین خرید",
|
|
description:
|
|
"در خبرنامه ما عضو شوید و از پیشنهادهای ویژه، نکات فنی، معرفی محصولات جدید و دسترسی زودهنگام به جدیدترین لوازم الکترونیکی باخبر شوید.",
|
|
};
|
|
|
|
const FOOTER_LINKS: FooterLinksSection[] = [
|
|
{
|
|
title: "برند",
|
|
id: "the-brand",
|
|
items: [
|
|
{
|
|
text: "درباره ما",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "پایداری",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "نظرات مشتریان",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "یافتن فروشگاه",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "معرفی به دوستان",
|
|
link: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "راهنما",
|
|
id: "help",
|
|
items: [
|
|
{
|
|
text: "تماس با ما",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "سؤالات متداول",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "ارسال و پیگیری",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "مرجوعی و تعویض",
|
|
link: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "اطلاعات",
|
|
id: "information",
|
|
items: [
|
|
{
|
|
text: "شرایط و ضوابط",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "حریم خصوصی",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "سیاست ضمانت",
|
|
link: "#",
|
|
},
|
|
{
|
|
text: "شرایط استفاده",
|
|
link: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "تماس",
|
|
id: "contact",
|
|
items: [
|
|
{
|
|
type: "email",
|
|
text: "support@techstore.com",
|
|
email: "support@techstore.com",
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const SOCIAL_ICONS = {
|
|
facebook: {
|
|
title: "Facebook",
|
|
light:
|
|
"/block-media/shadcnblocks/block/logos/facebook-icon.svg",
|
|
dark: "/block-media/shadcnblocks/block/logos/facebook-icon.svg",
|
|
},
|
|
x: {
|
|
title: "X",
|
|
light:
|
|
"/block-media/shadcnblocks/block/logos/x.svg",
|
|
dark: "/block-media/shadcnblocks/block/logos/x.svg",
|
|
},
|
|
instagram: {
|
|
title: "Instagram",
|
|
light:
|
|
"/block-media/shadcnblocks/block/logos/instagram-icon.svg",
|
|
dark: "/block-media/shadcnblocks/block/logos/instagram-icon.svg",
|
|
},
|
|
};
|
|
|
|
const SOCIAL_MEDIA_LINKS = [
|
|
{
|
|
icon: SOCIAL_ICONS.facebook,
|
|
link: "#",
|
|
},
|
|
{
|
|
icon: SOCIAL_ICONS.x,
|
|
link: "#",
|
|
},
|
|
{
|
|
icon: SOCIAL_ICONS.instagram,
|
|
link: "#",
|
|
},
|
|
];
|
|
|
|
const DESCRIPTION =
|
|
"جدیدترین اخبار فناوری، تخفیفهای ویژه، معرفی محصولات و نکات تخصصی را مستقیم در ایمیل خود دریافت کنید. همیشه یک قدم جلوتر از بقیه باشید.";
|
|
|
|
const EcommerceFooter2 = ({
|
|
newsletter = NEWSLETTER_DATA,
|
|
footerLinks = FOOTER_LINKS,
|
|
socialLinks = SOCIAL_MEDIA_LINKS,
|
|
description = DESCRIPTION,
|
|
className,
|
|
}: EcommerceFooter2Props) => {
|
|
return (
|
|
<footer
|
|
dir="rtl"
|
|
lang="fa"
|
|
className={cn("px-0 py-10 md:px-7.5 md:py-12 lg:px-20", className)}
|
|
>
|
|
<div className="container">
|
|
<div className="grid grid-cols-1 gap-12.5 lg:grid-cols-2 xl:grid-cols-3">
|
|
<div>
|
|
<NewsletterSection {...newsletter} />
|
|
</div>
|
|
<div>
|
|
<FooterLinksSection sections={footerLinks} />
|
|
</div>
|
|
<div className="space-y-10">
|
|
<p className="leading-normal font-light max-lg:text-center">
|
|
{description}
|
|
</p>
|
|
<SocialMediaSection links={socialLinks} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
);
|
|
};
|
|
|
|
const newsletterFormSchema = z.object({
|
|
email: z
|
|
.string()
|
|
.min(1, "ایمیل الزامی است")
|
|
.email("آدرس ایمیل نامعتبر است"),
|
|
});
|
|
|
|
type newsletterFormType = z.infer<typeof newsletterFormSchema>;
|
|
|
|
const NewsletterSection = ({ title, description }: NewsletterFormProps) => {
|
|
const form = useForm({
|
|
resolver: zodResolver(newsletterFormSchema),
|
|
defaultValues: {
|
|
email: "",
|
|
},
|
|
});
|
|
|
|
const onSubmit = (data: newsletterFormType) => {
|
|
console.log(data);
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
<Controller
|
|
name="email"
|
|
control={form.control}
|
|
render={({ field, fieldState }) => (
|
|
<Field data-invalid={fieldState.invalid}>
|
|
<div className="space-y-5">
|
|
<div className="space-y-4">
|
|
<FieldTitle className="text-lg leading-none font-bold">
|
|
{title}
|
|
</FieldTitle>
|
|
<FieldDescription className="text-sm leading-normal font-light">
|
|
{description}
|
|
</FieldDescription>
|
|
</div>
|
|
<InputGroup
|
|
aria-invalid={fieldState.invalid}
|
|
className="rounded-full"
|
|
>
|
|
<InputGroupInput
|
|
{...field}
|
|
aria-invalid={fieldState.invalid}
|
|
placeholder="آدرس ایمیل"
|
|
/>
|
|
<InputGroupAddon align="inline-end">
|
|
<InputGroupButton
|
|
type="submit"
|
|
size="icon-xs"
|
|
variant="default"
|
|
className="rounded-full"
|
|
>
|
|
<ArrowRight className="rtl:rotate-180" />
|
|
</InputGroupButton>
|
|
</InputGroupAddon>
|
|
</InputGroup>
|
|
</div>
|
|
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
|
|
</Field>
|
|
)}
|
|
/>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
const FooterLinksSection = ({ sections }: FooterLinksSectionProps) => {
|
|
const isDesktop = useMediaQuery("(min-width: 1024px)");
|
|
const [value, setValue] = useState("");
|
|
|
|
if (!sections) return;
|
|
|
|
const allAccordionIds = sections.map(({ id }) => id);
|
|
const handleOnValueChange = (value: string) => {
|
|
setValue(value);
|
|
};
|
|
|
|
if (isDesktop) {
|
|
return (
|
|
<Accordion
|
|
value={allAccordionIds}
|
|
type="multiple"
|
|
className="lg:grid lg:grid-cols-2 lg:gap-x-17 lg:gap-y-4"
|
|
>
|
|
<AccordionItems sections={sections} />
|
|
</Accordion>
|
|
);
|
|
} else {
|
|
return (
|
|
<Accordion
|
|
value={value}
|
|
type="single"
|
|
collapsible={true}
|
|
onValueChange={handleOnValueChange}
|
|
className="lg:grid lg:grid-cols-2 lg:gap-x-17 lg:gap-y-4"
|
|
>
|
|
<AccordionItems sections={sections} />
|
|
</Accordion>
|
|
);
|
|
}
|
|
};
|
|
|
|
const AccordionItems = ({ sections }: { sections: FooterLinksSection[] }) => {
|
|
return (
|
|
<Fragment>
|
|
{sections.map(({ id, title, items }) => (
|
|
<AccordionItem key={id} value={id} className="border-none">
|
|
<AccordionTrigger className="cursor-auto rounded-none pt-0 text-lg leading-none font-bold hover:no-underline max-lg:border-b max-lg:py-4 [&>svg]:hidden">
|
|
{title}
|
|
<div className="lg:hidden">
|
|
<Plus className="size-5" />
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="pb-0 max-lg:py-4 max-lg:ps-4">
|
|
<ul className="space-y-4 lg:space-y-2">
|
|
{items.map(({ link, text, type, email }) => (
|
|
<li
|
|
className="text-sm leading-tight font-light"
|
|
key={crypto.randomUUID()}
|
|
>
|
|
{type === "email" && <p className="mb-1.5">ایمیل ما:</p>}
|
|
<a
|
|
data-type={type}
|
|
href={type === "email" ? `mailto:${email}` : link}
|
|
className="data-[type=email]:underline data-[type=email]:underline-offset-2"
|
|
>
|
|
{text}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
))}
|
|
</Fragment>
|
|
);
|
|
};
|
|
|
|
const SocialMediaSection = ({ links }: SocialMediaSectionProps) => {
|
|
return (
|
|
<ul className="flex flex-wrap gap-4 max-lg:justify-center">
|
|
{links.map(({ icon, link }) => (
|
|
<li key={crypto.randomUUID()}>
|
|
<Button size="icon-lg" asChild className="rounded-full">
|
|
<a href={link}>
|
|
<img
|
|
className="size-5 invert dark:invert-0"
|
|
alt={icon.title}
|
|
src={icon.light}
|
|
/>
|
|
</a>
|
|
</Button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
);
|
|
};
|
|
|
|
export { EcommerceFooter2 };
|