import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { Search, Sparkles, ArrowRight, Tag, Award, Star } from 'lucide-react'; import * as LucideIcons from 'lucide-react'; import pageContentService, { PageContent } from '../services/pageContentService'; import serviceService, { Service } from '../../hotel_services/services/serviceService'; import Loading from '../../../shared/components/Loading'; import { useFormatCurrency } from '../../payments/hooks/useFormatCurrency'; import { useTheme } from '../../../shared/contexts/ThemeContext'; import { getThemeBackgroundClasses, getThemeHeroBackgroundClasses, getThemeTextClasses, getThemeCardClasses, getThemeInputClasses } from '../../../shared/utils/themeUtils'; // Helper function to get icon component from icon name (handles both PascalCase and lowercase) const getIconComponent = (iconName?: string, fallback: any = Award) => { if (!iconName) return fallback; // Try direct match first (for PascalCase names) if ((LucideIcons as any)[iconName]) { return (LucideIcons as any)[iconName]; } // Convert to PascalCase (capitalize first letter) const pascalCaseName = iconName.charAt(0).toUpperCase() + iconName.slice(1).toLowerCase(); if ((LucideIcons as any)[pascalCaseName]) { return (LucideIcons as any)[pascalCaseName]; } return fallback; }; const ServicesPage: React.FC = () => { const { theme } = useTheme(); const [pageContent, setPageContent] = useState(null); const [hotelServices, setHotelServices] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [selectedCategory, setSelectedCategory] = useState(null); const [allCategories, setAllCategories] = useState([]); const { formatCurrency } = useFormatCurrency(); useEffect(() => { fetchData(); }, []); const fetchData = async () => { try { setLoading(true); // Fetch page content for luxury services const contentResponse = await pageContentService.getHomeContent(); if (contentResponse.status === 'success' && contentResponse.data?.page_content) { const content = contentResponse.data.page_content; // Handle luxury_services - can be string, array, or null/undefined if (typeof content.luxury_services === 'string') { try { content.luxury_services = JSON.parse(content.luxury_services); } catch { content.luxury_services = []; } } else if (!Array.isArray(content.luxury_services)) { content.luxury_services = content.luxury_services || []; } setPageContent(content); // Extract categories from luxury services const categories = new Set(); if (Array.isArray(content.luxury_services)) { content.luxury_services.forEach((service: any) => { if (service.category) { categories.add(service.category); } }); } setAllCategories(Array.from(categories)); } // Fetch hotel services from API const servicesResponse = await serviceService.getServices({ status: 'active', limit: 100, }); if (servicesResponse.success && servicesResponse.data?.services) { setHotelServices(servicesResponse.data.services); // Add categories from hotel services const hotelCategories = new Set(allCategories); servicesResponse.data.services.forEach((service: Service) => { // You can add category logic here if services have categories }); setAllCategories(Array.from(hotelCategories)); } } catch (error: any) { console.error('Error fetching services:', error); } finally { setLoading(false); } }; // Combine hotel services (primary) with luxury services from page content (fallback) const allServices = React.useMemo(() => { const services: Array<{ id: string | number; title: string; description: string; image?: string; icon?: string; price?: number; unit?: string; category?: string; type: 'luxury' | 'hotel'; slug?: string; }> = []; // Add hotel services first (primary source) hotelServices.forEach((service: Service) => { // Generate slug if not present const serviceSlug = service.slug || service.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); services.push({ id: service.id, title: service.name, description: service.description || '', image: service.image, price: service.price, unit: service.unit, category: service.category || 'Services', type: 'hotel', slug: serviceSlug, }); }); // Add luxury services from page content (only if not already in hotel services) if (pageContent?.luxury_services && Array.isArray(pageContent.luxury_services)) { pageContent.luxury_services.forEach((service: any, index: number) => { // Check if this service already exists in hotel services by slug const existingSlug = service.slug || service.title?.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); const existsInHotel = hotelServices.some((hs: Service) => { const hotelSlug = hs.slug || hs.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); return hotelSlug === existingSlug; }); // Only add if not already in hotel services if (!existsInHotel) { services.push({ id: `luxury-${index}`, title: service.title || 'Service', description: service.description || '', image: service.image, icon: service.icon, category: service.category, type: 'luxury', slug: service.slug, }); } }); } return services; }, [pageContent, hotelServices]); // Filter services based on search and category const filteredServices = React.useMemo(() => { return allServices.filter((service) => { const matchesSearch = !searchTerm || service.title.toLowerCase().includes(searchTerm.toLowerCase()) || service.description.toLowerCase().includes(searchTerm.toLowerCase()); const matchesCategory = !selectedCategory || service.category === selectedCategory; return matchesSearch && matchesCategory; }); }, [allServices, searchTerm, selectedCategory]); if (loading && allServices.length === 0) { return ; } const bgClasses = getThemeBackgroundClasses(theme.theme_layout_mode); const heroBgClasses = getThemeHeroBackgroundClasses(theme.theme_layout_mode); const textClasses = getThemeTextClasses(theme.theme_layout_mode); const cardClasses = getThemeCardClasses(theme.theme_layout_mode); const inputClasses = getThemeInputClasses(theme.theme_layout_mode); return (
{/* Hero Section */}
{/* Background Effects */}

{pageContent?.luxury_services_section_title || 'Our Services'}

{pageContent?.luxury_services_section_subtitle || 'Discover our premium services designed to enhance your stay'}

Premium Services
{/* Main Content - Full Width */}
{/* Search Section */}
setSearchTerm(e.target.value)} className={`w-full pl-14 pr-5 py-4 ${inputClasses} border border-[var(--luxury-gold)]/20 rounded-xl placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[var(--luxury-gold)]/50 focus:border-[var(--luxury-gold)]/50 transition-all duration-300 backdrop-blur-sm font-light`} />
{/* Categories Filter - Top Center */} {allCategories.length > 0 && (
{allCategories.map((category) => ( ))}
)} {/* Services Section - Centered */}
{/* Results Count */} {!loading && filteredServices.length > 0 && (
Showing {filteredServices.length} of {allServices.length} services
)} {/* Services Grid - Luxury Design - Centered */} {filteredServices.length === 0 ? (

No services found

Try adjusting your search or filters

) : ( <>
{filteredServices.map((service, index) => { // Use the slug from the service object, or generate a fallback from title const serviceSlug = service.slug || service.title.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); if (!serviceSlug) { console.warn('Service missing slug:', service); } return ( {/* Premium Glow Effects */}
{/* Content */}
{service.image ? (
{service.title} {/* Premium Badge Overlay */} {service.type === 'luxury' && (
Premium
)} {/* Luxury Corner Accent */}
) : (
{service.icon && (LucideIcons as any)[service.icon] ? (
{React.createElement((LucideIcons as any)[service.icon], { className: 'w-16 h-16 sm:w-20 sm:h-20 text-[var(--luxury-gold)] relative z-10 drop-shadow-lg' })}
) : (
{React.createElement( getIconComponent(pageContent?.services_fallback_icon, Award), { className: 'w-16 h-16 sm:w-20 sm:h-20 text-[var(--luxury-gold)] relative z-10 drop-shadow-lg' } )}
)}
)}
{service.category && (
{service.category}
)}

{service.title}

{service.description && (

{service.description}

)} {service.price !== undefined && (
{formatCurrency(service.price)} {service.unit && ( / {service.unit} )}
)}
Learn More
); })}
)}
); }; export default ServicesPage;