277 lines
16 KiB
TypeScript
277 lines
16 KiB
TypeScript
"use client"
|
||
|
||
import { cn } from "@/lib/utils"
|
||
import { Info, Tag, Check, Shield, CircleHelp } from "lucide-react"
|
||
import { useLanguage } from "@/lib/language-context"
|
||
import { useState } from "react"
|
||
|
||
interface PricingRow {
|
||
persons: string
|
||
express: string
|
||
private: string
|
||
classic?: string
|
||
}
|
||
|
||
interface SpecialPackage {
|
||
name: string
|
||
price: string
|
||
description: string
|
||
}
|
||
|
||
interface PricingTableProps {
|
||
route: string
|
||
rows: PricingRow[]
|
||
specials?: SpecialPackage[]
|
||
vipInfo?: string[]
|
||
effectiveFrom?: string
|
||
expressInfo?: string
|
||
districtSurcharge?: {
|
||
label: string
|
||
title: string
|
||
description: string
|
||
items: string[]
|
||
closeLabel: string
|
||
}
|
||
}
|
||
|
||
const PricingTable = ({
|
||
route,
|
||
rows,
|
||
specials,
|
||
vipInfo,
|
||
effectiveFrom,
|
||
expressInfo,
|
||
districtSurcharge
|
||
}: PricingTableProps) => {
|
||
const { t } = useLanguage()
|
||
const [isSurchargeOpen, setIsSurchargeOpen] = useState(false)
|
||
|
||
return (
|
||
<div className="w-full space-y-8 mb-24">
|
||
{/* Route Header matching FeatureSection style */}
|
||
<div className="space-y-2 mb-8">
|
||
<h3 className="text-5xl md:text-7xl font-black uppercase tracking-tighter opacity-10 text-primary">
|
||
{route.includes("POZSONY") || route.includes("BRATISLAVA")
|
||
? "BRATISLAVA"
|
||
: (route.includes("BÉCS") || route.includes("VIENNA"))
|
||
? "VIENNA"
|
||
: "BUDAPEST"}
|
||
</h3>
|
||
<h2 className="text-2xl md:text-3xl font-black tracking-tight -mt-8 md:-mt-10 ml-1 text-slate-900 max-w-2xl uppercase">
|
||
{route}
|
||
</h2>
|
||
{districtSurcharge && (
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsSurchargeOpen(true)}
|
||
className="inline-flex items-center gap-2 rounded-full border border-secondary/40 bg-secondary/10 px-4 py-2 text-[11px] font-black uppercase tracking-[0.25em] text-secondary transition-colors hover:border-secondary hover:bg-secondary/20"
|
||
>
|
||
<CircleHelp className="h-4 w-4" />
|
||
{districtSurcharge.label}
|
||
</button>
|
||
)}
|
||
</div>
|
||
|
||
<div className="bg-white rounded-[2.5rem] shadow-xl border border-slate-100 overflow-hidden">
|
||
{/* Mobile cards */}
|
||
<div className="block md:hidden divide-y divide-slate-100">
|
||
{rows.map((row, idx) => (
|
||
<div key={idx} className={cn("p-5", idx % 2 === 0 ? "bg-white" : "bg-slate-50/30")}>
|
||
<div className="flex items-center gap-3 text-slate-900 font-bold mb-4">
|
||
<div className="w-1.5 h-1.5 rounded-full bg-primary" />
|
||
<span>{row.persons}</span>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||
<div className="text-center">
|
||
<div className="text-[10px] uppercase tracking-[0.2em] text-slate-400 mb-2">{t.pricing.table.express}</div>
|
||
<div className="font-extrabold text-blue-950 flex items-center justify-center gap-2">
|
||
<span>{row.express}</span>
|
||
{idx === 0 && expressInfo && (
|
||
<span className="relative inline-flex items-center group">
|
||
<Info className="w-3 h-3 text-slate-300 hover:text-primary cursor-help transition-colors" />
|
||
<span className="pointer-events-none absolute bottom-full left-1/2 z-10 mb-2 w-64 -translate-x-1/2 rounded-lg bg-slate-900 px-3 py-2 text-[11px] font-medium text-white opacity-0 shadow-lg transition-opacity duration-150 group-hover:opacity-100">
|
||
{expressInfo}
|
||
</span>
|
||
</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="text-center">
|
||
<div className="text-[10px] uppercase tracking-[0.2em] text-slate-400 mb-2">{t.pricing.table.private}</div>
|
||
<div className="font-extrabold text-white px-4 py-1.5 bg-secondary rounded-full text-xs tracking-wider shadow-sm inline-block">
|
||
{row.private}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Desktop table */}
|
||
<div className="hidden md:block overflow-x-auto">
|
||
<table className="w-full text-left border-collapse">
|
||
<thead>
|
||
<tr className="bg-slate-50/50 text-slate-500 text-[10px] uppercase tracking-[0.2em] border-b border-slate-100">
|
||
<th className="py-6 px-4 md:py-8 md:px-10 font-bold whitespace-nowrap">{t.pricing.table.passengers}</th>
|
||
<th className="py-6 px-2 md:py-8 md:px-4 font-bold text-center">
|
||
<div className="flex flex-col items-center gap-1 opacity-40">
|
||
<span className="text-slate-400">{t.pricing.table.classic}</span>
|
||
<span className="text-[10px] lowercase normal-case tracking-normal">{t.pricing.table.classicNote}</span>
|
||
</div>
|
||
</th>
|
||
<th className="py-8 px-4 font-bold text-center">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="text-primary font-black">{t.pricing.table.express}</span>
|
||
<div className="bg-primary/10 p-1 rounded-md">
|
||
<Tag className="w-3 h-3 text-primary" />
|
||
</div>
|
||
</div>
|
||
</th>
|
||
<th className="py-8 px-10 font-bold text-center">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="text-secondary font-black">{t.pricing.table.private}</span>
|
||
<div className="bg-secondary/10 p-1 rounded-md">
|
||
<Shield className="w-3 h-3 text-secondary" />
|
||
</div>
|
||
</div>
|
||
</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="text-slate-700">
|
||
{rows.map((row, idx) => (
|
||
<tr
|
||
key={idx}
|
||
className={cn(
|
||
"border-b border-slate-50 transition-colors hover:bg-slate-50/80",
|
||
idx % 2 === 0 ? "bg-white" : "bg-slate-50/20"
|
||
)}
|
||
>
|
||
<td className="py-4 px-4 md:py-5 md:px-10 font-bold text-slate-900 whitespace-nowrap">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-1.5 h-1.5 rounded-full bg-primary" />
|
||
{row.persons}
|
||
</div>
|
||
</td>
|
||
<td className="py-4 px-2 md:py-5 md:px-4 text-center text-slate-300">
|
||
<span className="text-xs">—</span>
|
||
</td>
|
||
<td className="py-5 px-4 text-center">
|
||
<div className="flex items-center justify-center gap-2">
|
||
<span className="font-extrabold text-blue-950">{row.express}</span>
|
||
{idx === 0 && expressInfo && (
|
||
<span className="relative inline-flex items-center group">
|
||
<Info className="w-3 h-3 text-slate-300 hover:text-primary cursor-help transition-colors" />
|
||
<span className="pointer-events-none absolute bottom-full left-1/2 z-10 mb-2 w-64 -translate-x-1/2 rounded-lg bg-slate-900 px-3 py-2 text-[11px] font-medium text-white opacity-0 shadow-lg transition-opacity duration-150 group-hover:opacity-100">
|
||
{expressInfo}
|
||
</span>
|
||
</span>
|
||
)}
|
||
</div>
|
||
</td>
|
||
<td className="py-5 px-10 text-center">
|
||
<span className="font-extrabold text-white px-5 py-1.5 bg-secondary rounded-full text-xs tracking-wider shadow-sm">
|
||
{row.private}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
{specials && specials.length > 0 && (
|
||
<div className="bg-gradient-to-r from-slate-950 to-slate-900 text-white p-10 space-y-8">
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10">
|
||
{specials.map((special, idx) => (
|
||
<div key={idx} className="space-y-3 group">
|
||
<div className="flex items-center gap-4">
|
||
<div className="bg-primary p-2 rounded-xl group-hover:scale-110 transition-transform duration-300 shadow-lg shadow-primary/20">
|
||
<Check className="w-4 h-4 text-white" />
|
||
</div>
|
||
<span className="font-black text-xl text-white group-hover:text-primary transition-colors tracking-tight">
|
||
{special.name} — {special.price}
|
||
</span>
|
||
</div>
|
||
<p className="text-slate-400 text-sm leading-relaxed pl-12 font-medium">
|
||
{special.description}
|
||
</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{(vipInfo && vipInfo.length > 0) && (
|
||
<div className="pt-8 border-t border-white/5">
|
||
<h4 className="text-[10px] uppercase tracking-[0.3em] text-primary font-black mb-6">{t.pricing.table.premium}</h4>
|
||
<div className="flex flex-wrap gap-x-12 gap-y-4">
|
||
{vipInfo.map((info, idx) => (
|
||
<div key={idx} className="flex items-center gap-3 text-sm text-slate-300 font-bold italic">
|
||
<div className="w-2 h-2 rounded-full bg-primary shadow-[0_0_10px_rgba(217,163,33,0.5)]" />
|
||
{info}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{effectiveFrom && (
|
||
<div className="text-right text-slate-400 text-[10px] uppercase tracking-[0.2em] font-black">
|
||
{effectiveFrom}
|
||
</div>
|
||
)}
|
||
|
||
{districtSurcharge && isSurchargeOpen && (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/70 px-4">
|
||
<div className="w-full max-w-2xl overflow-hidden rounded-[2rem] border border-slate-800/80 bg-slate-900 text-white shadow-[0_30px_80px_rgba(15,23,42,0.6)]">
|
||
<div className="relative px-8 py-6">
|
||
<div className="absolute inset-0 bg-gradient-to-br from-slate-900 via-slate-900 to-slate-800 opacity-90" />
|
||
<div className="relative flex items-center justify-between">
|
||
<div>
|
||
<p className="text-[10px] uppercase tracking-[0.35em] text-secondary/80">
|
||
{districtSurcharge.label}
|
||
</p>
|
||
<h4 className="text-lg font-black uppercase tracking-tight text-white">
|
||
{districtSurcharge.title}
|
||
</h4>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsSurchargeOpen(false)}
|
||
className="h-9 w-9 rounded-full border border-white/10 bg-white/5 text-white/70 transition-colors hover:bg-white/10 hover:text-white"
|
||
aria-label={districtSurcharge.closeLabel}
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div className="space-y-5 px-8 pb-8 pt-2 text-sm text-white/85">
|
||
<p className="leading-relaxed">{districtSurcharge.description}</p>
|
||
<div className="space-y-3">
|
||
{districtSurcharge.items.map((item, idx) => (
|
||
<div key={idx} className="flex items-start gap-3 rounded-xl border border-white/5 bg-white/5 px-4 py-3">
|
||
<span className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-secondary shadow-[0_0_10px_rgba(217,163,33,0.6)]" />
|
||
<span className="font-semibold text-white/90">{item}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div className="flex justify-end pt-2">
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsSurchargeOpen(false)}
|
||
className="rounded-full bg-secondary px-6 py-2 text-[11px] font-black uppercase tracking-[0.25em] text-white hover:bg-secondary/90"
|
||
>
|
||
{districtSurcharge.closeLabel}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default PricingTable
|