230 lines
6.6 KiB
TypeScript
230 lines
6.6 KiB
TypeScript
import { getCookie, setCookie } from "cookies-next/client";
|
|
import { add } from "date-fns";
|
|
import { X } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { type MouseEvent, useEffect, useRef, useState } from "react";
|
|
import { IconMatrix, type IconType } from "~/components/IconComponents";
|
|
import { cn } from "~/lib/utils";
|
|
import type { Banners } from "~/schemas/public/Banners";
|
|
|
|
const defaultHideDuration = 365; // days
|
|
export const BannerFactory = (bannerData: Banners) => {
|
|
const NEW_BANNER_KEY = `bannercookie_${bannerData.idbanner}`;
|
|
|
|
let bgColor = "";
|
|
let accentColor = "";
|
|
let closeHoverColor = "";
|
|
|
|
switch (bannerData.color) {
|
|
case "blu":
|
|
bgColor = "bg-blue-600";
|
|
accentColor = "bg-blue-800";
|
|
closeHoverColor = "hover:bg-blue-500";
|
|
break;
|
|
case "rosso":
|
|
bgColor = "bg-red-600";
|
|
accentColor = "bg-red-800";
|
|
closeHoverColor = "hover:bg-red-500";
|
|
break;
|
|
case "verde":
|
|
bgColor = "bg-green-600";
|
|
accentColor = "bg-green-800";
|
|
closeHoverColor = "hover:bg-green-500";
|
|
break;
|
|
case "indaco":
|
|
bgColor = "bg-indigo-600";
|
|
accentColor = "bg-indigo-800";
|
|
closeHoverColor = "hover:bg-indigo-500";
|
|
break;
|
|
default:
|
|
bgColor = "bg-indigo-600";
|
|
accentColor = "bg-indigo-800";
|
|
closeHoverColor = "hover:bg-indigo-500";
|
|
break;
|
|
}
|
|
|
|
const NewBanner = () => {
|
|
const [isBannerToShow, setIsBannerToShow] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (bannerData.is_unskippable === false) {
|
|
const cookievalue = getCookie(NEW_BANNER_KEY) !== "true";
|
|
|
|
setIsBannerToShow(cookievalue);
|
|
}
|
|
}, []);
|
|
|
|
const onClick = (e: MouseEvent<HTMLButtonElement>) => {
|
|
e.preventDefault();
|
|
setCookie(NEW_BANNER_KEY, "true", {
|
|
expires: add(new Date(), {
|
|
days: bannerData.hide_duration || defaultHideDuration,
|
|
}),
|
|
});
|
|
setIsBannerToShow(false);
|
|
};
|
|
|
|
if (!isBannerToShow && bannerData.is_unskippable === false) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div className={cn("bg-indigo-600", bgColor)}>
|
|
<div className="mx-auto flex max-w-7xl items-start justify-between px-4 py-3 text-white sm:items-center md:px-8">
|
|
<div className="flex flex-1 items-start justify-center gap-x-4 sm:items-center">
|
|
<div
|
|
className={cn(
|
|
"flex flex-none items-center justify-center rounded-full bg-indigo-800 p-1.5 px-4 font-medium text-sm",
|
|
accentColor,
|
|
)}
|
|
>
|
|
{bannerData.titolo}{" "}
|
|
</div>
|
|
<p className="flex gap-2 p-2 font-medium">
|
|
<span> {bannerData.testo}</span>
|
|
|
|
{bannerData.has_cta &&
|
|
bannerData.cta_href &&
|
|
bannerData.cta_icon && (
|
|
<Link
|
|
className="inline-flex items-center gap-x-1 font-semibold underline duration-150 hover:text-indigo-100"
|
|
href={bannerData.cta_href}
|
|
>
|
|
{bannerData.cta_text}
|
|
<IconMatrix
|
|
className="size-4"
|
|
type={bannerData.cta_icon as IconType}
|
|
/>
|
|
</Link>
|
|
)}
|
|
</p>
|
|
</div>
|
|
{bannerData.is_unskippable === false && (
|
|
<button
|
|
className={cn(
|
|
"rounded-lg p-2 ring-offset-2 duration-150 hover:bg-indigo-500 focus:ring",
|
|
closeHoverColor,
|
|
)}
|
|
onClick={onClick}
|
|
type="button"
|
|
>
|
|
<X className="size-5" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
return <NewBanner />;
|
|
};
|
|
|
|
export function AnniversaryBanner() {
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
const bannerRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry?.isIntersecting) {
|
|
setIsVisible(true);
|
|
}
|
|
},
|
|
{ threshold: 0.3 },
|
|
);
|
|
|
|
if (bannerRef.current) {
|
|
observer.observe(bannerRef.current);
|
|
}
|
|
|
|
return () => observer.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className="relative mx-auto w-full max-w-5xl overflow-hidden rounded-lg bg-secondary"
|
|
ref={bannerRef}
|
|
>
|
|
{/* Decorative background "25" */}
|
|
<div
|
|
className={`absolute top-1/2 -right-8 -translate-y-1/2 font-bold text-[8rem] text-primary/20 leading-none transition-all duration-1000 md:text-[12rem] ${
|
|
isVisible ? "translate-x-0 opacity-100" : "translate-x-16 opacity-0"
|
|
}`}
|
|
>
|
|
25
|
|
</div>
|
|
|
|
{/* Main content - horizontal layout */}
|
|
<div className="relative mx-auto flex max-w-7xl flex-col items-center justify-between gap-6 px-6 py-6 text-primary md:flex-row md:gap-8 md:px-8 md:py-8">
|
|
{/* Left: Badge + Number */}
|
|
<div
|
|
className={`flex items-center gap-4 transition-all delay-100 duration-700 md:gap-6 ${
|
|
isVisible ? "translate-x-0 opacity-100" : "-translate-x-8 opacity-0"
|
|
}`}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<div className="h-px w-6 bg-primary" />
|
|
<span className="whitespace-nowrap font-medium text-[10px] uppercase tracking-[0.2em] md:text-xs">
|
|
Da più di
|
|
</span>
|
|
</div>
|
|
<div className="flex items-baseline gap-2">
|
|
<span className="font-bold text-5xl leading-none tracking-tight md:text-6xl lg:text-7xl">
|
|
25
|
|
</span>
|
|
<span className="font-light text-sm uppercase tracking-[0.2em] md:text-base">
|
|
Anni
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Center: Tagline */}
|
|
<div
|
|
className={`flex-1 text-center text-primary transition-all delay-300 duration-700 md:text-left ${
|
|
isVisible ? "translate-y-0 opacity-100" : "translate-y-4 opacity-0"
|
|
}`}
|
|
>
|
|
<p className="font-light text-sm md:text-base lg:text-lg">
|
|
Un quarto di secolo di{" "}
|
|
<span className="font-semibold">eccellenza</span>,{" "}
|
|
<span className="font-semibold">innovazione</span>, e{" "}
|
|
<span className="font-semibold">fiducia</span>
|
|
</p>
|
|
</div>
|
|
|
|
{/* Right: Mini stats */}
|
|
<div
|
|
className={`flex items-center gap-6 transition-all delay-500 duration-700 md:gap-8 lg:gap-10 ${
|
|
isVisible ? "translate-x-0 opacity-100" : "translate-x-8 opacity-0"
|
|
}`}
|
|
>
|
|
<Stat label="Clienti" value="12.5K+" />
|
|
<Stat label="Contratti" value="10K+" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Accent lines */}
|
|
{/* <div
|
|
className={`absolute bottom-0 left-0 h-1 bg-primary transition-all delay-700 duration-1000 ${
|
|
isVisible ? "w-24 md:w-32" : "w-0"
|
|
}`}
|
|
/> */}
|
|
{/* <div
|
|
className={`absolute top-0 right-0 h-1 bg-primary transition-all delay-700 duration-1000 ${
|
|
isVisible ? "w-24 md:w-32" : "w-0"
|
|
}`}
|
|
/> */}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Stat({ value, label }: { value: string; label: string }) {
|
|
return (
|
|
<div className="flex flex-col items-center gap-0.5">
|
|
<span className="font-bold text-primary text-xl md:text-2xl">
|
|
{value}
|
|
</span>
|
|
<span className="font-medium text-primary text-xs uppercase tracking-wider">
|
|
{label}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|