morethanadiagnosis-hub/web/app/(app)/thejournal/page.tsx

120 lines
4.6 KiB
TypeScript

'use client'
import Link from 'next/link'
import { useEffect } from 'react'
import { useApi } from '@/lib/hooks/useApi'
import { LoadingState } from '@/components/ui/LoadingState'
import { ErrorState } from '@/components/ui/ErrorState'
interface BlogPost {
id: string
title: string
link: string
published_at: string
summary: string
image_url?: string
author?: string
}
interface BlogResponse {
title: string
description: string
items: BlogPost[]
}
export default function TheJournalPage() {
const { data, error, isLoading, execute } = useApi<BlogResponse>()
useEffect(() => {
execute({
url: '/blog/rss',
method: 'GET',
})
}, [])
return (
<main className="min-h-screen bg-white">
<header className="sticky top-0 z-50 bg-white shadow-sm border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div className="flex items-center justify-between">
<Link href="/" className="text-2xl font-bold text-gray-900">MoreThanADiagnosis</Link>
<nav className="hidden md:flex gap-8">
<Link href="/" className="text-gray-600 hover:text-blue-600">Home</Link>
<Link href="/thejournal" className="text-gray-600 hover:text-blue-600 font-semibold text-blue-600">The Journal</Link>
</nav>
</div>
</div>
</header>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
{isLoading && <LoadingState message="Loading journal entries..." />}
{error && <ErrorState message="Failed to load journal entries." onRetry={() => window.location.reload()} />}
{!isLoading && !error && (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white font-heading">
The Journal
</h1>
<p className="mt-2 text-gray-600 dark:text-gray-400">
Reflections, stories, and updates from our community.
</p>
</div>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{data?.items.map((post) => (
<article
key={post.id}
className="flex flex-col bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-300"
>
{post.image_url && (
<div className="flex-shrink-0 h-48 w-full relative">
<img
className="h-full w-full object-cover"
src={post.image_url}
alt={post.title}
/>
</div>
)}
<div className="flex-1 p-6 flex flex-col justify-between">
<div className="flex-1">
<p className="text-sm font-medium text-primary-600">
{post.author || 'MoreThanADiagnosis'}
</p>
<a href={post.link} target="_blank" rel="noopener noreferrer" className="block mt-2">
<p className="text-xl font-semibold text-gray-900 dark:text-white">
{post.title}
</p>
<div
className="mt-3 text-base text-gray-500 dark:text-gray-400 line-clamp-3"
dangerouslySetInnerHTML={{ __html: post.summary || '' }}
/>
</a>
</div>
<div className="mt-6 flex items-center">
<div className="flex-shrink-0">
<span className="sr-only">{post.published_at}</span>
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
<time dateTime={post.published_at}>
{new Date(post.published_at).toLocaleDateString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric',
})}
</time>
</div>
</div>
</div>
</article>
))}
</div>
</div>
)}
</div>
<footer className="bg-gray-900 text-white py-12 border-t border-gray-800">
<div className="max-w-7xl mx-auto px-4 text-center">
<p>&copy; 2025 More Than A Diagnosis. All rights reserved.</p>
</div>
</footer>
</main>
)
}