import { useState } from "react"; import { getGameTitle } from "../utils.ts"; export interface NewsData { date: string; identifier: string; type: string | null; timestamp: number; headline: string | null; content: string; url: string | null; images: Array<{ image: string; link: string | null; }>; en_headline: string | null; en_content: string | null; } interface NewsFeedProps { newsItems: NewsData[]; } export const NewsFeed: React.FC = ({ newsItems }) => { // Track which items are showing English content const [showEnglish, setShowEnglish] = useState>({}); // Track which items are expanded beyond the preview const [expanded, setExpanded] = useState>({}); // Track the current image index for each news item const [currentImageIndex, setCurrentImageIndex] = useState>({}); // Track loading state for images const [loadingImages, setLoadingImages] = useState>({}); const toggleLanguage = (itemId: string) => { setShowEnglish((prev) => ({ ...prev, [itemId]: !prev[itemId] })); }; const toggleExpand = (itemId: string) => { setExpanded((prev) => ({ ...prev, [itemId]: !prev[itemId] })); }; const changeImage = (itemId: string, index: number) => { setCurrentImageIndex((prev) => ({ ...prev, [itemId]: index })); setLoadingImages((prev) => ({ ...prev, [itemId]: true })); // Set loading state for the image }; const handleImageLoad = (itemId: string) => { setLoadingImages((prev) => ({ ...prev, [itemId]: false })); // Clear loading state when image loads }; const PREVIEW_CHAR_LIMIT = 600; return (
{newsItems.map((news) => { const formattedDate = new Date(news.timestamp * 1000).toLocaleDateString("ja-JP", { year: "numeric", month: "2-digit", day: "2-digit", }); const newsId = `${news.identifier}-${news.timestamp}-${news.content.substring(0, 20)}`; const isEnglish = !!showEnglish[newsId]; const hasTranslation = news.en_headline || news.en_content; const displayHeadline = isEnglish && news.en_headline ? news.en_headline : news.headline; const displayContent = isEnglish && news.en_content ? news.en_content! : news.content; // Read‑more logic const isLong = displayContent.length > PREVIEW_CHAR_LIMIT; const isExpanded = !!expanded[newsId]; const contentToShow = isLong && !isExpanded ? displayContent.slice(0, PREVIEW_CHAR_LIMIT) + "…" : displayContent; return (
{/* Header (Game Icon + Info) */}
{news.identifier.charAt(0)}
{getGameTitle(news.identifier)} {formattedDate} {news.type && ( {news.type} )}
{hasTranslation && ( )}
{/* Content Area */}
{displayHeadline && (

{displayHeadline}

)}

{contentToShow.split(/(\[.*?\]\(.*?\)|https?:\/\/[^\s]+)/g).map((part, idx) => { const m = part.match(/\[(.*?)\]\((.*?)\)/); const u = part.match(/https?:\/\/[^\s]+/); if (m) { return ( {m[1]} ); } else if (u) { return ( {u[0]} ); } return part; })}

{isLong && ( )}
{/* Images */}
{news.images.length > 0 && ( <> {/* Display only the current image */} {(() => { const currentIdx = currentImageIndex[newsId] || 0; const img = news.images[currentIdx]; return (
{loadingImages[newsId] && (
)} news visual handleImageLoad(newsId)} />
); })()} {/* Image selector buttons (only shown if there are multiple images) */} {news.images.length > 1 && (
{news.images.map((_, idx) => ( ))}
)} )}
{/* Footer */} {news.url && ( )}
); })}
); };