diff --git a/src/assets/1.jpg b/src/assets/1.jpg new file mode 100644 index 0000000..39095fc Binary files /dev/null and b/src/assets/1.jpg differ diff --git a/src/assets/mountain.jpg b/src/assets/mountain.jpg new file mode 100644 index 0000000..c6f4d3f Binary files /dev/null and b/src/assets/mountain.jpg differ diff --git a/src/pages/Blog/BlogContent.tsx b/src/pages/Blog/BlogContent.tsx index 5aab8f0..c9c2d60 100644 --- a/src/pages/Blog/BlogContent.tsx +++ b/src/pages/Blog/BlogContent.tsx @@ -6,16 +6,25 @@ import { import MaxWidthWrapper from '@/components/MaxWidthWrapper'; -interface Blog { +export interface Tag { + id: number; + name: string; + slug: string; +} + +export interface Blog { id: number; title: string; - excerpt: string; + slug: string; + cover_image: string; content: string; - date: string; - author: string; - category: string; - image: string; - readTime: string; + author_name: string; + tags: Tag[]; + reading_time: number; + published_at: string; + status: string; + created_at: string; + updated_at: string; } interface BlogContentProps { @@ -23,51 +32,93 @@ interface BlogContentProps { blogs: Blog[]; } +// Helper function to format date +const formatDate = (dateString: string) => new Date(dateString).toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', +}); + +// Helper function to strip HTML and create excerpt +const createExcerpt = (htmlContent: string, maxLength: number = 150) => { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = htmlContent; + const textContent = tempDiv.textContent || tempDiv.innerText || ''; + return textContent.length > maxLength + ? `${textContent.substring(0, maxLength)}...` + : textContent; +}; + function BlogContent(props: BlogContentProps) { - const { - selectedCategory, blogs, - } = props; + const { selectedCategory, blogs } = props; + + if (!blogs || blogs.length === 0) { + return ( +
+ +
+

No blog posts available.

+
+
+
+ ); + } return (
{/* Featured Post */} -
{blogs[0].title}
-
- - {blogs[0].category} - - - {blogs[0].date} +
+
+ {blogs[0].tags.map((tag) => ( + + {tag.name} + + ))} +
+
+ + {formatDate(blogs[0].published_at)} +

{blogs[0].title}

- {blogs[0].excerpt} + {createExcerpt(blogs[0].content, 200)}

- {blogs[0].author} + {blogs[0].author_name} +
+
+ + {blogs[0].reading_time} + {' '} + min read + + + Read More +
- - Read More -
@@ -79,31 +130,50 @@ function BlogContent(props: BlogContentProps) { {blogs.slice(selectedCategory === 'All' ? 1 : 0).map((blog) => (
{blog.title}
-
- - {blog.category} - - - {blog.date} +
+
+ {blog.tags.slice(0, 2).map((tag) => ( + + {tag.name} + + ))} + {blog.tags.length > 2 && ( + + + + {blog.tags.length - 2} + + )} +
+
+ + {formatDate(blog.published_at)} +

{blog.title}

- {blog.excerpt} + {createExcerpt(blog.content)}

- {blog.author} + {blog.author_name}
-
- {blog.readTime} +
+ + {blog.reading_time} + {' '} + min read + { + const response = await baseRequest({ + url: '/cms/blog-posts/', + method: 'GET', + }); + + if (!response.ok) { + throw new Error(`Failed to fetch blog posts: ${response.statusText}`); + } + + return response.data; + }, +}; function Blog() { const title = 'Our Blog'; const description = 'Stay updated with the latest news, stories, and updates from Mountain Children Home. Read about our children's achievements, ongoing projects, and community impact.'; - const blogs = [ - { - id: 1, - title: 'A Day in the Life at Mountain Children Home', - excerpt: 'Follow along as we share what a typical day looks like for our children, from morning prayers to evening activities. See how structure, love, and learning come together to create a nurturing environment.', - content: 'Every day at Mountain Children Home begins at 6:00 AM with the gentle sound of morning prayers...', - date: 'March 15, 2024', - author: 'Sarah Johnson', - category: 'Daily Life', - image: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '5 min read', - }, - { - id: 2, - title: "Success Story: Maria's Journey to University", - excerpt: 'Read about Maria, who grew up at our home and is now pursuing her dreams at university thanks to your support. Her story is a testament to what love and education can achieve.', - content: 'Maria arrived at Mountain Children Home when she was just 8 years old...', - date: 'March 10, 2024', - author: 'Michael Chen', - category: 'Success Stories', - image: 'https://images.unsplash.com/photo-1649972904349-6e44c42644a7?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '7 min read', - }, - { - id: 3, - title: 'Building Our New Learning Center', - excerpt: "We're excited to share updates on our new learning center construction, which will provide better educational facilities for our children and expand our capacity to serve more kids in need.", - content: 'Construction on our new learning center is progressing wonderfully...', - date: 'March 5, 2024', - author: 'Sarah Johnson', - category: 'Updates', - image: 'https://images.unsplash.com/photo-1518770660439-4636190af475?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '4 min read', - }, - { - id: 4, - title: 'Celebrating Our 15th Anniversary', - excerpt: 'This month marks 15 years since Mountain Children Home first opened its doors. Join us as we reflect on our journey and celebrate the hundreds of lives that have been transformed.', - content: 'Fifteen years ago, our founders had a simple but powerful vision...', - date: 'February 28, 2024', - author: 'Dr. Maria Rodriguez', - category: 'Milestones', - image: 'https://images.unsplash.com/photo-1527576539890-dfa815648363?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '6 min read', - }, - { - id: 5, - title: 'Health and Wellness Initiative Launch', - excerpt: "We're launching a comprehensive health and wellness program to ensure every child receives the physical and mental health support they need to thrive.", - content: "Good health is fundamental to a child's ability to learn and grow...", - date: 'February 20, 2024', - author: 'Dr. Maria Rodriguez', - category: 'Health', - image: 'https://images.unsplash.com/photo-1535268647677-300dbf3d78d1?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '5 min read', - }, - { - id: 6, - title: 'Community Partnership Spotlight', - excerpt: 'Learn about our amazing partnership with local businesses and organizations that help make our mission possible. Community support is the backbone of our work.', - content: 'Our work would not be possible without the incredible support of our community partners...', - date: 'February 15, 2024', - author: 'Michael Chen', - category: 'Community', - image: 'https://images.unsplash.com/photo-1439886183900-e79ec0057170?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '4 min read', - }, - ]; - const [selectedCategory] = useState('All'); + const { + data: blogResponse, + isLoading, + isError, + error, + } = useQuery({ + queryKey: ['blogs'], + queryFn: blogService.getPosts, + }); + + // Get published blogs only - with proper null checks + const publishedBlogs = blogResponse?.results?.filter((blog) => blog.status === 'published') || []; + + // Filter blogs by category (if you implement category filtering later) const filteredBlogs = selectedCategory === 'All' - ? blogs - : blogs.filter((blog) => blog.category === selectedCategory); + ? publishedBlogs + : publishedBlogs.filter((blog) => blog.tags?.some( + (tag) => tag.name === selectedCategory, + ) || false); + + // Handle loading state + if (isLoading) { + return ( + <> + +
+
+
+
+

Loading blog posts...

+
+
+
+ + ); + } + + // Handle error state + if (isError) { + return ( + <> + +
+
+
+

Failed to load blog posts

+

+ {error instanceof Error ? error.message : 'An unexpected error occurred'} +

+
+
+
+ + ); + } + + // Handle empty state + if (filteredBlogs.length === 0) { + return ( + <> + +
+
+
+

No blog posts found

+
+
+
+ + ); + } return ( <> @@ -93,5 +137,4 @@ function Blog() { ); } - export default Blog; diff --git a/src/pages/BlogDetail/index.tsx b/src/pages/BlogDetail/index.tsx index c759a9a..14904e8 100644 --- a/src/pages/BlogDetail/index.tsx +++ b/src/pages/BlogDetail/index.tsx @@ -3,6 +3,7 @@ import { Link, useParams, } from 'react-router-dom'; +import { useQuery } from '@tanstack/react-query'; import { Book, Calendar, @@ -10,120 +11,153 @@ import { } from 'lucide-react'; import MaxWidthWrapper from '@/components/MaxWidthWrapper'; +import { baseRequest } from '@/lib/base'; + +// Types +export interface Tag { + id: number; + name: string; + slug: string; +} + +export interface BlogPost { + id: number; + title: string; + slug: string; + cover_image: string; + content: string; + author_name: string; + tags: Tag[]; + reading_time: number; + published_at: string; + status: string; + created_at: string; + updated_at: string; +} + +export interface BlogAPIResponse { + count: number; + next: string | null; + previous: string | null; + results: BlogPost[]; +} + +// API service +const blogService = { + async getPosts(): Promise { + const response = await baseRequest({ + url: '/cms/blog-posts/', + method: 'GET', + }); + + if (!response.ok) { + throw new Error(`Failed to fetch blog posts: ${response.statusText}`); + } + + return response.data; + }, + + async getPostById(id: string): Promise { + const response = await baseRequest({ + url: `/cms/blog-posts/${id}/`, + method: 'GET', + }); + + if (!response.ok) { + throw new Error(`Failed to fetch blog post: ${response.statusText}`); + } + + return response.data; + }, +}; function BlogDetail() { const { id } = useParams(); - // This would typically come from an API or database - const blogs = [ - { - id: 1, - title: 'A Day in the Life at Mountain Children Home', - content: ` -

Every day at Mountain Children Home begins at 6:00 AM with the gentle sound of morning prayers. The children wake up naturally to this peaceful routine that has become second nature to them over the years.

- -

Morning Routine (6:00 AM - 8:00 AM)

-

After prayers, the children help each other get ready for the day. Personal hygiene is emphasized, and older children often help the younger ones brush their teeth and get dressed. Breakfast is served at 7:00 AM, featuring nutritious local foods prepared with love by our kitchen staff.

- -

School Time (8:00 AM - 3:00 PM)

-

Education is at the heart of everything we do. Our children attend both our on-site learning center and local schools in the community. We ensure each child receives quality education appropriate to their age and learning needs. Homework support is provided by our dedicated teaching staff.

- -

Afternoon Activities (3:00 PM - 6:00 PM)

-

After school, children engage in various activities including sports, arts and crafts, music lessons, and free play time. These activities help develop their creativity, physical fitness, and social skills.

- -

Evening Wind Down (6:00 PM - 9:00 PM)

-

Dinner is served at 6:00 PM, followed by family time where children share their daily experiences. Study time begins at 7:30 PM, and younger children have bedtime stories before lights out at 9:00 PM.

- -

This structured yet loving environment helps our children feel secure and supported as they grow and learn. Every day is filled with opportunities for growth, learning, and joy.

- `, - date: 'March 15, 2024', - author: 'Sarah Johnson', - category: 'Daily Life', - image: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '5 min read', - }, - { - id: 2, - title: "Success Story: Maria's Journey to University", - content: ` -

Maria arrived at Mountain Children Home when she was just 8 years old, having lost both parents in a tragic accident. Scared and alone, she barely spoke for the first few months of her stay with us.

- -

Finding Her Voice

-

With patience, love, and dedicated support from our care team, Maria slowly began to open up. She showed a natural aptitude for mathematics and science, subjects that became her refuge and passion.

- -

Academic Excellence

-

Throughout her years at Mountain Children Home, Maria consistently excelled in her studies. She received tutoring support from volunteers and participated in academic competitions, often placing in the top positions.

- -

Dreams Take Flight

-

When it came time for university applications, Maria set her sights high. With support from our education fund and her own determination, she was accepted into the prestigious State University's Engineering program.

- -

Giving Back

-

Now in her second year of studies, Maria regularly visits Mountain Children Home to tutor younger children in mathematics. She says our home gave her not just shelter and education, but hope and purpose.

- -

"Mountain Children Home didn't just save my life," Maria says, "they gave me the tools to build the life I dreamed of. Now I want to help other children discover their own potential."

- -

Maria's story is one of many that inspire us every day. It reminds us why we do this work and the incredible potential that lies within every child who walks through our doors.

- `, - date: 'March 10, 2024', - author: 'Michael Chen', - category: 'Success Stories', - image: 'https://images.unsplash.com/photo-1649972904349-6e44c42644a7?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '7 min read', - }, - { - id: 3, - title: 'Building Our New Learning Center', - content: ` -

Construction on our new learning center is progressing wonderfully, and we're excited to share this milestone with our supporters who have made this dream possible.

- -

Why We Need More Space

-

Our current facility has served us well for 15 years, but as our family has grown, so has our need for dedicated learning spaces. The new center will provide modern classrooms, a computer lab, library, and multipurpose rooms for arts and crafts.

- -

Construction Progress

-

Ground was broken in January 2024, and we're pleased to report that construction is on schedule. The foundation has been completed, and walls are now rising. Local contractors have generously donated their services, and community volunteers help with various tasks.

- -

Features of the New Center

-
    -
  • Six modern classrooms with improved lighting and ventilation
  • -
  • Computer lab with 20 workstations
  • -
  • Library with space for 2,000 books
  • -
  • Science laboratory for hands-on learning
  • -
  • Multipurpose hall for events and gatherings
  • -
- -

Expected Completion

-

We anticipate the learning center will be ready for use by the start of the new school year in September 2024. This will allow us to serve up to 50 more children and provide enhanced educational opportunities for all.

- -

Thank you to everyone who has supported this project. Your contributions are literally building the foundation for countless children's futures.

- `, - date: 'March 5, 2024', - author: 'Sarah Johnson', - category: 'Updates', - image: 'https://images.unsplash.com/photo-1518770660439-4636190af475?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - readTime: '4 min read', - }, - ]; - - const blog = blogs.find((b) => b.id === Number(id)); - const relatedBlogs = blogs.filter((b) => b.id !== Number(id)).slice(0, 3); + // Fetch all blog posts for related articles + const { + data: blogResponse, + isLoading: isLoadingBlogs, + isError: isBlogsError, + error: blogsError, + } = useQuery({ + queryKey: ['blogs'], + queryFn: blogService.getPosts, + }); + + // Fetch specific blog post by id + const { + data: blog, + isLoading: isLoadingBlog, + isError: isBlogError, + error: blogError, + } = useQuery({ + queryKey: ['blog', id], + queryFn: () => blogService.getPostById(id || ''), + }); + + // Format date helper + const formatDate = (dateString: string) => new Date(dateString).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + + // Loading state + if (isLoadingBlog || isLoadingBlogs) { + return ( + +
+
+

Loading blog post...

+
+ + ); + } + + // Error state + if (isBlogError || isBlogsError) { + return ( + +
+

+ {blogError?.message || blogsError?.message || 'Something went wrong'} +

+ + ← Back to Blog + +
+
+ ); + } + // Blog not found if (!blog) { return ( -
-

Blog post not found

- - ← Back to Blog - -
+ +
+

Blog post not found

+ + ← Back to Blog + +
+
); } - return ( + // Get related blogs (exclude current blog) + const relatedBlogs = blogResponse?.results + ?.filter((b) => b.id !== blog.id) + ?.slice(0, 3) || []; + // Get primary category from tags + const primaryTag = blog.tags?.[0]; + + return ( {/* Breadcrumb */} @@ -131,14 +165,18 @@ function BlogDetail() { {/* Article Header */}
- - {blog.category} - + {primaryTag && ( + + {primaryTag.name} + + )} - {blog.date} + {formatDate(blog.published_at)} - {blog.readTime} + {blog.reading_time} + {' '} + min read

@@ -150,13 +188,14 @@ function BlogDetail() { By - {blog.author} + {' '} + {blog.author_name}

{blog.title} @@ -165,29 +204,59 @@ function BlogDetail() { {/* Article Content */}
+ {/* Tags */} + {blog.tags && blog.tags.length > 0 && ( +
+

Tags

+
+ {blog.tags.map((tag) => ( + + {tag.name} + + ))} +
+
+ )} + {/* Social Sharing */}

Share this story

{/* Related Articles */} -
-

Related Stories

-
- {relatedBlogs.map((relatedBlog) => ( - -
- {relatedBlog.title} -
-
- - {relatedBlog.date} + {relatedBlogs.length > 0 && ( +
+

Related Stories

+
+ {relatedBlogs.map((relatedBlog) => ( + +
+ {relatedBlog.title} +
+
+ + {formatDate(relatedBlog.published_at)} +
+

+ {relatedBlog.title} +

+

+ {relatedBlog.content.replace(/<[^>]*>/g, '').substring(0, 100)} + ... +

-

- {relatedBlog.title} -

-

- {relatedBlog.content.replace(/<[^>]*>/g, '').substring(0, 100)} - ... -

-
-
- - ))} -
-
+
+ + ))} +
+
+ )} - ); } diff --git a/src/pages/ContactUs/ContactSection.tsx b/src/pages/ContactUs/ContactSection.tsx index a851b6a..ff3e7c5 100644 --- a/src/pages/ContactUs/ContactSection.tsx +++ b/src/pages/ContactUs/ContactSection.tsx @@ -135,7 +135,7 @@ function ContactSection(props:ContactSectionProps) { @@ -152,7 +152,7 @@ function ContactSection(props:ContactSectionProps) {

Contact Information

- +

Address

@@ -163,14 +163,14 @@ function ContactSection(props:ContactSectionProps) {

- +

Phone

(555) 123-4567

- +

Email

info@mountainchildrenhome.org

diff --git a/src/pages/Gallery/GallerySection.tsx b/src/pages/Gallery/GallerySection.tsx index bc2bcc7..7dac965 100644 --- a/src/pages/Gallery/GallerySection.tsx +++ b/src/pages/Gallery/GallerySection.tsx @@ -6,25 +6,30 @@ import { X } from 'lucide-react'; import MaxWidthWrapper from '@/components/MaxWidthWrapper'; -// Define interfaces - make sure these match the parent component -interface Image { - src: string; - alt: string; -} +export interface Photo { + id: number; + image: string; + caption: string; + created_at: string; + album: number; + } -interface Album { - id: string; // Changed from string | number to just string to match parent - cover: string; - name: string; - images: Image[]; -} +export interface Album { + id: number; + title: string; + slug: string; + description: string; + cover_image: string; + created_at: string; + photos: Photo[]; + } interface GalleryProps { - selectedAlbum: string | null; // Changed from string | number | null to string | null - setSelectedAlbum: (id: string | null) => void; // Changed from string | number | null + selectedAlbum: string | null; + setSelectedAlbum: (id: string | null) => void; albums: Album[]; currentAlbum: Album | undefined; - currentImages: Image[]; + currentImages: Photo[]; selectedImage: number | null; openImage: (index: number) => void; closeImage: () => void; @@ -67,18 +72,18 @@ function GallerySection(props: GalleryProps) {
setSelectedAlbum(album.id)} + onClick={() => setSelectedAlbum(album.slug)} >
{album.name}
-

{album.name}

+

{album.title}

- {album.images.length} + {album.photos.length} {' '} photos

@@ -100,21 +105,21 @@ function GallerySection(props: GalleryProps) { > ← Back to Albums -

{currentAlbum?.name}

+

{currentAlbum?.title}

{currentImages.map((image, index) => (
openImage(index)} >
{image.alt}
@@ -144,8 +149,8 @@ function GallerySection(props: GalleryProps) { {currentImages[selectedImage].alt} e.stopPropagation()} /> diff --git a/src/pages/Gallery/index.tsx b/src/pages/Gallery/index.tsx index 31a648e..95a7a66 100644 --- a/src/pages/Gallery/index.tsx +++ b/src/pages/Gallery/index.tsx @@ -1,99 +1,71 @@ import { useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; -import GallerySection from './GallerySection'; +import GallerySection, { type Album } from './GallerySection'; import HeroSection from '@/components/HeroSection'; +import { baseRequest } from '@/lib/base'; + +interface AlbumAPIResponse { + count: number; + next: string | null; + previous: string | null; + results: Album[]; +} + +export interface Photo { + id: number; + image: string; + caption: string; + created_at: string; + album: number; + } + +const galleryService = { + async getAlbums(): Promise { + const response = await baseRequest({ + url: '/cms/albums/', + method: 'GET', + }); + + if (!response.ok) { + throw new Error(`Failed to fetch albums: ${response.statusText}`); + } + + return response.data; + }, +}; + +const QUERY_KEYS = { + photos: ['photos'] as const, + albums: ['albums'] as const, +} as const; function Gallery() { const [selectedImage, setSelectedImage] = useState(null); const [selectedAlbum, setSelectedAlbum] = useState(null); const title = 'Our Gallery'; const description = 'Explore the moments of joy, learning, and growth at Mountain Children Home through our photo gallery.'; - const albums = [ - { - id: 'daily-life', - name: 'Daily Life', - cover: 'https://images.unsplash.com/photo-1517022812141-23620dba5c23?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', - images: [ - { - src: 'https://images.unsplash.com/photo-1517022812141-23620dba5c23?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Children playing together', - }, - { - src: 'https://images.unsplash.com/photo-1535268647677-300dbf3d78d1?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Study time', - }, - { - src: 'https://images.unsplash.com/photo-1439886183900-e79ec0057170?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Outdoor activities', - }, - { - src: 'https://images.unsplash.com/photo-1649972904349-6e44c42644a7?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Learning together', - }, - ], - }, - { - id: 'education', - name: 'Education & Learning', - cover: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', - images: [ - { - src: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Classroom learning', - }, - { - src: 'https://images.unsplash.com/photo-1518770660439-4636190af475?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Computer learning', - }, - { - src: 'https://images.unsplash.com/photo-1649972904349-6e44c42644a7?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Reading time', - }, - ], - }, - { - id: 'events', - name: 'Special Events', - cover: 'https://images.unsplash.com/photo-1527576539890-dfa815648363?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', - images: [ - { - src: 'https://images.unsplash.com/photo-1527576539890-dfa815648363?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Birthday celebration', - }, - { - src: 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Holiday gathering', - }, - { - src: 'https://images.unsplash.com/photo-1517022812141-23620dba5c23?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Graduation ceremony', - }, - ], - }, - { - id: 'facilities', - name: 'Our Facilities', - cover: 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', - images: [ - { - src: 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Main building', - }, - { - src: 'https://images.unsplash.com/photo-1527576539890-dfa815648363?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Dormitory rooms', - }, - { - src: 'https://images.unsplash.com/photo-1518770660439-4636190af475?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80', - alt: 'Learning center', - }, - ], - }, - ]; - - const currentAlbum = albums.find((album) => album.id === selectedAlbum); - const currentImages = currentAlbum?.images || []; + + const { + data: albumsResponse, + isLoading, + isError, + error, + } = useQuery({ + queryKey: QUERY_KEYS.albums, // Add this to your QUERY_KEYS constant + queryFn: galleryService.getAlbums, + staleTime: 5 * 60 * 1000, // 5 minutes + gcTime: 10 * 60 * 1000, // 10 minutes + retry: 2, + refetchOnWindowFocus: false, + }); + + // Use API data directly to match GallerySection component types + const albums = albumsResponse?.results || []; + + const currentAlbum = albums.find((album) => album.slug === selectedAlbum); + const currentImages = currentAlbum?.photos || []; const openImage = (index: number) => { setSelectedImage(index); @@ -121,10 +93,63 @@ function Gallery() { if (e.key === 'Escape') closeImage(); }; + // Handle loading state + if (isLoading) { + return ( + <> + +
+
+
+
+

Loading gallery...

+
+
+
+ + ); + } + + // Handle error state + if (isError) { + return ( + <> + +
+
+
+

Failed to load gallery

+

+ {error instanceof Error ? error.message : 'An unexpected error occurred'} +

+
+
+
+ + ); + } + + // Handle empty state + if (albums.length === 0) { + return ( + <> + +
+
+
+

No albums found

+
+
+
+ + ); + } + return ( <> {/* Hero Section */} + {/* Gallery Content */} { + const response = await baseRequest({ + url: '/cms/photos/', + method: 'GET', + }); + + if (!response.ok) { + throw new Error(`Failed to fetch photos: ${response.statusText}`); + } + + return response.data; + }, +}; + +interface GalleryProps { + maxImages?: number; +} + +function GalleryPreview({ maxImages = 5 }: GalleryProps) { + const { data: photosResponse, isLoading } = useQuery({ + queryKey: ['photos'], + queryFn: galleryService.getPhotos, + }); + + // Memoize the display photos to prevent unnecessary recalculations + const displayPhotos = useMemo(() => { + const photos = photosResponse?.results || []; + return photos.slice(0, maxImages); + }, [photosResponse?.results, maxImages]); + + // Memoize loading skeleton to prevent recreation + const loadingSkeleton = useMemo(() => ( +
+ +
+

Our Gallery

+

+ Take a glimpse into the daily lives of our children and see the joy, + learning, and growth happening at Mountain Children Home. +

+
+ +
+ {Array.from({ length: maxImages }, (_, index) => ( +
+
+
+ ))} +
+ +
+ ), [maxImages]); + + if (isLoading) { + return loadingSkeleton; + } return (
@@ -34,13 +91,26 @@ function GalleryPreview() {
- {images.map((image) => ( -
+ {displayPhotos.map((photo) => ( +
{image.alt} { + const target = e.target as HTMLImageElement; + target.src = '/placeholder-image.jpg'; + }} /> + {photo.caption && ( +
+ {photo.caption} +
+ )}
))}
diff --git a/src/pages/Home/Hero.tsx b/src/pages/Home/Hero.tsx index 51dfb0d..75c3382 100644 --- a/src/pages/Home/Hero.tsx +++ b/src/pages/Home/Hero.tsx @@ -1,5 +1,6 @@ import { Link } from 'react-router-dom'; +import image1 from '@/assets/1.jpg'; import MaxWidthWrapper from '@/components/MaxWidthWrapper'; function HeroSection() { @@ -9,7 +10,8 @@ function HeroSection() {
diff --git a/src/pages/Home/WhoWeAreSection.tsx b/src/pages/Home/WhoWeAreSection.tsx index 279fb7a..9e2d66c 100644 --- a/src/pages/Home/WhoWeAreSection.tsx +++ b/src/pages/Home/WhoWeAreSection.tsx @@ -1,3 +1,4 @@ +import img1 from '@/assets/mountain.jpg'; import MaxWidthWrapper from '@/components/MaxWidthWrapper'; function WhoWeAreSection() { @@ -37,7 +38,7 @@ function WhoWeAreSection() {
Children at Mountain Children Home