205 lines
8.3 KiB
TypeScript
205 lines
8.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import ReactMarkdown from 'react-markdown';
|
|
import { Link } from '@/lib/navigation';
|
|
import { getLocalizedValue } from '@/lib/i18n';
|
|
|
|
interface NewsItem {
|
|
id: number;
|
|
title: any;
|
|
content: any;
|
|
author: string | null;
|
|
publishedAt: string;
|
|
featured: boolean;
|
|
special: {
|
|
id: number;
|
|
name: any;
|
|
} | null;
|
|
}
|
|
|
|
interface NewsSectionProps {
|
|
locale: string;
|
|
}
|
|
|
|
export default function NewsSection({ locale }: NewsSectionProps) {
|
|
const [news, setNews] = useState<NewsItem[]>([]);
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
fetchNews();
|
|
}, [locale]);
|
|
|
|
const fetchNews = async () => {
|
|
try {
|
|
const res = await fetch(`/api/news?limit=3&locale=${locale}`);
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
setNews(data);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch news:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading || news.length === 0) {
|
|
return null; // Don't show anything if no news
|
|
}
|
|
|
|
return (
|
|
<div style={{
|
|
background: '#f9fafb',
|
|
borderRadius: '0.5rem',
|
|
margin: '1rem auto',
|
|
maxWidth: '800px',
|
|
overflow: 'hidden',
|
|
border: '1px solid #e5e7eb'
|
|
}}>
|
|
{/* Header */}
|
|
<button
|
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
style={{
|
|
width: '100%',
|
|
padding: '0.75rem 1rem',
|
|
background: 'transparent',
|
|
border: 'none',
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
cursor: 'pointer',
|
|
fontSize: '0.875rem',
|
|
fontWeight: '600',
|
|
color: '#374151'
|
|
}}
|
|
>
|
|
<span>📰 News & Updates</span>
|
|
<span style={{ fontSize: '0.75rem', color: '#9ca3af' }}>
|
|
{isExpanded ? '▼' : '▶'}
|
|
</span>
|
|
</button>
|
|
|
|
{/* Content */}
|
|
{isExpanded && (
|
|
<div style={{
|
|
padding: '0 1rem 1rem 1rem',
|
|
borderTop: '1px solid #e5e7eb'
|
|
}}>
|
|
{news.map((item, index) => (
|
|
<div
|
|
key={item.id}
|
|
style={{
|
|
padding: '0.75rem 0',
|
|
borderBottom: index < news.length - 1 ? '1px solid #e5e7eb' : 'none'
|
|
}}
|
|
>
|
|
{/* Title */}
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '0.5rem',
|
|
marginBottom: '0.25rem'
|
|
}}>
|
|
{item.featured && (
|
|
<span style={{
|
|
background: '#fef3c7',
|
|
color: '#92400e',
|
|
padding: '0.125rem 0.375rem',
|
|
borderRadius: '0.25rem',
|
|
fontSize: '0.625rem',
|
|
fontWeight: '600'
|
|
}}>
|
|
⭐ FEATURED
|
|
</span>
|
|
)}
|
|
<h3 style={{
|
|
margin: 0,
|
|
fontSize: '0.875rem',
|
|
fontWeight: '600',
|
|
color: '#111827'
|
|
}}>
|
|
{getLocalizedValue(item.title, locale)}
|
|
</h3>
|
|
</div>
|
|
|
|
{/* Metadata */}
|
|
<div style={{
|
|
fontSize: '0.75rem',
|
|
color: '#6b7280',
|
|
marginBottom: '0.5rem',
|
|
display: 'flex',
|
|
gap: '0.5rem',
|
|
flexWrap: 'wrap'
|
|
}}>
|
|
<span>
|
|
{new Date(item.publishedAt).toLocaleDateString('de-DE', {
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
year: 'numeric'
|
|
})}
|
|
</span>
|
|
{item.author && (
|
|
<>
|
|
<span>•</span>
|
|
<span>by {item.author}</span>
|
|
</>
|
|
)}
|
|
{item.special && (
|
|
<>
|
|
<span>•</span>
|
|
<Link
|
|
href={`/special/${getLocalizedValue(item.special.name, locale)}`}
|
|
style={{
|
|
color: '#be185d',
|
|
textDecoration: 'none',
|
|
fontWeight: '500'
|
|
}}
|
|
>
|
|
★ {getLocalizedValue(item.special.name, locale)}
|
|
</Link>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div
|
|
className="news-content"
|
|
style={{
|
|
fontSize: '0.875rem',
|
|
color: '#374151',
|
|
lineHeight: '1.5'
|
|
}}
|
|
>
|
|
<ReactMarkdown
|
|
components={{
|
|
p: ({ children }) => <p style={{ margin: '0.5rem 0' }}>{children}</p>,
|
|
a: ({ children, href }) => (
|
|
<a
|
|
href={href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
style={{ color: '#4f46e5', textDecoration: 'underline' }}
|
|
>
|
|
{children}
|
|
</a>
|
|
),
|
|
strong: ({ children }) => <strong style={{ fontWeight: '600' }}>{children}</strong>,
|
|
em: ({ children }) => <em style={{ fontStyle: 'italic' }}>{children}</em>,
|
|
ul: ({ children }) => <ul style={{ margin: '0.5rem 0', paddingLeft: '1.5rem' }}>{children}</ul>,
|
|
ol: ({ children }) => <ol style={{ margin: '0.5rem 0', paddingLeft: '1.5rem' }}>{children}</ol>,
|
|
li: ({ children }) => <li style={{ margin: '0.25rem 0' }}>{children}</li>
|
|
}}
|
|
>
|
|
{getLocalizedValue(item.content, locale)}
|
|
</ReactMarkdown>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|