// frontend-fetch-example.js // Frontend code snippet for Reuben OS to fetch and display session files // React Component Example for Session Management import React, { useState, useEffect, useCallback } from 'react'; // Configuration const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'; const POLL_INTERVAL = 5000; // Poll every 5 seconds // ===== SESSION MANAGER COMPONENT ===== export function SessionManager() { const [sessionId, setSessionId] = useState(''); const [files, setFiles] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [quizDetected, setQuizDetected] = useState(false); // Generate a new session ID on component mount useEffect(() => { const generateSessionId = () => { const timestamp = Date.now(); const random = Math.random().toString(36).substring(2, 9); return `session_${timestamp}_${random}`; }; // Check if session ID exists in localStorage, otherwise generate new one const storedSessionId = localStorage.getItem('reubenOSSessionId'); if (storedSessionId) { setSessionId(storedSessionId); } else { const newSessionId = generateSessionId(); setSessionId(newSessionId); localStorage.setItem('reubenOSSessionId', newSessionId); } }, []); // Fetch files for the current session const fetchFiles = useCallback(async () => { if (!sessionId) return; setLoading(true); setError(null); try { const response = await fetch(`${API_URL}/api/mcp-handler?sessionId=${sessionId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); if (data.success) { setFiles(data.files || []); // Check if quiz.json exists const hasQuiz = data.files.some(file => file.name === 'quiz.json'); setQuizDetected(hasQuiz); } else { setError(data.error || 'Failed to fetch files'); } } catch (err) { console.error('Error fetching files:', err); setError(err.message); } finally { setLoading(false); } }, [sessionId]); // Set up polling useEffect(() => { if (!sessionId) return; // Initial fetch fetchFiles(); // Set up polling interval const interval = setInterval(fetchFiles, POLL_INTERVAL); return () => clearInterval(interval); }, [sessionId, fetchFiles]); // Handle manual refresh const handleRefresh = () => { fetchFiles(); }; // Copy session ID to clipboard const copySessionId = () => { navigator.clipboard.writeText(sessionId); alert('Session ID copied to clipboard!'); }; return (

Session Manager

Session ID: {sessionId}
{error && (
Error: {error}
)} {quizDetected && (
🎯 Quiz Detected! Click to launch Quiz App
)}

Files ({files.length})

{files.length === 0 ? (

No files yet. Use Claude to save files to this session.

) : ( )}
); } // ===== FILE ITEM COMPONENT ===== function FileItem({ file, sessionId }) { const [showContent, setShowContent] = useState(false); const handleDownload = () => { // Create a download link const blob = new Blob([file.content || ''], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = file.name; a.click(); URL.revokeObjectURL(url); }; const getFileIcon = (fileName) => { if (fileName.endsWith('.dart')) return '🎯'; if (fileName.endsWith('.tex')) return '📜'; if (fileName.endsWith('.json')) return '📋'; if (fileName.endsWith('.js') || fileName.endsWith('.ts')) return '📝'; if (fileName.endsWith('.py')) return '🐍'; return '📄'; }; return (
  • {getFileIcon(file.name)} {file.name} ({(file.size / 1024).toFixed(2)} KB)
    {showContent && file.content && (
    {file.content.substring(0, 500)}
    {file.content.length > 500 &&

    ... (truncated)

    }
    )}
  • ); } // ===== QUIZ APP LAUNCHER ===== function launchQuizApp(sessionId) { // This function would navigate to your Quiz app with the session ID window.location.href = `/apps/quiz?sessionId=${sessionId}`; } // ===== UTILITY FUNCTIONS ===== // Function to save a file from the frontend (for testing) export async function saveFile(sessionId, fileName, content) { try { const response = await fetch(`${API_URL}/api/mcp-handler`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId, action: 'save_file', fileName, content, }), }); const data = await response.json(); return data; } catch (error) { console.error('Error saving file:', error); throw error; } } // Function to clear all files for a session export async function clearSession(sessionId) { try { const response = await fetch(`${API_URL}/api/mcp-handler`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId, action: 'clear_session', fileName: '', content: '', }), }); const data = await response.json(); return data; } catch (error) { console.error('Error clearing session:', error); throw error; } } // ===== FLUTTER APP COMPONENT ===== export function FlutterAppViewer({ sessionId }) { const [dartFiles, setDartFiles] = useState([]); useEffect(() => { const fetchDartFiles = async () => { try { const response = await fetch(`${API_URL}/api/mcp-handler?sessionId=${sessionId}`); const data = await response.json(); if (data.success) { // Filter only .dart files const dartOnly = data.files.filter(f => f.name.endsWith('.dart')); setDartFiles(dartOnly); } } catch (error) { console.error('Error fetching Dart files:', error); } }; if (sessionId) { fetchDartFiles(); const interval = setInterval(fetchDartFiles, POLL_INTERVAL); return () => clearInterval(interval); } }, [sessionId]); const openInZapp = (file) => { // Open Dart code in Zapp runner const zappUrl = 'https://zapp.run/'; const code = encodeURIComponent(file.content); window.open(`${zappUrl}?code=${code}`, '_blank'); }; return (

    Flutter/Dart Files

    {dartFiles.map((file, index) => (
    {file.name}
    ))}
    ); } // ===== LATEX VIEWER COMPONENT ===== export function LaTeXViewer({ sessionId }) { const [texFiles, setTexFiles] = useState([]); useEffect(() => { const fetchTexFiles = async () => { try { const response = await fetch(`${API_URL}/api/mcp-handler?sessionId=${sessionId}`); const data = await response.json(); if (data.success) { // Filter only .tex files const texOnly = data.files.filter(f => f.name.endsWith('.tex')); setTexFiles(texOnly); } } catch (error) { console.error('Error fetching LaTeX files:', error); } }; if (sessionId) { fetchTexFiles(); const interval = setInterval(fetchTexFiles, POLL_INTERVAL); return () => clearInterval(interval); } }, [sessionId]); return (

    LaTeX Documents

    {texFiles.map((file, index) => (
    {file.name}
    ))}
    ); } function openInLatexEditor(file) { // Your LaTeX editor integration window.location.href = `/apps/latex-studio?file=${file.name}`; } // ===== EXAMPLE USAGE IN NEXT.JS PAGE ===== /* // pages/index.js or pages/dashboard.js import { SessionManager } from '../components/SessionManager'; export default function Dashboard() { return (

    Reuben OS - File Manager

    ); } */ // ===== CSS STYLES (add to your global styles or styled-components) ===== const styles = ` .session-manager { max-width: 800px; margin: 0 auto; padding: 20px; } .session-header { background: #f5f5f5; padding: 15px; border-radius: 8px; margin-bottom: 20px; } .session-info { display: flex; align-items: center; gap: 10px; margin: 10px 0; font-family: monospace; background: white; padding: 10px; border-radius: 4px; } .error-message { background: #fee; color: #c00; padding: 10px; border-radius: 4px; margin: 10px 0; } .quiz-alert { background: #efe; color: #060; padding: 15px; border-radius: 4px; margin: 10px 0; display: flex; justify-content: space-between; align-items: center; } .files-list { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .file-item { list-style: none; padding: 10px; border-bottom: 1px solid #eee; } .file-header { display: flex; align-items: center; gap: 10px; } .file-icon { font-size: 20px; } .file-name { flex: 1; font-weight: 500; } .file-size { color: #666; font-size: 0.9em; } .file-content { margin-top: 10px; padding: 10px; background: #f5f5f5; border-radius: 4px; overflow-x: auto; } .file-content pre { margin: 0; font-size: 0.9em; line-height: 1.4; } button { padding: 6px 12px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover { background: #0056b3; } button:disabled { opacity: 0.5; cursor: not-allowed; } `;