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)
{/* Cell Status */}
{cellStatus && (
Cell Status
Cell Name
{cellStatus.cell_name}
Peers
{cellStatus.peers_count}
Uptime
{formatUptime(cellStatus.uptime || 0)}
)}
{/* 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;