Files
copy-of-local-network-dashb…/App.tsx
2025-09-14 13:09:39 -07:00

89 lines
3.4 KiB
TypeScript

import React, { useState, useCallback } from 'react';
import { type Service } from './types';
import { useLocalStorage } from './hooks/useLocalStorage';
import { PRECONFIGURED_SERVICES } from './constants';
import ServiceCard from './components/ServiceCard';
import AddServiceModal from './components/AddServiceModal';
import Header from './components/Header';
import ScanInfoModal from './components/ScanInfoModal';
import { Plus } from 'lucide-react';
import { Globe } from 'lucide-react';
const App: React.FC = () => {
const [services, setServices] = useLocalStorage<Service[]>('dashboard-services', PRECONFIGURED_SERVICES);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isScanInfoModalOpen, setIsScanInfoModalOpen] = useState(false);
const addService = useCallback((newService: Omit<Service, 'id'>) => {
setServices(prevServices => [
...prevServices,
{ ...newService, id: Date.now().toString() }
]);
}, [setServices]);
const addDiscoveredServices = useCallback((discoveredServices: Omit<Service, 'id'>[]) => {
setServices(prevServices => {
const existingUrls = new Set(prevServices.map(s => s.url));
const newServices = discoveredServices
.filter(ds => !existingUrls.has(ds.url))
.map(ds => ({
...ds,
id: `${ds.name}-${ds.url}-${Math.random()}`, // Create a unique ID
icon: Globe, // Default icon for discovered services
}));
return [...prevServices, ...newServices];
});
}, [setServices]);
const deleteService = useCallback((id: string) => {
setServices(prevServices => prevServices.filter(service => service.id !== id));
}, [setServices]);
return (
<div className="min-h-screen bg-gray-900 text-gray-100 font-sans">
<Header
onAddService={() => setIsModalOpen(true)}
onScanNetwork={() => setIsScanInfoModalOpen(true)}
/>
<main className="container mx-auto p-4 md:p-8">
{services.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
{services.map(service => (
<ServiceCard key={service.id} service={service} onDelete={deleteService} />
))}
</div>
) : (
<div className="text-center py-20">
<h2 className="text-2xl font-semibold text-gray-400">Your Dashboard is Empty</h2>
<p className="text-gray-500 mt-2">Click the button below to start adding your local services.</p>
<button
onClick={() => setIsModalOpen(true)}
className="mt-6 inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-teal-500 hover:bg-teal-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-teal-500 transition-colors"
>
<Plus className="-ml-1 mr-3 h-5 w-5" />
Add Your First Service
</button>
</div>
)}
</main>
{isModalOpen && (
<AddServiceModal
onClose={() => setIsModalOpen(false)}
onAddService={addService}
/>
)}
{isScanInfoModalOpen && (
<ScanInfoModal
onClose={() => setIsScanInfoModalOpen(false)}
onScanComplete={addDiscoveredServices}
/>
)}
</div>
);
};
export default App;