diff --git a/src/pages/News/AuthorsPage.tsx b/src/pages/News/AuthorsPage.tsx new file mode 100644 index 00000000..1c5ff95a --- /dev/null +++ b/src/pages/News/AuthorsPage.tsx @@ -0,0 +1,201 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { motion } from 'framer-motion'; +import { User, Building, BookOpen } from 'lucide-react'; + +import Header from '@/sections/Header'; +import Footer from '@/sections/Footer'; +import { fetchAllAuthors, Author } from '@/utils/author-utils'; +import { getPostsByAuthor } from '@/utils/posts-utils'; + +type AuthorWithPostCount = Author & { + postCount: number; +}; + +const AuthorsPage: React.FC = () => { + const navigate = useNavigate(); + const [authors, setAuthors] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const loadAllAuthors = async () => { + setIsLoading(true); + document.title = 'Our Authors - SugarLabs'; + try { + + const allAuthors = await fetchAllAuthors(); + + if (!allAuthors || allAuthors.length === 0) { + setAuthors([]); + return; + } + console.log(allAuthors); + const authorsWithData = await Promise.all( + allAuthors.map(async (author) => { + try { + const posts = await getPostsByAuthor(author.slug); + return { ...author, postCount: posts.length }; + } catch (postError) { + console.error( + `Failed to get post count for ${author.name}`, + postError, + ); + return { ...author, postCount: 0 }; + } + }), + ); + + setAuthors(authorsWithData); + } catch (err) { + console.error('Error loading authors:', err); + setError('Failed to load author information'); + } finally { + setIsLoading(false); + } + }; + + loadAllAuthors(); + }, []); + + const handleAuthorClick = (slug: string) => { + navigate(`/authors/${slug}`); + }; + + const renderContent = () => { + if (isLoading) { + return ( +
+
+
+

Loading authors...

+
+
+ ); + } + + if (error) { + return ( +
+

+ Something went wrong +

+

{error}

+
+ ); + } + + if (authors.length === 0) { + return ( +
+

No Authors

+

+ There are no authors to display at this time. +

+
+ ); + } + + return ( +
+ {authors.map((author, index) => ( + handleAuthorClick(author.slug)} + className="cursor-pointer group" + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: index * 0.1 }} + whileHover={{ scale: 1.02 }} + > +
+
+ {/* Avatar */} +
+ {author.avatar ? ( + {author.name} + ) : ( +
+ +
+ )} +
+ + {/* Author Info */} +
+

+ {author.name} +

+
+ + {author.title} + + {author.organization && ( + <> + + at + +
+ + + {author.organization} + +
+ + )} +
+

+ {author.description} +

+ + {/* Quick Stats */} +
+
+ + + {author.postCount}{' '} + {author.postCount === 1 ? 'Article' : 'Articles'} + +
+ {author.organization && ( +
+ + {author.organization} +
+ )} +
+
+
+
+
+ ))} +
+ ); + }; + + return ( + <> +
+
+
+ + Meet Our Authors + + {renderContent()} +
+
+