/* global React */ const { createContext, useContext, useState, useEffect, useCallback, useRef } = React; const AppCtx = createContext({}); window.AppCtx = AppCtx; function useApp() { return useContext(AppCtx); } window.useApp = useApp; // ── Router ────────────────────────────────────────────────────────── function useRouter() { const get = () => location.hash.replace(/^#\/?/, '') || 'login'; const [route, setRoute] = useState(get); useEffect(() => { const h = () => setRoute(get()); window.addEventListener('hashchange', h); return () => window.removeEventListener('hashchange', h); }, []); const go = useCallback(r => { location.hash = '/' + r; setRoute(r); }, []); return [route, go]; } window.useRouter = useRouter; function uid() { return Math.random().toString(36).slice(2, 10); } function persist(key, val) { try { localStorage.setItem('luna:' + key, JSON.stringify(val)); } catch {} } function restore(key, fallback) { try { const raw = localStorage.getItem('luna:' + key); return raw != null ? JSON.parse(raw) : fallback; } catch { return fallback; } } window.persist = persist; window.restore = restore; // ── Provider ──────────────────────────────────────────────────────── function AppProvider({ children }) { const [route, go] = useRouter(); // Theme const [theme, setThemeState] = useState(() => restore('theme', 'dark')); const setTheme = useCallback(t => { setThemeState(t); persist('theme', t); document.documentElement.setAttribute('data-theme', t); }, []); // User: { token, name } — flush old format (had initials/email/plan) const [user, setUser] = useState(() => { const u = restore('user', null); if (u && !u.token) return null; return u; }); // tokenRef lets callbacks always see the current token without stale closures const tokenRef = useRef(user?.token || null); useEffect(() => { tokenRef.current = user?.token || null; }, [user]); // Per-user helpers so chats are never shared between different users function persistChats(next) { if (tokenRef.current) persist('chats:' + tokenRef.current, next); } function persistActive(id) { if (tokenRef.current) persist('active:' + tokenRef.current, id); } // Chats — loaded for the currently logged-in user const [chats, setChats] = useState(() => { const u = restore('user', null); if (!u?.token) return []; return restore('chats:' + u.token, []); }); const [activeChatId, setActiveChatId] = useState(() => { const u = restore('user', null); if (!u?.token) return null; return restore('active:' + u.token, null); }); const activeChat = chats.find(c => c.id === activeChatId) || chats[0] || null; const login = useCallback(u => { tokenRef.current = u.token; setUser(u); persist('user', u); // Load this user's own chats const savedChats = restore('chats:' + u.token, []); const savedActive = restore('active:' + u.token, null); setChats(savedChats); setActiveChatId(savedActive); go('chat'); }, [go]); const logout = useCallback(() => { tokenRef.current = null; setUser(null); persist('user', null); setChats([]); setActiveChatId(null); go('login'); }, [go]); const updateUser = useCallback(updates => { setUser(prev => { const next = { ...prev, ...updates }; persist('user', next); return next; }); }, []); const newChat = useCallback(() => { const id = uid(); const chat = { id, title: 'Neuer Chat', messages: [] }; setChats(prev => { const next = [chat, ...prev]; persistChats(next); return next; }); setActiveChatId(id); persistActive(id); return id; }, []); const selectChat = useCallback(id => { setActiveChatId(id); persistActive(id); go('chat'); }, [go]); const deleteChat = useCallback(id => { setChats(prev => { const next = prev.filter(c => c.id !== id); persistChats(next); return next; }); setActiveChatId(prev => { if (prev !== id) return prev; persistActive(null); return null; }); }, []); const addMessage = useCallback((chatId, msg) => { setChats(prev => { const next = prev.map(c => c.id === chatId ? { ...c, messages: [...c.messages, msg], title: c.title === 'Neuer Chat' && msg.role === 'user' ? msg.content.slice(0, 42) : c.title, } : c); persistChats(next); return next; }); }, []); const updateMessage = useCallback((chatId, msgId, updates) => { setChats(prev => { const next = prev.map(c => c.id === chatId ? { ...c, messages: c.messages.map(m => m.id === msgId ? { ...m, ...updates } : m), } : c); if (!updates.streaming) persistChats(next); return next; }); }, []); // Theme beim Start setzen useEffect(() => { document.documentElement.setAttribute('data-theme', theme); }, []); // Routing-Guard useEffect(() => { if (!user && route !== 'login') go('login'); if (user && route === 'login') go('chat'); }, [route, user]); const ctx = { route, go, theme, setTheme, user, login, logout, updateUser, chats, activeChat, activeChatId, newChat, selectChat, deleteChat, addMessage, updateMessage, sidebarOpen: true, }; return React.createElement(AppCtx.Provider, { value: ctx }, children); } window.AppProvider = AppProvider;