266 lines
15 KiB
JavaScript

// src/App.jsx
import React, { useState, useCallback, useEffect, useMemo } from 'react';
import GlobeCanvas from './components/GlobeCanvas';
import NewsPanel from './components/NewsPanel';
import StatsPanel from './components/StatsPanel';
import GlobalNav from './components/GlobalNav';
import PopUpDetail from './components/PopUpDetail';
import LocalMap from './components/LocalMap'; // ต้องสร้างไฟล์นี้ด้วย (จากคำตอบก่อนหน้า)
function App() {
const [isNewsMode, setIsNewsMode] = useState(true);
const [activePanel, setActivePanel] = useState('world_news');
const [selectedPoint, setSelectedPoint] = useState(null);
const [isPanelVisible, setIsPanelVisible] = useState(true);
// State ใหม่สำหรับ Local View
const [isLocalView, setIsLocalView] = useState(false);
const [localViewCenter, setLocalViewCenter] = useState({ lat: 0, lon: 0 });
const [localViewZoom, setLocalViewZoom] = useState(10); // ซูมเริ่มต้นสำหรับ Leaflet
// Data สำหรับ Panel ต่างๆ - เหมือนเดิม
const panelData = {
'world_news': { title: 'WORLD NEWS', type: 'news', content: 'Global events unfold across continents, shaping economies and societies.', youtubeVideoId: 'dQw4w9WgXcQ' },
'euro_news': { title: 'EURO NEWS', type: 'news', content: 'Key developments in European politics and markets are impacting global trends.', youtubeVideoId: '1' },
'america_news': { title: 'AMERICA NEWS', type: 'news', content: 'Breaking news from North and South America, focusing on economic shifts.', youtubeVideoId: '6' },
'china_japan_news': { title: 'CHINA / JAPAN NEWS', type: 'news', content: 'Latest economic and cultural updates from China and Japan, shaping regional dynamics.', youtubeVideoId: '11' },
'asia_news': { title: 'ASIA NEWS', type: 'news', content: 'Emerging tech and market news from Asia, driving innovation forward.', youtubeVideoId: 'k4F9c40tWnQ' },
'market_review': {
title: 'MARKET REVIEW', type: 'stats',
data: [
{ label: 'DOW JONES', value: '38,712', trend: 'up' },
{ label: 'S&P 500', value: '5,472', trend: 'down' },
{ label: 'NASDAQ', value: '17,857', trend: 'up' },
{ label: 'NIKKEI', value: '38,622', trend: 'same' },
{ label: 'FTSE 100', value: '8,208', trend: 'up' },
],
youtubeVideoId: 'F90M73o9y5c'
},
'next_dollar_currencies': {
title: 'NEXT DOLLAR CURRENCIES', type: 'stats',
data: [],
youtubeVideoId: '041pM7vYwYI'
},
'global_population': {
title: 'GLOBAL POPULATION', type: 'stats',
data: [
{ label: 'Current', value: '7.42 Billion People', trend: 'up' },
{ label: 'Growth Rate', value: '1.09%', trend: 'same' },
{ label: 'Births Today', value: '385,000', trend: 'up' },
{ label: 'Deaths Today', value: '160,000', trend: 'up' },
]
},
'energy_consumption': {
title: 'ENERGY CONSUMPTION', type: 'stats',
data: [
{ label: 'Oil Price (USD)', value: '80.50', trend: 'down' },
{ label: 'Natural Gas', value: '2.80 MMBtu', trend: 'up' },
{ label: 'Renewable Share', value: '25.3%', trend: 'up' },
{ label: 'Coal Consumption', value: 'Down 5%', trend: 'down' },
]
},
'russia_news_stats': {
title: 'RUSSIA ECONOMIC NEWS', type: 'stats',
data: [
{ label: 'BIX Index', value: '124.5', trend: 'up' },
{ label: 'MICEX Index', value: '3,200', trend: 'up' },
{ label: 'Oil Production', value: '10.5 M bbl/d', trend: 'same' },
],
youtubeVideoId: 'your-russia-video-id'
},
};
const globePoints = [
{ id: 'us', name: 'USA', lat: 39.8283, lon: -98.5795, type: 'news', panel: 'america_news', news: ['US stock market surges.', 'Tech innovation continues.'] },
{ id: 'uk', name: 'UK', lat: 51.5074, lon: -0.1278, type: 'news', panel: 'euro_news', news: ['Brexit impact on trade.', 'New UK climate policies.'] },
{ id: 'germany', name: 'Germany', lat: 51.1657, lon: 10.4515, type: 'news', panel: 'euro_news', news: ['German economy outlook.', 'Renewable energy growth.'] },
{ id: 'china', name: 'China', lat: 35.8617, lon: 104.1954, type: 'news', panel: 'china_japan_news', news: ['China trade balance.', 'Digital currency trials.'] },
{ id: 'japan', name: 'Japan', lat: 36.2048, lon: 138.2529, type: 'news', panel: 'china_japan_news', news: ['Japan tech advancements.', 'Olympic preparations.'] },
{ id: 'russia', name: 'Russia', lat: 61.5240, lon: 105.3188, type: 'stats', panel: 'russia_news_stats', news: ['Russia energy exports.', 'Geopolitical developments.'] },
{ id: 'brazil', name: 'Brazil', lat: -14.2350, lon: -51.9253, type: 'stats', panel: 'next_dollar_currencies', news: ['Brazilian Real fluctuation.', 'Agricultural exports outlook.'] },
{ id: 'india', name: 'India', lat: 20.5937, lon: 78.9629, type: 'stats', panel: 'market_review', news: ['Indian market growth.', 'Startup ecosystem booming.'] },
{ id: 'australia', name: 'Australia', lat: -25.2744, lon: 133.7751, type: 'news', panel: 'world_news', news: ['Australia bushfire recovery.', 'Mining sector update.'] },
];
const globePointsWithRussia = useMemo(() => {
const existingRussiaPoint = globePoints.find(p => p.id === 'russia');
if (!existingRussiaPoint) {
return [...globePoints, { id: 'russia', name: 'Russia', lat: 61.5240, lon: 105.3188, type: 'stats', panel: 'russia_news_stats', news: ['Russia energy exports.', 'Geopolitical developments.'] }];
}
return globePoints;
}, [globePoints]);
const globeConnections = [
{ id: 'us-uk', startLat: 39.8283, startLon: -98.5795, endLat: 51.5074, endLon: -0.1278 },
{ id: 'uk-germany', startLat: 51.5074, startLon: -0.1278, endLat: 51.1657, endLon: 10.4515 },
{ id: 'china-japan', startLat: 35.8617, startLon: 104.1954, endLat: 36.2048, endLon: 138.2529 },
{ id: 'us-china', startLat: 39.8283, startLon: -98.5795, endLat: 35.8617, endLon: 104.1954 },
];
const panelLocations = useMemo(() => {
const locations = {};
for (const panelId in panelData) {
locations[panelId] = { ...panelData[panelId] };
}
globePointsWithRussia.forEach(point => {
if (point.panel && locations[point.panel]) {
locations[point.panel].lat = point.lat;
locations[point.panel].lon = point.lon;
}
});
if (!locations['world_news'].lat && !locations['world_news'].lon) { locations['world_news'].lat = -25.2744; locations['world_news'].lon = 133.7751; }
if (!locations['asia_news'].lat && !locations['asia_news'].lon) { locations['asia_news'].lat = 30; locations['asia_news'].lon = 90; }
if (!locations['euro_news'].lat && !locations['euro_news'].lon) { locations['euro_news'].lat = 50; locations['euro_news'].lon = 10; }
if (!locations['america_news'].lat && !locations['america_news'].lon) { locations['america_news'].lat = 35; locations['america_news'].lon = -100; }
if (!locations['global_population'].lat && !locations['global_population'].lon) { locations['global_population'].lat = 0; locations['global_population'].lon = 0; }
if (!locations['energy_consumption'].lat && !locations['energy_consumption'].lon) { locations['energy_consumption'].lat = 0; locations['energy_consumption'].lon = 0; }
if (!locations['russia_news_stats'].lat && !locations['russia_news_stats'].lon) { locations['russia_news_stats'].lat = 61.5240; locations['russia_news_stats'].lon = 105.3188; }
return locations;
}, [panelData, globePointsWithRussia]);
const handlePointClick = useCallback((point) => {
setSelectedPoint(point);
if (point.panel) {
setActivePanel(point.panel);
if (point.type === 'news') setIsNewsMode(true);
else if (point.type === 'stats') setIsNewsMode(false);
setIsPanelVisible(true);
// ไม่ต้องเปลี่ยนเป็น Local View ที่นี่ ให้ GlobeCanvas จัดการเมื่อซูมเข้า
}
}, []);
const closePopUp = useCallback(() => {
setSelectedPoint(null);
}, []);
// Callback เมื่อ GlobeCanvas ตรวจพบการซูมเข้าสู่ Local View
const handleZoomToLocal = useCallback(({ lat, lon }) => {
if (!isLocalView) {
setIsLocalView(true);
setLocalViewCenter({ lat, lon });
setLocalViewZoom(10);
console.log(`App.jsx: Switching to Local View at Lat: ${lat}, Lon: ${lon}`);
}
}, [isLocalView]);
const handleExitLocalView = useCallback(() => {
if (isLocalView) { // ตรวจสอบเพื่อไม่ให้เปลี่ยนโหมดซ้ำซ้อน
setIsLocalView(false);
console.log("App.jsx: Exiting Local View");
}
}, [isLocalView]);
const currentPanel = panelData[activePanel];
const [currentTime, setCurrentTime] = useState('');
const [population, setPopulation] = useState('7.42 Billion People');
useEffect(() => {
const timer = setInterval(() => {
const now = new Date();
setCurrentTime(now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }));
}, 1000);
return () => clearInterval(timer);
}, []);
return (
<div className="relative flex flex-col md:flex-row h-screen w-screen bg-black font-mono overflow-hidden">
{/* Conditional Rendering: แสดง GlobeCanvas หรือ LocalMap */}
{!isLocalView ? (
<GlobeCanvas
activePanel={activePanel}
isNewsMode={isNewsMode}
panelLocations={panelLocations}
globePoints={globePointsWithRussia}
globeConnections={globeConnections}
onPointClick={handlePointClick}
onZoomToLocal={handleZoomToLocal} // ส่ง callback ไปยัง GlobeCanvas
isLocalView={isLocalView} // ส่ง state ไปยัง GlobeCanvas เพื่อควบคุม OrbitControls
/>
) : (
<div className="absolute inset-0 z-0">
<LocalMap
center={localViewCenter}
zoom={localViewZoom}
points={globePointsWithRussia} // ส่งจุดที่ต้องการแสดงบนแผนที่
onPointClick={handlePointClick} // หากต้องการให้คลิกจุดบน Leaflet แล้วแสดง PopUp
/>
{/* ปุ่มสำหรับออกจาก Local View */}
<button
className="btn btn-secondary absolute top-4 left-1/2 -translate-x-1/2 z-30 pointer-events-auto"
onClick={handleExitLocalView}
>
Exit Local View
</button>
</div>
)}
{/* UI Elements Overlay (ด้านหน้า) - ยังคงอยู่เหนือ Globe/Map */}
<div className="absolute inset-0 flex flex-col md:flex-row justify-between items-center p-8 z-20 pointer-events-none">
{/* GlobalNav - อยู่ทางซ้ายมือของโลก */}
<div className="flex-none p-4 md:p-0 pointer-events-auto w-full md:w-auto self-start md:self-center">
<GlobalNav
activePanel={activePanel}
setActivePanel={setActivePanel}
isNewsMode={isNewsMode}
setIsNewsMode={setIsNewsMode}
/>
</div>
{/* ส่วนกลางที่ว่างอยู่สำหรับโลก (ไม่ได้มี div แยก) */}
{/* NewsPanel และ StatsPanel - อยู่ทางขวามือของโลก */}
{currentPanel && (
<div className="flex-none p-4 md:p-0 pointer-events-auto w-full md:w-auto self-end md:self-center">
<div className={`
transition-all duration-500 ease-in-out transform
${isPanelVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-full pointer-events-none'}
${currentPanel.type === 'news' ? 'md:ml-auto' : ''}
`}>
{isNewsMode && currentPanel.type === 'news' && (
<NewsPanel
title={currentPanel.title}
content={currentPanel.content}
youtubeVideoId={currentPanel.youtubeVideoId}
isActive={true}
/>
)}
{!isNewsMode && currentPanel.type === 'stats' && (
<StatsPanel
title={currentPanel.title}
data={currentPanel.data}
youtubeVideoId={currentPanel.youtubeVideoId}
isActive={true}
/>
)}
</div>
</div>
)}
</div>
{/* Top Right - Time Display & Population */}
<div className="absolute top-8 right-8 text-right text-lg z-10 pointer-events-auto text-white" style={{ textShadow: '0px 0px 5px rgba(0, 0, 0, 0.5)' }}>
{/* เปลี่ยน text-base-content เป็น text-white เพื่อสีที่สว่างขึ้น */}
{/* เพิ่ม text-shadow เพื่อให้ข้อความมีมิติและอ่านง่ายขึ้นบนพื้นหลังมืด */}
<div className="font-bold text-3xl">{currentTime}</div>
<div>{population}</div>
</div>
{/* Pop-up Detail (ถ้ามี) */}
{selectedPoint && (
<PopUpDetail
point={selectedPoint}
onClose={closePopUp}
/>
)}
</div>
);
}
export default App;