247 lines
15 KiB
TypeScript
247 lines
15 KiB
TypeScript
"use client"
|
|
|
|
import { Button } from "@/components/ui/button"
|
|
import { Card } from "@/components/ui/card"
|
|
import { Star, Clock, Users, ShieldCheck } from "lucide-react"
|
|
import Link from "next/link"
|
|
import { useLanguage } from "@/lib/language-context"
|
|
import Image from "next/image"
|
|
import { useEffect, useMemo, useState } from "react"
|
|
|
|
const Hero = () => {
|
|
const { t, language } = useLanguage()
|
|
|
|
const [ratingsData, setRatingsData] = useState<any>(null)
|
|
const [featuredReview, setFeaturedReview] = useState<any>(null)
|
|
|
|
useEffect(() => {
|
|
const fetchRatings = async () => {
|
|
try {
|
|
const response = await fetch(`/ratings_${language}.json`)
|
|
const data = await response.json()
|
|
setRatingsData(data)
|
|
|
|
const reviews = data?.data?.[0]?.reviews ?? []
|
|
if (reviews.length > 0) {
|
|
const randomIndex = Math.floor(Math.random() * reviews.length)
|
|
setFeaturedReview(reviews[randomIndex])
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching ratings:", error)
|
|
}
|
|
}
|
|
fetchRatings()
|
|
}, [language])
|
|
|
|
const ratingValue = ratingsData?.data?.[0]?.rating ?? 5.0
|
|
const ratingCount = ratingsData?.data?.[0]?.userRatingCount ?? 0
|
|
const ratingPercent = Math.max(0, Math.min(100, (ratingValue / 5) * 100))
|
|
|
|
const reviewAuthor = featuredReview?.author ?? t.hero.cards.reviewAuthor
|
|
const reviewInitials = useMemo(() => {
|
|
if (!reviewAuthor) return t.hero.cards.reviewInitial
|
|
const initials = reviewAuthor
|
|
.split(" ")
|
|
.filter(Boolean)
|
|
.slice(0, 2)
|
|
.map((part: string) => part[0]?.toUpperCase())
|
|
.join("")
|
|
return initials || t.hero.cards.reviewInitial
|
|
}, [reviewAuthor, t.hero.cards.reviewInitial])
|
|
const reviewRating = Math.max(0, Math.min(5, Math.round(featuredReview?.rating ?? 5)))
|
|
const reviewTextRaw = featuredReview?.text ?? t.hero.cards.reviewText
|
|
const reviewText = reviewTextRaw.length > 120 ? `${reviewTextRaw.slice(0, 120).trimEnd()}...` : reviewTextRaw
|
|
|
|
return (
|
|
<section className="relative min-h-screen flex items-center pt-20 overflow-hidden">
|
|
{/* Background with diagonal slice */}
|
|
<div className="absolute inset-0 bg-diagonal -z-10" />
|
|
<div className="absolute bottom-0 left-0 w-full h-[20vh] bg-background transform -skew-y-3 origin-bottom-left -z-10" />
|
|
|
|
<div className="max-w-7xl mx-auto px-6 grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
|
<div className="text-white space-y-8">
|
|
<a
|
|
href="https://g.page/r/CRltVP4lAy7lEBM/review"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="group flex items-center space-x-2 py-1 px-3 bg-white/10 rounded-full w-fit backdrop-blur-sm border border-white/20 transition-all duration-300 hover:bg-white/20 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_-12px_rgba(0,0,0,0.4)] hover:border-white/40"
|
|
aria-label={`${ratingValue.toFixed(1)} ${t.hero.rating} (${ratingCount})`}
|
|
>
|
|
<span className="text-xs font-semibold text-white/90 transition-transform duration-300 group-hover:scale-105">{ratingValue.toFixed(1)}/5.0</span>
|
|
<div className="relative flex items-center leading-none">
|
|
<span
|
|
className="text-[14px] leading-none tracking-[0.08em] font-semibold transition-all duration-300 group-hover:tracking-[0.12em]"
|
|
style={{
|
|
backgroundImage: `linear-gradient(90deg, #fde047 ${ratingPercent}%, rgba(255,255,255,0.35) ${ratingPercent}%)`,
|
|
WebkitBackgroundClip: "text",
|
|
color: "transparent",
|
|
}}
|
|
aria-hidden="true"
|
|
>
|
|
★★★★★
|
|
</span>
|
|
</div>
|
|
<span className="text-xs font-semibold text-white/80 transition-colors duration-300 group-hover:text-white/90">({ratingCount})</span>
|
|
<span className="text-xs font-semibold text-white/90 transition-colors duration-300 group-hover:text-white">{t.hero.rating}</span>
|
|
</a>
|
|
|
|
<h1 className="text-4xl md:text-7xl font-black leading-[0.9] tracking-tighter">
|
|
{t.hero.title} <br />
|
|
<span className="text-primary-foreground underline decoration-primary decoration-8 underline-offset-[12px]">
|
|
{t.hero.titleAccent}
|
|
</span>
|
|
</h1>
|
|
|
|
<p className="text-sm md:text-base font-bold text-white/60 tracking-widest uppercase mb-4">
|
|
{t.hero.subtitle}
|
|
</p>
|
|
|
|
<p className="text-xl text-white/80 max-w-lg leading-relaxed font-medium">
|
|
{t.hero.description}
|
|
</p>
|
|
|
|
<div className="flex flex-wrap gap-4 pt-4">
|
|
<Button asChild size="lg" className="bg-slate-900 text-white hover:bg-slate-800 rounded-full px-10 h-14 text-sm font-bold uppercase tracking-widest shadow-xl">
|
|
<a href="https://app.skyflytravel.hu/public/offers/new">
|
|
{t.hero.booking}
|
|
</a>
|
|
</Button>
|
|
<Button asChild size="lg" variant="default" className="bg-white text-slate-900 hover:bg-slate-100 rounded-full px-10 h-14 text-sm font-bold uppercase tracking-widest shadow-lg">
|
|
<Link href="/arak">{t.hero.fares}</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative hidden lg:block">
|
|
{/* Main Floating Card - Booking Status */}
|
|
<div className="animate-float">
|
|
<Card className="w-full max-w-[500px] mx-auto bg-white shadow-2xl rounded-[2.5rem] p-6 transform lg:-rotate-2 overflow-hidden border-none backdrop-blur-sm bg-white/95">
|
|
<div className="space-y-6">
|
|
<div className="flex justify-between items-center border-b border-slate-100 pb-4">
|
|
<div className="flex items-center space-x-2">
|
|
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
|
|
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">{t.hero.cards.activeBooking}</span>
|
|
</div>
|
|
<div className="py-1 px-3 bg-primary/10 rounded-full text-primary text-[10px] font-bold">{t.hero.cards.fixedPrice}</div>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between gap-4">
|
|
<div className="space-y-1">
|
|
<p className="text-[10px] text-slate-400 font-bold uppercase">{t.hero.cards.departure}</p>
|
|
<p className="text-lg md:text-xl font-black text-slate-900">{t.hero.cards.fromCity}</p>
|
|
</div>
|
|
<div className="flex-1 px-2 md:px-6 flex flex-col items-center">
|
|
<div className="w-full h-px bg-slate-200 relative">
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white px-2">
|
|
<Star className="w-4 h-4 text-primary fill-primary" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="text-right space-y-1">
|
|
<p className="text-[10px] text-slate-400 font-bold uppercase">{t.hero.cards.destination}</p>
|
|
<p className="text-lg md:text-xl font-black text-slate-900">{t.hero.cards.toAirport}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-3 gap-3 md:gap-4 pt-4">
|
|
<div className="p-3 bg-slate-50 rounded-2xl flex flex-col items-center text-center space-y-1 border border-slate-100">
|
|
<Clock className="w-5 h-5 text-primary" />
|
|
<p className="text-[10px] font-bold">{t.hero.cards.duration}</p>
|
|
</div>
|
|
<div className="p-3 bg-slate-50 rounded-2xl flex flex-col items-center text-center space-y-1 border border-slate-100">
|
|
<Users className="w-5 h-5 text-primary" />
|
|
<p className="text-[10px] font-bold">{t.hero.cards.passengers}</p>
|
|
</div>
|
|
<div className="p-3 bg-slate-50 rounded-2xl flex flex-col items-center text-center space-y-1 border border-slate-100">
|
|
<ShieldCheck className="w-5 h-5 text-primary" />
|
|
<p className="text-[10px] font-bold">{t.hero.cards.insured}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<Button className="w-full h-12 rounded-xl bg-slate-900 hover:bg-slate-800 text-white font-bold text-xs uppercase tracking-widest transition-all active:scale-[0.98]">
|
|
{t.hero.cards.manageBooking}
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Overlapping small cards - Hidden on mobile, only visible from lg up */}
|
|
<div className="absolute -top-16 -right-10 hidden lg:block animate-float animation-delay-2000">
|
|
<Card className="w-56 bg-white shadow-xl rounded-3xl p-3 transform rotate-6 border-none overflow-hidden group">
|
|
<div className="relative w-full h-40 rounded-2xl overflow-hidden mb-3">
|
|
<Image
|
|
src="/images/family.jpg"
|
|
alt="Family Travel"
|
|
fill
|
|
sizes="(min-width: 1024px) 224px, 50vw"
|
|
className="object-cover group-hover:scale-110 transition-transform duration-500"
|
|
/>
|
|
<div className="absolute top-2 right-2 bg-primary text-white text-[10px] font-bold px-2 py-1 rounded-lg shadow-lg">{t.hero.cards.familyTag}</div>
|
|
</div>
|
|
<div className="px-1">
|
|
<p className="text-sm font-black text-slate-900">{t.hero.cards.freeChildSeat}</p>
|
|
<p className="text-[10px] text-slate-500 font-medium">{t.hero.cards.familyDesc}</p>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
<div className="absolute -bottom-16 -left-10 hidden lg:block animate-float animation-delay-4000">
|
|
<Card className="w-64 bg-white shadow-xl rounded-3xl p-3 transform -rotate-3 border-none overflow-hidden group">
|
|
<div className="flex items-center space-x-3 mb-3">
|
|
<div className="relative w-16 h-16 rounded-2xl overflow-hidden shrink-0">
|
|
<Image
|
|
src="/images/premium_van.png"
|
|
alt="Premium Fleet"
|
|
fill
|
|
sizes="64px"
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm font-black text-slate-900">{t.hero.cards.premiumFleet}</p>
|
|
<p className="text-[10px] text-primary font-bold uppercase">{t.hero.cards.mercedes}</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center justify-between pt-2 border-t border-slate-50">
|
|
<div className="flex items-center space-x-1">
|
|
<div className="w-1.5 h-1.5 bg-green-500 rounded-full" />
|
|
<span className="text-[9px] font-bold text-slate-400 uppercase">{t.hero.cards.nonStop}</span>
|
|
</div>
|
|
<span className="text-[10px] font-black text-slate-900">{t.hero.cards.supportTime}</span>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Review Snippet - Hidden on mobile, only visible from lg up */}
|
|
<div className="absolute top-1/2 -right-16 translate-y-1/2 hidden lg:block animate-float animation-delay-3000">
|
|
<Card className="w-52 bg-primary/10 backdrop-blur-md shadow-lg rounded-2xl p-4 border border-white/20 transform -rotate-6">
|
|
<div className="flex mb-2">
|
|
{[1, 2, 3, 4, 5].map((i) => (
|
|
<Star
|
|
key={i}
|
|
className="w-3 h-3 text-primary"
|
|
fill={i <= reviewRating ? "currentColor" : "none"}
|
|
stroke="currentColor"
|
|
/>
|
|
))}
|
|
</div>
|
|
<p className="text-[10px] font-medium text-slate-800 leading-tight italic">
|
|
{reviewText}
|
|
</p>
|
|
<div className="flex items-center space-x-2 mt-3">
|
|
<div className="w-6 h-6 rounded-full bg-primary/20 flex items-center justify-center text-[8px] font-bold">
|
|
{reviewInitials}
|
|
</div>
|
|
<span className="text-[8px] font-bold text-slate-500">{reviewAuthor}</span>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|
|
|
|
export default Hero
|