import Link from 'next/link' import { storefrontFetchOrDefault } from '@/lib/api' import { getStorefrontLanguage } from '@/lib/i18n.server' import StorefrontSearchForm from './_components/StorefrontSearchForm' import StorefrontVehicleGrid from './_components/StorefrontVehicleGrid' interface Vehicle { id: string make: string model: string year: number category: string dailyRate: number photos: string[] pickupLocations: string[] allowDifferentDropoff: boolean dropoffLocations: string[] availability?: boolean | null availabilityStatus?: 'AVAILABLE' | 'RESERVED' | 'MAINTENANCE' | 'UNAVAILABLE' nextAvailableAt?: string | null company: { slug: string brand: { displayName: string logoUrl: string | null subdomain: string marketplaceRating: number | null } | null } } interface Offer { id: string title: string discountValue: number validUntil: string company: { brand: { displayName: string subdomain: string } | null } } interface CompanyCard { id: string brand: { displayName: string subdomain: string publicCity: string | null marketplaceRating: number | null } | null _count: { vehicles: number } } const CATEGORY_VALUES = [ 'ECONOMY', 'COMPACT', 'MIDSIZE', 'FULLSIZE', 'SUV', 'LUXURY', 'VAN', 'TRUCK', ] as const export default async function StorefrontPage({ searchParams }: { searchParams?: Promise> }) { const resolvedSearchParams = await searchParams const language = await getStorefrontLanguage() const dict = { en: { kicker: 'Discovery only', title: 'Find your next rental from trusted local companies.', body: 'Browse, filter, and reserve — the company confirms and contacts you directly.', searchTitle: 'Find a vehicle', pickupLocation: 'Pick-up location', dropoffLocation: 'Drop-off location', sameDropoff: 'Same drop-off', differentDropoff: 'Different drop-off', sameAsPickup: 'Return to the same location', pickupDate: 'Start date', returnDate: 'Return date', hour: 'Hour', promoCode: 'I have a promo code', myAge: 'My age', ageDescription: 'Driver age can affect availability, deposit amount, and final pricing.', ageOptions: ['18+', '21+', '23+', '25+', '30+'], search: 'Search', currentDeals: 'Current deals', featuredOffers: 'Featured storefront offers', company: 'Company', validUntil: 'Valid until', offersUnavailable: 'Storefront offers are unavailable right now.', availableVehicles: 'Available vehicles', listings: 'listings', rentalCompany: 'Rental company', checkAvailability: 'Check availability', available: 'Available', reserved: 'Reserved', maintenance: 'In maintenance', unavailableStatus: 'Unavailable', from: 'From', viewVehicle: 'View vehicle', availableFrom: 'Available from', unavailableNoDate: 'This vehicle is temporarily unavailable for new reservations.', vehicleUnavailable: 'Vehicle listings are unavailable right now.', browseByCategory: 'Browse by category', browseByCompany: 'Browse by company', storefrontPartners: 'Storefront partners', storefrontPartner: 'Storefront partner', rating: 'Rating', new: 'New', publishedVehicles: 'published vehicles', viewFleet: 'View fleet', categories: ['Economy', 'Compact', 'Midsize', 'Full-size', 'SUV', 'Luxury', 'Van', 'Truck'], }, fr: { kicker: 'Découverte uniquement', title: "Trouvez votre prochaine location auprès d'entreprises locales fiables.", body: "Parcourez, filtrez et réservez — l'entreprise confirme et vous contacte directement.", searchTitle: 'Trouver un véhicule', pickupLocation: 'Lieu de départ', dropoffLocation: "Lieu de retour", sameDropoff: 'Même retour', differentDropoff: 'Retour différent', sameAsPickup: 'Retour au même lieu', pickupDate: 'Date de départ', returnDate: 'Date de retour', hour: 'Heure', promoCode: "J'ai un code promo", myAge: 'Mon âge', ageDescription: "L'âge du conducteur peut influencer la disponibilité, le dépôt de garantie et le prix final.", ageOptions: ['18+', '21+', '23+', '25+', '30+'], search: 'Rechercher', currentDeals: 'Offres du moment', featuredOffers: 'Offres storefront mises en avant', company: 'Entreprise', validUntil: "Valable jusqu'au", offersUnavailable: 'Les offres storefront sont indisponibles pour le moment.', availableVehicles: 'Véhicules disponibles', listings: 'annonces', rentalCompany: 'Société de location', checkAvailability: 'Vérifier la disponibilité', available: 'Disponible', reserved: 'Réservé', maintenance: 'En maintenance', unavailableStatus: 'Indisponible', from: 'À partir de', viewVehicle: 'Voir le véhicule', availableFrom: 'Disponible à partir du', unavailableNoDate: 'Ce véhicule est temporairement indisponible pour les nouvelles réservations.', vehicleUnavailable: 'Les annonces véhicules sont indisponibles pour le moment.', browseByCategory: 'Parcourir par catégorie', browseByCompany: 'Parcourir par entreprise', storefrontPartners: 'Partenaires storefront', storefrontPartner: 'Partenaire storefront', rating: 'Note', new: 'Nouveau', publishedVehicles: 'véhicules publiés', viewFleet: 'Voir la flotte', categories: ['Économie', 'Compacte', 'Intermédiaire', 'Grande berline', 'SUV', 'Luxe', 'Van', 'Camion'], }, ar: { kicker: 'للاستكشاف فقط', title: 'اعثر على سيارتك القادمة من شركات محلية موثوقة.', body: 'تصفّح وابحث واحجز — تؤكد الشركة وتتواصل معك مباشرةً.', searchTitle: 'احجز سيارة', pickupLocation: 'موقع الاستلام', dropoffLocation: 'موقع الإرجاع', sameDropoff: 'نفس موقع الإرجاع', differentDropoff: 'موقع إرجاع مختلف', sameAsPickup: 'الإرجاع في نفس موقع الاستلام', pickupDate: 'تاريخ البدء', returnDate: 'تاريخ الإرجاع', hour: 'الساعة', promoCode: 'لدي رمز ترويجي', myAge: 'عمري', ageDescription: 'قد يؤثر عمر السائق على التوفر ومبلغ التأمين والسعر النهائي.', ageOptions: ['18+', '21+', '23+', '25+', '30+'], search: 'بحث', currentDeals: 'العروض الحالية', featuredOffers: 'عروض السوق المميزة', company: 'شركة', validUntil: 'صالح حتى', offersUnavailable: 'عروض السوق غير متاحة حالياً.', availableVehicles: 'السيارات المتاحة', listings: 'إعلانات', rentalCompany: 'شركة تأجير', checkAvailability: 'تحقق من التوفر', available: 'متاح', reserved: 'محجوز', maintenance: 'قيد الصيانة', unavailableStatus: 'غير متاح', from: 'ابتداءً من', viewVehicle: 'عرض السيارة', availableFrom: 'متاح ابتداءً من', unavailableNoDate: 'هذه السيارة غير متاحة مؤقتاً للحجوزات الجديدة.', vehicleUnavailable: 'قوائم السيارات غير متاحة حالياً.', browseByCategory: 'تصفح حسب الفئة', browseByCompany: 'تصفح حسب الشركة', storefrontPartners: 'شركاء السوق', storefrontPartner: 'شريك في السوق', rating: 'التقييم', new: 'جديد', publishedVehicles: 'سيارات منشورة', viewFleet: 'عرض الأسطول', categories: ['اقتصادية', 'مدمجة', 'متوسطة', 'كبيرة', 'SUV', 'فاخرة', 'فان', 'شاحنة'], }, }[language] const city = typeof resolvedSearchParams?.city === 'string' ? resolvedSearchParams.city : '' const pickupLocation = typeof resolvedSearchParams?.pickupLocation === 'string' ? resolvedSearchParams.pickupLocation : city const dropoffLocation = typeof resolvedSearchParams?.dropoffLocation === 'string' ? resolvedSearchParams.dropoffLocation : '' const dropoffMode = resolvedSearchParams?.dropoffMode === 'different' ? 'different' : 'same' const pickupDate = typeof resolvedSearchParams?.pickupDate === 'string' ? resolvedSearchParams.pickupDate : '' const pickupTime = typeof resolvedSearchParams?.pickupTime === 'string' ? resolvedSearchParams.pickupTime : '10:00' const returnDate = typeof resolvedSearchParams?.returnDate === 'string' ? resolvedSearchParams.returnDate : '' const returnTime = typeof resolvedSearchParams?.returnTime === 'string' ? resolvedSearchParams.returnTime : '10:00' const promoCode = typeof resolvedSearchParams?.promoCode === 'string' ? resolvedSearchParams.promoCode : '' const driverAge = typeof resolvedSearchParams?.driverAge === 'string' ? resolvedSearchParams.driverAge : '23+' const category = typeof resolvedSearchParams?.category === 'string' ? resolvedSearchParams.category : '' const transmission = typeof resolvedSearchParams?.transmission === 'string' ? resolvedSearchParams.transmission : '' const make = typeof resolvedSearchParams?.make === 'string' ? resolvedSearchParams.make : '' const model = typeof resolvedSearchParams?.model === 'string' ? resolvedSearchParams.model : '' const startDate = typeof resolvedSearchParams?.startDate === 'string' ? resolvedSearchParams.startDate : '' const endDate = typeof resolvedSearchParams?.endDate === 'string' ? resolvedSearchParams.endDate : '' const query = new URLSearchParams() if (pickupLocation) query.set('city', pickupLocation) if (pickupLocation) query.set('pickupLocation', pickupLocation) query.set('dropoffMode', dropoffMode) if (dropoffMode === 'different' && dropoffLocation) query.set('dropoffLocation', dropoffLocation) if (startDate) query.set('startDate', startDate) if (endDate) query.set('endDate', endDate) if (category) query.set('category', category) if (transmission) query.set('transmission', transmission) if (make) query.set('make', make) if (model) query.set('model', model) query.set('pageSize', '24') const [offers, vehicles, companies] = await Promise.all([ storefrontFetchOrDefault('/storefront/offers', []), storefrontFetchOrDefault(`/storefront/search?${query.toString()}`, []), storefrontFetchOrDefault('/storefront/companies?pageSize=8', []), ]) const cities = Array.from( new Set( companies .map((company) => company.brand?.publicCity?.trim()) .filter((city): city is string => Boolean(city)) ) ).sort((left, right) => left.localeCompare(right)) return (

{dict.kicker}

{dict.title}

{dict.body}

{dict.currentDeals}

{dict.featuredOffers}

{offers.map((offer) => (

{offer.company.brand?.displayName ?? dict.company}

{offer.title}

{offer.discountValue}%

{dict.validUntil} {new Date(offer.validUntil).toLocaleDateString()}

))} {offers.length === 0 &&
{dict.offersUnavailable}
}

{dict.browseByCategory}

{dict.categories.map((categoryName, index) => ( {categoryName} ))}

{dict.browseByCompany}

{dict.storefrontPartners}

{companies.map((company) => (

{company.brand?.publicCity ?? dict.storefrontPartner}

{company.brand?.displayName ?? dict.rentalCompany}

{dict.rating} {company.brand?.marketplaceRating?.toFixed(1) ?? dict.new}

{company._count.vehicles} {dict.publishedVehicles}

{dict.viewFleet} ))}
) }