import React, { useState, useEffect } from 'react'; import './App.css'; import Scene3D from './components/Scene3D'; import LocationSelector from './components/LocationSelector'; import { weatherService } from './services/weatherService'; function App() { const [weatherData, setWeatherData] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [currentLocationName, setCurrentLocationName] = useState(''); const [isPortalMode, setIsPortalMode] = useState(false); const [exitPortalFunction, setExitPortalFunction] = useState(null); const [portalWeatherData, setPortalWeatherData] = useState(null); const [errorSearchQuery, setErrorSearchQuery] = useState(''); useEffect(() => { loadCurrentLocationWeather(); }, []); const loadCurrentLocationWeather = async () => { setIsLoading(true); setError(null); try { const location = await weatherService.getCurrentLocation(); const data = await weatherService.getCurrentWeather(location); setWeatherData(data); setCurrentLocationName(`${data.location.name}, ${data.location.region}`); } catch (error) { console.error('Error loading weather:', error); setError('Unable to load weather data. Please try entering a city manually.'); } finally { setIsLoading(false); } }; const handleLocationChange = async (location) => { setIsLoading(true); setError(null); try { const data = await weatherService.getCurrentWeather(location); setWeatherData(data); setCurrentLocationName(`${data.location.name}, ${data.location.region}`); } catch (error) { console.error('Error loading weather for location:', error); setError('Unable to load weather data for this location. Please try a different city.'); } finally { setIsLoading(false); } }; const isNightTime = () => { if (!weatherData?.location?.localtime) return false; const localTime = weatherData.location.localtime; const currentHour = new Date(localTime).getHours(); return currentHour >= 19 || currentHour <= 6; }; const handlePortalWeatherDataChange = (data) => { setPortalWeatherData(data); }; const handleErrorSearch = async (e) => { e.preventDefault(); if (errorSearchQuery.trim()) { await handleLocationChange(errorSearchQuery.trim()); setErrorSearchQuery(''); } }; // Use portal weather data when in portal mode, otherwise use main weather data const displayWeatherData = isPortalMode && portalWeatherData ? portalWeatherData : weatherData; const isNight = isNightTime(); const textColor = (isPortalMode || !isNight) ? 'text-black' : 'text-white'; return (
{/* 3D Scene fills entire viewport - base layer */}
{/* All UI elements overlay on top of the canvas */} {weatherData && !isLoading && ( <> {/* Header - changes layout based on portal mode */} {isPortalMode ? ( <> {/* Portal Mode Header */}
{displayWeatherData.location.name} {displayWeatherData.rateLimited && ( DEMO )}
{displayWeatherData.location.region}
) : ( /* Normal Mode Header */
{displayWeatherData.location.name} {displayWeatherData.rateLimited && ( DEMO )}
{displayWeatherData.location.region}
)} {/* Main Temperature Card - Bottom Left */}
{Math.round(displayWeatherData.current.temp_f)} °
{displayWeatherData.current.condition.text}
H: {Math.round(displayWeatherData.current.temp_f + 5)}° L: {Math.round(displayWeatherData.current.temp_f - 10)}°
{/* Compact Stats Bar - Bottom Right */}
HUMIDITY {displayWeatherData.current.humidity}%
WIND {Math.round(displayWeatherData.current.wind_mph)} mph
FEELS {Math.round(displayWeatherData.current.feelslike_f)}°
VISIBILITY {Math.round(displayWeatherData.current.vis_miles)} mi
)} {isLoading && (

Loading weather data...

)} {error && (

{error}

{/* Search form for manual city entry */}
setErrorSearchQuery(e.target.value)} placeholder="Enter city name..." className="flex-1 bg-transparent text-white placeholder-white/60 focus:outline-none text-sm font-light" disabled={isLoading} />
{/* Buttons */}
)}
); } export default App;