133 lines
5.4 KiB
TypeScript
133 lines
5.4 KiB
TypeScript
'use client';
|
|
|
|
import { dishImageUrl } from '@/lib/assets';
|
|
import type { CateringPackage } from '@/lib/catering-data';
|
|
import {
|
|
CATERING_CATEGORY_ORDER,
|
|
groupDishesByCategory,
|
|
} from '@/lib/catering-data';
|
|
import { buildCateringPackagePricingMessage } from '@/application/messaging/whatsapp-message-builder';
|
|
import { container } from '@/infrastructure/di/container';
|
|
import { getWhatsAppInquiryTranslation } from '@/application/messaging/inquiry-language';
|
|
import { useLanguage } from '@/lib/language-context';
|
|
import { getTranslation } from '@/lib/translations';
|
|
import { MessageCircle, Users, UtensilsCrossed } from 'lucide-react';
|
|
import { motion } from 'framer-motion';
|
|
|
|
interface CateringPackageCardProps {
|
|
pkg: CateringPackage;
|
|
index?: number;
|
|
}
|
|
|
|
export default function CateringPackageCard({ pkg, index = 0 }: CateringPackageCardProps) {
|
|
const { language } = useLanguage();
|
|
const t = getTranslation(language);
|
|
const grouped = groupDishesByCategory(pkg.includedDishes);
|
|
|
|
const packageName =
|
|
(t.catering.packages as Record<string, string>)?.[pkg.id] ?? pkg.name;
|
|
const packageDescription =
|
|
(t.catering.packageDescriptions as Record<string, string>)?.[pkg.id] ?? pkg.description;
|
|
|
|
const handlePricingInquiry = () => {
|
|
const inquiryT = getWhatsAppInquiryTranslation(language);
|
|
const template = (inquiryT.catering as { packagePricingInquiry?: string }).packagePricingInquiry;
|
|
if (!template) return;
|
|
const inquiryPackageName =
|
|
(inquiryT.catering.packages as Record<string, string>)?.[pkg.id] ?? pkg.name;
|
|
const message = buildCateringPackagePricingMessage(inquiryPackageName, template);
|
|
container.messagingGateway.openWhatsApp(message);
|
|
};
|
|
|
|
return (
|
|
<motion.article
|
|
initial={{ opacity: 0, y: 28 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: '-40px' }}
|
|
transition={{ duration: 0.55, delay: index * 0.08, ease: [0.25, 1, 0.5, 1] }}
|
|
className={`luxury-card flex h-full flex-col overflow-hidden rounded-[2rem] border bg-white transition-all duration-300 ${
|
|
pkg.highlight
|
|
? 'border-[#c99a2e]/50 shadow-lg shadow-[#c99a2e]/15 ring-1 ring-[#c99a2e]/25'
|
|
: 'border-[#EDE6D9] hover:border-[#c99a2e]/35'
|
|
}`}
|
|
>
|
|
{pkg.image && (
|
|
<div className="relative h-48 overflow-hidden bg-[#F2EDE4] sm:h-52">
|
|
<img
|
|
src={dishImageUrl(pkg.image)}
|
|
alt={packageName}
|
|
className="h-full w-full object-cover transition-transform duration-500 hover:scale-105"
|
|
loading="lazy"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-[#101724]/50 via-transparent to-transparent" />
|
|
{pkg.highlight && (
|
|
<span className="absolute top-4 left-4 rounded-full bg-gradient-to-r from-[#c99a2e] to-[#e8c56a] px-3 py-1 text-[10px] font-bold uppercase tracking-[0.2em] text-[#241806] shadow-md">
|
|
{t.catering.mostPopular}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-1 flex-col p-6 sm:p-7">
|
|
<div className="mb-4 flex items-start justify-between gap-4">
|
|
<div>
|
|
<h3 className="text-lg sm:text-[22px] leading-tight tracking-[-0.4px] text-[#101724] break-words">
|
|
{packageName}
|
|
</h3>
|
|
<p className="mt-2 text-sm leading-relaxed text-[#6B665F]">
|
|
{packageDescription}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={handlePricingInquiry}
|
|
className="mb-5 flex w-full items-center justify-center gap-2 rounded-2xl border border-[#c99a2e]/35 bg-[#fffdf8] px-4 py-3.5 text-base font-semibold tracking-[-0.2px] text-[#B38B4D] transition-all hover:border-[#c99a2e] hover:bg-[#fff6dc] hover:text-[#8C6B3A] active:scale-[0.98]"
|
|
>
|
|
<MessageCircle className="h-4 w-4 shrink-0" aria-hidden />
|
|
{t.catering.contactForPricing}
|
|
</button>
|
|
|
|
<div className="mb-2 flex items-center gap-2 text-xs font-bold uppercase tracking-[0.18em] text-[#8a6a25]">
|
|
<UtensilsCrossed className="h-3.5 w-3.5 text-[#c99a2e]" />
|
|
{t.catering.includedDishes}
|
|
</div>
|
|
|
|
<div className="flex-1 space-y-4">
|
|
{CATERING_CATEGORY_ORDER.map((category) => {
|
|
const dishes = grouped[category];
|
|
if (dishes.length === 0) return null;
|
|
|
|
const categoryLabel =
|
|
(t.catering.categories as Record<string, string>)?.[category] ?? category;
|
|
|
|
return (
|
|
<div key={category}>
|
|
<p className="mb-1.5 text-[10px] font-bold uppercase tracking-[0.22em] text-[#c99a2e]">
|
|
{categoryLabel}
|
|
</p>
|
|
<ul className="space-y-1">
|
|
{dishes.map((dish) => (
|
|
<li
|
|
key={dish.id}
|
|
className="flex items-center gap-2 text-sm text-[#3d4654]"
|
|
>
|
|
<span className="h-1 w-1 shrink-0 rounded-full bg-[#c99a2e]" aria-hidden />
|
|
{dish.name}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="mt-6 flex items-center gap-2 border-t border-[#EDE6D9] pt-4 text-xs text-[#8A8478]">
|
|
<Users className="h-3.5 w-3.5 text-[#B38B4D]" />
|
|
{t.catering.guestNote}
|
|
</div>
|
|
</div>
|
|
</motion.article>
|
|
);
|
|
} |