import { useState, useEffect } from "react"; import { getGameTitle, getShortenedGameName } from "../utils.ts"; import { useSearchParams } from "react-router-dom"; 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; is_ai_summary: boolean | null; } interface NewsFeedProps { newsItems: NewsData[]; } export const NewsFeed: React.FC = ({ newsItems }) => { const [showEnglish, setShowEnglish] = useState>({}); const [expanded, setExpanded] = useState>({}); const [currentImageIndex, setCurrentImageIndex] = useState< Record >({}); const [loadingImages, setLoadingImages] = useState>( {}, ); const [searchParams] = useSearchParams(); const isMoe = searchParams.has("moe"); const pfpBaseUrl = import.meta.env.VITE_PFP_BASE_URL; const middlewareBase = import.meta.env.VITE_MIDDLEWARE_BASE_URL; const toggleLanguage = (id: string) => setShowEnglish((prev) => ({ ...prev, [id]: !prev[id] })); const toggleExpand = (id: string) => setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); const changeImage = (id: string, i: number) => { if (currentImageIndex[id] == i) return; setCurrentImageIndex((p) => ({ ...p, [id]: i })); setLoadingImages((p) => ({ ...p, [id]: true })); }; const handleImageLoad = (id: string) => setLoadingImages((p) => ({ ...p, [id]: false })); const PREVIEW_CHAR_LIMIT = 600; useEffect(() => { const initialImageIndex: Record = {}; newsItems.forEach((news) => { const contentHash = news.content .split("") .reduce( (hash, char) => (hash << 5) + hash + char.charCodeAt(0), 5381, ) >>> 0; const headlineHash = (news.headline || "null") .split("") .reduce( (hash, char) => (hash << 5) + hash + char.charCodeAt(0), 5381, ) >>> 0; const newsId = `${news.identifier}-${news.timestamp}-${contentHash.toString(16)}-${headlineHash.toString(16)}`; initialImageIndex[newsId] = 0; }); setCurrentImageIndex(initialImageIndex); }, [newsItems]); useEffect(() => { const fragment = window.location.hash.slice(1); if (fragment) { const el = document.getElementById(fragment); if (el) { el.scrollIntoView({ behavior: "smooth", block: "start" }); } else { alert("News Post doesn't or no longer exists..."); } } }, [newsItems]); return (
{newsItems.map((news) => { const date = new Date(news.timestamp * 1000).toLocaleDateString( "ja-JP", { year: "numeric", month: "2-digit", day: "2-digit" }, ); const contentHash = news.content .split("") .reduce( (hash, char) => (hash << 5) + hash + char.charCodeAt(0), 5381, ) >>> 0; const headlineHash = (news.headline || "null") .split("") .reduce( (hash, char) => (hash << 5) + hash + char.charCodeAt(0), 5381, ) >>> 0; const newsId = `${news.identifier}-${news.timestamp}-${contentHash.toString(16)}-${headlineHash.toString(16)}`; 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; const isLong = displayContent.length > PREVIEW_CHAR_LIMIT; const isExpanded = !!expanded[newsId]; const contentToShow = isLong && !isExpanded ? displayContent.slice(0, PREVIEW_CHAR_LIMIT) + "…" : displayContent; return (
{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]} ); if (u) return ( {u[0]} ); return part; })}

{isLong && ( )}
{/* Copy Link to Post */} {/* AI Disclaimer */} {news.is_ai_summary && (
The information above is written by AI / 上記の情報はAIによって生成されました。
)} {/* Machine TL Disclaimer */} {hasTranslation && isEnglish && (
The information above is machine translated and may contain inaccuracies
)} {/* Images */} {news.images.length > 0 && (
{(() => { const idx = currentImageIndex[newsId] || 0; const img = news.images[idx]; return (
{loadingImages[newsId] && (
)} news visual handleImageLoad(newsId)} />
); })()} {news.images.length > 1 && (
{news.images.map((_, idx) => ( ))}
)}
)} {news.url && ( )}
); })}
); };