import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Server, Users, Shield, Mail, Calendar, FolderOpen, Wifi, Activity, CheckCircle, XCircle, AlertCircle, Play, Square, RotateCcw } from 'lucide-react'; import { cellAPI, servicesAPI } from '../services/api'; const SERVICES = [ { name: 'Cell Home', url: 'http://mycell.cell', desc: 'Main UI — no login needed' }, { name: 'Calendar', url: 'http://calendar.cell', desc: 'Login: your WireGuard username' }, { name: 'Files', url: 'http://files.cell', desc: 'Login: admin / admin123' }, { name: 'Webmail', url: 'http://mail.cell', desc: 'Login: admin@rainloop.net / 12345' }, ]; function Dashboard({ isOnline }) { const navigate = useNavigate(); const [cellStatus, setCellStatus] = useState(null); const [servicesStatus, setServicesStatus] = useState(null); const [isLoading, setIsLoading] = useState(true); const [serviceControls, setServiceControls] = useState({}); useEffect(() => { fetchData(); const interval = setInterval(fetchData, 5000); // Refresh every 30 seconds return () => clearInterval(interval); }, [isOnline]); const getStatusIcon = (status) => { if (status === true || status?.status === 'online' || status?.running === true) { return ; } else if (status === false || status?.status === 'offline' || status?.running === false) { return ; } else { return ; } }; const getStatusText = (status) => { if (status === true || status?.status === 'online' || status?.running === true) { return 'Online'; } else if (status === false || status?.status === 'offline' || status?.running === false) { return 'Offline'; } else { return 'Unknown'; } }; const getStatusColor = (status) => { if (status === true || status?.status === 'online' || status?.running === true) { return 'text-success-600'; } else if (status === false || status?.status === 'offline' || status?.running === false) { return 'text-danger-600'; } else { return 'text-warning-600'; } }; const formatUptime = (seconds) => { if (!seconds || seconds < 0) return '0s'; const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); const parts = []; if (days > 0) parts.push(`${days}d`); if (hours > 0) parts.push(`${hours}h`); if (minutes > 0) parts.push(`${minutes}m`); if (secs > 0 || parts.length === 0) parts.push(`${secs}s`); return parts.join(' '); }; const handleServiceControl = async (serviceName, action) => { if (!isOnline) return; setServiceControls(prev => ({ ...prev, [serviceName]: { ...prev[serviceName], [action]: 'loading' } })); try { let response; switch (action) { case 'start': response = await servicesAPI.startService(serviceName); break; case 'stop': response = await servicesAPI.stopService(serviceName); break; case 'restart': response = await servicesAPI.restartService(serviceName); break; default: throw new Error('Invalid action'); } if (response.data.success || response.data.message) { // Refresh status after successful control action setTimeout(() => { fetchData(); }, 1000); } } catch (error) { console.error(`Failed to ${action} ${serviceName}:`, error); } finally { setServiceControls(prev => ({ ...prev, [serviceName]: { ...prev[serviceName], [action]: 'idle' } })); } }; const renderServiceCard = (serviceName, icon, displayName, status) => { return (
{icon} {displayName}
{getStatusIcon(status)} {getStatusText(status)}
); }; const fetchData = async () => { if (!isOnline) { setIsLoading(false); return; } try { const [statusResponse, servicesResponse] = await Promise.all([ cellAPI.getStatus(), servicesAPI.getAllStatus() ]); setCellStatus(statusResponse.data); // Transform services data to match expected structure const servicesData = servicesResponse.data; const transformedServices = { wireguard: servicesData.wireguard || { running: false, status: 'offline' }, email: servicesData.email || { running: false, status: 'offline' }, calendar: servicesData.calendar || { running: false, status: 'offline' }, files: servicesData.files || { running: false, status: 'offline' }, routing: servicesData.routing || { running: false, status: 'offline' }, network: servicesData.network || { running: false, status: 'offline' } }; setServicesStatus(transformedServices); } catch (error) { console.error('Failed to fetch dashboard data:', error); } finally { setIsLoading(false); } }; if (isLoading) { return (
); } return (

Dashboard

Personal Internet Cell — connect via WireGuard to access services

{/* Access Services — shown first, no scroll needed */}

Services (connect via WireGuard first)

{SERVICES.map(svc => (

{svc.name}

{svc.url}

{svc.desc}

))}
{/* Cell Status */} {cellStatus && (

Cell Status

Cell Name

{cellStatus.cell_name}

Peers

{cellStatus.peers_count}

Uptime

{formatUptime(cellStatus.uptime || 0)}

Status

Active

)} {/* Services Status */} {servicesStatus && (

Services Status

{renderServiceCard('wireguard', , 'WireGuard', servicesStatus.wireguard)} {renderServiceCard('email', , 'Email', servicesStatus.email)} {renderServiceCard('calendar', , 'Calendar', servicesStatus.calendar)} {renderServiceCard('files', , 'Files', servicesStatus.files)} {renderServiceCard('routing', , 'Routing', servicesStatus.routing)} {renderServiceCard('network', , 'Network', servicesStatus.network)}
)} {/* Quick Actions */}

Quick Actions

); } export default Dashboard;