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

402 lines
10 KiB
TypeScript

"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import type { LucideIcon } from "lucide-react";
import { Clock, MapPin, Phone } from "lucide-react";
import { Fragment } from "react";
import { Controller, useForm } from "react-hook-form";
import z from "zod";
import { Button } from "@/components/ui/button";
import { Field, FieldError } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
type NewsletterData = {
title?: string;
description?: string;
};
type NewsletterFormProps = NewsletterData;
type FooterLink = {
text: string;
link: string;
};
type FooterLinksSectionData = {
title: string;
items: FooterLink[];
};
interface FooterLinksSectionProps {
sections: FooterLinksSectionData[];
}
type SocialIcon = {
title: string;
src: string;
className?: string;
};
type SocialLink = {
link: string;
icon: SocialIcon;
};
type ContactLink = {
icon: LucideIcon;
text: string;
type: LinkTypes;
link?: string;
};
type ContactLinks = {
contactDetails: ContactLink[];
socialMedia: SocialLink[];
};
interface ContactSectionProps {
links: ContactLinks;
}
interface EcommerceFooter1Props {
newsletter: NewsletterData;
footerLinks: FooterLinksSectionData[];
contactLinks: ContactLinks;
className?: string;
}
const LINK_TYPES = {
NO_LINK: "NO_LINK",
PHONE_LINK: "PHONE_LINK",
EMAIL_LINK: "EMAIL_LINK",
};
type LinkTypes = keyof typeof LINK_TYPES;
const NEWSLETTER_DATA = {
title: "خبرنامه",
description:
"در خبرنامه ما عضو شوید و از پیشنهادهای ویژه، نکات فنی و معرفی محصولات جدید باخبر شوید.",
};
const FOOTER_LINKS: FooterLinksSectionData[] = [
{
title: "اطلاعات",
items: [
{
text: "شرایط و ضوابط",
link: "#",
},
{
text: "حریم خصوصی",
link: "#",
},
{
text: "سیاست ضمانت",
link: "#",
},
{
text: "شرایط استفاده",
link: "#",
},
],
},
{
title: "مجموعه‌ها",
items: [
{
text: "تازه‌ها",
link: "#",
},
{
text: "پرفروش‌ترین‌ها",
link: "#",
},
{
text: "پیشنهادهای فصلی",
link: "#",
},
{
text: "محصولات ضروری",
link: "#",
},
],
},
];
const SOCIAL_ICONS = {
facebook: {
title: "Facebook",
src: "/block-media/shadcnblocks/block/logos/facebook-icon.svg",
},
x: {
title: "X",
src: "/block-media/shadcnblocks/block/logos/x.svg",
className: "dark:invert",
},
instagram: {
title: "Instagram",
src: "/block-media/shadcnblocks/block/logos/instagram-icon.svg",
},
};
const CONTACT_LINKS: ContactLinks = {
contactDetails: [
{
icon: MapPin,
text: "support@store.com",
link: "support@store.com",
type: LINK_TYPES.EMAIL_LINK as LinkTypes,
},
{
icon: Phone,
text: "+12345678910",
link: "+12345678910",
type: LINK_TYPES.PHONE_LINK as LinkTypes,
},
{
icon: Clock,
text: "شنبه تا پنج‌شنبه، ۹ صبح تا ۹ شب",
type: LINK_TYPES.NO_LINK as LinkTypes,
},
],
socialMedia: [
{
icon: SOCIAL_ICONS.facebook,
link: "#",
},
{
icon: SOCIAL_ICONS.x,
link: "#",
},
{
icon: SOCIAL_ICONS.instagram,
link: "#",
},
],
};
const EcommerceFooter1 = ({
newsletter = NEWSLETTER_DATA,
footerLinks = FOOTER_LINKS,
contactLinks = CONTACT_LINKS,
className,
}: EcommerceFooter1Props) => {
return (
<section
dir="rtl"
lang="fa"
className={cn("pt-8 pb-8 xl:pt-12", className)}
>
<div className="container space-y-10">
<div className="grid grid-cols-1 gap-x-16 gap-y-8 md:grid-cols-2 xl:grid-cols-4">
<div>
<NewsletterSection {...newsletter} />
</div>
<FooterLinksSection sections={footerLinks} />
<ContactSection links={contactLinks} />
</div>
<div>
<div className="flex items-center justify-between gap-4 md:gap-12.5">
<Separator className="flex-1" />
<div className="basis-10 md:basis-10">
<a href="https://ShadcnBlocks">
<img
className="block size-10 dark:hidden"
src="/block-media/shadcnblocks/block/logos/ShadcnBlockscom-icon.svg"
alt="لوگو"
/>
<img
className="hidden size-10 dark:block"
src="/block-media/shadcnblocks/block/logos/ShadcnBlockscom-icon-white.svg"
alt="لوگو"
/>
</a>
</div>
<Separator className="flex-1" />
</div>
</div>
<div className="flex flex-wrap items-center justify-between gap-4">
<p className="text-muted-foreground max-md:text-xs">
© ۱۴۰۵ ری یو آی. تمامی حقوق محفوظ است.
</p>
<div className="flex flex-wrap items-center gap-4">
<div className="flex items-center gap-2">
<img
src="/block-media/shadcnblocks/block/ecommerce/payment-methods/visa.svg"
alt="Visa"
className="h-6"
/>
<img
src="/block-media/shadcnblocks/block/ecommerce/payment-methods/mastercard.svg"
alt="Mastercard"
className="h-6"
/>
<img
src="/block-media/shadcnblocks/block/ecommerce/payment-methods/amex.svg"
alt="کارت ویژه"
className="h-6"
/>
<img
src="/block-media/shadcnblocks/block/ecommerce/payment-methods/paypal.svg"
alt="PayPal"
className="h-6"
/>
</div>
<Select defaultValue="farsi">
<SelectTrigger className="h-8 w-24 text-xs">
<SelectValue placeholder="انتخاب زبان..." />
</SelectTrigger>
<SelectContent align="start">
<SelectGroup>
<SelectItem value="farsi">فارسی</SelectItem>
<SelectItem value="english">انگلیسی</SelectItem>
<SelectItem value="arabic">العربية</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
</div>
</section>
);
};
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 (
<div className="space-y-6">
<div className="space-y-4">
<h3 className="font-serif text-3xl leading-none font-medium">
{title}
</h3>
<p className="leading-normal font-light">{description}</p>
</div>
<form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
<Controller
name="email"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<Input
{...field}
aria-invalid={fieldState.invalid}
placeholder="آدرس ایمیل"
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Button className="w-full">عضویت</Button>
</form>
</div>
);
};
const FooterLinksSection = ({ sections }: FooterLinksSectionProps) => {
return (
<Fragment>
{sections.map(({ title, items }) => (
<div key={crypto.randomUUID()}>
<h2 className="mb-6 text-sm leading-tight font-medium text-muted-foreground uppercase">
{title}
</h2>
<ul className="space-y-3">
{items.map(({ text, link }) => (
<li key={crypto.randomUUID()}>
<a href={link} className="underline-offset-4 hover:underline">
{text}
</a>
</li>
))}
</ul>
</div>
))}
</Fragment>
);
};
const ContactSection = ({ links }: ContactSectionProps) => {
const { socialMedia, contactDetails } = links;
return (
<div>
<h2 className="mb-6 text-sm leading-tight font-medium text-muted-foreground uppercase">
تماس با ما
</h2>
<div className="space-y-6">
<ul className="space-y-3">
{contactDetails.map((item) => (
<li className="flex items-center gap-3" key={crypto.randomUUID()}>
<item.icon className="size-4 shrink-0 basis-4" />
<div className="flex-1">
{item.type === LINK_TYPES.NO_LINK ? (
<p>{item.text}</p>
) : (
<a
href={
item.type === LINK_TYPES.EMAIL_LINK
? `mailto:${item.link}`
: `tel:${item.link}`
}
className="underline-offset-4 hover:underline"
>
{item.text}
</a>
)}
</div>
</li>
))}
</ul>
<ul className="flex flex-wrap gap-3">
{socialMedia.map(({ icon, link }) => (
<li key={crypto.randomUUID()}>
<Button size="icon-lg" variant="outline" asChild>
<a href={link}>
<img
className={cn("size-5", icon.className)}
alt={icon.title}
src={icon.src}
/>
</a>
</Button>
</li>
))}
</ul>
</div>
</div>
);
};
export { EcommerceFooter1 };