88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import {
|
|
View,
|
|
Text,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
ActivityIndicator,
|
|
} from 'react-native'
|
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
|
import { useLocalSearchParams, useRouter } from 'expo-router'
|
|
import { useEffect } from 'react'
|
|
import { trpc } from '@/lib/trpc'
|
|
import { useNewsReadStore } from '@/store/news.store'
|
|
import { AttachmentRow } from '@/components/news/AttachmentRow'
|
|
import { Badge } from '@/components/ui/Badge'
|
|
import { NEWS_KATEGORIE_LABELS } from '@innungsapp/shared'
|
|
import { format } from 'date-fns'
|
|
import { de } from 'date-fns/locale'
|
|
|
|
export default function NewsDetailScreen() {
|
|
const { id } = useLocalSearchParams<{ id: string }>()
|
|
const router = useRouter()
|
|
const markRead = useNewsReadStore((s) => s.markRead)
|
|
const markReadMutation = trpc.news.markRead.useMutation()
|
|
|
|
const { data: news, isLoading } = trpc.news.byId.useQuery({ id })
|
|
|
|
useEffect(() => {
|
|
if (news) {
|
|
markRead(id)
|
|
markReadMutation.mutate({ newsId: id })
|
|
}
|
|
}, [news?.id])
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<SafeAreaView className="flex-1 bg-white items-center justify-center">
|
|
<ActivityIndicator size="large" color="#E63946" />
|
|
</SafeAreaView>
|
|
)
|
|
}
|
|
|
|
if (!news) return null
|
|
|
|
return (
|
|
<SafeAreaView className="flex-1 bg-white" edges={['top']}>
|
|
{/* Header */}
|
|
<View className="flex-row items-center px-4 py-3 border-b border-gray-100">
|
|
<TouchableOpacity onPress={() => router.back()} className="mr-3">
|
|
<Text className="text-brand-500 text-base">← Zurück</Text>
|
|
</TouchableOpacity>
|
|
<Text className="font-semibold text-gray-900 flex-1" numberOfLines={1}>
|
|
{news.title}
|
|
</Text>
|
|
</View>
|
|
|
|
<ScrollView contentContainerStyle={{ padding: 16 }}>
|
|
<Badge label={NEWS_KATEGORIE_LABELS[news.kategorie]} kategorie={news.kategorie} />
|
|
|
|
<Text className="text-2xl font-bold text-gray-900 mt-3 mb-2">
|
|
{news.title}
|
|
</Text>
|
|
|
|
<Text className="text-sm text-gray-500 mb-6">
|
|
{news.author?.name ?? 'InnungsApp'} ·{' '}
|
|
{news.publishedAt
|
|
? format(new Date(news.publishedAt), 'dd. MMMM yyyy', { locale: de })
|
|
: ''}
|
|
</Text>
|
|
|
|
{/* Simple Markdown renderer — plain text for MVP */}
|
|
<Text className="text-base text-gray-700 leading-7">
|
|
{news.body.replace(/^#+\s/gm, '').replace(/\*\*(.*?)\*\*/g, '$1')}
|
|
</Text>
|
|
|
|
{/* Attachments */}
|
|
{news.attachments.length > 0 && (
|
|
<View className="mt-8 border-t border-gray-100 pt-4">
|
|
<Text className="font-semibold text-gray-900 mb-3">Anhänge</Text>
|
|
{news.attachments.map((a) => (
|
|
<AttachmentRow key={a.id} attachment={a} />
|
|
))}
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
)
|
|
}
|