Sample car images (Tesla, Sportage etc.) now only appear as fallback when the API fails to respond within 3 seconds. During normal loading, a pulse-animated skeleton is shown instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
155 lines
6.8 KiB
TypeScript
155 lines
6.8 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import FilmStripSlider from '@/components/FilmStripSlider';
|
|
import PromoPreference from '@/components/PromoPreference';
|
|
import { HeroBanner, HeroBannerSettings } from '@/types';
|
|
import { heroBannersApi } from '@/lib/api';
|
|
import { useTranslation } from '@/lib/i18n';
|
|
|
|
export default function Home() {
|
|
const { t, language } = useTranslation();
|
|
const [banners, setBanners] = useState<HeroBanner[]>([]);
|
|
const [bannerSettings, setBannerSettings] = useState<HeroBannerSettings | undefined>();
|
|
const [bannerLoaded, setBannerLoaded] = useState(false);
|
|
const [showFallback, setShowFallback] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setBannerLoaded(false);
|
|
setShowFallback(false);
|
|
|
|
// 3초 후에도 로딩 안 되면 샘플 배너 표시
|
|
const fallbackTimer = setTimeout(() => {
|
|
setShowFallback(true);
|
|
}, 3000);
|
|
|
|
const loadBanners = async () => {
|
|
try {
|
|
const [bannersData, settingsData] = await Promise.all([
|
|
heroBannersApi.getList(language),
|
|
heroBannersApi.getSettings(),
|
|
]);
|
|
setBanners(bannersData);
|
|
setBannerSettings(settingsData);
|
|
} catch (error) {
|
|
console.error('Failed to load banners:', error);
|
|
setShowFallback(true);
|
|
} finally {
|
|
setBannerLoaded(true);
|
|
clearTimeout(fallbackTimer);
|
|
}
|
|
};
|
|
loadBanners();
|
|
|
|
return () => clearTimeout(fallbackTimer);
|
|
}, [language]);
|
|
|
|
return (
|
|
<div>
|
|
{/* Hero Section with Film Strip Slider */}
|
|
<section className="bg-gradient-to-r from-primary-700 to-primary-900 text-white">
|
|
<div className="container mx-auto px-4 pt-6 sm:pt-12 pb-2 sm:pb-4 text-center">
|
|
<h1 className="text-2xl sm:text-4xl md:text-5xl font-bold mb-2 sm:mb-4">
|
|
{t.premiumKoreanUsedCars}
|
|
</h1>
|
|
<p className="text-base sm:text-xl md:text-2xl text-primary-100 mb-4 sm:mb-6">
|
|
{t.qualityVehiclesExported}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Film Strip Slider */}
|
|
<FilmStripSlider
|
|
banners={banners}
|
|
settings={bannerSettings}
|
|
loading={!bannerLoaded && !showFallback}
|
|
/>
|
|
|
|
<div className="container mx-auto px-4 py-4 sm:py-8">
|
|
<div className="flex flex-col lg:flex-row items-center gap-4 lg:gap-6">
|
|
{/* Spacer for centering Request Vehicle */}
|
|
<div className="hidden lg:block lg:flex-1"></div>
|
|
|
|
{/* Request Vehicle Button - Centered */}
|
|
<Link
|
|
href="/vehicle-request"
|
|
className="inline-block bg-yellow-500 text-white font-semibold px-6 py-2.5 sm:px-8 sm:py-3 rounded-lg hover:bg-yellow-600 transition shadow-lg text-sm sm:text-base"
|
|
>
|
|
{t.requestVehicle}
|
|
</Link>
|
|
|
|
{/* Divider */}
|
|
<div className="hidden lg:block w-px h-16 bg-white/30"></div>
|
|
<div className="lg:hidden w-32 h-px bg-white/30"></div>
|
|
|
|
{/* Promo Preference - Right side */}
|
|
<div className="lg:flex-1 flex justify-center lg:justify-start">
|
|
<PromoPreference />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Features */}
|
|
<section className="py-10 sm:py-16 bg-gray-50">
|
|
<div className="container mx-auto px-4">
|
|
<h2 className="text-2xl sm:text-3xl font-bold text-center mb-8 sm:mb-12">{t.whyChooseUs}</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8">
|
|
<div className="text-center p-4 sm:p-6">
|
|
<div className="w-12 h-12 sm:w-16 sm:h-16 bg-primary-100 text-primary-600 rounded-full flex items-center justify-center mx-auto mb-3 sm:mb-4">
|
|
<svg className="w-6 h-6 sm:w-8 sm:h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-lg sm:text-xl font-semibold mb-2">{t.qualityAssured}</h3>
|
|
<p className="text-gray-600 text-sm sm:text-base">{t.qualityAssuredDesc}</p>
|
|
</div>
|
|
<div className="text-center p-4 sm:p-6">
|
|
<div className="w-12 h-12 sm:w-16 sm:h-16 bg-primary-100 text-primary-600 rounded-full flex items-center justify-center mx-auto mb-3 sm:mb-4">
|
|
<svg className="w-6 h-6 sm:w-8 sm:h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-lg sm:text-xl font-semibold mb-2">{t.bestPrices}</h3>
|
|
<p className="text-gray-600 text-sm sm:text-base">{t.bestPricesDesc}</p>
|
|
</div>
|
|
<div className="text-center p-4 sm:p-6">
|
|
<div className="w-12 h-12 sm:w-16 sm:h-16 bg-primary-100 text-primary-600 rounded-full flex items-center justify-center mx-auto mb-3 sm:mb-4">
|
|
<svg className="w-6 h-6 sm:w-8 sm:h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-lg sm:text-xl font-semibold mb-2">{t.fullSupport}</h3>
|
|
<p className="text-gray-600 text-sm sm:text-base">{t.fullSupportDesc}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* CTA */}
|
|
<section className="bg-primary-700 text-white py-10 sm:py-16">
|
|
<div className="container mx-auto px-4 text-center">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4">{t.readyToFindYourCar}</h2>
|
|
<p className="text-primary-100 mb-6 sm:mb-8 max-w-2xl mx-auto text-sm sm:text-base">
|
|
{t.browseOurCollection}
|
|
</p>
|
|
<div className="flex flex-col sm:flex-row justify-center gap-3 sm:space-x-4">
|
|
<Link
|
|
href="/cars"
|
|
className="bg-white text-primary-700 font-semibold px-5 py-2.5 sm:px-6 sm:py-3 rounded-lg hover:bg-primary-100 transition text-sm sm:text-base"
|
|
>
|
|
{t.browseCars}
|
|
</Link>
|
|
<Link
|
|
href="/contact"
|
|
className="border-2 border-white text-white font-semibold px-5 py-2.5 sm:px-6 sm:py-3 rounded-lg hover:bg-white hover:text-primary-700 transition text-sm sm:text-base"
|
|
>
|
|
{t.contactUs}
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|