add sqllite

This commit is contained in:
2026-02-06 15:35:54 +09:00
parent e7b7414d73
commit 921455749e
9 changed files with 2745 additions and 26 deletions

45
App.tsx
View File

@@ -4,7 +4,7 @@ import { MapContainer, TileLayer, Marker, Popup, useMapEvents, useMap, Circle }
import L from 'leaflet';
import { QRCodeCanvas } from 'qrcode.react';
import { WiFiHotspot } from './types';
import { storageService } from './services/storage';
import { apiService } from './services/api';
import { geminiService, DetailedSearchResult } from './services/geminiService';
import {
Wifi,
@@ -105,7 +105,7 @@ const MapInterface = ({ onMapClick, onLocate, onAdd, onStatsUpdate, onMapMove }:
};
const App: React.FC = () => {
const [hotspots, setHotspots] = useState<WiFiHotspot[]>(() => storageService.getHotspots());
const [hotspots, setHotspots] = useState<WiFiHotspot[]>([]);
const [searchQuery, setSearchQuery] = useState('');
const [isAdding, setIsAdding] = useState(false);
const [selectedHotspot, setSelectedHotspot] = useState<WiFiHotspot | null>(null);
@@ -127,30 +127,35 @@ const App: React.FC = () => {
const markerRef = useRef<any>(null);
useEffect(() => {
const saved = storageService.getHotspots();
if (saved.length > 0) {
setHotspots(saved);
const lastSpot = saved[saved.length-1];
setMapCenter([lastSpot.lat, lastSpot.lng]);
setInputLat(lastSpot.lat.toFixed(6));
setInputLng(lastSpot.lng.toFixed(6));
}
const loadHotspots = async () => {
const saved = await apiService.getHotspots();
if (saved.length > 0) {
setHotspots(saved);
const lastSpot = saved[saved.length-1];
setMapCenter([lastSpot.lat, lastSpot.lng]);
setInputLat(lastSpot.lat.toFixed(6));
setInputLng(lastSpot.lng.toFixed(6));
} else if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((pos) => {
const newPos: [number, number] = [pos.coords.latitude, pos.coords.longitude];
setMapCenter(newPos);
setInputLat(newPos[0].toFixed(6));
setInputLng(newPos[1].toFixed(6));
});
}
};
loadHotspots();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((pos) => {
const newPos: [number, number] = [pos.coords.latitude, pos.coords.longitude];
setUserLocation(newPos);
if (saved.length === 0) {
setMapCenter(newPos);
setInputLat(newPos[0].toFixed(6));
setInputLng(newPos[1].toFixed(6));
}
}, null, { enableHighAccuracy: true });
}
}, []);
useEffect(() => {
const handleSync = () => setHotspots(storageService.getHotspots());
const handleSync = async () => setHotspots(await apiService.getHotspots());
window.addEventListener('storage_updated', handleSync);
return () => window.removeEventListener('storage_updated', handleSync);
}, []);
@@ -211,7 +216,7 @@ const App: React.FC = () => {
}
};
const saveWiFi = (e: React.FormEvent<HTMLFormElement>) => {
const saveWiFi = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const newHotspot: WiFiHotspot = {
@@ -228,8 +233,8 @@ const App: React.FC = () => {
isPublic: true
};
storageService.saveHotspot(newHotspot);
setHotspots(storageService.getHotspots());
await apiService.saveHotspot(newHotspot);
setHotspots(await apiService.getHotspots());
setIsAdding(false);
setNewHotspotPos(null);
setSelectedHotspot(newHotspot);
@@ -457,7 +462,7 @@ const App: React.FC = () => {
<div className="flex flex-col gap-4 pt-6">
<button onClick={() => { if(selectedHotspot.password) { navigator.clipboard.writeText(selectedHotspot.password); alert("비밀번호가 복사되었습니다!"); } }} className="w-full py-6 bg-slate-900 hover:bg-black text-white font-black rounded-3xl shadow-xl transition-all"> </button>
<button onClick={() => { if(confirm("삭제하시겠습니까?")) { storageService.deleteHotspot(selectedHotspot.id); setHotspots(storageService.getHotspots()); setSelectedHotspot(null); } }} className="w-full py-5 text-red-500 hover:bg-red-50 font-black rounded-3xl transition-colors flex items-center justify-center gap-2">
<button onClick={async () => { if(confirm("삭제하시겠습니까?")) { await apiService.deleteHotspot(selectedHotspot.id); setHotspots(await apiService.getHotspots()); setSelectedHotspot(null); } }} className="w-full py-5 text-red-500 hover:bg-red-50 font-black rounded-3xl transition-colors flex items-center justify-center gap-2">
<Trash2 size={20} />
</button>
</div>