{"ast":null,"code":"import React,{useState,useEffect}from'react';import{useParams,Link,useNavigate}from'react-router-dom';import{FiArrowLeft,FiEdit,FiTrash2,FiRefreshCw,FiBattery,FiWifi,FiMapPin,FiClock,FiInfo,FiSave,FiCopy,FiServer,FiKey,FiChevronDown,FiChevronUp,FiCode}from'react-icons/fi';import{MapContainer,TileLayer,Marker,Popup}from'react-leaflet';import'leaflet/dist/leaflet.css';import L from'leaflet';import EditDeviceModal from'../components/EditDeviceModal';import{deviceApi}from'../services/api';// Fix for Leaflet marker icons\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";delete L.Icon.Default.prototype._getIconUrl;L.Icon.Default.mergeOptions({iconRetinaUrl:'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',iconUrl:'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png',shadowUrl:'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png'});// Dummy data for demonstration\nconst dummyDevices=[{id:'device-001',name:'SIM7000E-001',description:'Solar panel monitoring device',model:'SIM7000E',firmware_version:'1.2.3',status:'online',battery:{level:85,status:'good'},signal:{strength:-65,status:'good'},location:{latitude:47.3769,longitude:8.5417,altitude:408},last_seen:new Date().toISOString(),created_at:new Date(Date.now()-7776000000).toISOString()// 90 days ago\n},{id:'device-002',name:'SIM7000E-002',description:'Wind turbine monitoring device',model:'SIM7000E',firmware_version:'1.2.3',status:'idle',battery:{level:42,status:'low'},signal:{strength:-85,status:'fair'},location:{latitude:47.3780,longitude:8.5390,altitude:410},last_seen:new Date(Date.now()-3600000).toISOString(),// 1 hour ago\ncreated_at:new Date(Date.now()-15552000000).toISOString()// 180 days ago\n}];// Dummy telemetry data\nconst dummyTelemetry=[{id:1,device_id:'device-001',latitude:47.3769,longitude:8.5417,altitude:408,battery_level:85,signal_strength:-65,temperature:24.5,timestamp:new Date().toISOString()},{id:2,device_id:'device-001',latitude:47.3769,longitude:8.5417,altitude:408,battery_level:86,signal_strength:-64,temperature:24.2,timestamp:new Date(Date.now()-3600000).toISOString()// 1 hour ago\n},{id:3,device_id:'device-001',latitude:47.3770,longitude:8.5418,altitude:408,battery_level:87,signal_strength:-63,temperature:23.8,timestamp:new Date(Date.now()-7200000).toISOString()// 2 hours ago\n}];// Dummy logs data\nconst dummyLogs=[{id:1,device_id:'device-001',level:'info',message:'Device connected to network',source:'connection_manager',timestamp:new Date().toISOString()},{id:2,device_id:'device-001',level:'warning',message:'Battery level below 90%',source:'power_monitor',timestamp:new Date(Date.now()-1800000).toISOString()// 30 minutes ago\n},{id:3,device_id:'device-001',level:'info',message:'GPS location updated',source:'gps_module',timestamp:new Date(Date.now()-3600000).toISOString()// 1 hour ago\n}];const DeviceDetail=()=>{const{id}=useParams();const navigate=useNavigate();const[device,setDevice]=useState(null);const[telemetry,setTelemetry]=useState([]);const[logs,setLogs]=useState([]);const[loading,setLoading]=useState(true);const[activeTab,setActiveTab]=useState('overview');const[refreshing,setRefreshing]=useState(false);const[copySuccess,setCopySuccess]=useState('');const[expandedApiSection,setExpandedApiSection]=useState('');const[showEditModal,setShowEditModal]=useState(false);const[deleteConfirm,setDeleteConfirm]=useState(false);useEffect(()=>{fetchDeviceData();},[id]);const fetchDeviceData=async()=>{try{setLoading(true);const token=localStorage.getItem('token');// Fetch device data from API\nconst deviceResponse=await fetch(`/api/devices/${id}`,{headers:{'Authorization':`Bearer ${token}`}});if(deviceResponse.ok){const deviceData=await deviceResponse.json();// Transform the device data to include frontend display properties\nconst transformedDevice={...deviceData,status:getDeviceStatus(deviceData),battery:getBatteryInfo(deviceData),signal:getSignalInfo(deviceData),location:{latitude:deviceData.latitude||47.3769,// Default location if none set\nlongitude:deviceData.longitude||8.5417,altitude:deviceData.altitude||408}};setDevice(transformedDevice);// For now, use dummy telemetry and logs until those APIs are implemented\nconst deviceTelemetry=dummyTelemetry.filter(t=>t.device_id===id);const deviceLogs=dummyLogs.filter(l=>l.device_id===id);setTelemetry(deviceTelemetry);setLogs(deviceLogs);}else if(deviceResponse.status===404){// Device not found in API, try dummy data for existing demo devices\nconst foundDevice=dummyDevices.find(d=>d.id===id);if(foundDevice){setDevice(foundDevice);const deviceTelemetry=dummyTelemetry.filter(t=>t.device_id===id);const deviceLogs=dummyLogs.filter(l=>l.device_id===id);setTelemetry(deviceTelemetry);setLogs(deviceLogs);}else{setDevice(null);// This will show the \"Device Not Found\" message\n}}else{console.error('Failed to fetch device:',deviceResponse.status);setDevice(null);}}catch(error){console.error('Error fetching device data:',error);// Fall back to dummy data\nconst foundDevice=dummyDevices.find(d=>d.id===id);if(foundDevice){setDevice(foundDevice);const deviceTelemetry=dummyTelemetry.filter(t=>t.device_id===id);const deviceLogs=dummyLogs.filter(l=>l.device_id===id);setTelemetry(deviceTelemetry);setLogs(deviceLogs);}else{setDevice(null);}}finally{setLoading(false);}};// Helper functions to transform backend data\nconst getDeviceStatus=device=>{if(!device.is_active)return'offline';if(!device.last_seen)return'offline';const lastSeen=new Date(device.last_seen);const now=new Date();const diffMinutes=(now-lastSeen)/(1000*60);if(diffMinutes<5)return'online';if(diffMinutes<30)return'idle';return'offline';};const getBatteryInfo=device=>{const level=device.battery_level||0;let status='good';if(level<20)status='critical';else if(level<50)status='low';return{level,status};};const getSignalInfo=device=>{const strength=device.signal_strength||-100;let status='poor';if(strength>-70)status='good';else if(strength>-85)status='fair';return{strength,status};};// Helper function to format date\nconst formatDate=dateString=>{const date=new Date(dateString);return date.toLocaleString();};// Helper function to get status color\nconst getStatusColor=status=>{switch(status){case'online':return'text-success-500';case'idle':return'text-warning-500';case'offline':return'text-danger-500';default:return'text-gray-500';}};// Helper function to get battery color\nconst getBatteryColor=status=>{switch(status){case'good':return'text-success-500';case'low':return'text-warning-500';case'critical':return'text-danger-500';default:return'text-gray-500';}};// Helper function to get signal color\nconst getSignalColor=status=>{switch(status){case'good':return'text-success-500';case'fair':return'text-warning-500';case'poor':return'text-danger-500';default:return'text-gray-500';}};// Helper function to get log level color\nconst getLevelColor=level=>{switch(level){case'debug':return'text-gray-500 bg-gray-100';case'info':return'text-blue-500 bg-blue-100';case'warning':return'text-yellow-500 bg-yellow-100';case'error':return'text-red-500 bg-red-100';case'critical':return'text-white bg-red-500';default:return'text-gray-500 bg-gray-100';}};// Handle refresh\nconst handleRefresh=async()=>{setRefreshing(true);await fetchDeviceData();setRefreshing(false);};// Handle copy to clipboard\nconst handleCopy=async(text,label)=>{try{await navigator.clipboard.writeText(text);setCopySuccess(label);setTimeout(()=>setCopySuccess(''),2000);}catch(err){console.error('Failed to copy: ',err);}};// Generate API endpoints for the device\nconst getApiEndpoints=()=>{const baseUrl=window.location.origin;return{telemetry:`${baseUrl}/api/data/${device===null||device===void 0?void 0:device.id}`,status:`${baseUrl}/api/devices/${device===null||device===void 0?void 0:device.id}`,logs:`${baseUrl}/api/logs/${device===null||device===void 0?void 0:device.id}`};};// Toggle API documentation sections\nconst toggleApiSection=section=>{setExpandedApiSection(expandedApiSection===section?'':section);};// Handle edit device\nconst handleEditDevice=()=>{setShowEditModal(true);};const handleCloseEditModal=()=>{setShowEditModal(false);};const handleDeviceUpdated=updatedDevice=>{// Transform the updated device data\nconst transformedDevice={...updatedDevice,status:getDeviceStatus(updatedDevice),battery:getBatteryInfo(updatedDevice),signal:getSignalInfo(updatedDevice),location:{latitude:updatedDevice.latitude||0,longitude:updatedDevice.longitude||0,altitude:updatedDevice.altitude||0}};setDevice(transformedDevice);};// Handle delete device\nconst handleDeleteDevice=()=>{setDeleteConfirm(true);};const confirmDeleteDevice=async()=>{try{await deviceApi.deleteDevice(device.id);navigate('/devices');// Redirect to devices list after deletion\n}catch(error){console.error('Error deleting device:',error);alert('Failed to delete device. Please try again.');setDeleteConfirm(false);}};const cancelDeleteDevice=()=>{setDeleteConfirm(false);};// Generate example API data\nconst getApiExamples=()=>{return{telemetry:{request:{method:'POST',headers:{'Content-Type':'application/json'},body:{device_id:(device===null||device===void 0?void 0:device.id)||'LILYGO_001',device_name:(device===null||device===void 0?void 0:device.name)||'Zurich_Station_1',firmware:'1.1.0',temp:24.3,hum:65.2,solar_volt:12.8,battery_volt:3.8,signal:-65,gps_fixed:true,latitude:47.3769,longitude:8.5417,altitude:408,satellites:8,timestamp:Math.floor(Date.now()/1000)}},response:{status:201,body:{id:123,device_id:(device===null||device===void 0?void 0:device.id)||'LILYGO_001',latitude:47.3769,longitude:8.5417,altitude:408,temperature:24.3,humidity:65.2,solar_voltage:12.8,battery_level:85.5,battery_voltage:3.8,signal_strength:-65,gps_fixed:true,satellites:8,timestamp:new Date().toISOString(),device_timestamp:new Date().toISOString()}}},status:{request:{method:'PUT',headers:{'Content-Type':'application/json','Authorization':'Bearer your-token-here'},body:{name:(device===null||device===void 0?void 0:device.name)||'Your Device Name',firmware_version:\"1.1.0\",is_active:true,battery_level:87.2,signal_strength:-62}},response:{status:200,body:{id:(device===null||device===void 0?void 0:device.id)||'your-device-id',name:(device===null||device===void 0?void 0:device.name)||'Your Device Name',model:'LILYGO T-A7670G',firmware_version:'1.1.0',is_active:true,battery_level:87.2,signal_strength:-62,last_seen:new Date().toISOString(),created_at:new Date().toISOString(),updated_at:new Date().toISOString()}}},logs:{request:{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer your-token-here'},body:{device_id:(device===null||device===void 0?void 0:device.id)||'LILYGO_001',level:\"info\",message:\"Device connected to cellular network\",source:\"network_manager\",timestamp:new Date().toISOString(),metadata:{network_type:\"LTE\",signal_quality:\"good\",operator:\"Swisscom\",modem_model:\"A7670G\"}}},response:{status:201,body:{id:456,device_id:(device===null||device===void 0?void 0:device.id)||'LILYGO_001',level:\"info\",message:\"Device connected to cellular network\",source:\"network_manager\",timestamp:new Date().toISOString(),metadata:{network_type:\"LTE\",signal_quality:\"good\",operator:\"Swisscom\",modem_model:\"A7670G\"}}}}};};if(loading){return/*#__PURE__*/_jsx(\"div\",{className:\"flex items-center justify-center h-full\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"text-center\",children:[/*#__PURE__*/_jsx(\"div\",{className:\"w-16 h-16 border-4 border-primary-500 border-t-transparent rounded-full animate-spin mx-auto\"}),/*#__PURE__*/_jsx(\"p\",{className:\"mt-4 text-gray-600\",children:\"Loading device data...\"})]})});}if(!device){return/*#__PURE__*/_jsxs(\"div\",{className:\"text-center py-10\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-2xl font-semibold text-gray-800 mb-4\",children:\"Device Not Found\"}),/*#__PURE__*/_jsx(\"p\",{className:\"text-gray-600 mb-6\",children:\"The device you are looking for does not exist or has been removed.\"}),/*#__PURE__*/_jsx(Link,{to:\"/devices\",className:\"px-4 py-2 bg-primary-500 text-white rounded-md hover:bg-primary-600 transition-colors\",children:\"Back to Devices\"})]});}return/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-6\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-4\",children:[/*#__PURE__*/_jsx(Link,{to:\"/devices\",className:\"p-2 text-gray-500 rounded-full hover:bg-gray-100\",children:/*#__PURE__*/_jsx(FiArrowLeft,{className:\"w-5 h-5\"})}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"h1\",{className:\"text-2xl font-semibold text-gray-800\",children:device.name}),/*#__PURE__*/_jsx(\"p\",{className:\"text-gray-500\",children:device.description||'No description'})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2\",children:[/*#__PURE__*/_jsxs(\"button\",{className:`flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors ${refreshing?'opacity-50 cursor-not-allowed':''}`,onClick:handleRefresh,disabled:refreshing,children:[/*#__PURE__*/_jsx(FiRefreshCw,{className:refreshing?'animate-spin':''}),/*#__PURE__*/_jsx(\"span\",{children:\"Refresh\"})]}),/*#__PURE__*/_jsxs(\"button\",{onClick:handleEditDevice,className:\"flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors\",children:[/*#__PURE__*/_jsx(FiEdit,{}),/*#__PURE__*/_jsx(\"span\",{children:\"Edit\"})]}),/*#__PURE__*/_jsxs(\"button\",{onClick:handleDeleteDevice,className:\"flex items-center gap-2 px-4 py-2 bg-danger-500 text-white rounded-md hover:bg-danger-600 transition-colors\",children:[/*#__PURE__*/_jsx(FiTrash2,{}),/*#__PURE__*/_jsx(\"span\",{children:\"Delete\"})]})]})]}),/*#__PURE__*/_jsx(\"div\",{className:\"dashboard-card\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"grid grid-cols-1 md:grid-cols-4 gap-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center p-4 bg-gray-50 rounded-lg\",children:[/*#__PURE__*/_jsx(\"div\",{className:`h-3 w-3 rounded-full mr-2 ${device.status==='online'?'bg-success-500':device.status==='idle'?'bg-warning-500':'bg-danger-500'}`}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Status\"}),/*#__PURE__*/_jsx(\"p\",{className:`text-lg font-semibold capitalize ${getStatusColor(device.status)}`,children:device.status})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center p-4 bg-gray-50 rounded-lg\",children:[/*#__PURE__*/_jsx(FiBattery,{className:`w-6 h-6 mr-2 ${getBatteryColor(device.battery.status)}`}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Battery\"}),/*#__PURE__*/_jsxs(\"p\",{className:`text-lg font-semibold ${getBatteryColor(device.battery.status)}`,children:[device.battery.level,\"%\"]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center p-4 bg-gray-50 rounded-lg\",children:[/*#__PURE__*/_jsx(FiWifi,{className:`w-6 h-6 mr-2 ${getSignalColor(device.signal.status)}`}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Signal\"}),/*#__PURE__*/_jsxs(\"p\",{className:`text-lg font-semibold ${getSignalColor(device.signal.status)}`,children:[device.signal.strength,\" dBm\"]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center p-4 bg-gray-50 rounded-lg\",children:[/*#__PURE__*/_jsx(FiClock,{className:\"w-6 h-6 mr-2 text-gray-500\"}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Last Seen\"}),/*#__PURE__*/_jsx(\"p\",{className:\"text-lg font-semibold text-gray-800\",children:formatDate(device.last_seen)})]})]})]})}),/*#__PURE__*/_jsx(\"div\",{className:\"border-b border-gray-200\",children:/*#__PURE__*/_jsxs(\"nav\",{className:\"-mb-px flex space-x-8\",children:[/*#__PURE__*/_jsx(\"button\",{className:`py-4 px-1 border-b-2 font-medium text-sm ${activeTab==='overview'?'border-primary-500 text-primary-600':'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`,onClick:()=>setActiveTab('overview'),children:\"Overview\"}),/*#__PURE__*/_jsx(\"button\",{className:`py-4 px-1 border-b-2 font-medium text-sm ${activeTab==='telemetry'?'border-primary-500 text-primary-600':'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`,onClick:()=>setActiveTab('telemetry'),children:\"Telemetry\"}),/*#__PURE__*/_jsx(\"button\",{className:`py-4 px-1 border-b-2 font-medium text-sm ${activeTab==='logs'?'border-primary-500 text-primary-600':'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`,onClick:()=>setActiveTab('logs'),children:\"Logs\"}),/*#__PURE__*/_jsx(\"button\",{className:`py-4 px-1 border-b-2 font-medium text-sm ${activeTab==='settings'?'border-primary-500 text-primary-600':'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`,onClick:()=>setActiveTab('settings'),children:\"Settings\"})]})}),/*#__PURE__*/_jsxs(\"div\",{children:[activeTab==='overview'&&/*#__PURE__*/_jsxs(\"div\",{className:\"grid grid-cols-1 md:grid-cols-2 gap-6\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Device Information\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"grid grid-cols-1 sm:grid-cols-2 gap-4\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Device ID\"}),/*#__PURE__*/_jsx(\"p\",{className:\"font-medium\",children:device.id})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Model\"}),/*#__PURE__*/_jsx(\"p\",{className:\"font-medium\",children:device.model})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Firmware Version\"}),/*#__PURE__*/_jsxs(\"p\",{className:\"font-medium\",children:[\"v\",device.firmware_version]})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Created At\"}),/*#__PURE__*/_jsx(\"p\",{className:\"font-medium\",children:formatDate(device.created_at)})]})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-500\",children:\"Description\"}),/*#__PURE__*/_jsx(\"p\",{className:\"font-medium\",children:device.description||'No description'})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card h-[300px]\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Location\"}),/*#__PURE__*/_jsxs(MapContainer,{center:[device.location.latitude,device.location.longitude],zoom:15,style:{height:'calc(100% - 2rem)',width:'100%'},children:[/*#__PURE__*/_jsx(TileLayer,{attribution:\"\\xA9 OpenStreetMap contributors\",url:\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"}),/*#__PURE__*/_jsx(Marker,{position:[device.location.latitude,device.location.longitude],children:/*#__PURE__*/_jsx(Popup,{children:/*#__PURE__*/_jsxs(\"div\",{className:\"p-1\",children:[/*#__PURE__*/_jsx(\"h3\",{className:\"font-semibold\",children:device.name}),/*#__PURE__*/_jsxs(\"p\",{className:\"text-xs text-gray-500\",children:[device.location.latitude.toFixed(6),\", \",device.location.longitude.toFixed(6)]}),/*#__PURE__*/_jsxs(\"p\",{className:\"text-xs text-gray-500\",children:[\"Altitude: \",device.location.altitude,\" m\"]})]})})})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card md:col-span-2\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Recent Activity\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-4\",children:[logs.slice(0,5).map(log=>/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-start gap-3 p-3 bg-gray-50 rounded-lg\",children:[/*#__PURE__*/_jsx(\"div\",{className:`p-2 rounded-full ${log.level==='info'?'bg-blue-100 text-blue-500':log.level==='warning'?'bg-yellow-100 text-yellow-500':log.level==='error'?'bg-red-100 text-red-500':log.level==='critical'?'bg-red-500 text-white':'bg-gray-100 text-gray-500'}`,children:/*#__PURE__*/_jsx(FiInfo,{className:\"w-5 h-5\"})}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex-1\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex justify-between\",children:[/*#__PURE__*/_jsx(\"p\",{className:\"font-medium text-gray-800\",children:log.message}),/*#__PURE__*/_jsx(\"span\",{className:\"text-sm text-gray-500\",children:formatDate(log.timestamp)})]}),/*#__PURE__*/_jsxs(\"p\",{className:\"text-sm text-gray-500\",children:[\"Source: \",log.source]})]})]},log.id)),logs.length===0&&/*#__PURE__*/_jsx(\"p\",{className:\"text-center py-4 text-gray-500\",children:\"No recent activity\"})]})]})]}),activeTab==='telemetry'&&/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Telemetry Data\"}),telemetry.length===0?/*#__PURE__*/_jsx(\"p\",{className:\"text-center py-4 text-gray-500\",children:\"No telemetry data available\"}):/*#__PURE__*/_jsx(\"div\",{className:\"overflow-x-auto\",children:/*#__PURE__*/_jsxs(\"table\",{className:\"min-w-full divide-y divide-gray-200\",children:[/*#__PURE__*/_jsx(\"thead\",{className:\"bg-gray-50\",children:/*#__PURE__*/_jsxs(\"tr\",{children:[/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Timestamp\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Location\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Battery\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Signal\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Temperature\"})]})}),/*#__PURE__*/_jsx(\"tbody\",{className:\"bg-white divide-y divide-gray-200\",children:telemetry.map(item=>/*#__PURE__*/_jsxs(\"tr\",{className:\"hover:bg-gray-50\",children:[/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\",children:formatDate(item.timestamp)}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center\",children:[/*#__PURE__*/_jsx(FiMapPin,{className:\"mr-2 text-gray-500\"}),/*#__PURE__*/_jsxs(\"span\",{className:\"text-gray-800\",children:[item.latitude.toFixed(6),\", \",item.longitude.toFixed(6)]})]})}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center\",children:[/*#__PURE__*/_jsx(FiBattery,{className:\"mr-2 text-gray-500\"}),/*#__PURE__*/_jsxs(\"span\",{className:\"text-gray-800\",children:[item.battery_level,\"%\"]})]})}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center\",children:[/*#__PURE__*/_jsx(FiWifi,{className:\"mr-2 text-gray-500\"}),/*#__PURE__*/_jsxs(\"span\",{className:\"text-gray-800\",children:[item.signal_strength,\" dBm\"]})]})}),/*#__PURE__*/_jsxs(\"td\",{className:\"px-6 py-4 whitespace-nowrap text-gray-800\",children:[item.temperature,\"\\xB0C\"]})]},item.id))})]})})]}),activeTab==='logs'&&/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Device Logs\"}),logs.length===0?/*#__PURE__*/_jsx(\"p\",{className:\"text-center py-4 text-gray-500\",children:\"No logs available\"}):/*#__PURE__*/_jsx(\"div\",{className:\"overflow-x-auto\",children:/*#__PURE__*/_jsxs(\"table\",{className:\"min-w-full divide-y divide-gray-200\",children:[/*#__PURE__*/_jsx(\"thead\",{className:\"bg-gray-50\",children:/*#__PURE__*/_jsxs(\"tr\",{children:[/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Timestamp\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Level\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Message\"}),/*#__PURE__*/_jsx(\"th\",{className:\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\",children:\"Source\"})]})}),/*#__PURE__*/_jsx(\"tbody\",{className:\"bg-white divide-y divide-gray-200\",children:logs.map(log=>/*#__PURE__*/_jsxs(\"tr\",{className:\"hover:bg-gray-50\",children:[/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\",children:formatDate(log.timestamp)}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap\",children:/*#__PURE__*/_jsx(\"span\",{className:`px-2 py-1 text-xs font-medium rounded-full ${getLevelColor(log.level)}`,children:log.level.toUpperCase()})}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 text-sm text-gray-900\",children:log.message}),/*#__PURE__*/_jsx(\"td\",{className:\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\",children:log.source})]},log.id))})]})})]}),activeTab==='settings'&&/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-6\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2 mb-4\",children:[/*#__PURE__*/_jsx(FiServer,{className:\"w-5 h-5 text-primary-500\"}),/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800\",children:\"API Configuration\"})]}),/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-600 mb-6\",children:\"Configure your device to send data to these endpoints. Copy the URLs below and configure them in your IoT device.\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"p-4 bg-blue-50 border border-blue-200 rounded-lg\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center justify-between mb-2\",children:[/*#__PURE__*/_jsx(\"h3\",{className:\"font-medium text-blue-900\",children:\"IoT Device Data Endpoint (LILYGO Format)\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded\",children:\"POST\"}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>toggleApiSection('telemetry'),className:\"flex items-center gap-1 px-2 py-1 text-blue-600 hover:text-blue-800 transition-colors\",children:[/*#__PURE__*/_jsx(FiCode,{size:14}),expandedApiSection==='telemetry'?/*#__PURE__*/_jsx(FiChevronUp,{size:14}):/*#__PURE__*/_jsx(FiChevronDown,{size:14})]})]})]}),/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-blue-700 mb-3\",children:\"Send LILYGO T-A7670G device data including temperature, humidity, solar voltage, GPS and battery info\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2 mb-3\",children:[/*#__PURE__*/_jsxs(\"code\",{className:\"flex-1 p-2 bg-white border border-blue-300 rounded text-sm font-mono text-gray-800 overflow-x-auto\",children:[getApiEndpoints().telemetry,\"/iot\"]}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>handleCopy(getApiEndpoints().telemetry,'telemetry'),className:\"flex items-center gap-1 px-3 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors\",children:[/*#__PURE__*/_jsx(FiCopy,{size:14}),copySuccess==='telemetry'?'Copied!':'Copy']})]}),expandedApiSection==='telemetry'&&/*#__PURE__*/_jsxs(\"div\",{className:\"mt-4 space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-blue-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-green-500 rounded-full\"}),\"Request Example\"]}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-3\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Headers:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().telemetry.request.headers,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Body (JSON):\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().telemetry.request.body,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"cURL Example:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:`curl -X POST \"${getApiEndpoints().telemetry}/iot\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '${JSON.stringify(getApiExamples().telemetry.request.body)}'`})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Arduino/ESP32 Example:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:`String json = \"{\";\njson += \"\\\\\"device_id\\\\\":\\\\\"${(device===null||device===void 0?void 0:device.id)||'LILYGO_001'}\\\\\",\";\njson += \"\\\\\"temp\\\\\":\" + String(temperature) + \",\";\njson += \"\\\\\"hum\\\\\":\" + String(humidity) + \",\";\njson += \"\\\\\"solar_volt\\\\\":\" + String(solarVoltage) + \",\";\njson += \"\\\\\"battery_volt\\\\\":\" + String(batteryVoltage) + \",\";\njson += \"\\\\\"signal\\\\\":\" + String(signalStrength) + \",\";\njson += \"\\\\\"gps_fixed\\\\\":\" + (gpsFixed ? \"true\" : \"false\") + \",\";\njson += \"\\\\\"latitude\\\\\":\" + String(latitude, 6) + \",\";\njson += \"\\\\\"longitude\\\\\":\" + String(longitude, 6) + \",\";\njson += \"\\\\\"timestamp\\\\\":\" + String(millis() / 1000);\njson += \"}\";\n\n// Send via HTTP POST to ${getApiEndpoints().telemetry}/iot`})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-blue-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-blue-500 rounded-full\"}),\"Response Example\"]}),/*#__PURE__*/_jsx(\"div\",{className:\"space-y-3\",children:/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsxs(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:[\"Status: \",getApiExamples().telemetry.response.status]}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().telemetry.response.body,null,2)})]})})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-blue-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsx(\"h4\",{className:\"font-medium text-gray-800 mb-2\",children:\"LILYGO Field Descriptions\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"text-xs space-y-1\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"device_id:\"}),\" Unique device identifier (required)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"device_name:\"}),\" Human-readable device name (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"firmware:\"}),\" Device firmware version (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"temp:\"}),\" Temperature in Celsius (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"hum:\"}),\" Humidity percentage (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"solar_volt:\"}),\" Solar panel voltage (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"battery_volt:\"}),\" Battery voltage (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"signal:\"}),\" Cellular signal in dBm (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"gps_fixed:\"}),\" GPS fix status boolean (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"latitude/longitude:\"}),\" GPS coordinates (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"altitude:\"}),\" Elevation in meters (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"satellites:\"}),\" Number of GPS satellites (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"timestamp:\"}),\" Unix timestamp from device (optional)\"]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"mt-3 p-2 bg-blue-50 rounded text-xs\",children:[/*#__PURE__*/_jsx(\"strong\",{children:\"Note:\"}),\" This endpoint automatically converts battery voltage to percentage, updates device information, and handles the LILYGO device data format.\"]})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"p-4 bg-green-50 border border-green-200 rounded-lg\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center justify-between mb-2\",children:[/*#__PURE__*/_jsx(\"h3\",{className:\"font-medium text-green-900\",children:\"Device Status Endpoint\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"text-xs bg-green-100 text-green-800 px-2 py-1 rounded\",children:\"PUT\"}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>toggleApiSection('status'),className:\"flex items-center gap-1 px-2 py-1 text-green-600 hover:text-green-800 transition-colors\",children:[/*#__PURE__*/_jsx(FiCode,{size:14}),expandedApiSection==='status'?/*#__PURE__*/_jsx(FiChevronUp,{size:14}):/*#__PURE__*/_jsx(FiChevronDown,{size:14})]})]})]}),/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-green-700 mb-3\",children:\"Update device configuration and status information\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2 mb-3\",children:[/*#__PURE__*/_jsx(\"code\",{className:\"flex-1 p-2 bg-white border border-green-300 rounded text-sm font-mono text-gray-800 overflow-x-auto\",children:getApiEndpoints().status}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>handleCopy(getApiEndpoints().status,'status'),className:\"flex items-center gap-1 px-3 py-2 bg-green-600 text-white rounded hover:bg-green-700 transition-colors\",children:[/*#__PURE__*/_jsx(FiCopy,{size:14}),copySuccess==='status'?'Copied!':'Copy']})]}),expandedApiSection==='status'&&/*#__PURE__*/_jsxs(\"div\",{className:\"mt-4 space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-green-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-green-500 rounded-full\"}),\"Request Example\"]}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-3\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Headers:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().status.request.headers,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Body (JSON):\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().status.request.body,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"cURL Example:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:`curl -X PUT \"${getApiEndpoints().status}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -H \"Device-ID: ${(device===null||device===void 0?void 0:device.id)||'your-device-id'}\" \\\\\n -d '${JSON.stringify(getApiExamples().status.request.body)}'`})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-green-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-blue-500 rounded-full\"}),\"Response Example\"]}),/*#__PURE__*/_jsx(\"div\",{className:\"space-y-3\",children:/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsxs(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:[\"Status: \",getApiExamples().status.response.status]}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().status.response.body,null,2)})]})})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-green-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsx(\"h4\",{className:\"font-medium text-gray-800 mb-2\",children:\"Field Descriptions\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"text-xs space-y-1\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"battery_level:\"}),\" Current battery percentage (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"signal_strength:\"}),\" Cellular signal strength in dBm (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"firmware_version:\"}),\" Current firmware version string (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"is_active:\"}),\" Device active status boolean (optional)\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"last_seen:\"}),\" Last communication timestamp (optional)\"]})]})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"p-4 bg-yellow-50 border border-yellow-200 rounded-lg\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center justify-between mb-2\",children:[/*#__PURE__*/_jsx(\"h3\",{className:\"font-medium text-yellow-900\",children:\"Device Logs Endpoint\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded\",children:\"POST\"}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>toggleApiSection('logs'),className:\"flex items-center gap-1 px-2 py-1 text-yellow-600 hover:text-yellow-800 transition-colors\",children:[/*#__PURE__*/_jsx(FiCode,{size:14}),expandedApiSection==='logs'?/*#__PURE__*/_jsx(FiChevronUp,{size:14}):/*#__PURE__*/_jsx(FiChevronDown,{size:14})]})]})]}),/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-yellow-700 mb-3\",children:\"Send device logs, errors, and diagnostic information\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2 mb-3\",children:[/*#__PURE__*/_jsx(\"code\",{className:\"flex-1 p-2 bg-white border border-yellow-300 rounded text-sm font-mono text-gray-800 overflow-x-auto\",children:getApiEndpoints().logs}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>handleCopy(getApiEndpoints().logs,'logs'),className:\"flex items-center gap-1 px-3 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700 transition-colors\",children:[/*#__PURE__*/_jsx(FiCopy,{size:14}),copySuccess==='logs'?'Copied!':'Copy']})]}),expandedApiSection==='logs'&&/*#__PURE__*/_jsxs(\"div\",{className:\"mt-4 space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-yellow-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-green-500 rounded-full\"}),\"Request Example\"]}),/*#__PURE__*/_jsxs(\"div\",{className:\"space-y-3\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Headers:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().logs.request.headers,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"Body (JSON):\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().logs.request.body,null,2)})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:\"cURL Example:\"}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:`curl -X POST \"${getApiEndpoints().logs}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -H \"Device-ID: ${(device===null||device===void 0?void 0:device.id)||'your-device-id'}\" \\\\\n -d '${JSON.stringify(getApiExamples().logs.request.body)}'`})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-yellow-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsxs(\"h4\",{className:\"font-medium text-gray-800 mb-2 flex items-center gap-2\",children:[/*#__PURE__*/_jsx(\"span\",{className:\"w-2 h-2 bg-blue-500 rounded-full\"}),\"Response Example\"]}),/*#__PURE__*/_jsx(\"div\",{className:\"space-y-3\",children:/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsxs(\"p\",{className:\"text-xs font-medium text-gray-600 mb-1\",children:[\"Status: \",getApiExamples().logs.response.status]}),/*#__PURE__*/_jsx(\"pre\",{className:\"text-xs bg-gray-50 p-2 rounded border overflow-x-auto\",children:JSON.stringify(getApiExamples().logs.response.body,null,2)})]})})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"bg-white border border-yellow-300 rounded-lg p-4\",children:[/*#__PURE__*/_jsx(\"h4\",{className:\"font-medium text-gray-800 mb-2\",children:\"Field Descriptions\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"text-xs space-y-1\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"level:\"}),\" Log level (debug, info, warning, error, critical) - required\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"message:\"}),\" Log message content - required\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"source:\"}),\" Component/module that generated the log - required\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"timestamp:\"}),\" ISO 8601 datetime string - required\"]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"strong\",{children:\"metadata:\"}),\" Additional structured data object - optional\"]})]})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"p-4 bg-gray-50 border border-gray-200 rounded-lg\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2 mb-2\",children:[/*#__PURE__*/_jsx(FiKey,{className:\"w-4 h-4 text-gray-600\"}),/*#__PURE__*/_jsx(\"h3\",{className:\"font-medium text-gray-900\",children:\"Authentication\"})]}),/*#__PURE__*/_jsx(\"p\",{className:\"text-sm text-gray-600 mb-3\",children:\"Include this device ID in your requests for authentication\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center gap-2\",children:[/*#__PURE__*/_jsxs(\"code\",{className:\"flex-1 p-2 bg-white border border-gray-300 rounded text-sm font-mono text-gray-800\",children:[\"Device-ID: \",device===null||device===void 0?void 0:device.id]}),/*#__PURE__*/_jsxs(\"button\",{onClick:()=>handleCopy(device===null||device===void 0?void 0:device.id,'deviceId'),className:\"flex items-center gap-1 px-3 py-2 bg-gray-600 text-white rounded hover:bg-gray-700 transition-colors\",children:[/*#__PURE__*/_jsx(FiCopy,{size:14}),copySuccess==='deviceId'?'Copied!':'Copy']})]})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"dashboard-card\",children:[/*#__PURE__*/_jsx(\"h2\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Device Settings\"}),/*#__PURE__*/_jsxs(\"form\",{onSubmit:e=>{e.preventDefault();const formData=new FormData(e.target);const updateData={name:formData.get('deviceName'),description:formData.get('deviceDescription'),firmware_version:formData.get('firmwareVersion'),model:formData.get('deviceModel'),is_active:formData.get('status')==='active'};deviceApi.updateDevice(device.id,updateData).then(response=>{handleDeviceUpdated(response.data);alert('Device settings updated successfully!');}).catch(error=>{console.error('Error updating device:',error);alert('Failed to update device settings. Please try again.');});},className:\"space-y-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"grid grid-cols-1 md:grid-cols-2 gap-4\",children:[/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"label\",{htmlFor:\"deviceName\",className:\"block text-sm font-medium text-gray-700 mb-1\",children:\"Device Name\"}),/*#__PURE__*/_jsx(\"input\",{type:\"text\",id:\"deviceName\",name:\"deviceName\",className:\"block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm\",defaultValue:device.name})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"label\",{htmlFor:\"deviceDescription\",className:\"block text-sm font-medium text-gray-700 mb-1\",children:\"Description\"}),/*#__PURE__*/_jsx(\"input\",{type:\"text\",id:\"deviceDescription\",name:\"deviceDescription\",className:\"block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm\",defaultValue:device.description||''})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"label\",{htmlFor:\"firmwareVersion\",className:\"block text-sm font-medium text-gray-700 mb-1\",children:\"Firmware Version\"}),/*#__PURE__*/_jsx(\"input\",{type:\"text\",id:\"firmwareVersion\",name:\"firmwareVersion\",className:\"block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm\",defaultValue:device.firmware_version||''})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"label\",{htmlFor:\"deviceModel\",className:\"block text-sm font-medium text-gray-700 mb-1\",children:\"Model\"}),/*#__PURE__*/_jsxs(\"select\",{id:\"deviceModel\",name:\"deviceModel\",className:\"block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm\",defaultValue:device.model,children:[/*#__PURE__*/_jsx(\"option\",{value:\"SIM7000E\",children:\"SIM7000E\"}),/*#__PURE__*/_jsx(\"option\",{value:\"SIM7000A\",children:\"SIM7000A\"}),/*#__PURE__*/_jsx(\"option\",{value:\"SIM7000G\",children:\"SIM7000G\"}),/*#__PURE__*/_jsx(\"option\",{value:\"Custom\",children:\"Custom\"})]})]})]}),/*#__PURE__*/_jsxs(\"div\",{children:[/*#__PURE__*/_jsx(\"label\",{className:\"block text-sm font-medium text-gray-700 mb-1\",children:\"Device Status\"}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex space-x-4\",children:[/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center\",children:[/*#__PURE__*/_jsx(\"input\",{id:\"status-active\",name:\"status\",type:\"radio\",value:\"active\",defaultChecked:device.is_active,className:\"h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300\"}),/*#__PURE__*/_jsx(\"label\",{htmlFor:\"status-active\",className:\"ml-2 block text-sm text-gray-700\",children:\"Active\"})]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex items-center\",children:[/*#__PURE__*/_jsx(\"input\",{id:\"status-inactive\",name:\"status\",type:\"radio\",value:\"inactive\",defaultChecked:!device.is_active,className:\"h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300\"}),/*#__PURE__*/_jsx(\"label\",{htmlFor:\"status-inactive\",className:\"ml-2 block text-sm text-gray-700\",children:\"Inactive\"})]})]})]}),/*#__PURE__*/_jsx(\"div\",{className:\"pt-4\",children:/*#__PURE__*/_jsxs(\"button\",{type:\"submit\",className:\"flex items-center gap-2 px-4 py-2 bg-primary-500 text-white rounded-md hover:bg-primary-600 transition-colors\",children:[/*#__PURE__*/_jsx(FiSave,{}),/*#__PURE__*/_jsx(\"span\",{children:\"Save Changes\"})]})})]})]})]})]}),/*#__PURE__*/_jsx(EditDeviceModal,{isOpen:showEditModal,onClose:handleCloseEditModal,device:device,onDeviceUpdated:handleDeviceUpdated}),deleteConfirm&&/*#__PURE__*/_jsx(\"div\",{className:\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50\",children:/*#__PURE__*/_jsx(\"div\",{className:\"bg-white rounded-lg shadow-xl max-w-md w-full mx-4\",children:/*#__PURE__*/_jsxs(\"div\",{className:\"p-6\",children:[/*#__PURE__*/_jsx(\"h3\",{className:\"text-lg font-semibold text-gray-800 mb-4\",children:\"Delete Device\"}),/*#__PURE__*/_jsxs(\"p\",{className:\"text-gray-600 mb-6\",children:[\"Are you sure you want to delete \\\"\",device===null||device===void 0?void 0:device.name,\"\\\"? This action cannot be undone and will remove all associated telemetry data and logs.\"]}),/*#__PURE__*/_jsxs(\"div\",{className:\"flex justify-end gap-3\",children:[/*#__PURE__*/_jsx(\"button\",{onClick:cancelDeleteDevice,className:\"px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors\",children:\"Cancel\"}),/*#__PURE__*/_jsx(\"button\",{onClick:confirmDeleteDevice,className:\"px-4 py-2 bg-red-500 text-white rounded-md text-sm font-medium hover:bg-red-600 transition-colors\",children:\"Delete Device\"})]})]})})})]});};export default DeviceDetail;","map":{"version":3,"names":["React","useState","useEffect","useParams","Link","useNavigate","FiArrowLeft","FiEdit","FiTrash2","FiRefreshCw","FiBattery","FiWifi","FiMapPin","FiClock","FiInfo","FiSave","FiCopy","FiServer","FiKey","FiChevronDown","FiChevronUp","FiCode","MapContainer","TileLayer","Marker","Popup","L","EditDeviceModal","deviceApi","jsx","_jsx","jsxs","_jsxs","Icon","Default","prototype","_getIconUrl","mergeOptions","iconRetinaUrl","iconUrl","shadowUrl","dummyDevices","id","name","description","model","firmware_version","status","battery","level","signal","strength","location","latitude","longitude","altitude","last_seen","Date","toISOString","created_at","now","dummyTelemetry","device_id","battery_level","signal_strength","temperature","timestamp","dummyLogs","message","source","DeviceDetail","navigate","device","setDevice","telemetry","setTelemetry","logs","setLogs","loading","setLoading","activeTab","setActiveTab","refreshing","setRefreshing","copySuccess","setCopySuccess","expandedApiSection","setExpandedApiSection","showEditModal","setShowEditModal","deleteConfirm","setDeleteConfirm","fetchDeviceData","token","localStorage","getItem","deviceResponse","fetch","headers","ok","deviceData","json","transformedDevice","getDeviceStatus","getBatteryInfo","getSignalInfo","deviceTelemetry","filter","t","deviceLogs","l","foundDevice","find","d","console","error","is_active","lastSeen","diffMinutes","formatDate","dateString","date","toLocaleString","getStatusColor","getBatteryColor","getSignalColor","getLevelColor","handleRefresh","handleCopy","text","label","navigator","clipboard","writeText","setTimeout","err","getApiEndpoints","baseUrl","window","origin","toggleApiSection","section","handleEditDevice","handleCloseEditModal","handleDeviceUpdated","updatedDevice","handleDeleteDevice","confirmDeleteDevice","deleteDevice","alert","cancelDeleteDevice","getApiExamples","request","method","body","device_name","firmware","temp","hum","solar_volt","battery_volt","gps_fixed","satellites","Math","floor","response","humidity","solar_voltage","battery_voltage","device_timestamp","updated_at","metadata","network_type","signal_quality","operator","modem_model","className","children","to","onClick","disabled","center","zoom","style","height","width","attribution","url","position","toFixed","slice","map","log","length","item","toUpperCase","size","JSON","stringify","onSubmit","e","preventDefault","formData","FormData","target","updateData","get","updateDevice","then","data","catch","htmlFor","type","defaultValue","value","defaultChecked","isOpen","onClose","onDeviceUpdated"],"sources":["/home/m3mo/Desktop/temparea/solarbank/frontend/src/pages/DeviceDetail.js"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport { useParams, Link, useNavigate } from 'react-router-dom';\nimport { FiArrowLeft, FiEdit, FiTrash2, FiRefreshCw, FiBattery, FiWifi, FiMapPin, FiClock, FiInfo, FiSave, FiCopy, FiServer, FiKey, FiChevronDown, FiChevronUp, FiCode } from 'react-icons/fi';\nimport { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';\nimport 'leaflet/dist/leaflet.css';\nimport L from 'leaflet';\nimport EditDeviceModal from '../components/EditDeviceModal';\nimport { deviceApi } from '../services/api';\n\n// Fix for Leaflet marker icons\ndelete L.Icon.Default.prototype._getIconUrl;\nL.Icon.Default.mergeOptions({\n iconRetinaUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',\n iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png',\n shadowUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png',\n});\n\n// Dummy data for demonstration\nconst dummyDevices = [\n {\n id: 'device-001',\n name: 'SIM7000E-001',\n description: 'Solar panel monitoring device',\n model: 'SIM7000E',\n firmware_version: '1.2.3',\n status: 'online',\n battery: { level: 85, status: 'good' },\n signal: { strength: -65, status: 'good' },\n location: { latitude: 47.3769, longitude: 8.5417, altitude: 408 },\n last_seen: new Date().toISOString(),\n created_at: new Date(Date.now() - 7776000000).toISOString() // 90 days ago\n },\n {\n id: 'device-002',\n name: 'SIM7000E-002',\n description: 'Wind turbine monitoring device',\n model: 'SIM7000E',\n firmware_version: '1.2.3',\n status: 'idle',\n battery: { level: 42, status: 'low' },\n signal: { strength: -85, status: 'fair' },\n location: { latitude: 47.3780, longitude: 8.5390, altitude: 410 },\n last_seen: new Date(Date.now() - 3600000).toISOString(), // 1 hour ago\n created_at: new Date(Date.now() - 15552000000).toISOString() // 180 days ago\n }\n];\n\n// Dummy telemetry data\nconst dummyTelemetry = [\n {\n id: 1,\n device_id: 'device-001',\n latitude: 47.3769,\n longitude: 8.5417,\n altitude: 408,\n battery_level: 85,\n signal_strength: -65,\n temperature: 24.5,\n timestamp: new Date().toISOString()\n },\n {\n id: 2,\n device_id: 'device-001',\n latitude: 47.3769,\n longitude: 8.5417,\n altitude: 408,\n battery_level: 86,\n signal_strength: -64,\n temperature: 24.2,\n timestamp: new Date(Date.now() - 3600000).toISOString() // 1 hour ago\n },\n {\n id: 3,\n device_id: 'device-001',\n latitude: 47.3770,\n longitude: 8.5418,\n altitude: 408,\n battery_level: 87,\n signal_strength: -63,\n temperature: 23.8,\n timestamp: new Date(Date.now() - 7200000).toISOString() // 2 hours ago\n }\n];\n\n// Dummy logs data\nconst dummyLogs = [\n {\n id: 1,\n device_id: 'device-001',\n level: 'info',\n message: 'Device connected to network',\n source: 'connection_manager',\n timestamp: new Date().toISOString()\n },\n {\n id: 2,\n device_id: 'device-001',\n level: 'warning',\n message: 'Battery level below 90%',\n source: 'power_monitor',\n timestamp: new Date(Date.now() - 1800000).toISOString() // 30 minutes ago\n },\n {\n id: 3,\n device_id: 'device-001',\n level: 'info',\n message: 'GPS location updated',\n source: 'gps_module',\n timestamp: new Date(Date.now() - 3600000).toISOString() // 1 hour ago\n }\n];\n\nconst DeviceDetail = () => {\n const { id } = useParams();\n const navigate = useNavigate();\n const [device, setDevice] = useState(null);\n const [telemetry, setTelemetry] = useState([]);\n const [logs, setLogs] = useState([]);\n const [loading, setLoading] = useState(true);\n const [activeTab, setActiveTab] = useState('overview');\n const [refreshing, setRefreshing] = useState(false);\n const [copySuccess, setCopySuccess] = useState('');\n const [expandedApiSection, setExpandedApiSection] = useState('');\n const [showEditModal, setShowEditModal] = useState(false);\n const [deleteConfirm, setDeleteConfirm] = useState(false);\n\n useEffect(() => {\n fetchDeviceData();\n }, [id]);\n\n const fetchDeviceData = async () => {\n try {\n setLoading(true);\n const token = localStorage.getItem('token');\n \n // Fetch device data from API\n const deviceResponse = await fetch(`/api/devices/${id}`, {\n headers: {\n 'Authorization': `Bearer ${token}`,\n },\n });\n\n if (deviceResponse.ok) {\n const deviceData = await deviceResponse.json();\n \n // Transform the device data to include frontend display properties\n const transformedDevice = {\n ...deviceData,\n status: getDeviceStatus(deviceData),\n battery: getBatteryInfo(deviceData),\n signal: getSignalInfo(deviceData),\n location: {\n latitude: deviceData.latitude || 47.3769, // Default location if none set\n longitude: deviceData.longitude || 8.5417,\n altitude: deviceData.altitude || 408\n }\n };\n \n setDevice(transformedDevice);\n \n // For now, use dummy telemetry and logs until those APIs are implemented\n const deviceTelemetry = dummyTelemetry.filter(t => t.device_id === id);\n const deviceLogs = dummyLogs.filter(l => l.device_id === id);\n \n setTelemetry(deviceTelemetry);\n setLogs(deviceLogs);\n } else if (deviceResponse.status === 404) {\n // Device not found in API, try dummy data for existing demo devices\n const foundDevice = dummyDevices.find(d => d.id === id);\n if (foundDevice) {\n setDevice(foundDevice);\n \n const deviceTelemetry = dummyTelemetry.filter(t => t.device_id === id);\n const deviceLogs = dummyLogs.filter(l => l.device_id === id);\n \n setTelemetry(deviceTelemetry);\n setLogs(deviceLogs);\n } else {\n setDevice(null); // This will show the \"Device Not Found\" message\n }\n } else {\n console.error('Failed to fetch device:', deviceResponse.status);\n setDevice(null);\n }\n } catch (error) {\n console.error('Error fetching device data:', error);\n // Fall back to dummy data\n const foundDevice = dummyDevices.find(d => d.id === id);\n if (foundDevice) {\n setDevice(foundDevice);\n \n const deviceTelemetry = dummyTelemetry.filter(t => t.device_id === id);\n const deviceLogs = dummyLogs.filter(l => l.device_id === id);\n \n setTelemetry(deviceTelemetry);\n setLogs(deviceLogs);\n } else {\n setDevice(null);\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Helper functions to transform backend data\n const getDeviceStatus = (device) => {\n if (!device.is_active) return 'offline';\n if (!device.last_seen) return 'offline';\n \n const lastSeen = new Date(device.last_seen);\n const now = new Date();\n const diffMinutes = (now - lastSeen) / (1000 * 60);\n \n if (diffMinutes < 5) return 'online';\n if (diffMinutes < 30) return 'idle';\n return 'offline';\n };\n\n const getBatteryInfo = (device) => {\n const level = device.battery_level || 0;\n let status = 'good';\n if (level < 20) status = 'critical';\n else if (level < 50) status = 'low';\n \n return { level, status };\n };\n\n const getSignalInfo = (device) => {\n const strength = device.signal_strength || -100;\n let status = 'poor';\n if (strength > -70) status = 'good';\n else if (strength > -85) status = 'fair';\n \n return { strength, status };\n };\n\n // Helper function to format date\n const formatDate = (dateString) => {\n const date = new Date(dateString);\n return date.toLocaleString();\n };\n\n // Helper function to get status color\n const getStatusColor = (status) => {\n switch (status) {\n case 'online':\n return 'text-success-500';\n case 'idle':\n return 'text-warning-500';\n case 'offline':\n return 'text-danger-500';\n default:\n return 'text-gray-500';\n }\n };\n\n // Helper function to get battery color\n const getBatteryColor = (status) => {\n switch (status) {\n case 'good':\n return 'text-success-500';\n case 'low':\n return 'text-warning-500';\n case 'critical':\n return 'text-danger-500';\n default:\n return 'text-gray-500';\n }\n };\n\n // Helper function to get signal color\n const getSignalColor = (status) => {\n switch (status) {\n case 'good':\n return 'text-success-500';\n case 'fair':\n return 'text-warning-500';\n case 'poor':\n return 'text-danger-500';\n default:\n return 'text-gray-500';\n }\n };\n\n // Helper function to get log level color\n const getLevelColor = (level) => {\n switch (level) {\n case 'debug':\n return 'text-gray-500 bg-gray-100';\n case 'info':\n return 'text-blue-500 bg-blue-100';\n case 'warning':\n return 'text-yellow-500 bg-yellow-100';\n case 'error':\n return 'text-red-500 bg-red-100';\n case 'critical':\n return 'text-white bg-red-500';\n default:\n return 'text-gray-500 bg-gray-100';\n }\n };\n\n // Handle refresh\n const handleRefresh = async () => {\n setRefreshing(true);\n await fetchDeviceData();\n setRefreshing(false);\n };\n\n // Handle copy to clipboard\n const handleCopy = async (text, label) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopySuccess(label);\n setTimeout(() => setCopySuccess(''), 2000);\n } catch (err) {\n console.error('Failed to copy: ', err);\n }\n };\n\n // Generate API endpoints for the device\n const getApiEndpoints = () => {\n const baseUrl = window.location.origin;\n return {\n telemetry: `${baseUrl}/api/data/${device?.id}`,\n status: `${baseUrl}/api/devices/${device?.id}`,\n logs: `${baseUrl}/api/logs/${device?.id}`\n };\n };\n\n // Toggle API documentation sections\n const toggleApiSection = (section) => {\n setExpandedApiSection(expandedApiSection === section ? '' : section);\n };\n\n // Handle edit device\n const handleEditDevice = () => {\n setShowEditModal(true);\n };\n\n const handleCloseEditModal = () => {\n setShowEditModal(false);\n };\n\n const handleDeviceUpdated = (updatedDevice) => {\n // Transform the updated device data\n const transformedDevice = {\n ...updatedDevice,\n status: getDeviceStatus(updatedDevice),\n battery: getBatteryInfo(updatedDevice),\n signal: getSignalInfo(updatedDevice),\n location: {\n latitude: updatedDevice.latitude || 0,\n longitude: updatedDevice.longitude || 0,\n altitude: updatedDevice.altitude || 0\n }\n };\n \n setDevice(transformedDevice);\n };\n\n // Handle delete device\n const handleDeleteDevice = () => {\n setDeleteConfirm(true);\n };\n\n const confirmDeleteDevice = async () => {\n try {\n await deviceApi.deleteDevice(device.id);\n navigate('/devices'); // Redirect to devices list after deletion\n } catch (error) {\n console.error('Error deleting device:', error);\n alert('Failed to delete device. Please try again.');\n setDeleteConfirm(false);\n }\n };\n\n const cancelDeleteDevice = () => {\n setDeleteConfirm(false);\n };\n\n // Generate example API data\n const getApiExamples = () => {\n return {\n telemetry: {\n request: {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: {\n device_id: device?.id || 'LILYGO_001',\n device_name: device?.name || 'Zurich_Station_1',\n firmware: '1.1.0',\n temp: 24.3,\n hum: 65.2,\n solar_volt: 12.8,\n battery_volt: 3.8,\n signal: -65,\n gps_fixed: true,\n latitude: 47.3769,\n longitude: 8.5417,\n altitude: 408,\n satellites: 8,\n timestamp: Math.floor(Date.now() / 1000)\n }\n },\n response: {\n status: 201,\n body: {\n id: 123,\n device_id: device?.id || 'LILYGO_001',\n latitude: 47.3769,\n longitude: 8.5417,\n altitude: 408,\n temperature: 24.3,\n humidity: 65.2,\n solar_voltage: 12.8,\n battery_level: 85.5,\n battery_voltage: 3.8,\n signal_strength: -65,\n gps_fixed: true,\n satellites: 8,\n timestamp: new Date().toISOString(),\n device_timestamp: new Date().toISOString()\n }\n }\n },\n status: {\n request: {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer your-token-here'\n },\n body: {\n name: device?.name || 'Your Device Name',\n firmware_version: \"1.1.0\",\n is_active: true,\n battery_level: 87.2,\n signal_strength: -62\n }\n },\n response: {\n status: 200,\n body: {\n id: device?.id || 'your-device-id',\n name: device?.name || 'Your Device Name',\n model: 'LILYGO T-A7670G',\n firmware_version: '1.1.0',\n is_active: true,\n battery_level: 87.2,\n signal_strength: -62,\n last_seen: new Date().toISOString(),\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString()\n }\n }\n },\n logs: {\n request: {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer your-token-here'\n },\n body: {\n device_id: device?.id || 'LILYGO_001',\n level: \"info\",\n message: \"Device connected to cellular network\",\n source: \"network_manager\",\n timestamp: new Date().toISOString(),\n metadata: {\n network_type: \"LTE\",\n signal_quality: \"good\",\n operator: \"Swisscom\",\n modem_model: \"A7670G\"\n }\n }\n },\n response: {\n status: 201,\n body: {\n id: 456,\n device_id: device?.id || 'LILYGO_001',\n level: \"info\",\n message: \"Device connected to cellular network\",\n source: \"network_manager\",\n timestamp: new Date().toISOString(),\n metadata: {\n network_type: \"LTE\",\n signal_quality: \"good\",\n operator: \"Swisscom\",\n modem_model: \"A7670G\"\n }\n }\n }\n }\n };\n };\n\n if (loading) {\n return (\n
Loading device data...
\nThe device you are looking for does not exist or has been removed.
\n \n Back to Devices\n \n{device.description || 'No description'}
\nStatus
\n{device.status}
\nBattery
\n{device.battery.level}%
\nSignal
\n{device.signal.strength} dBm
\nLast Seen
\n{formatDate(device.last_seen)}
\nDevice ID
\n{device.id}
\nModel
\n{device.model}
\nFirmware Version
\nv{device.firmware_version}
\nCreated At
\n{formatDate(device.created_at)}
\nDescription
\n{device.description || 'No description'}
\n\n {device.location.latitude.toFixed(6)}, {device.location.longitude.toFixed(6)}\n
\n\n Altitude: {device.location.altitude} m\n
\n{log.message}
\n {formatDate(log.timestamp)}\nSource: {log.source}
\nNo recent activity
\n )}\nNo telemetry data available
\n ) : (\n| Timestamp | \nLocation | \nBattery | \nSignal | \nTemperature | \n
|---|---|---|---|---|
| \n {formatDate(item.timestamp)}\n | \n\n \n \n | \n \n \n \n | \n \n \n \n | \n \n {item.temperature}°C\n | \n
No logs available
\n ) : (\n| Timestamp | \nLevel | \nMessage | \nSource | \n
|---|---|---|---|
| \n {formatDate(log.timestamp)}\n | \n\n \n {log.level.toUpperCase()}\n \n | \n\n {log.message}\n | \n\n {log.source}\n | \n
\n Configure your device to send data to these endpoints. Copy the URLs below and configure them in your IoT device.\n
\n \nSend LILYGO T-A7670G device data including temperature, humidity, solar voltage, GPS and battery info
\n\n {getApiEndpoints().telemetry}/iot\n \n \n Headers:
\n\n{JSON.stringify(getApiExamples().telemetry.request.headers, null, 2)}\n \n Body (JSON):
\n\n{JSON.stringify(getApiExamples().telemetry.request.body, null, 2)}\n \n cURL Example:
\n\n{`curl -X POST \"${getApiEndpoints().telemetry}/iot\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '${JSON.stringify(getApiExamples().telemetry.request.body)}'`}\n \n Arduino/ESP32 Example:
\n\n{`String json = \"{\";\njson += \"\\\\\"device_id\\\\\":\\\\\"${device?.id || 'LILYGO_001'}\\\\\",\";\njson += \"\\\\\"temp\\\\\":\" + String(temperature) + \",\";\njson += \"\\\\\"hum\\\\\":\" + String(humidity) + \",\";\njson += \"\\\\\"solar_volt\\\\\":\" + String(solarVoltage) + \",\";\njson += \"\\\\\"battery_volt\\\\\":\" + String(batteryVoltage) + \",\";\njson += \"\\\\\"signal\\\\\":\" + String(signalStrength) + \",\";\njson += \"\\\\\"gps_fixed\\\\\":\" + (gpsFixed ? \"true\" : \"false\") + \",\";\njson += \"\\\\\"latitude\\\\\":\" + String(latitude, 6) + \",\";\njson += \"\\\\\"longitude\\\\\":\" + String(longitude, 6) + \",\";\njson += \"\\\\\"timestamp\\\\\":\" + String(millis() / 1000);\njson += \"}\";\n\n// Send via HTTP POST to ${getApiEndpoints().telemetry}/iot`}\n \n Status: {getApiExamples().telemetry.response.status}
\n\n{JSON.stringify(getApiExamples().telemetry.response.body, null, 2)}\n \n Update device configuration and status information
\n\n {getApiEndpoints().status}\n \n \n Headers:
\n\n{JSON.stringify(getApiExamples().status.request.headers, null, 2)}\n \n Body (JSON):
\n\n{JSON.stringify(getApiExamples().status.request.body, null, 2)}\n \n cURL Example:
\n\n{`curl -X PUT \"${getApiEndpoints().status}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -H \"Device-ID: ${device?.id || 'your-device-id'}\" \\\\\n -d '${JSON.stringify(getApiExamples().status.request.body)}'`}\n \n Status: {getApiExamples().status.response.status}
\n\n{JSON.stringify(getApiExamples().status.response.body, null, 2)}\n \n Send device logs, errors, and diagnostic information
\n\n {getApiEndpoints().logs}\n \n \n Headers:
\n\n{JSON.stringify(getApiExamples().logs.request.headers, null, 2)}\n \n Body (JSON):
\n\n{JSON.stringify(getApiExamples().logs.request.body, null, 2)}\n \n cURL Example:
\n\n{`curl -X POST \"${getApiEndpoints().logs}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -H \"Device-ID: ${device?.id || 'your-device-id'}\" \\\\\n -d '${JSON.stringify(getApiExamples().logs.request.body)}'`}\n \n Status: {getApiExamples().logs.response.status}
\n\n{JSON.stringify(getApiExamples().logs.response.body, null, 2)}\n \n Include this device ID in your requests for authentication
\n\n Device-ID: {device?.id}\n \n \n \n Are you sure you want to delete \"{device?.name}\"? This action cannot be undone and will remove all associated telemetry data and logs.\n
\n