From 99da0afecdca93560ae27f540e87a13297d320ce Mon Sep 17 00:00:00 2001 From: Iliyan Angelov Date: Fri, 5 Dec 2025 00:01:15 +0200 Subject: [PATCH] update --- ...nventory_management_tables.cpython-312.pyc | Bin 14712 -> 14712 bytes .../add_service_detail_fields.cpython-312.pyc | Bin 0 -> 2841 bytes .../add_staff_shifts_tables.cpython-312.pyc | Bin 0 -> 9091 bytes .../versions/add_service_detail_fields.py | 51 + .../seed_homepage_footer.cpython-312.pyc | Bin 0 -> 19790 bytes Backend/seeds_data/seed_homepage_footer.py | 55 +- Backend/seeds_data/seed_services.py | 218 ++++ .../seeds_data/seed_services_enterprise.py | 756 ++++++++++++++ Backend/src/__pycache__/main.cpython-312.pyc | Bin 28210 -> 28210 bytes .../__pycache__/service.cpython-312.pyc | Bin 1421 -> 1846 bytes Backend/src/hotel_services/models/service.py | 9 +- .../service_routes.cpython-312.pyc | Bin 11929 -> 17023 bytes .../hotel_services/routes/service_routes.py | 129 ++- Frontend/src/App.tsx | 15 + .../src/features/content/pages/HomePage.tsx | 99 +- .../content/pages/ServiceDetailPage.tsx | 709 +++++++++++++ .../features/content/pages/ServicesPage.tsx | 393 +++++++ .../content/services/pageContentService.ts | 56 +- .../hotel_services/services/serviceService.ts | 54 + .../src/pages/admin/PageContentDashboard.tsx | 972 +++++++++++++++--- .../pages/admin/ReceptionDashboardPage.tsx | 398 +------ .../src/pages/admin/ServiceManagementPage.tsx | 346 ++++++- .../src/pages/customer/RoomDetailPage.tsx | 9 + Frontend/src/shared/components/Navbar.tsx | 1 + 24 files changed, 3701 insertions(+), 569 deletions(-) create mode 100644 Backend/alembic/versions/__pycache__/add_service_detail_fields.cpython-312.pyc create mode 100644 Backend/alembic/versions/__pycache__/add_staff_shifts_tables.cpython-312.pyc create mode 100644 Backend/alembic/versions/add_service_detail_fields.py create mode 100644 Backend/seeds_data/__pycache__/seed_homepage_footer.cpython-312.pyc create mode 100644 Backend/seeds_data/seed_services.py create mode 100644 Backend/seeds_data/seed_services_enterprise.py create mode 100644 Frontend/src/features/content/pages/ServiceDetailPage.tsx create mode 100644 Frontend/src/features/content/pages/ServicesPage.tsx diff --git a/Backend/alembic/versions/__pycache__/add_inventory_management_tables.cpython-312.pyc b/Backend/alembic/versions/__pycache__/add_inventory_management_tables.cpython-312.pyc index 916e7c568162d407db224d8ee91d4df7e88a7d11..6d4a4910f867db8b0efeafdebeafec0036bd27a5 100644 GIT binary patch delta 18 YcmexS^rMLLG%qg~0}x!^$eC{m07J6|0ssI2 delta 18 YcmexS^rMLLG%qg~0}yQA$eC{m07EAQ<^TWy diff --git a/Backend/alembic/versions/__pycache__/add_service_detail_fields.cpython-312.pyc b/Backend/alembic/versions/__pycache__/add_service_detail_fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b01d96b2ac155c3f80de20ba170ba93a7d56015 GIT binary patch literal 2841 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 literal 0 HcmV?d00001 diff --git a/Backend/alembic/versions/add_service_detail_fields.py b/Backend/alembic/versions/add_service_detail_fields.py new file mode 100644 index 00000000..755192f4 --- /dev/null +++ b/Backend/alembic/versions/add_service_detail_fields.py @@ -0,0 +1,51 @@ +"""add_service_detail_fields + +Revision ID: service_detail_001 +Revises: staff_shifts_001 +Create Date: 2024-12-04 22:00:00.000000 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = 'service_detail_001' +down_revision = 'staff_shifts_001' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Add slug column with unique index + op.add_column('services', sa.Column('slug', sa.String(200), nullable=True)) + op.create_index(op.f('ix_services_slug'), 'services', ['slug'], unique=True) + + # Add image column + op.add_column('services', sa.Column('image', sa.String(1000), nullable=True)) + + # Add content column for full HTML content + op.add_column('services', sa.Column('content', sa.Text(), nullable=True)) + + # Add sections column for advanced content blocks (stored as JSON) + op.add_column('services', sa.Column('sections', sa.Text(), nullable=True)) + + # Add SEO meta fields + op.add_column('services', sa.Column('meta_title', sa.String(500), nullable=True)) + op.add_column('services', sa.Column('meta_description', sa.Text(), nullable=True)) + op.add_column('services', sa.Column('meta_keywords', sa.String(1000), nullable=True)) + + # Rename is_active to status for consistency (optional, but let's keep is_active and add status) + # Actually, let's keep is_active as is for backward compatibility + + +def downgrade() -> None: + op.drop_index(op.f('ix_services_slug'), table_name='services') + op.drop_column('services', 'meta_keywords') + op.drop_column('services', 'meta_description') + op.drop_column('services', 'meta_title') + op.drop_column('services', 'sections') + op.drop_column('services', 'content') + op.drop_column('services', 'image') + op.drop_column('services', 'slug') + diff --git a/Backend/seeds_data/__pycache__/seed_homepage_footer.cpython-312.pyc b/Backend/seeds_data/__pycache__/seed_homepage_footer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81890ff4cb773136655c318d42345e399b6660b6 GIT binary patch literal 19790 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 literal 0 HcmV?d00001 diff --git a/Backend/seeds_data/seed_homepage_footer.py b/Backend/seeds_data/seed_homepage_footer.py index 18b13836..e41e5654 100644 --- a/Backend/seeds_data/seed_homepage_footer.py +++ b/Backend/seeds_data/seed_homepage_footer.py @@ -12,7 +12,60 @@ def seed_homepage_content(db: Session): luxury_features = [{'icon': 'Sparkles', 'title': 'Premium Amenities', 'description': 'World-class facilities designed for your comfort and relaxation'}, {'icon': 'Crown', 'title': 'Royal Service', 'description': 'Dedicated concierge service available 24/7 for all your needs'}, {'icon': 'Award', 'title': 'Award-Winning', 'description': 'Recognized for excellence in hospitality and guest satisfaction'}, {'icon': 'Shield', 'title': 'Secure & Private', 'description': 'Your privacy and security are our top priorities'}, {'icon': 'Heart', 'title': 'Personalized Care', 'description': 'Tailored experiences crafted just for you'}, {'icon': 'Gem', 'title': 'Luxury Design', 'description': 'Elegantly designed spaces with attention to every detail'}] luxury_gallery = ['https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800', 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800', 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800', 'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=800', 'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=800', 'https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=800'] luxury_testimonials = [{'name': 'Sarah Johnson', 'title': 'Business Executive', 'quote': 'An absolutely stunning experience. The attention to detail and level of service exceeded all expectations.', 'image': 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200'}, {'name': 'Michael Chen', 'title': 'Travel Enthusiast', 'quote': 'The epitome of luxury. Every moment was perfect, from check-in to check-out.', 'image': 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200'}, {'name': 'Emma Williams', 'title': 'Luxury Traveler', 'quote': 'This hotel redefines what luxury means. I will definitely return.', 'image': 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200'}] - luxury_services = [{'icon': 'UtensilsCrossed', 'title': 'Fine Dining', 'description': 'Michelin-starred restaurants offering world-class cuisine', 'image': 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=600'}, {'icon': 'Wine', 'title': 'Premium Bar', 'description': 'Extensive wine collection and craft cocktails in elegant settings', 'image': 'https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?w=600'}, {'icon': 'Dumbbell', 'title': 'Spa & Wellness', 'description': 'Rejuvenating spa treatments and state-of-the-art fitness center', 'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=600'}, {'icon': 'Car', 'title': 'Concierge Services', 'description': 'Personalized assistance for all your travel and entertainment needs', 'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=600'}] + luxury_services = [ + { + 'icon': 'UtensilsCrossed', + 'title': 'Fine Dining', + 'description': 'Michelin-starred restaurants offering world-class cuisine', + 'image': 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=600', + 'slug': 'fine-dining', + 'category': 'Dining', + 'content': '

Experience culinary excellence at our Michelin-starred restaurants. Our world-renowned chefs craft exquisite dishes using the finest ingredients sourced from around the globe. From intimate dining experiences to grand celebrations, we offer a variety of settings to suit every occasion.

Our restaurants feature seasonal menus that showcase the best of local and international cuisine, paired with an extensive wine collection curated by our master sommelier.

', + 'sections': [], + 'meta_title': 'Fine Dining Experience - Luxury Hotel', + 'meta_description': 'Discover our Michelin-starred restaurants offering world-class cuisine in elegant settings.', + 'meta_keywords': 'fine dining, michelin star, luxury restaurant, gourmet cuisine' + }, + { + 'icon': 'Wine', + 'title': 'Premium Bar', + 'description': 'Extensive wine collection and craft cocktails in elegant settings', + 'image': 'https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?w=600', + 'slug': 'premium-bar', + 'category': 'Dining', + 'content': '

Unwind in sophistication at our premium bar, featuring an extensive collection of rare wines, vintage spirits, and expertly crafted cocktails. Our master mixologists create unique beverages tailored to your preferences.

The elegant ambiance, combined with live music on select evenings, creates the perfect setting for business meetings, romantic evenings, or casual gatherings with friends.

', + 'sections': [], + 'meta_title': 'Premium Bar & Lounge - Luxury Hotel', + 'meta_description': 'Enjoy an extensive wine collection and craft cocktails in our elegant bar and lounge.', + 'meta_keywords': 'premium bar, wine collection, craft cocktails, luxury lounge' + }, + { + 'icon': 'Dumbbell', + 'title': 'Spa & Wellness', + 'description': 'Rejuvenating spa treatments and state-of-the-art fitness center', + 'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=600', + 'slug': 'spa-wellness', + 'category': 'Wellness', + 'content': '

Escape to tranquility at our world-class spa and wellness center. Indulge in a range of rejuvenating treatments designed to restore balance and vitality. Our expert therapists use premium products and ancient techniques to provide an unparalleled wellness experience.

Our state-of-the-art fitness center is equipped with the latest equipment and offers personal training sessions, yoga classes, and wellness programs tailored to your needs.

', + 'sections': [], + 'meta_title': 'Spa & Wellness Center - Luxury Hotel', + 'meta_description': 'Rejuvenate with our spa treatments and state-of-the-art fitness facilities.', + 'meta_keywords': 'spa, wellness, fitness center, massage, luxury spa' + }, + { + 'icon': 'Car', + 'title': 'Concierge Services', + 'description': 'Personalized assistance for all your travel and entertainment needs', + 'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=600', + 'slug': 'concierge-services', + 'category': 'Services', + 'content': '

Our dedicated concierge team is available 24/7 to ensure your stay is nothing short of extraordinary. From restaurant reservations and event tickets to private tours and transportation arrangements, we handle every detail with precision and care.

Whether you need assistance with business arrangements, special celebrations, or unique local experiences, our concierge team has the expertise and connections to make it happen.

', + 'sections': [], + 'meta_title': 'Concierge Services - Luxury Hotel', + 'meta_description': 'Personalized assistance for all your travel and entertainment needs, available 24/7.', + 'meta_keywords': 'concierge, personal assistant, travel services, luxury service' + } + ] luxury_experiences = [{'icon': 'Sunset', 'title': 'Sunset Rooftop', 'description': 'Breathtaking views and exclusive rooftop experiences', 'image': 'https://images.unsplash.com/photo-1514933651103-005eec06c04b?w=600'}, {'icon': 'Ship', 'title': 'Yacht Excursions', 'description': 'Private yacht charters for unforgettable sea adventures', 'image': 'https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=600'}, {'icon': 'Music', 'title': 'Live Entertainment', 'description': 'World-class performances and exclusive events', 'image': 'https://images.unsplash.com/photo-1470229722913-7c0e2dbbafd3?w=600'}, {'icon': 'Palette', 'title': 'Art & Culture', 'description': 'Curated art collections and cultural experiences', 'image': 'https://images.unsplash.com/photo-1578301978018-3005759f48f7?w=600'}] awards = [{'icon': 'Trophy', 'title': 'Best Luxury Hotel 2024', 'description': 'Awarded by International Luxury Travel Association', 'image': 'https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5?w=400', 'year': '2024'}, {'icon': 'Star', 'title': '5-Star Excellence', 'description': 'Consistently rated 5 stars by leading travel publications', 'image': 'https://images.unsplash.com/photo-1606761568499-6d2451b23c66?w=400', 'year': '2023'}, {'icon': 'Award', 'title': 'Sustainable Luxury', 'description': 'Recognized for environmental responsibility and sustainability', 'image': 'https://images.unsplash.com/photo-1473341304170-971dccb5ac1e?w=400', 'year': '2024'}] partners = [{'name': 'Luxury Travel Group', 'logo': 'https://images.unsplash.com/photo-1599305445671-ac291c95aaa9?w=200', 'link': '#'}, {'name': 'Premium Airlines', 'logo': 'https://images.unsplash.com/photo-1436491865332-7a61a109cc05?w=200', 'link': '#'}, {'name': 'Exclusive Events', 'logo': 'https://images.unsplash.com/photo-1511578314322-379afb476865?w=200', 'link': '#'}, {'name': 'Fine Dining Network', 'logo': 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=200', 'link': '#'}] diff --git a/Backend/seeds_data/seed_services.py b/Backend/seeds_data/seed_services.py new file mode 100644 index 00000000..a382e99f --- /dev/null +++ b/Backend/seeds_data/seed_services.py @@ -0,0 +1,218 @@ +import sys +import os +import json +import re +from pathlib import Path +# Add parent directory to path to import from src +sys.path.insert(0, str(Path(__file__).parent.parent)) +from sqlalchemy.orm import Session +from src.shared.config.database import SessionLocal +# Import all models to ensure relationships are set up +from src.models import * # This ensures all models are loaded and relationships are configured +from src.hotel_services.models.service import Service + +def generate_slug(name: str) -> str: + """Generate a URL-friendly slug from a name""" + slug = name.lower() + slug = re.sub(r'[^a-z0-9\s-]', '', slug) + slug = re.sub(r'\s+', '-', slug) + slug = re.sub(r'-+', '-', slug) + return slug.strip('-') + +def seed_services(db: Session): + """Seed initial services data""" + print('Seeding services...') + + services_data = [ + { + 'name': 'Room Service', + 'description': '24/7 in-room dining service with a wide selection of gourmet meals, snacks, and beverages delivered directly to your room.', + 'price': 25.00, + 'category': 'Dining', + 'slug': 'room-service', + 'image': 'https://images.unsplash.com/photo-1556911220-bff31c812dba?w=600', + 'content': '

Enjoy the convenience of 24/7 room service with our extensive menu featuring international cuisine, local specialties, and premium beverages. Our professional staff ensures your meals are delivered hot, fresh, and beautifully presented.

From breakfast in bed to late-night snacks, we cater to all your dining needs with the highest standards of quality and service.

', + 'sections': json.dumps([]), + 'meta_title': 'Room Service - Luxury Hotel', + 'meta_description': '24/7 in-room dining service with gourmet meals delivered to your room.', + 'meta_keywords': 'room service, in-room dining, hotel service, 24/7 service', + 'is_active': True + }, + { + 'name': 'Spa & Massage', + 'description': 'Relaxing spa treatments and professional massage therapy to rejuvenate your mind and body.', + 'price': 120.00, + 'category': 'Wellness', + 'slug': 'spa-massage', + 'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=600', + 'content': '

Indulge in our world-class spa treatments designed to restore balance and vitality. Our expert therapists offer a range of services including Swedish massage, deep tissue massage, hot stone therapy, and aromatherapy.

Each treatment is customized to your preferences, using premium products and ancient techniques to provide an unparalleled wellness experience.

', + 'sections': json.dumps([]), + 'meta_title': 'Spa & Massage Services - Luxury Hotel', + 'meta_description': 'Professional spa treatments and massage therapy for ultimate relaxation and rejuvenation.', + 'meta_keywords': 'spa, massage, wellness, relaxation, therapy', + 'is_active': True + }, + { + 'name': 'Laundry Service', + 'description': 'Professional dry cleaning and laundry service with same-day or next-day delivery options.', + 'price': 15.00, + 'category': 'Housekeeping', + 'slug': 'laundry-service', + 'image': 'https://images.unsplash.com/photo-1582735689369-4fe89db7114c?w=600', + 'content': '

Keep your wardrobe fresh and clean with our professional laundry and dry cleaning service. We handle everything from delicate garments to business suits with the utmost care and attention.

Choose from same-day express service or standard next-day delivery. All items are professionally cleaned, pressed, and returned to your room.

', + 'sections': json.dumps([]), + 'meta_title': 'Laundry & Dry Cleaning Service - Luxury Hotel', + 'meta_description': 'Professional laundry and dry cleaning service with same-day or next-day delivery.', + 'meta_keywords': 'laundry, dry cleaning, hotel service, cleaning', + 'is_active': True + }, + { + 'name': 'Airport Transfer', + 'description': 'Complimentary airport pickup and drop-off service in luxury vehicles with professional drivers.', + 'price': 50.00, + 'category': 'Transportation', + 'slug': 'airport-transfer', + 'image': 'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=600', + 'content': '

Travel in comfort and style with our premium airport transfer service. Our fleet of luxury vehicles, including sedans and SUVs, ensures a smooth and comfortable journey to or from the airport.

Our professional drivers are punctual, courteous, and knowledgeable about the local area. Flight monitoring ensures we adjust to any delays or early arrivals.

', + 'sections': json.dumps([]), + 'meta_title': 'Airport Transfer Service - Luxury Hotel', + 'meta_description': 'Premium airport pickup and drop-off service in luxury vehicles.', + 'meta_keywords': 'airport transfer, transportation, airport shuttle, luxury car', + 'is_active': True + }, + { + 'name': 'Concierge Service', + 'description': 'Personalized assistance for restaurant reservations, event tickets, tours, and special requests.', + 'price': 0.00, + 'category': 'Concierge', + 'slug': 'concierge-service', + 'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=600', + 'content': '

Our dedicated concierge team is available 24/7 to ensure your stay is nothing short of extraordinary. From restaurant reservations and event tickets to private tours and transportation arrangements, we handle every detail with precision and care.

Whether you need assistance with business arrangements, special celebrations, or unique local experiences, our concierge team has the expertise and connections to make it happen.

', + 'sections': json.dumps([]), + 'meta_title': 'Concierge Services - Luxury Hotel', + 'meta_description': 'Personalized assistance for all your travel and entertainment needs, available 24/7.', + 'meta_keywords': 'concierge, personal assistant, travel services, luxury service', + 'is_active': True + }, + { + 'name': 'Fitness Center Access', + 'description': 'Access to our state-of-the-art fitness center with modern equipment and personal training options.', + 'price': 20.00, + 'category': 'Wellness', + 'slug': 'fitness-center', + 'image': 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=600', + 'content': '

Maintain your fitness routine at our fully equipped fitness center featuring the latest cardio and strength training equipment. Our facilities are open 24/7 for your convenience.

Enhance your workout with personal training sessions, group fitness classes, or yoga sessions led by certified instructors. Towels, water, and fresh fruit are provided.

', + 'sections': json.dumps([]), + 'meta_title': 'Fitness Center - Luxury Hotel', + 'meta_description': 'State-of-the-art fitness center with modern equipment and personal training options.', + 'meta_keywords': 'fitness center, gym, workout, exercise, personal training', + 'is_active': True + }, + { + 'name': 'Business Center', + 'description': 'Fully equipped business center with meeting rooms, printing, copying, and secretarial services.', + 'price': 30.00, + 'category': 'Business', + 'slug': 'business-center', + 'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=600', + 'content': '

Stay productive with our fully equipped business center featuring private meeting rooms, high-speed internet, printing and copying services, and professional secretarial support.

Our meeting rooms can accommodate small groups and are equipped with presentation equipment, video conferencing capabilities, and refreshments.

', + 'sections': json.dumps([]), + 'meta_title': 'Business Center Services - Luxury Hotel', + 'meta_description': 'Fully equipped business center with meeting rooms and professional services.', + 'meta_keywords': 'business center, meeting room, conference, office services', + 'is_active': True + }, + { + 'name': 'Valet Parking', + 'description': 'Secure valet parking service with 24/7 vehicle care and quick retrieval.', + 'price': 35.00, + 'category': 'Transportation', + 'slug': 'valet-parking', + 'image': 'https://images.unsplash.com/photo-1502877338535-766e1452684a?w=600', + 'content': '

Enjoy the convenience of valet parking with our professional service. Your vehicle will be safely parked and secured, ready for quick retrieval whenever you need it.

Our valet team is available 24/7 and can also assist with luggage handling and vehicle care services.

', + 'sections': json.dumps([]), + 'meta_title': 'Valet Parking Service - Luxury Hotel', + 'meta_description': 'Secure valet parking service with 24/7 vehicle care and quick retrieval.', + 'meta_keywords': 'valet parking, parking service, car service, vehicle care', + 'is_active': True + }, + { + 'name': 'Babysitting Service', + 'description': 'Professional and certified babysitting service for your peace of mind.', + 'price': 25.00, + 'category': 'Family', + 'slug': 'babysitting-service', + 'image': 'https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?w=600', + 'content': '

Enjoy your time knowing your children are in safe hands with our professional babysitting service. Our certified caregivers are experienced, background-checked, and trained in child safety and first aid.

Available for both in-room care and supervised activities, we ensure your children are entertained and well-cared for while you enjoy your stay.

', + 'sections': json.dumps([]), + 'meta_title': 'Babysitting Service - Luxury Hotel', + 'meta_description': 'Professional and certified babysitting service for your peace of mind.', + 'meta_keywords': 'babysitting, childcare, kids service, family service', + 'is_active': True + }, + { + 'name': 'Pet Care Service', + 'description': 'Pet-friendly accommodations with pet care services including walking, feeding, and grooming.', + 'price': 20.00, + 'category': 'Pet Services', + 'slug': 'pet-care-service', + 'image': 'https://images.unsplash.com/photo-1601758228041-f3b2795255f1?w=600', + 'content': '

Your furry friends are welcome at our hotel! We offer pet-friendly accommodations and a range of pet care services including daily walks, feeding, and grooming.

Our pet care team ensures your pets are comfortable and well-cared for during your stay. Pet amenities including beds, bowls, and treats are provided.

', + 'sections': json.dumps([]), + 'meta_title': 'Pet Care Services - Luxury Hotel', + 'meta_description': 'Pet-friendly accommodations with professional pet care services.', + 'meta_keywords': 'pet care, pet service, dog walking, pet friendly', + 'is_active': True + } + ] + + created_count = 0 + updated_count = 0 + + for service_data in services_data: + # Check if service already exists by slug + existing = db.query(Service).filter(Service.slug == service_data['slug']).first() + + if existing: + # Update existing service + for key, value in service_data.items(): + if key != 'slug': # Don't update slug + setattr(existing, key, value) + updated_count += 1 + print(f' ✓ Updated service: {service_data["name"]}') + else: + # Create new service + service = Service(**service_data) + db.add(service) + created_count += 1 + print(f' ✓ Created service: {service_data["name"]}') + + db.commit() + print(f'\n✓ Services seeded successfully!') + print(f' - Created: {created_count}') + print(f' - Updated: {updated_count}') + print(f' - Total: {len(services_data)}\n') + +def main(): + db: Session = SessionLocal() + try: + print('=' * 80) + print('SEEDING SERVICES') + print('=' * 80) + print() + seed_services(db) + print('=' * 80) + print('✓ All services data seeded successfully!') + print('=' * 80) + except Exception as e: + db.rollback() + print(f'\n✗ Error seeding services: {e}') + import traceback + traceback.print_exc() + raise + finally: + db.close() + +if __name__ == '__main__': + main() + diff --git a/Backend/seeds_data/seed_services_enterprise.py b/Backend/seeds_data/seed_services_enterprise.py new file mode 100644 index 00000000..b2190617 --- /dev/null +++ b/Backend/seeds_data/seed_services_enterprise.py @@ -0,0 +1,756 @@ +import sys +import os +import json +import re +from pathlib import Path +# Add parent directory to path to import from src +sys.path.insert(0, str(Path(__file__).parent.parent)) +from sqlalchemy.orm import Session +from src.shared.config.database import SessionLocal +# Import all models to ensure relationships are set up +from src.models import * # This ensures all models are loaded and relationships are configured +from src.hotel_services.models.service import Service + +def generate_slug(name: str) -> str: + """Generate a URL-friendly slug from a name""" + slug = name.lower() + slug = re.sub(r'[^a-z0-9\s-]', '', slug) + slug = re.sub(r'\s+', '-', slug) + slug = re.sub(r'-+', '-', slug) + return slug.strip('-') + +def seed_enterprise_services(db: Session): + """Seed enterprise-level services with rich detail page content""" + print('Seeding enterprise services...') + + services_data = [ + { + 'name': 'Luxury Spa & Wellness Retreat', + 'description': 'Indulge in our world-class spa treatments designed to restore balance and vitality. Experience ultimate relaxation with our expert therapists.', + 'price': 250.00, + 'category': 'Wellness', + 'slug': 'luxury-spa-wellness-retreat', + 'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop', + 'content': '''
+

Experience Ultimate Relaxation

+

Our Luxury Spa & Wellness Retreat offers an unparalleled journey of rejuvenation and tranquility. Nestled in a serene environment, our spa combines ancient healing traditions with modern wellness techniques to create a transformative experience.

+ +

What's Included

+
    +
  • 90-minute signature massage therapy
  • +
  • Access to steam room and sauna
  • +
  • Complimentary herbal tea and refreshments
  • +
  • Premium aromatherapy oils and products
  • +
  • Relaxation lounge access
  • +
+ +

Our Signature Treatments

+

Choose from our curated selection of treatments including Swedish massage, deep tissue therapy, hot stone massage, and aromatherapy sessions. Each treatment is customized to your specific needs and preferences.

+ +

Expert Therapists

+

Our team of certified therapists brings years of experience and a deep understanding of holistic wellness. They are trained in various massage techniques and wellness practices to ensure you receive the highest quality care.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Transform Your Wellbeing', + 'content': 'Discover a sanctuary of peace and rejuvenation where every detail is designed to restore your mind, body, and spirit.', + 'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Why Choose Our Spa', + 'features': [ + {'title': 'Expert Therapists', 'description': 'Certified professionals with years of experience', 'icon': 'User'}, + {'title': 'Premium Products', 'description': 'Luxury skincare and aromatherapy products', 'icon': 'Sparkles'}, + {'title': 'Customized Treatments', 'description': 'Personalized sessions tailored to your needs', 'icon': 'Heart'}, + {'title': 'Serene Environment', 'description': 'Peaceful setting designed for relaxation', 'icon': 'Leaf'} + ] + }, + { + 'type': 'quote', + 'quote': 'The most luxurious spa experience I\'ve ever had. Truly transformative.', + 'author': 'Sarah M., Guest' + } + ]), + 'meta_title': 'Luxury Spa & Wellness Retreat - Premium Hotel Services', + 'meta_description': 'Experience ultimate relaxation with our world-class spa treatments. Expert therapists, premium products, and a serene environment await you.', + 'meta_keywords': 'luxury spa, wellness retreat, massage therapy, hotel spa, relaxation, aromatherapy, wellness services', + 'is_active': True + }, + { + 'name': 'Fine Dining Experience', + 'description': 'Savor culinary excellence at our Michelin-starred restaurants. World-renowned chefs craft exquisite dishes using the finest ingredients.', + 'price': 150.00, + 'category': 'Dining', + 'slug': 'fine-dining-experience', + 'image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1200&h=800&fit=crop', + 'content': '''
+

Culinary Excellence Awaits

+

Embark on a gastronomic journey at our award-winning restaurants, where culinary artistry meets exceptional service. Our Michelin-starred chefs create masterpieces that celebrate both local traditions and international flavors.

+ +

Our Restaurants

+
    +
  • The Grand Ballroom: Elegant fine dining with seasonal tasting menus
  • +
  • Sky Terrace: Rooftop dining with panoramic city views
  • +
  • Chef's Table: Intimate 8-seat private dining experience
  • +
  • Wine Cellar: Exclusive wine pairing dinners
  • +
+ +

What's Included

+
    +
  • Multi-course tasting menu
  • +
  • Wine pairing recommendations
  • +
  • Complimentary amuse-bouche
  • +
  • Professional sommelier service
  • +
  • Personalized menu customization
  • +
+ +

Reservation Information

+

Reservations are recommended and can be made through our concierge or directly at the restaurant. Special dietary requirements and preferences are accommodated with advance notice.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'A Culinary Journey Like No Other', + 'content': 'Where every dish tells a story and every meal becomes a memory.', + 'image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1200&h=600&fit=crop' + }, + { + 'type': 'gallery', + 'title': 'Our Culinary Creations', + 'images': [ + 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=800', + 'https://images.unsplash.com/photo-1556911220-bff31c812dba?w=800', + 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=800' + ] + }, + { + 'type': 'quote', + 'quote': 'An extraordinary dining experience that exceeded all expectations. The attention to detail is remarkable.', + 'author': 'Michael R., Food Critic' + } + ]), + 'meta_title': 'Fine Dining Experience - Michelin-Starred Restaurant', + 'meta_description': 'Savor culinary excellence at our Michelin-starred restaurants. World-renowned chefs, exquisite dishes, and exceptional service.', + 'meta_keywords': 'fine dining, michelin star, luxury restaurant, gourmet cuisine, fine dining hotel', + 'is_active': True + }, + { + 'name': '24/7 Premium Room Service', + 'description': 'Enjoy the convenience of round-the-clock in-room dining with our extensive menu featuring international cuisine and premium beverages.', + 'price': 35.00, + 'category': 'Dining', + 'slug': 'premium-room-service', + 'image': 'https://images.unsplash.com/photo-1556911220-bff31c812dba?w=1200&h=800&fit=crop', + 'content': '''
+

Dining at Your Convenience

+

Experience the ultimate in-room dining service available 24 hours a day. From breakfast in bed to late-night snacks, our extensive menu caters to every craving with the highest standards of quality and presentation.

+ +

Menu Highlights

+
    +
  • Breakfast: Continental, American, and healthy options
  • +
  • Lunch & Dinner: International cuisine, local specialties, and chef's recommendations
  • +
  • Desserts: Artisanal pastries and premium ice creams
  • +
  • Beverages: Premium wines, craft cocktails, and specialty coffees
  • +
+ +

Service Features

+
    +
  • Average delivery time: 25-30 minutes
  • +
  • Professional table setup in your room
  • +
  • Hot meals served at optimal temperature
  • +
  • Special dietary accommodations available
  • +
  • Complimentary bread and butter service
  • +
+ +

How to Order

+

Simply call our room service line from your in-room phone or use our mobile app. Our team is available 24/7 to take your order and ensure prompt delivery.

+
''', + 'sections': json.dumps([ + { + 'type': 'features', + 'title': 'Why Choose Our Room Service', + 'features': [ + {'title': '24/7 Availability', 'description': 'Order anytime, day or night', 'icon': 'Clock'}, + {'title': 'Fast Delivery', 'description': 'Average 25-30 minute delivery time', 'icon': 'Zap'}, + {'title': 'Premium Quality', 'description': 'Restaurant-quality meals in your room', 'icon': 'Award'}, + {'title': 'Professional Service', 'description': 'Elegant table setup and presentation', 'icon': 'UserCheck'} + ] + } + ]), + 'meta_title': '24/7 Premium Room Service - Luxury Hotel', + 'meta_description': 'Enjoy round-the-clock in-room dining with our extensive menu. International cuisine, premium beverages, and professional service delivered to your room.', + 'meta_keywords': 'room service, in-room dining, 24/7 service, hotel dining, room service menu', + 'is_active': True + }, + { + 'name': 'Executive Business Center', + 'description': 'Fully equipped business center with private meeting rooms, high-speed internet, printing services, and professional secretarial support.', + 'price': 75.00, + 'category': 'Business', + 'slug': 'executive-business-center', + 'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop', + 'content': '''
+

Your Office Away From Office

+

Stay productive with our state-of-the-art Executive Business Center, designed to meet all your professional needs. Whether you need a quiet workspace, a meeting room, or professional support services, we have everything you need.

+ +

Facilities & Services

+
    +
  • Private Meeting Rooms: Various sizes accommodating 2-20 people
  • +
  • High-Speed Internet: Fiber-optic connection with secure Wi-Fi
  • +
  • Printing & Copying: Color and black & white printing, scanning, and binding
  • +
  • Presentation Equipment: Projectors, screens, video conferencing
  • +
  • Secretarial Services: Typing, translation, and administrative support
  • +
  • Refreshments: Complimentary coffee, tea, and water
  • +
+ +

Meeting Room Features

+
    +
  • Soundproof walls for privacy
  • +
  • Ergonomic seating and modern furniture
  • +
  • Whiteboards and flip charts
  • +
  • Video conferencing capabilities
  • +
  • Climate control and natural lighting
  • +
+ +

Reservation

+

Meeting rooms can be reserved in advance through our concierge or business center. Hourly and daily rates available. Special packages for extended stays.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Productivity Meets Luxury', + 'content': 'A professional workspace designed for success, equipped with everything you need to stay productive.', + 'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Everything You Need', + 'features': [ + {'title': 'Private Meeting Rooms', 'description': 'Various sizes for any business need', 'icon': 'Users'}, + {'title': 'High-Speed Internet', 'description': 'Fiber-optic connection with secure Wi-Fi', 'icon': 'Wifi'}, + {'title': 'Professional Support', 'description': 'Secretarial and administrative services', 'icon': 'Briefcase'}, + {'title': 'Modern Equipment', 'description': 'Latest technology and presentation tools', 'icon': 'Monitor'} + ] + } + ]), + 'meta_title': 'Executive Business Center - Professional Workspace', + 'meta_description': 'Fully equipped business center with meeting rooms, high-speed internet, printing services, and professional support. Your office away from office.', + 'meta_keywords': 'business center, meeting room, conference room, office services, hotel business center', + 'is_active': True + }, + { + 'name': 'Luxury Airport Transfer', + 'description': 'Travel in comfort and style with our premium airport transfer service. Luxury vehicles, professional drivers, and flight monitoring for a seamless journey.', + 'price': 85.00, + 'category': 'Transportation', + 'slug': 'luxury-airport-transfer', + 'image': 'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=1200&h=800&fit=crop', + 'content': '''
+

Arrive in Style

+

Begin or end your journey with our premium airport transfer service. Our fleet of luxury vehicles and professional drivers ensure a comfortable, punctual, and stress-free experience.

+ +

Our Fleet

+
    +
  • Luxury Sedans: Premium sedans for up to 3 passengers
  • +
  • Executive SUVs: Spacious SUVs for up to 6 passengers
  • +
  • Luxury Vans: Large vehicles for groups up to 8 passengers
  • +
  • VIP Limousines: Ultimate luxury for special occasions
  • +
+ +

Service Features

+
    +
  • Flight monitoring for delays and early arrivals
  • +
  • Meet & greet service at the airport
  • +
  • Complimentary bottled water and newspapers
  • +
  • Luggage assistance
  • +
  • Wi-Fi connectivity in vehicles
  • +
  • Professional, licensed, and insured drivers
  • +
+ +

Booking Information

+

Reservations should be made at least 24 hours in advance. Please provide flight details for arrival transfers. Our team monitors flights and adjusts pickup times accordingly.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Your Journey Starts Here', + 'content': 'Experience the comfort and convenience of premium airport transfers.', + 'image': 'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Why Choose Our Transfer Service', + 'features': [ + {'title': 'Luxury Fleet', 'description': 'Premium vehicles for every need', 'icon': 'Car'}, + {'title': 'Professional Drivers', 'description': 'Licensed, experienced, and courteous', 'icon': 'User'}, + {'title': 'Flight Monitoring', 'description': 'Automatic updates for delays', 'icon': 'Plane'}, + {'title': 'Complimentary Amenities', 'description': 'Water, Wi-Fi, and newspapers', 'icon': 'Gift'} + ] + } + ]), + 'meta_title': 'Luxury Airport Transfer - Premium Transportation', + 'meta_description': 'Travel in comfort with our premium airport transfer service. Luxury vehicles, professional drivers, and flight monitoring for a seamless journey.', + 'meta_keywords': 'airport transfer, luxury transportation, airport shuttle, hotel transfer, airport service', + 'is_active': True + }, + { + 'name': 'Personal Concierge Service', + 'description': 'Dedicated 24/7 concierge assistance for restaurant reservations, event tickets, tours, transportation, and all your special requests.', + 'price': 0.00, + 'category': 'Concierge', + 'slug': 'personal-concierge-service', + 'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&h=800&fit=crop', + 'content': '''
+

Your Personal Assistant

+

Our dedicated concierge team is available 24/7 to ensure your stay is nothing short of extraordinary. From restaurant reservations and event tickets to private tours and unique experiences, we handle every detail with precision and care.

+ +

Services We Provide

+
    +
  • Dining: Restaurant reservations at the finest establishments
  • +
  • Entertainment: Theater tickets, concerts, and event access
  • +
  • Tours & Activities: Private tours, cultural experiences, and adventure activities
  • +
  • Transportation: Car rentals, chauffeur services, and travel arrangements
  • +
  • Business Services: Meeting room bookings, translation services, and more
  • +
  • Special Requests: Gift arrangements, celebrations, and unique experiences
  • +
+ +

How We Can Help

+

Whether you need last-minute reservations at a popular restaurant, tickets to a sold-out show, or help planning a special celebration, our concierge team has the expertise and connections to make it happen. No request is too big or too small.

+ +

Contact Us

+

Reach our concierge team 24/7 via phone, email, or in-person at the concierge desk. We're here to make your stay unforgettable.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Making Your Dreams Come True', + 'content': 'Your personal assistant, available 24/7 to fulfill every request.', + 'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&h=600&fit=crop' + }, + { + 'type': 'cta', + 'title': 'Need Assistance?', + 'cta_text': 'Contact Our Concierge', + 'cta_link': '/contact', + 'content': 'Our team is standing by to help with any request, big or small.' + } + ]), + 'meta_title': 'Personal Concierge Service - 24/7 Assistance', + 'meta_description': 'Dedicated 24/7 concierge service for restaurant reservations, event tickets, tours, and all your special requests. Making your stay extraordinary.', + 'meta_keywords': 'concierge service, personal assistant, hotel concierge, travel services, luxury service', + 'is_active': True + }, + { + 'name': 'State-of-the-Art Fitness Center', + 'description': 'Access our fully equipped fitness center with modern equipment, personal training options, and group fitness classes. Open 24/7 for your convenience.', + 'price': 30.00, + 'category': 'Wellness', + 'slug': 'fitness-center-access', + 'image': 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=1200&h=800&fit=crop', + 'content': '''
+

Stay Fit, Stay Strong

+

Maintain your fitness routine at our state-of-the-art fitness center featuring the latest cardio and strength training equipment. Our facilities are designed to meet the needs of both casual exercisers and serious athletes.

+ +

Equipment & Facilities

+
    +
  • Cardio Equipment: Treadmills, ellipticals, stationary bikes, and rowing machines
  • +
  • Strength Training: Free weights, weight machines, and functional training equipment
  • +
  • Group Fitness Studio: Space for yoga, Pilates, and group classes
  • +
  • Locker Rooms: Spacious lockers, showers, and sauna access
  • +
  • Complimentary Amenities: Towels, water, fresh fruit, and protein bars
  • +
+ +

Additional Services

+
    +
  • Personal Training: One-on-one sessions with certified trainers
  • +
  • Group Classes: Yoga, Pilates, spinning, and HIIT classes
  • +
  • Fitness Assessments: Body composition analysis and fitness evaluations
  • +
  • Nutritional Guidance: Consultation with our wellness experts
  • +
+ +

Operating Hours

+

Our fitness center is open 24/7 for your convenience. Personal training and group classes are available by appointment. Check the schedule at the front desk or contact our fitness team.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Your Fitness Journey Continues', + 'content': 'World-class equipment and expert guidance to help you achieve your fitness goals.', + 'image': 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Why Our Fitness Center', + 'features': [ + {'title': '24/7 Access', 'description': 'Work out on your schedule', 'icon': 'Clock'}, + {'title': 'Modern Equipment', 'description': 'Latest cardio and strength training machines', 'icon': 'Activity'}, + {'title': 'Expert Trainers', 'description': 'Certified personal trainers available', 'icon': 'User'}, + {'title': 'Group Classes', 'description': 'Yoga, Pilates, and more', 'icon': 'Users'} + ] + } + ]), + 'meta_title': 'State-of-the-Art Fitness Center - 24/7 Access', + 'meta_description': 'Fully equipped fitness center with modern equipment, personal training, and group classes. Open 24/7 for your convenience.', + 'meta_keywords': 'fitness center, gym, hotel gym, workout, exercise, personal training, 24/7 gym', + 'is_active': True + }, + { + 'name': 'Premium Laundry & Dry Cleaning', + 'description': 'Professional laundry and dry cleaning service with same-day express or next-day standard delivery. Expert care for all your garments.', + 'price': 20.00, + 'category': 'Housekeeping', + 'slug': 'premium-laundry-dry-cleaning', + 'image': 'https://images.unsplash.com/photo-1582735689369-4fe89db7114c?w=1200&h=800&fit=crop', + 'content': '''
+

Expert Garment Care

+

Keep your wardrobe fresh and impeccably maintained with our professional laundry and dry cleaning service. We handle everything from delicate silk garments to business suits with the utmost care and attention to detail.

+ +

Our Services

+
    +
  • Dry Cleaning: Professional cleaning for suits, dresses, and delicate fabrics
  • +
  • Laundry Service: Washing, drying, and pressing for everyday garments
  • +
  • Pressing Only: Professional pressing and steaming services
  • +
  • Alterations: Minor repairs and adjustments available
  • +
  • Specialty Items: Wedding dresses, formal wear, and designer garments
  • +
+ +

Delivery Options

+
    +
  • Express Service: Same-day delivery (orders before 9 AM)
  • +
  • Standard Service: Next-day delivery
  • +
  • Bulk Service: Special rates for multiple items
  • +
+ +

How to Use

+

Simply place your items in the laundry bag provided in your room and call housekeeping. Our team will collect your items, process them with care, and return them to your room at the specified time.

+
''', + 'sections': json.dumps([ + { + 'type': 'features', + 'title': 'Why Choose Our Service', + 'features': [ + {'title': 'Expert Care', 'description': 'Professional handling of all garment types', 'icon': 'Shield'}, + {'title': 'Fast Service', 'description': 'Same-day express option available', 'icon': 'Zap'}, + {'title': 'Quality Guarantee', 'description': 'Satisfaction guaranteed on all services', 'icon': 'CheckCircle'}, + {'title': 'Eco-Friendly', 'description': 'Environmentally conscious cleaning methods', 'icon': 'Leaf'} + ] + } + ]), + 'meta_title': 'Premium Laundry & Dry Cleaning - Professional Service', + 'meta_description': 'Professional laundry and dry cleaning with same-day or next-day delivery. Expert care for all your garments.', + 'meta_keywords': 'laundry service, dry cleaning, hotel laundry, garment care, cleaning service', + 'is_active': True + }, + { + 'name': 'Valet Parking Service', + 'description': 'Secure valet parking with 24/7 vehicle care, quick retrieval, and optional car wash services. Your vehicle is in safe hands.', + 'price': 45.00, + 'category': 'Transportation', + 'slug': 'valet-parking-service', + 'image': 'https://images.unsplash.com/photo-1502877338535-766e1452684a?w=1200&h=800&fit=crop', + 'content': '''
+

Secure & Convenient Parking

+

Enjoy the ultimate convenience of valet parking with our professional service. Your vehicle will be safely parked and secured, ready for quick retrieval whenever you need it. Our valet team is available 24/7 to assist you.

+ +

Service Features

+
    +
  • Secure, monitored parking facility
  • +
  • 24/7 valet service availability
  • +
  • Quick vehicle retrieval (average 5 minutes)
  • +
  • Complimentary vehicle inspection
  • +
  • Luggage assistance included
  • +
  • Optional car wash and detailing services
  • +
+ +

Additional Services

+
    +
  • Car Wash: Exterior wash and interior vacuum
  • +
  • Detailing: Full interior and exterior detailing
  • +
  • Battery Jump Start: Assistance with vehicle issues
  • +
  • Tire Pressure Check: Complimentary tire service
  • +
+ +

Pricing

+

Daily rates available for extended stays. Weekly and monthly packages offer significant savings. Contact our valet team for special rates.

+
''', + 'sections': json.dumps([ + { + 'type': 'features', + 'title': 'Why Choose Our Valet Service', + 'features': [ + {'title': 'Secure Facility', 'description': 'Monitored and protected parking', 'icon': 'Shield'}, + {'title': 'Quick Service', 'description': 'Average 5-minute retrieval time', 'icon': 'Clock'}, + {'title': '24/7 Availability', 'description': 'Service available around the clock', 'icon': 'Sun'}, + {'title': 'Additional Services', 'description': 'Car wash and detailing available', 'icon': 'Sparkles'} + ] + } + ]), + 'meta_title': 'Valet Parking Service - Secure & Convenient', + 'meta_description': 'Secure valet parking with 24/7 service, quick retrieval, and optional car care services. Your vehicle is in safe hands.', + 'meta_keywords': 'valet parking, parking service, hotel parking, car service, valet', + 'is_active': True + }, + { + 'name': 'Professional Babysitting Service', + 'description': 'Certified and experienced babysitters available for in-room care and supervised activities. Background-checked professionals for your peace of mind.', + 'price': 35.00, + 'category': 'Family', + 'slug': 'professional-babysitting-service', + 'image': 'https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?w=1200&h=800&fit=crop', + 'content': '''
+

Your Children in Safe Hands

+

Enjoy your time knowing your children are in the care of our professional babysitting service. Our certified caregivers are experienced, background-checked, and trained in child safety and first aid.

+ +

Our Caregivers

+
    +
  • Certified in CPR and first aid
  • +
  • Background-checked and verified
  • +
  • Experienced with children of all ages
  • +
  • Multilingual capabilities available
  • +
  • References available upon request
  • +
+ +

Services Offered

+
    +
  • In-Room Care: Supervised care in your hotel room
  • +
  • Activity Supervision: Accompany children to hotel activities
  • +
  • Evening Care: Bedtime routines and overnight care
  • +
  • Group Care: Multiple children from the same family
  • +
+ +

Booking Information

+

Reservations should be made at least 4 hours in advance. Same-day service may be available subject to caregiver availability. Minimum booking: 2 hours.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Peace of Mind for Parents', + 'content': 'Certified professionals ensuring your children are safe, happy, and well-cared for.', + 'image': 'https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Why Parents Trust Us', + 'features': [ + {'title': 'Certified Caregivers', 'description': 'CPR and first aid certified', 'icon': 'Shield'}, + {'title': 'Background Checked', 'description': 'Thoroughly vetted professionals', 'icon': 'UserCheck'}, + {'title': 'Experienced', 'description': 'Years of childcare experience', 'icon': 'Heart'}, + {'title': 'Flexible Service', 'description': 'In-room or activity supervision', 'icon': 'Clock'} + ] + } + ]), + 'meta_title': 'Professional Babysitting Service - Certified Caregivers', + 'meta_description': 'Certified and experienced babysitters for in-room care and supervised activities. Background-checked professionals for your peace of mind.', + 'meta_keywords': 'babysitting service, childcare, hotel babysitting, kids care, family services', + 'is_active': True + }, + { + 'name': 'Pet Care & Accommodation', + 'description': 'Pet-friendly accommodations with professional pet care services including walking, feeding, grooming, and pet-sitting. Your furry friends are welcome!', + 'price': 25.00, + 'category': 'Pet Services', + 'slug': 'pet-care-accommodation', + 'image': 'https://images.unsplash.com/photo-1601758228041-f3b2795255f1?w=1200&h=800&fit=crop', + 'content': '''
+

Your Pets Are Family Too

+

We welcome your furry family members! Our pet-friendly accommodations and professional pet care services ensure your pets are as comfortable and well-cared for as you are during your stay.

+ +

Pet Amenities

+
    +
  • Comfortable pet beds and blankets
  • +
  • Food and water bowls
  • +
  • Complimentary treats and toys
  • +
  • Pet waste bags and disposal
  • +
  • Designated pet relief areas
  • +
+ +

Pet Care Services

+
    +
  • Dog Walking: Regular walks and exercise
  • +
  • Pet Sitting: In-room care while you're away
  • +
  • Feeding Service: Scheduled feeding times
  • +
  • Grooming: Basic grooming and bathing
  • +
  • Veterinary Referrals: Local vet recommendations
  • +
+ +

Pet Policy

+

Pets up to 50 lbs are welcome. A pet fee applies per night. Please inform us in advance about your pet's stay. We ask that pets be leashed in public areas and that owners clean up after their pets.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'A Home Away From Home for Your Pets', + 'content': 'Because your pets deserve the same luxury experience as you.', + 'image': 'https://images.unsplash.com/photo-1601758228041-f3b2795255f1?w=1200&h=600&fit=crop' + }, + { + 'type': 'features', + 'title': 'Pet-Friendly Features', + 'features': [ + {'title': 'Pet Amenities', 'description': 'Beds, bowls, treats, and toys provided', 'icon': 'Heart'}, + {'title': 'Professional Care', 'description': 'Walking, feeding, and grooming services', 'icon': 'User'}, + {'title': 'Designated Areas', 'description': 'Pet relief areas and walking paths', 'icon': 'MapPin'}, + {'title': 'Vet Referrals', 'description': 'Local veterinary recommendations', 'icon': 'Stethoscope'} + ] + } + ]), + 'meta_title': 'Pet Care & Accommodation - Pet-Friendly Hotel', + 'meta_description': 'Pet-friendly accommodations with professional pet care services. Walking, feeding, grooming, and pet-sitting available. Your pets are welcome!', + 'meta_keywords': 'pet care, pet friendly hotel, dog walking, pet services, pet accommodation', + 'is_active': True + }, + { + 'name': 'Premium Wine & Spirits Collection', + 'description': 'Extensive collection of fine wines, premium spirits, and craft cocktails. Expert sommelier service and private wine tastings available.', + 'price': 0.00, + 'category': 'Dining', + 'slug': 'premium-wine-spirits-collection', + 'image': 'https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?w=1200&h=800&fit=crop', + 'content': '''
+

Curated Excellence

+

Discover our extensive collection of fine wines, premium spirits, and artisanal cocktails. Our master sommelier has curated a selection that spans the globe, featuring rare vintages, limited editions, and exceptional spirits.

+ +

Our Collection

+
    +
  • Fine Wines: Over 500 labels from renowned vineyards worldwide
  • +
  • Premium Spirits: Rare whiskeys, cognacs, and artisanal spirits
  • +
  • Craft Cocktails: Signature cocktails created by our expert mixologists
  • +
  • Champagne & Sparkling: Exclusive selection of premium bubbles
  • +
+ +

Services

+
    +
  • Sommelier Service: Expert wine recommendations and pairings
  • +
  • Wine Tastings: Private tastings and educational sessions
  • +
  • Bar Service: Craft cocktails at our premium bars
  • +
  • Private Events: Wine dinners and tasting events
  • +
+ +

Locations

+

Enjoy our collection at our signature bars, restaurants, or through our room service. Our sommelier is available for consultations and recommendations.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'A World of Flavors', + 'content': 'Curated by experts, enjoyed by connoisseurs.', + 'image': 'https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?w=1200&h=600&fit=crop' + }, + { + 'type': 'quote', + 'quote': 'An exceptional collection that rivals the finest establishments in the world.', + 'author': 'Wine Enthusiast Magazine' + } + ]), + 'meta_title': 'Premium Wine & Spirits Collection - Fine Beverages', + 'meta_description': 'Extensive collection of fine wines, premium spirits, and craft cocktails. Expert sommelier service and private tastings available.', + 'meta_keywords': 'wine collection, premium spirits, sommelier, wine tasting, luxury bar, craft cocktails', + 'is_active': True + }, + { + 'name': 'Private Event & Catering Services', + 'description': 'Professional event planning and catering services for weddings, corporate events, celebrations, and private gatherings. Make your special occasion unforgettable.', + 'price': 0.00, + 'category': 'Entertainment', + 'slug': 'private-event-catering-services', + 'image': 'https://images.unsplash.com/photo-1519167758481-83f550bb49b3?w=1200&h=800&fit=crop', + 'content': '''
+

Unforgettable Events

+

From intimate gatherings to grand celebrations, our professional event planning and catering team will ensure your special occasion is executed flawlessly. We handle every detail so you can enjoy your event.

+ +

Event Types

+
    +
  • Weddings: Ceremonies, receptions, and rehearsal dinners
  • +
  • Corporate Events: Conferences, meetings, and team building
  • +
  • Celebrations: Birthdays, anniversaries, and milestones
  • +
  • Private Dinners: Intimate gatherings and special occasions
  • +
+ +

Our Services

+
    +
  • Complete event planning and coordination
  • +
  • Customized menu design and catering
  • +
  • Venue selection and setup
  • +
  • Floral arrangements and decorations
  • +
  • Entertainment coordination
  • +
  • Photography and videography services
  • +
  • Technical support and AV equipment
  • +
+ +

Planning Process

+

Our event specialists will work with you from initial consultation through event execution. We offer flexible packages and can customize services to meet your specific needs and budget.

+
''', + 'sections': json.dumps([ + { + 'type': 'hero', + 'title': 'Making Memories That Last', + 'content': 'Professional event planning and catering for your most important occasions.', + 'image': 'https://images.unsplash.com/photo-1519167758481-83f550bb49b3?w=1200&h=600&fit=crop' + }, + { + 'type': 'cta', + 'title': 'Planning an Event?', + 'cta_text': 'Contact Our Event Team', + 'cta_link': '/contact', + 'content': 'Let us help you create an unforgettable experience.' + } + ]), + 'meta_title': 'Private Event & Catering Services - Professional Planning', + 'meta_description': 'Professional event planning and catering for weddings, corporate events, and celebrations. Make your special occasion unforgettable.', + 'meta_keywords': 'event planning, catering, wedding planning, corporate events, private events, hotel events', + 'is_active': True + } + ] + + created_count = 0 + updated_count = 0 + + for service_data in services_data: + # Check if service already exists by slug + existing = db.query(Service).filter(Service.slug == service_data['slug']).first() + + if existing: + # Update existing service + for key, value in service_data.items(): + if key != 'slug': # Don't update slug + setattr(existing, key, value) + updated_count += 1 + print(f' ✓ Updated service: {service_data["name"]}') + else: + # Create new service + service = Service(**service_data) + db.add(service) + created_count += 1 + print(f' ✓ Created service: {service_data["name"]}') + + db.commit() + print(f'\n✓ Enterprise services seeded successfully!') + print(f' - Created: {created_count}') + print(f' - Updated: {updated_count}') + print(f' - Total: {len(services_data)}\n') + +def main(): + db: Session = SessionLocal() + try: + print('=' * 80) + print('SEEDING ENTERPRISE SERVICES') + print('=' * 80) + print() + seed_enterprise_services(db) + print('=' * 80) + print('✓ All enterprise services data seeded successfully!') + print('=' * 80) + except Exception as e: + db.rollback() + print(f'\n✗ Error seeding services: {e}') + import traceback + traceback.print_exc() + raise + finally: + db.close() + +if __name__ == '__main__': + main() + diff --git a/Backend/src/__pycache__/main.cpython-312.pyc b/Backend/src/__pycache__/main.cpython-312.pyc index faa19b45c719e1e8f82305553ac84c9ec1244468..023dbee5b1fef55f600817b3cc4dbb7f2df82f3c 100644 GIT binary patch delta 21 bcmdmVhjG&#My}Jmyj%=GuwdavE{!|@Qwj#E delta 21 bcmdmVhjG&#My}Jmyj%=G@FZy?mqs1{Q)dRR diff --git a/Backend/src/hotel_services/models/__pycache__/service.cpython-312.pyc b/Backend/src/hotel_services/models/__pycache__/service.cpython-312.pyc index d2f89b947726bbc965fc2973ae7ed15040135daf..1a6121f72c2c8ec5912c5cc7a61f66f432b7c77d 100644 GIT binary patch delta 936 zcmZuwPiWIn7=JHG+q6m3c1_zcHxF8!*`UJ-n_$t)-28u#!XzLg_PuS45>pb8}BP{Y6aoP&7Di|yPJeB*BF2!DAs|L0!SBnZwnpnAXg=V za{)&@r)TB`38|Ig=c&uHKXQMxZWy15)^GAKmaOZ_8fgK7>B z-k)?oz|44}j|?3m2iyO5?eR}0`-eY9_`@iL2Da1v1CP{YCF9O9>g~OEM6R$_mc0CM zt)j2iu$3l>{*_E$-zOtgm;*F|@S;{T9Fh+cLQo`18vA^;Qd>cqgRQK)!xZ3g_c!Ap zpRB#8#AULUf<8c__HASUs7f1-gXEW3$jb!`)dHQq9w?v^(DBUYFj= zo-o^(>52o*saD=Cw)37i(YV}| zFVbEr$!&bdtXo~6jo22=$!q%3=&)&}W#f!R88>uzJ0c%5R?_k8{hzD954ImZ}@ z{Q^gkx5&_^Qt_HNaLI~aW)!h*EwJ$>B7~lx_5ihes0|@Mg!v&XzDp|FK&SWv_#4H1 E0qo^pC;$Ke diff --git a/Backend/src/hotel_services/models/service.py b/Backend/src/hotel_services/models/service.py index 37d90c72..994d4273 100644 --- a/Backend/src/hotel_services/models/service.py +++ b/Backend/src/hotel_services/models/service.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, Numeric, Boolean, Text, DateTime +from sqlalchemy import Column, Integer, String, Numeric, Boolean, Text, DateTime, Index from sqlalchemy.orm import relationship from datetime import datetime from ...shared.config.database import Base @@ -10,6 +10,13 @@ class Service(Base): description = Column(Text, nullable=True) price = Column(Numeric(10, 2), nullable=False) category = Column(String(50), nullable=True) + slug = Column(String(200), nullable=True, unique=True, index=True) + image = Column(String(1000), nullable=True) + content = Column(Text, nullable=True) + sections = Column(Text, nullable=True) # JSON string for advanced content blocks + meta_title = Column(String(500), nullable=True) + meta_description = Column(Text, nullable=True) + meta_keywords = Column(String(1000), nullable=True) is_active = Column(Boolean, nullable=False, default=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) diff --git a/Backend/src/hotel_services/routes/__pycache__/service_routes.cpython-312.pyc b/Backend/src/hotel_services/routes/__pycache__/service_routes.cpython-312.pyc index 0807dda60f042aff79e71bb00d6d8f2486337e89..bf7f9ca803b847d3f67e1f1037e51a4e24fd9882 100644 GIT binary patch literal 17023 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 BJ=y>O delta 3711 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 import('./features/content/pages/Accessibil const FAQPage = lazy(() => import('./features/content/pages/FAQPage')); const BlogPage = lazy(() => import('./features/content/pages/BlogPage')); const BlogDetailPage = lazy(() => import('./features/content/pages/BlogDetailPage')); +const ServicesPage = lazy(() => import('./features/content/pages/ServicesPage')); +const ServiceDetailPage = lazy(() => import('./features/content/pages/ServiceDetailPage')); const AdminDashboardPage = lazy(() => import('./pages/admin/DashboardPage')); const InvoiceManagementPage = lazy(() => import('./pages/admin/InvoiceManagementPage')); @@ -109,6 +111,7 @@ const GDPRManagementPage = lazy(() => import('./pages/admin/GDPRManagementPage') const WebhookManagementPage = lazy(() => import('./pages/admin/WebhookManagementPage')); const APIKeyManagementPage = lazy(() => import('./pages/admin/APIKeyManagementPage')); const BackupManagementPage = lazy(() => import('./pages/admin/BackupManagementPage')); +const ServiceManagementPage = lazy(() => import('./pages/admin/ServiceManagementPage')); const StaffDashboardPage = lazy(() => import('./pages/staff/DashboardPage')); const StaffBookingManagementPage = lazy(() => import('./pages/staff/BookingManagementPage')); @@ -361,6 +364,14 @@ function App() { path="blog/:slug" element={} /> + } + /> + } + /> {} } /> + } + /> } diff --git a/Frontend/src/features/content/pages/HomePage.tsx b/Frontend/src/features/content/pages/HomePage.tsx index cd78a256..b35a4156 100644 --- a/Frontend/src/features/content/pages/HomePage.tsx +++ b/Frontend/src/features/content/pages/HomePage.tsx @@ -19,20 +19,26 @@ import { import bannerService from '../services/bannerService'; import roomService from '../../rooms/services/roomService'; import pageContentService from '../services/pageContentService'; +import serviceService from '../../hotel_services/services/serviceService'; +import { useFormatCurrency } from '../../payments/hooks/useFormatCurrency'; import type { Banner } from '../services/bannerService'; import type { Room } from '../../rooms/services/roomService'; import type { PageContent } from '../services/pageContentService'; +import type { Service } from '../../hotel_services/services/serviceService'; const HomePage: React.FC = () => { + const { formatCurrency } = useFormatCurrency(); const [banners, setBanners] = useState([]); const [featuredRooms, setFeaturedRooms] = useState([]); const [newestRooms, setNewestRooms] = useState([]); const [pageContent, setPageContent] = useState(null); + const [services, setServices] = useState([]); const [isLoadingBanners, setIsLoadingBanners] = useState(true); const [isLoadingRooms, setIsLoadingRooms] = useState(true); const [isLoadingNewest, setIsLoadingNewest] = useState(true); const [, setIsLoadingContent] = useState(true); + const [isLoadingServices, setIsLoadingServices] = useState(true); const [error, setError] = useState(null); const [apiError, setApiError] = useState(false); const [apiErrorMessage, setApiErrorMessage] = useState(''); @@ -95,6 +101,27 @@ const HomePage: React.FC = () => { }, [featuredRooms, newestRooms]); + useEffect(() => { + fetchServices(); + }, []); + + const fetchServices = async () => { + try { + setIsLoadingServices(true); + const response = await serviceService.getServices({ + status: 'active', + limit: 6, // Only fetch first 6 for homepage + }); + if (response.success && response.data?.services) { + setServices(response.data.services); + } + } catch (error: any) { + console.error('Error fetching services:', error); + } finally { + setIsLoadingServices(false); + } + }; + useEffect(() => { const fetchPageContent = async () => { try { @@ -967,48 +994,64 @@ const HomePage: React.FC = () => { )} {} - {pageContent?.luxury_services && pageContent.luxury_services.length > 0 && ( + {services.length > 0 && (

- {pageContent.luxury_services_section_title || 'Luxury Services'} + {pageContent?.luxury_services_section_title || 'Luxury Services'}

- {pageContent.luxury_services_section_subtitle && ( + {pageContent?.luxury_services_section_subtitle && (

{pageContent.luxury_services_section_subtitle}

)}
- {pageContent.luxury_services.map((service: any, index: number) => ( -
-
- {service.image ? ( -
- {service.title} -
- ) : ( -
- {service.icon && (LucideIcons as any)[service.icon] ? ( - React.createElement((LucideIcons as any)[service.icon], { - className: 'w-7 h-7 md:w-8 md:h-8 text-[#d4af37] drop-shadow-md' - }) - ) : ( + {services.slice(0, 6).map((service, index: number) => { + const serviceSlug = service.slug || service.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); + return ( + +
+ {service.image ? ( +
+ {service.name} +
+ ) : ( +
- )} -
- )} -

- {service.title} -

-

- {service.description} -

-
- ))} +
+ )} +

+ {service.name} +

+

+ {service.description || 'Premium service for your comfort'} +

+ {service.price && ( +
+ Starting from {formatCurrency(service.price)} +
+ )} + + ); + })} +
+
+ + View All Services + +
)} diff --git a/Frontend/src/features/content/pages/ServiceDetailPage.tsx b/Frontend/src/features/content/pages/ServiceDetailPage.tsx new file mode 100644 index 00000000..6c65d469 --- /dev/null +++ b/Frontend/src/features/content/pages/ServiceDetailPage.tsx @@ -0,0 +1,709 @@ +import React, { useState, useEffect } from 'react'; +import { useParams, Link, useNavigate } from 'react-router-dom'; +import { ArrowLeft, Share2, Tag, Star } from 'lucide-react'; +import * as LucideIcons from 'lucide-react'; +import pageContentService, { PageContent } from '../services/pageContentService'; +import serviceService from '../../hotel_services/services/serviceService'; +import Loading from '../../../shared/components/Loading'; +import { createSanitizedHtml } from '../../../shared/utils/htmlSanitizer'; +import { useFormatCurrency } from '../../payments/hooks/useFormatCurrency'; + +interface ServiceSection { + type: 'hero' | 'text' | 'image' | 'gallery' | 'quote' | 'features' | 'cta' | 'video'; + title?: string; + content?: string; + image?: string; + images?: string[]; + quote?: string; + author?: string; + features?: Array<{ title: string; description: string; icon?: string }>; + cta_text?: string; + cta_link?: string; + video_url?: string; + alignment?: 'left' | 'center' | 'right'; + background_color?: string; + text_color?: string; + is_visible?: boolean; +} + +interface ServiceDetail { + id: string | number; + title: string; + slug: string; + description?: string; + content?: string; + image?: string; + icon?: string; + price?: number; + unit?: string; + category?: string; + type: 'luxury' | 'hotel'; + sections?: ServiceSection[]; + meta_title?: string; + meta_description?: string; + meta_keywords?: string; +} + +const ServiceDetailPage: React.FC = () => { + const { slug } = useParams<{ slug: string }>(); + const navigate = useNavigate(); + const { formatCurrency } = useFormatCurrency(); + const [service, setService] = useState(null); + const [loading, setLoading] = useState(true); + const [relatedServices, setRelatedServices] = useState([]); + const [pageContent, setPageContent] = useState(null); + + useEffect(() => { + if (slug) { + fetchService(); + } + }, [slug]); + + const fetchService = async () => { + try { + setLoading(true); + + // First, try to fetch from hotel services by slug (primary source) + try { + const serviceResponse = await serviceService.getServiceBySlug(slug!); + if (serviceResponse.success && serviceResponse.data?.service) { + const service = serviceResponse.data.service; + + // Parse sections if it's a string + let sections: ServiceSection[] = []; + if (service.sections) { + if (typeof service.sections === 'string') { + try { + sections = JSON.parse(service.sections); + } catch { + sections = []; + } + } else if (Array.isArray(service.sections)) { + sections = service.sections; + } + } + + const serviceDetail: ServiceDetail = { + id: service.id, + title: service.name, + slug: service.slug || slug!, + description: service.description, + content: service.content, + image: service.image, + category: service.category, + type: 'hotel', + price: service.price, + unit: service.unit, + sections: sections, + meta_title: service.meta_title, + meta_description: service.meta_description, + meta_keywords: service.meta_keywords, + }; + + setService(serviceDetail); + + // Set meta tags + if (serviceDetail.meta_title) { + document.title = serviceDetail.meta_title; + } + if (serviceDetail.meta_description) { + let metaDescription = document.querySelector('meta[name="description"]'); + if (!metaDescription) { + metaDescription = document.createElement('meta'); + metaDescription.setAttribute('name', 'description'); + document.head.appendChild(metaDescription); + } + metaDescription.setAttribute('content', serviceDetail.meta_description); + } + + // Fetch related services + await fetchRelatedServices(serviceDetail); + + setLoading(false); + return; + } + } catch (error) { + // If hotel service not found, fall back to luxury services + console.log('Hotel service not found, trying luxury services...'); + } + + // Fallback: 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 + 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); + + // Find service by slug + const luxuryService = content.luxury_services?.find((s: any) => s.slug === slug); + if (luxuryService) { + const serviceDetail: ServiceDetail = { + id: `luxury-${luxuryService.slug}`, + title: luxuryService.title || 'Service', + slug: luxuryService.slug || slug || '', + description: luxuryService.description, + content: luxuryService.content, + image: luxuryService.image, + icon: luxuryService.icon, + category: luxuryService.category, + type: 'luxury', + sections: luxuryService.sections || [], + meta_title: luxuryService.meta_title, + meta_description: luxuryService.meta_description, + meta_keywords: luxuryService.meta_keywords, + }; + + setService(serviceDetail); + + // Set meta tags + if (serviceDetail.meta_title) { + document.title = serviceDetail.meta_title; + } + if (serviceDetail.meta_description) { + let metaDescription = document.querySelector('meta[name="description"]'); + if (!metaDescription) { + metaDescription = document.createElement('meta'); + metaDescription.setAttribute('name', 'description'); + document.head.appendChild(metaDescription); + } + metaDescription.setAttribute('content', serviceDetail.meta_description); + } + + // Fetch related services + await fetchRelatedServices(serviceDetail); + setLoading(false); + return; + } + } + + // Service not found + navigate('/services'); + } catch (error: any) { + console.error('Error fetching service:', error); + navigate('/services'); + } finally { + setLoading(false); + } + }; + + const fetchRelatedServices = async (currentService: ServiceDetail) => { + try { + const services: ServiceDetail[] = []; + + // Fetch hotel services first + const servicesResponse = await serviceService.getServices({ + status: 'active', + limit: 100, + }); + + if (servicesResponse.success && servicesResponse.data?.services) { + servicesResponse.data.services.forEach((service: any) => { + // Skip current service + if (currentService.type === 'hotel' && service.id === currentService.id) { + return; + } + + // Filter by category if available + if (currentService.category && service.category !== currentService.category) { + return; + } + + const serviceSlug = service.slug || service.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); + services.push({ + id: service.id, + title: service.name, + slug: serviceSlug, + description: service.description, + image: service.image, + category: service.category, + type: 'hotel', + price: service.price, + }); + }); + } + + // Add luxury services as fallback + if (pageContent?.luxury_services && Array.isArray(pageContent.luxury_services)) { + pageContent.luxury_services.forEach((s: any, index: number) => { + if (s.slug && s.slug !== currentService.slug) { + if (!currentService.category || s.category === currentService.category) { + // Check if already in services (by slug) + const serviceSlug = s.slug || s.title?.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); + const exists = services.some(serv => serv.slug === serviceSlug); + if (!exists) { + services.push({ + id: `luxury-${index}`, + title: s.title || 'Service', + slug: s.slug, + description: s.description, + image: s.image, + icon: s.icon, + category: s.category, + type: 'luxury', + }); + } + } + } + }); + } + + setRelatedServices(services.slice(0, 3)); + } catch (error) { + console.error('Error fetching related services:', error); + } + }; + + const handleShare = async () => { + if (navigator.share && service) { + try { + await navigator.share({ + title: service.title, + text: service.description, + url: window.location.href, + }); + } catch (error) { + // User cancelled or error occurred + } + } else { + // Fallback: copy to clipboard + navigator.clipboard.writeText(window.location.href); + alert('Link copied to clipboard!'); + } + }; + + if (loading) { + return ; + } + + if (!service) { + return ( +
+
+

Service not found

+ + Back to Services + +
+
+ ); + } + + return ( +
+ {/* Hero Section with Featured Image - Enhanced Luxury */} + {service.image && ( +
+
+ {service.title} +
+
+
+ + {/* Luxury Overlay Pattern */} +
+
+
+
+ + {/* Hero Content Overlay */} +
+
+
+ {service.category && ( +
+ + + {service.category} + + {service.type === 'luxury' && ( + + + Premium + + )} +
+ )} +

+ {service.title} +

+ {service.description && ( +

+ {service.description} +

+ )} + {service.price !== undefined && ( +
+ + {formatCurrency(service.price)} + + {service.unit && ( + + / {service.unit} + + )} +
+ )} +
+
+
+ + {/* Decorative Bottom Border */} +
+
+ )} + + {/* Main Content - Enhanced Luxury Layout */} +
+
+
+ {/* Back Button - Only show if no hero image */} + {!service.image && ( + + + Back to Services + + )} + + {/* Service Header - Only if no hero image */} + {!service.image && ( +
+ {service.category && ( +
+ + + {service.category} + + {service.type === 'luxury' && ( + + + Premium + + )} +
+ )} + +
+ {service.icon && (LucideIcons as any)[service.icon] && ( +
+
+ {React.createElement((LucideIcons as any)[service.icon], { + className: 'w-20 h-20 sm:w-24 sm:h-24 text-[#d4af37] relative z-10 drop-shadow-2xl' + })} +
+ )} +
+

+ {service.title} +

+ {service.price !== undefined && ( +
+ + {formatCurrency(service.price)} + + {service.unit && ( + + / {service.unit} + + )} +
+ )} +
+
+ + {service.description && ( +

+ {service.description} +

+ )} + +
+ +
+
+ )} + + {/* Share Button for Hero Image Layout */} + {service.image && ( +
+ +
+ )} + + {/* Service Content - Enhanced Luxury Styling */} + {service.content && ( +
+
No content available.

' + )} + /> +
+ )} + + {/* Luxury Sections - Enhanced */} + {service.sections && service.sections.length > 0 && ( +
+ {service.sections + .filter((section) => section.is_visible !== false) + .map((section, index) => ( +
+ {/* Hero Section - Enhanced */} + {section.type === 'hero' && ( +
+ {section.image && ( +
+ {section.title} +
+
+
+ )} +
+
+
+
+
+ {section.title && ( +

+ {section.title} +

+ )} + {section.content && ( +

+ {section.content} +

+ )} +
+
+
+ )} + + {/* Text Section */} + {section.type === 'text' && ( +
+ {section.title && ( +

+ {section.title} +

+ )} + {section.content && ( +
+ )} +
+ )} + + {/* Image Section */} + {section.type === 'image' && section.image && ( +
+ {section.title + {section.title && ( +
+

{section.title}

+
+ )} +
+ )} + + {/* Gallery Section */} + {section.type === 'gallery' && section.images && section.images.length > 0 && ( +
+ {section.images.map((img, imgIndex) => ( +
+ {`Gallery +
+ ))} +
+ )} + + {/* Quote Section */} + {section.type === 'quote' && ( +
+
"
+ {section.quote && ( +
+ {section.quote} +
+ )} + {section.author && ( + + — {section.author} + + )} +
+ )} + + {/* Features Section - Enhanced */} + {section.type === 'features' && section.features && ( +
+ {section.title && ( +

+ {section.title} +

+ )} +
+ {section.features.map((feature, featIndex) => { + const IconComponent = feature.icon && (LucideIcons as any)[feature.icon] + ? (LucideIcons as any)[feature.icon] + : null; + return ( +
+
+
+ {IconComponent && ( +
+
+ {React.createElement(IconComponent, { + className: 'w-12 h-12 text-[#d4af37] relative z-10 group-hover:scale-110 transition-transform duration-300' + })} +
+ )} +

{feature.title}

+

{feature.description}

+
+
+ ); + })} +
+
+ )} + + {/* CTA Section */} + {section.type === 'cta' && ( +
+ )} + + {/* Video Section */} + {section.type === 'video' && section.video_url && ( +
+
+