import React, { useState, useEffect, useRef } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth'; import { getFirestore, doc, setDoc, onSnapshot, collection } from 'firebase/firestore'; // --- CONFIGURATION --- const firebaseConfig = JSON.parse(__firebase_config); const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'family-hub-default'; // --- ICONS (Inline SVG for reliability) --- const IconClock = () => ; const IconSun = ({ className }) => ; const IconCloud = ({ className }) => ; const IconCalendar = ({ className }) => ; const IconSettings = ({ size = 24 }) => ; const IconSave = () => ; const IconLock = () => ; export default function App() { const [user, setUser] = useState(null); const [view, setView] = useState('display'); const [adminAuth, setAdminAuth] = useState(false); const [password, setPassword] = useState(''); const [currentTime, setCurrentTime] = useState(new Date()); const [settings, setSettings] = useState({ city: 'Stockholm', weatherApiKey: '', greeting: 'Välkomna hem familjen!', photoUrls: [ 'https://images.unsplash.com/photo-1506744038136-46273834b3fb', 'https://images.unsplash.com/photo-1470770841072-f978cf4d019e' ], calendarEvents: [ { id: 1, title: 'Gympa - Elsa', time: '17:30' }, { id: 2, title: 'Middag hos mormor', time: '18:30' } ] }); const [weather, setWeather] = useState(null); const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); // 1. Firebase Auth useEffect(() => { const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (err) { console.error("Auth error:", err); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, setUser); return () => unsubscribe(); }, []); // 2. Sync Settings (Fixed Path Segments) useEffect(() => { if (!user) return; // RULE 1: artifacts/{appId}/public/data/{collectionName}/{documentId} const settingsRef = doc(db, 'artifacts', appId, 'public', 'data', 'config', 'settings'); const unsubscribe = onSnapshot(settingsRef, (docSnap) => { if (docSnap.exists()) { setSettings(docSnap.data()); } else { setDoc(settingsRef, settings).catch(e => console.error("Initial set error:", e)); } }, (error) => console.error("Firestore sync error:", error)); return () => unsubscribe(); }, [user]); // 3. Timers useEffect(() => { const timer = setInterval(() => setCurrentTime(new Date()), 1000); const photoTimer = setInterval(() => { setCurrentPhotoIndex((prev) => (prev + 1) % settings.photoUrls.length); }, 15000); return () => { clearInterval(timer); clearInterval(photoTimer); }; }, [settings.photoUrls.length]); // 4. Weather Fetch useEffect(() => { const fetchWeather = async () => { const key = settings.weatherApiKey; if (!key) return; try { const res = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${settings.city}&units=metric&lang=se&appid=${key}`); const data = await res.json(); if (data.main) setWeather(data); } catch (err) { console.error("Weather fetch error:", err); } }; fetchWeather(); const interval = setInterval(fetchWeather, 600000); return () => clearInterval(interval); }, [settings.city, settings.weatherApiKey]); const saveSettings = async (newSettings) => { if (!user) return; const settingsRef = doc(db, 'artifacts', appId, 'public', 'data', 'config', 'settings'); await setDoc(settingsRef, newSettings); }; // --- VIEWS --- const AdminPanel = () => { const [localSettings, setLocalSettings] = useState({...settings}); const [newPhotoUrl, setNewPhotoUrl] = useState(''); if (!adminAuth) { return (
{dateStr}
{weather.weather[0].description}
{settings.city}