From 4b053ce7035f0a3d5b4df6a3fdbfcfd2f8294fd6 Mon Sep 17 00:00:00 2001 From: Iliyan Angelov Date: Tue, 2 Dec 2025 08:06:00 +0200 Subject: [PATCH] updates --- Backend/seeds_data/seed_homepage_footer.py | 8 +- .../__pycache__/home_routes.cpython-312.pyc | Bin 8407 -> 8122 bytes Backend/src/content/routes/home_routes.py | 88 +++++++++++++++++- .../src/features/content/pages/HomePage.tsx | 35 ++++++- 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/Backend/seeds_data/seed_homepage_footer.py b/Backend/seeds_data/seed_homepage_footer.py index fb514a89..18b13836 100644 --- a/Backend/seeds_data/seed_homepage_footer.py +++ b/Backend/seeds_data/seed_homepage_footer.py @@ -1,10 +1,11 @@ import sys import os import json -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) +# Add parent directory to path to import from src +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from sqlalchemy.orm import Session from src.shared.config.database import SessionLocal -from src.models.page_content import PageContent, PageType +from src.content.models.page_content import PageContent, PageType def seed_homepage_content(db: Session): existing = db.query(PageContent).filter(PageContent.page_type == PageType.HOME).first() @@ -17,9 +18,10 @@ def seed_homepage_content(db: Session): 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': '#'}] stats = [{'icon': 'Users', 'number': '50,000+', 'label': 'Happy Guests'}, {'icon': 'Award', 'number': '25+', 'label': 'Awards Won'}, {'icon': 'Star', 'number': '4.9', 'label': 'Average Rating'}, {'icon': 'Globe', 'number': '100+', 'label': 'Countries Served'}] amenities = [{'icon': 'Wifi', 'title': 'High-Speed WiFi', 'description': 'Complimentary high-speed internet throughout the property', 'image': ''}, {'icon': 'Coffee', 'title': '24/7 Room Service', 'description': 'Round-the-clock dining and beverage service', 'image': ''}, {'icon': 'Car', 'title': 'Valet Parking', 'description': 'Complimentary valet parking for all guests', 'image': ''}, {'icon': 'Plane', 'title': 'Airport Transfer', 'description': 'Luxury airport transfer service available', 'image': ''}] + features = [{'icon': 'Shield', 'title': 'Secure & Safe', 'description': '24/7 security and state-of-the-art safety systems'}, {'icon': 'Wifi', 'title': 'Free WiFi', 'description': 'High-speed internet access throughout the property'}, {'icon': 'Coffee', 'title': 'Room Service', 'description': '24/7 room service available for your convenience'}, {'icon': 'Car', 'title': 'Parking', 'description': 'Complimentary valet parking for all guests'}, {'icon': 'UtensilsCrossed', 'title': 'Fine Dining', 'description': 'World-class restaurants and dining experiences'}, {'icon': 'Dumbbell', 'title': 'Fitness Center', 'description': 'State-of-the-art fitness facilities'}] testimonials = [{'name': 'Robert Martinez', 'role': 'CEO, Tech Corp', 'image': 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=200', 'rating': 5, 'comment': 'Exceptional service and attention to detail. The staff went above and beyond to make our stay memorable.'}, {'name': 'Lisa Anderson', 'role': 'Travel Blogger', 'image': 'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200', 'rating': 5, 'comment': "The most luxurious hotel experience I've ever had. Every detail was perfect."}, {'name': 'David Thompson', 'role': 'Investment Banker', 'image': 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=200', 'rating': 5, 'comment': 'Outstanding facilities and impeccable service. Highly recommend for business travelers.'}] gallery_images = ['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', 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800', 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800', 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800'] - homepage_data = {'page_type': PageType.HOME, 'title': 'Luxury Hotel - Experience Unparalleled Elegance', 'subtitle': 'Where timeless luxury meets modern sophistication', 'description': 'Discover a world of refined elegance and exceptional service', 'hero_title': 'Welcome to Luxury', 'hero_subtitle': 'Experience the pinnacle of hospitality', 'hero_image': 'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200', 'luxury_section_title': 'Experience Unparalleled Luxury', 'luxury_section_subtitle': 'Where elegance meets comfort in every detail', 'luxury_section_image': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200', 'luxury_features': json.dumps(luxury_features), 'luxury_gallery_section_title': 'Our Luxury Gallery', 'luxury_gallery_section_subtitle': 'A glimpse into our world of elegance', 'luxury_gallery': json.dumps(luxury_gallery), 'luxury_testimonials_section_title': 'What Our Guests Say', 'luxury_testimonials_section_subtitle': 'Testimonials from our valued guests', 'luxury_testimonials': json.dumps(luxury_testimonials), 'luxury_services_section_title': 'Premium Services', 'luxury_services_section_subtitle': 'Indulge in our world-class amenities', 'luxury_services': json.dumps(luxury_services), 'luxury_experiences_section_title': 'Exclusive Experiences', 'luxury_experiences_section_subtitle': 'Create unforgettable memories', 'luxury_experiences': json.dumps(luxury_experiences), 'awards_section_title': 'Awards & Recognition', 'awards_section_subtitle': 'Recognized for excellence worldwide', 'awards': json.dumps(awards), 'partners_section_title': 'Our Partners', 'partners_section_subtitle': 'Trusted by leading brands', 'partners': json.dumps(partners), 'amenities_section_title': 'Premium Amenities', 'amenities_section_subtitle': 'Everything you need for a perfect stay', 'amenities': json.dumps(amenities), 'testimonials_section_title': 'Guest Reviews', 'testimonials_section_subtitle': 'Hear from our satisfied guests', 'testimonials': json.dumps(testimonials), 'gallery_section_title': 'Photo Gallery', 'gallery_section_subtitle': 'Explore our beautiful spaces', 'gallery_images': json.dumps(gallery_images), 'about_preview_title': 'About Our Luxury Hotel', 'about_preview_subtitle': 'A legacy of excellence', 'about_preview_content': 'Discover a world of refined elegance and exceptional service. Our hotel combines timeless luxury with modern amenities to create an unforgettable experience. With over 50,000 satisfied guests and numerous awards, we continue to set the standard for luxury hospitality.', 'about_preview_image': 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800', 'stats': json.dumps(stats), 'cta_title': 'Ready to Experience Luxury?', 'cta_subtitle': 'Book your stay today and discover the difference', 'cta_button_text': 'Book Now', 'cta_button_link': '/rooms', 'cta_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200', 'is_active': True} + homepage_data = {'page_type': PageType.HOME, 'title': 'Luxury Hotel - Experience Unparalleled Elegance', 'subtitle': 'Where timeless luxury meets modern sophistication', 'description': 'Discover a world of refined elegance and exceptional service', 'hero_title': 'Welcome to Luxury', 'hero_subtitle': 'Experience the pinnacle of hospitality', 'hero_image': 'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200', 'features': json.dumps(features), 'luxury_section_title': 'Experience Unparalleled Luxury', 'luxury_section_subtitle': 'Where elegance meets comfort in every detail', 'luxury_section_image': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200', 'luxury_features': json.dumps(luxury_features), 'luxury_gallery_section_title': 'Our Luxury Gallery', 'luxury_gallery_section_subtitle': 'A glimpse into our world of elegance', 'luxury_gallery': json.dumps(luxury_gallery), 'luxury_testimonials_section_title': 'What Our Guests Say', 'luxury_testimonials_section_subtitle': 'Testimonials from our valued guests', 'luxury_testimonials': json.dumps(luxury_testimonials), 'luxury_services_section_title': 'Premium Services', 'luxury_services_section_subtitle': 'Indulge in our world-class amenities', 'luxury_services': json.dumps(luxury_services), 'luxury_experiences_section_title': 'Exclusive Experiences', 'luxury_experiences_section_subtitle': 'Create unforgettable memories', 'luxury_experiences': json.dumps(luxury_experiences), 'awards_section_title': 'Awards & Recognition', 'awards_section_subtitle': 'Recognized for excellence worldwide', 'awards': json.dumps(awards), 'partners_section_title': 'Our Partners', 'partners_section_subtitle': 'Trusted by leading brands', 'partners': json.dumps(partners), 'amenities_section_title': 'Premium Amenities', 'amenities_section_subtitle': 'Everything you need for a perfect stay', 'amenities': json.dumps(amenities), 'testimonials_section_title': 'Guest Reviews', 'testimonials_section_subtitle': 'Hear from our satisfied guests', 'testimonials': json.dumps(testimonials), 'gallery_section_title': 'Photo Gallery', 'gallery_section_subtitle': 'Explore our beautiful spaces', 'gallery_images': json.dumps(gallery_images), 'about_preview_title': 'About Our Luxury Hotel', 'about_preview_subtitle': 'A legacy of excellence', 'about_preview_content': 'Discover a world of refined elegance and exceptional service. Our hotel combines timeless luxury with modern amenities to create an unforgettable experience. With over 50,000 satisfied guests and numerous awards, we continue to set the standard for luxury hospitality.', 'about_preview_image': 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800', 'stats': json.dumps(stats), 'cta_title': 'Ready to Experience Luxury?', 'cta_subtitle': 'Book your stay today and discover the difference', 'cta_button_text': 'Book Now', 'cta_button_link': '/rooms', 'cta_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200', 'is_active': True} if existing: for key, value in homepage_data.items(): if key != 'page_type': diff --git a/Backend/src/content/routes/__pycache__/home_routes.cpython-312.pyc b/Backend/src/content/routes/__pycache__/home_routes.cpython-312.pyc index 2d710ae40af153debefe7de0a599e67a9ccec417..bfe13d86fcb99078269cb722ebe44b32b74c9294 100644 GIT binary patch literal 8122 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 Jo>I!R{vXuGdlmoy diff --git a/Backend/src/content/routes/home_routes.py b/Backend/src/content/routes/home_routes.py index dcedfa30..85f809e8 100644 --- a/Backend/src/content/routes/home_routes.py +++ b/Backend/src/content/routes/home_routes.py @@ -8,7 +8,93 @@ logger = get_logger(__name__) router = APIRouter(prefix='/home', tags=['home']) def serialize_page_content(content: PageContent) -> dict: - return {'id': content.id, 'page_type': content.page_type.value, 'title': content.title, 'subtitle': content.subtitle, 'description': content.description, 'content': content.content, 'meta_title': content.meta_title, 'meta_description': content.meta_description, 'meta_keywords': content.meta_keywords, 'og_title': content.og_title, 'og_description': content.og_description, 'og_image': content.og_image, 'canonical_url': content.canonical_url, 'hero_title': content.hero_title, 'hero_subtitle': content.hero_subtitle, 'hero_image': content.hero_image, 'amenities_section_title': content.amenities_section_title, 'amenities_section_subtitle': content.amenities_section_subtitle, 'amenities': json.loads(content.amenities) if content.amenities else None, 'testimonials_section_title': content.testimonials_section_title, 'testimonials_section_subtitle': content.testimonials_section_subtitle, 'testimonials': json.loads(content.testimonials) if content.testimonials else None, 'gallery_section_title': content.gallery_section_title, 'gallery_section_subtitle': content.gallery_section_subtitle, 'gallery_images': json.loads(content.gallery_images) if content.gallery_images else None, 'luxury_section_title': content.luxury_section_title, 'luxury_section_subtitle': content.luxury_section_subtitle, 'luxury_section_image': content.luxury_section_image, 'luxury_features': json.loads(content.luxury_features) if content.luxury_features else None, 'luxury_gallery_section_title': content.luxury_gallery_section_title, 'luxury_gallery_section_subtitle': content.luxury_gallery_section_subtitle, 'luxury_gallery': json.loads(content.luxury_gallery) if content.luxury_gallery else None, 'luxury_testimonials_section_title': content.luxury_testimonials_section_title, 'luxury_testimonials_section_subtitle': content.luxury_testimonials_section_subtitle, 'luxury_testimonials': json.loads(content.luxury_testimonials) if content.luxury_testimonials else None, 'about_preview_title': content.about_preview_title, 'about_preview_subtitle': content.about_preview_subtitle, 'about_preview_content': content.about_preview_content, 'about_preview_image': content.about_preview_image, 'stats': json.loads(content.stats) if content.stats else None, 'luxury_services_section_title': content.luxury_services_section_title, 'luxury_services_section_subtitle': content.luxury_services_section_subtitle, 'luxury_services': json.loads(content.luxury_services) if content.luxury_services else None, 'luxury_experiences_section_title': content.luxury_experiences_section_title, 'luxury_experiences_section_subtitle': content.luxury_experiences_section_subtitle, 'luxury_experiences': json.loads(content.luxury_experiences) if content.luxury_experiences else None, 'awards_section_title': content.awards_section_title, 'awards_section_subtitle': content.awards_section_subtitle, 'awards': json.loads(content.awards) if content.awards else None, 'cta_title': content.cta_title, 'cta_subtitle': content.cta_subtitle, 'cta_button_text': content.cta_button_text, 'cta_button_link': content.cta_button_link, 'cta_image': content.cta_image, 'partners_section_title': content.partners_section_title, 'partners_section_subtitle': content.partners_section_subtitle, 'partners': json.loads(content.partners) if content.partners else None, 'is_active': content.is_active, 'created_at': content.created_at.isoformat() if content.created_at else None, 'updated_at': content.updated_at.isoformat() if content.updated_at else None} + def safe_json_loads(value, default=None): + """Safely parse JSON string, return default if invalid or empty""" + if not value: + return default + try: + parsed = json.loads(value) + return parsed if parsed else default + except (json.JSONDecodeError, TypeError): + return default + + return { + 'id': content.id, + 'page_type': content.page_type.value, + 'title': content.title, + 'subtitle': content.subtitle, + 'description': content.description, + 'content': content.content, + 'meta_title': content.meta_title, + 'meta_description': content.meta_description, + 'meta_keywords': content.meta_keywords, + 'og_title': content.og_title, + 'og_description': content.og_description, + 'og_image': content.og_image, + 'canonical_url': content.canonical_url, + 'contact_info': safe_json_loads(content.contact_info, {}), + 'map_url': content.map_url, + 'social_links': safe_json_loads(content.social_links, {}), + 'footer_links': safe_json_loads(content.footer_links, {}), + 'badges': safe_json_loads(content.badges, []), + 'copyright_text': content.copyright_text, + 'hero_title': content.hero_title, + 'hero_subtitle': content.hero_subtitle, + 'hero_image': content.hero_image, + 'story_content': content.story_content, + 'values': safe_json_loads(content.values, []), + 'features': safe_json_loads(content.features, []), + 'about_hero_image': content.about_hero_image, + 'mission': content.mission, + 'vision': content.vision, + 'team': safe_json_loads(content.team, []), + 'timeline': safe_json_loads(content.timeline, []), + 'achievements': safe_json_loads(content.achievements, []), + 'amenities_section_title': content.amenities_section_title, + 'amenities_section_subtitle': content.amenities_section_subtitle, + 'amenities': safe_json_loads(content.amenities, []), + 'testimonials_section_title': content.testimonials_section_title, + 'testimonials_section_subtitle': content.testimonials_section_subtitle, + 'testimonials': safe_json_loads(content.testimonials, []), + 'gallery_section_title': content.gallery_section_title, + 'gallery_section_subtitle': content.gallery_section_subtitle, + 'gallery_images': safe_json_loads(content.gallery_images, []), + 'luxury_section_title': content.luxury_section_title, + 'luxury_section_subtitle': content.luxury_section_subtitle, + 'luxury_section_image': content.luxury_section_image, + 'luxury_features': safe_json_loads(content.luxury_features, []), + 'luxury_gallery_section_title': content.luxury_gallery_section_title, + 'luxury_gallery_section_subtitle': content.luxury_gallery_section_subtitle, + 'luxury_gallery': safe_json_loads(content.luxury_gallery, []), + 'luxury_testimonials_section_title': content.luxury_testimonials_section_title, + 'luxury_testimonials_section_subtitle': content.luxury_testimonials_section_subtitle, + 'luxury_testimonials': safe_json_loads(content.luxury_testimonials, []), + 'about_preview_title': content.about_preview_title, + 'about_preview_subtitle': content.about_preview_subtitle, + 'about_preview_content': content.about_preview_content, + 'about_preview_image': content.about_preview_image, + 'stats': safe_json_loads(content.stats, []), + 'luxury_services_section_title': content.luxury_services_section_title, + 'luxury_services_section_subtitle': content.luxury_services_section_subtitle, + 'luxury_services': safe_json_loads(content.luxury_services, []), + 'luxury_experiences_section_title': content.luxury_experiences_section_title, + 'luxury_experiences_section_subtitle': content.luxury_experiences_section_subtitle, + 'luxury_experiences': safe_json_loads(content.luxury_experiences, []), + 'awards_section_title': content.awards_section_title, + 'awards_section_subtitle': content.awards_section_subtitle, + 'awards': safe_json_loads(content.awards, []), + 'cta_title': content.cta_title, + 'cta_subtitle': content.cta_subtitle, + 'cta_button_text': content.cta_button_text, + 'cta_button_link': content.cta_button_link, + 'cta_image': content.cta_image, + 'partners_section_title': content.partners_section_title, + 'partners_section_subtitle': content.partners_section_subtitle, + 'partners': safe_json_loads(content.partners, []), + 'is_active': content.is_active, + 'created_at': content.created_at.isoformat() if content.created_at else None, + 'updated_at': content.updated_at.isoformat() if content.updated_at else None + } @router.get('/') async def get_home_content(db: Session=Depends(get_db)): diff --git a/Frontend/src/features/content/pages/HomePage.tsx b/Frontend/src/features/content/pages/HomePage.tsx index 2a4b174a..cd78a256 100644 --- a/Frontend/src/features/content/pages/HomePage.tsx +++ b/Frontend/src/features/content/pages/HomePage.tsx @@ -105,48 +105,66 @@ const HomePage: React.FC = () => { const content = response.data.page_content; + // Handle features - can be string, array, or null/undefined if (typeof content.features === 'string') { try { content.features = JSON.parse(content.features); } catch { content.features = []; } + } else if (!Array.isArray(content.features)) { + content.features = content.features || []; } + // Handle amenities - can be string, array, or null/undefined if (typeof content.amenities === 'string') { try { content.amenities = JSON.parse(content.amenities); } catch { content.amenities = []; } + } else if (!Array.isArray(content.amenities)) { + content.amenities = content.amenities || []; } + // Handle testimonials - can be string, array, or null/undefined if (typeof content.testimonials === 'string') { try { content.testimonials = JSON.parse(content.testimonials); } catch (e) { content.testimonials = []; } + } else if (!Array.isArray(content.testimonials)) { + content.testimonials = content.testimonials || []; } + // Handle gallery_images - can be string, array, or null/undefined if (typeof content.gallery_images === 'string') { try { content.gallery_images = JSON.parse(content.gallery_images); } catch (e) { content.gallery_images = []; } + } else if (!Array.isArray(content.gallery_images)) { + content.gallery_images = content.gallery_images || []; } + // Handle stats - can be string, array, or null/undefined if (typeof content.stats === 'string') { try { content.stats = JSON.parse(content.stats); } catch (e) { content.stats = []; } + } else if (!Array.isArray(content.stats)) { + content.stats = content.stats || []; } + // Handle luxury_features - can be string, array, or null/undefined if (typeof content.luxury_features === 'string') { try { content.luxury_features = JSON.parse(content.luxury_features); } catch (e) { content.luxury_features = []; } + } else if (!Array.isArray(content.luxury_features)) { + content.luxury_features = content.luxury_features || []; } if (typeof content.luxury_gallery === 'string') { try { @@ -162,40 +180,55 @@ const HomePage: React.FC = () => { } else { content.luxury_gallery = []; } + // Handle luxury_testimonials - can be string, array, or null/undefined if (typeof content.luxury_testimonials === 'string') { try { content.luxury_testimonials = JSON.parse(content.luxury_testimonials); } catch (e) { content.luxury_testimonials = []; } + } else if (!Array.isArray(content.luxury_testimonials)) { + content.luxury_testimonials = content.luxury_testimonials || []; } + // 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 (e) { content.luxury_services = []; } + } else if (!Array.isArray(content.luxury_services)) { + content.luxury_services = content.luxury_services || []; } + // Handle luxury_experiences - can be string, array, or null/undefined if (typeof content.luxury_experiences === 'string') { try { content.luxury_experiences = JSON.parse(content.luxury_experiences); } catch (e) { content.luxury_experiences = []; } + } else if (!Array.isArray(content.luxury_experiences)) { + content.luxury_experiences = content.luxury_experiences || []; } + // Handle awards - can be string, array, or null/undefined if (typeof content.awards === 'string') { try { content.awards = JSON.parse(content.awards); } catch (e) { content.awards = []; } + } else if (!Array.isArray(content.awards)) { + content.awards = content.awards || []; } + // Handle partners - can be string, array, or null/undefined if (typeof content.partners === 'string') { try { content.partners = JSON.parse(content.partners); } catch (e) { content.partners = []; } + } else if (!Array.isArray(content.partners)) { + content.partners = content.partners || []; } setPageContent(content); @@ -212,8 +245,6 @@ const HomePage: React.FC = () => { document.head.appendChild(metaDescription); } metaDescription.setAttribute('content', content.meta_description); - } else { - setPageContent(null); } } else { setPageContent(null);