188 lines
4.9 KiB
TypeScript
188 lines
4.9 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
IonPage,
|
|
IonContent,
|
|
IonHeader,
|
|
IonToolbar,
|
|
IonButtons,
|
|
IonButton,
|
|
IonIcon,
|
|
IonSpinner,
|
|
useIonViewWillEnter,
|
|
} from '@ionic/react';
|
|
import { useHistory, useParams } from 'react-router-dom';
|
|
import { supabase } from '../supabase';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { NewsItem } from '../types';
|
|
import { chevronBackOutline, createOutline } from 'ionicons/icons';
|
|
|
|
const NewsDetail: React.FC = () => {
|
|
const history = useHistory();
|
|
const { id } = useParams<{ id: string }>();
|
|
const { profile } = useAuth();
|
|
const [news, setNews] = useState<NewsItem | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useIonViewWillEnter(() => {
|
|
fetchNewsItem();
|
|
});
|
|
|
|
const fetchNewsItem = async () => {
|
|
try {
|
|
const { data, error } = await supabase
|
|
.from('news')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
if (error) throw error;
|
|
setNews(data);
|
|
} catch (err) {
|
|
console.error('Error fetching news:', err);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<IonPage>
|
|
<IonHeader className="ion-no-border">
|
|
<IonToolbar style={{ '--background': '#f5f7f4' }}>
|
|
<IonButtons slot="start">
|
|
<IonButton onClick={() => history.goBack()}>
|
|
<IonIcon icon={chevronBackOutline} slot="icon-only" />
|
|
</IonButton>
|
|
</IonButtons>
|
|
</IonToolbar>
|
|
</IonHeader>
|
|
<IonContent style={{ '--background': '#f5f7f4' }}>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
marginTop: '40px',
|
|
}}
|
|
>
|
|
<IonSpinner name="crescent" />
|
|
</div>
|
|
</IonContent>
|
|
</IonPage>
|
|
);
|
|
}
|
|
|
|
if (!news) {
|
|
return (
|
|
<IonPage>
|
|
<IonHeader className="ion-no-border">
|
|
<IonToolbar style={{ '--background': '#f5f7f4' }}>
|
|
<IonButtons slot="start">
|
|
<IonButton onClick={() => history.goBack()}>
|
|
<IonIcon icon={chevronBackOutline} slot="icon-only" />
|
|
</IonButton>
|
|
</IonButtons>
|
|
</IonToolbar>
|
|
</IonHeader>
|
|
<IonContent style={{ '--background': '#f5f7f4' }}>
|
|
<div
|
|
style={{ textAlign: 'center', marginTop: '60px', color: '#6b7280' }}
|
|
>
|
|
News item not found.
|
|
</div>
|
|
</IonContent>
|
|
</IonPage>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<IonPage>
|
|
<IonHeader className="ion-no-border">
|
|
<IonToolbar style={{ '--background': '#f5f7f4' }}>
|
|
<IonButtons slot="start">
|
|
<IonButton onClick={() => history.goBack()}>
|
|
<IonIcon icon={chevronBackOutline} slot="icon-only" />
|
|
</IonButton>
|
|
</IonButtons>
|
|
{profile?.role === 'admin' && (
|
|
<IonButtons slot="end">
|
|
<IonButton onClick={() => history.push(`/admin/news/${news.id}`)}>
|
|
<IonIcon
|
|
icon={createOutline}
|
|
slot="icon-only"
|
|
style={{ color: '#2f6b4f' }}
|
|
/>
|
|
</IonButton>
|
|
</IonButtons>
|
|
)}
|
|
</IonToolbar>
|
|
</IonHeader>
|
|
|
|
<IonContent style={{ '--background': '#f5f7f4' }}>
|
|
<div
|
|
style={{
|
|
padding: '0 20px 40px',
|
|
maxWidth: '600px',
|
|
margin: '0 auto',
|
|
}}
|
|
>
|
|
{news.image_url && (
|
|
<div style={{ marginBottom: '24px' }}>
|
|
<img
|
|
src={news.image_url}
|
|
alt=""
|
|
style={{
|
|
width: '100%',
|
|
height: '240px',
|
|
objectFit: 'cover',
|
|
borderRadius: '24px',
|
|
background: '#eef2ec',
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
style={{
|
|
fontSize: '14px',
|
|
fontWeight: '600',
|
|
color: '#2f6b4f',
|
|
marginBottom: '12px',
|
|
}}
|
|
>
|
|
{new Date(news.created_at).toLocaleDateString(undefined, {
|
|
weekday: 'long',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
year: 'numeric',
|
|
})}
|
|
</div>
|
|
|
|
<h1
|
|
style={{
|
|
margin: '0 0 24px',
|
|
fontSize: '28px',
|
|
fontWeight: '800',
|
|
color: '#1f2937',
|
|
lineHeight: '1.2',
|
|
}}
|
|
>
|
|
{news.title}
|
|
</h1>
|
|
|
|
<div
|
|
style={{
|
|
fontSize: '16px',
|
|
color: '#4b5563',
|
|
lineHeight: '1.6',
|
|
whiteSpace: 'pre-wrap',
|
|
}}
|
|
>
|
|
{news.content}
|
|
</div>
|
|
</div>
|
|
</IonContent>
|
|
</IonPage>
|
|
);
|
|
};
|
|
|
|
export default NewsDetail;
|