// app.jsx — BeanScriptor top-level function BeanScriptor() { const [screen, setScreen] = React.useState('home'); const tg = window.Telegram?.WebApp; // Telegram Mini App initialization React.useEffect(() => { if (tg) { tg.ready(); tg.expand(); // Swiping down minimizes the Mini App — interferes with slider drags (Bot API 7.7+) if (typeof tg.disableVerticalSwipes === 'function') tg.disableVerticalSwipes(); } }, [tg]); // Navigation listener for Tweaks (handy for testing) React.useEffect(() => { const fn = (e) => setScreen(e.detail); window.addEventListener('beanscriptor-go', fn); return () => window.removeEventListener('beanscriptor-go', fn); }, []); const API_BASE = window.APP_API_BASE ?? ''; // "Saved" toast — behaves identically in Telegram and in the browser. const [toast, setToast] = React.useState(null); React.useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 2500); return () => clearTimeout(t); }, [toast]); // Outside Telegram, telegram-web-app.js reports version 6.0, while // showAlert/showPopup require 6.2+ and THROW WebAppMethodUnsupported — // hence the version check + try/catch with a window.alert fallback. const notifyError = (msg) => { try { if (tg?.isVersionAtLeast?.('6.2')) { tg.showAlert(msg); return; } } catch (e) { /* fall through to window.alert */ } window.alert(msg); }; const savingRef = React.useRef(false); const handleSaveData = async (formData) => { if (savingRef.current) return; // guard against double-tapping Save savingRef.current = true; try { const response = await fetch(`${API_BASE}/api/logs`, { method: 'POST', headers: { 'Content-Type': 'application/json', // Signed initData string — the backend verifies the HMAC and derives // the user id itself when TELEGRAM_BOT_TOKEN is configured. 'X-Telegram-Init-Data': tg?.initData || '', }, body: JSON.stringify({ ...formData, telegram_user_id: tg?.initDataUnsafe?.user?.id || null, }) }); if (response.ok) { setScreen('home'); setToast('Log saved ✓'); } else { const err = await response.json().catch(() => ({})); notifyError("Server error " + response.status + (err.detail ? ': ' + JSON.stringify(err.detail) : '')); } } catch (err) { console.error(err); notifyError("Could not reach the backend. Check the Docker container."); } finally { savingRef.current = false; } }; return (
{screen === 'home' ? ( setScreen('log')} onOpenLog={() => setScreen('log')} /> ) : ( setScreen('home')} onSave={handleSaveData} /> )} {toast && (
{toast}
)}
); } ReactDOM.createRoot(document.getElementById('root')).render();