import React, { useState, useEffect, useCallback } from "react"; import { View, ScrollView, Pressable, ActivityIndicator, FlatList, Dimensions, RefreshControl, } from "react-native"; import { Text } from "@/components/ui/text"; import { Card } from "@/components/ui/card"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { Newspaper, ChevronRight, Clock } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { StandardHeader } from "@/components/StandardHeader"; import { EmptyState } from "@/components/EmptyState"; import { PERMISSION_MAP, hasPermission } from "@/lib/permissions"; import { api, newsApi } from "@/lib/api"; import { ShadowWrapper } from "@/components/ShadowWrapper"; import { useAuthStore } from "@/lib/auth-store"; const { width } = Dimensions.get("window"); const LATEST_CARD_WIDTH = width * 0.8; interface NewsItem { id: string; title: string; content: string; category: "ANNOUNCEMENT" | "UPDATE" | "MAINTENANCE" | "NEWS"; priority: "LOW" | "MEDIUM" | "HIGH"; publishedAt: string; viewCount: number; } export default function NewsScreen() { const nav = useSirouRouter(); const permissions = useAuthStore((s: { permissions: string[] }) => s.permissions); // Safe accessor to handle initialization race conditions const getNewsApi = () => { if (newsApi) return newsApi; return api.news; }; // Latest News State const [latestNews, setLatestNews] = useState([]); const [loadingLatest, setLoadingLatest] = useState(true); // All News State const [allNews, setAllNews] = useState([]); const [loadingAll, setLoadingAll] = useState(true); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const [refreshing, setRefreshing] = useState(false); // Check permissions (none for viewing news) const fetchLatest = async () => { try { setLoadingLatest(true); const service = getNewsApi(); if (!service) throw new Error("News service unavailable"); const data = await service.getLatest({ query: { limit: 5 } }); setLatestNews(data || []); } catch (err) { console.error("[News] Latest fetch error:", err); } finally { setLoadingLatest(false); } }; const fetchAll = async (pageNum: number, isRefresh = false) => { try { if (!isRefresh) { pageNum === 1 ? setLoadingAll(true) : setLoadingMore(true); } const service = getNewsApi(); if (!service) throw new Error("News service unavailable"); const response = await service.getAll({ query: { page: pageNum, limit: 10, isPublished: true }, }); const newData = response.data || []; if (isRefresh) { setAllNews(newData); } else { setAllNews((prev) => (pageNum === 1 ? newData : [...prev, ...newData])); } setHasMore(response?.meta?.hasNextPage ?? false); setPage(pageNum); } catch (err) { console.error("[News] All fetch error:", err); } finally { setLoadingAll(false); setLoadingMore(false); setRefreshing(false); } }; const onRefresh = () => { setRefreshing(true); fetchLatest(); fetchAll(1, true); }; useEffect(() => { fetchLatest(); fetchAll(1); }, []); const loadMore = () => { if (hasMore && !loadingMore && !loadingAll) { fetchAll(page + 1); } }; const getCategoryColor = (category: string) => { switch (category) { case "ANNOUNCEMENT": return "bg-amber-500"; case "UPDATE": return "bg-blue-500"; case "MAINTENANCE": return "bg-red-500"; default: return "bg-emerald-500"; } }; const LatestItem = ({ item }: { item: NewsItem }) => ( {item.category} {new Date(item.publishedAt).toLocaleDateString()} {item.title} Tap to read more ); const NewsItem = ({ item }: { item: NewsItem }) => ( {item.category} {item.title} {item.content} {new Date(item.publishedAt).toLocaleDateString()} ); return ( } > {/* Latest News Section */} Latest News {loadingLatest ? ( ) : latestNews.length > 0 ? ( {latestNews.map((item) => ( ))} ) : ( )} {/* All News Section */} All News {loadingAll ? ( ) : allNews.length > 0 ? ( <> {allNews.map((item) => ( ))} {hasMore && ( {loadingMore ? ( ) : ( Load More )} )} ) : ( )} ); }