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

108 lines
3.4 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
interface PodcastEpisode {
id: string;
title: string;
description: string;
audio_url: string;
published_at: string;
duration: string;
image_url: string;
}
interface PodcastFeed {
title: string;
description: string;
image_url: string;
episodes: PodcastEpisode[];
}
const API_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://216.158.230.94:8001/api/v1';
export default function PodcastPage() {
const [feed, setFeed] = useState<PodcastFeed | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchPodcasts = async () => {
try {
const response = await fetch(`${API_URL}/podcast/`);
if (!response.ok) {
throw new Error('Failed to fetch podcasts');
}
const data = await response.json();
setFeed(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setLoading(false);
}
};
fetchPodcasts();
}, []);
if (loading) {
return (
<div className="flex justify-center items-center min-h-screen bg-background">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
</div>
);
}
if (error) {
return (
<div className="flex justify-center items-center min-h-screen bg-background">
<div className="text-red-500 text-xl">Error: {error}</div>
</div>
);
}
return (
<div className="min-h-screen bg-background text-text p-8">
<div className="max-w-4xl mx-auto">
<header className="mb-12 text-center">
<h1 className="text-4xl font-heading font-bold text-primary mb-4">Podcasts</h1>
<p className="text-lg text-text opacity-80 font-body">Listen to our latest episodes and stories.</p>
</header>
<div className="space-y-8">
{feed?.episodes.map((episode) => (
<div key={episode.id} className="bg-surface rounded-xl shadow-card p-6 flex flex-col md:flex-row gap-6 transition-transform hover:scale-[1.01]">
<div className="flex-shrink-0">
<img
src={episode.image_url || feed.image_url}
alt={episode.title}
className="w-32 h-32 rounded-lg object-cover bg-secondary"
/>
</div>
<div className="flex-grow">
<h2 className="text-2xl font-heading font-semibold text-primary mb-2">{episode.title}</h2>
<div className="flex items-center gap-4 text-sm text-text opacity-60 mb-4 font-body">
<span>{new Date(episode.published_at).toLocaleDateString()}</span>
<span></span>
<span>{episode.duration}</span>
</div>
<div
className="text-text opacity-80 mb-6 font-body line-clamp-3"
dangerouslySetInnerHTML={{ __html: episode.description }}
/>
<audio
controls
className="w-full"
src={episode.audio_url}
>
Your browser does not support the audio element.
</audio>
</div>
</div>
))}
</div>
</div>
</div>
);
}