Initial commit
This commit is contained in:
89
App.tsx
Normal file
89
App.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user