Files
reui-blocks/blocks/ecommerce-footer2.tsx
T

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 };