지도크기오류 수정
This commit is contained in:
21
App.tsx
21
App.tsx
@@ -58,6 +58,24 @@ const UserLocationIcon = L.divIcon({
|
|||||||
iconAnchor: [20, 20],
|
iconAnchor: [20, 20],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const MapResizer = () => {
|
||||||
|
const map = useMap();
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
map.invalidateSize();
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial resize to fix gray area on load
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [map]);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
const ChangeView = ({ center, zoom }: { center: [number, number], zoom?: number }) => {
|
const ChangeView = ({ center, zoom }: { center: [number, number], zoom?: number }) => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -365,7 +383,8 @@ const App: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 relative">
|
<div className="flex-1 relative">
|
||||||
<MapContainer center={mapCenter} zoom={17} zoomControl={false}>
|
<MapContainer center={mapCenter} zoom={currentZoom} zoomControl={false} style={{ height: '100%', width: '100%' }}>
|
||||||
|
<MapResizer />
|
||||||
<ChangeView center={mapCenter} />
|
<ChangeView center={mapCenter} />
|
||||||
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||||
<MapInterface
|
<MapInterface
|
||||||
|
|||||||
13
server.js
13
server.js
@@ -11,6 +11,7 @@ const __dirname = path.dirname(__filename);
|
|||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
const isDebug = process.env.NODE_ENV !== 'production' || process.env.DEBUG === 'true';
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
@@ -57,10 +58,10 @@ async function initializeDB() {
|
|||||||
// Routes
|
// Routes
|
||||||
app.get('/api/markers', async (req, res) => {
|
app.get('/api/markers', async (req, res) => {
|
||||||
const host = req.headers.host;
|
const host = req.headers.host;
|
||||||
console.log(`[API] GET /api/markers - Host: ${host} - Fetching from SQLite`);
|
if (isDebug) console.log(`[API] GET /api/markers - Host: ${host} - Fetching from SQLite`);
|
||||||
try {
|
try {
|
||||||
const markers = await db.all('SELECT * FROM markers');
|
const markers = await db.all('SELECT * FROM markers');
|
||||||
console.log(`[API] Found ${markers.length} markers`);
|
if (isDebug) console.log(`[API] Found ${markers.length} markers`);
|
||||||
// Convert isPublic from 0/1 to boolean
|
// Convert isPublic from 0/1 to boolean
|
||||||
const formattedMarkers = markers.map(m => ({
|
const formattedMarkers = markers.map(m => ({
|
||||||
...m,
|
...m,
|
||||||
@@ -75,7 +76,7 @@ app.get('/api/markers', async (req, res) => {
|
|||||||
|
|
||||||
app.post('/api/markers', async (req, res) => {
|
app.post('/api/markers', async (req, res) => {
|
||||||
const { id, name, ssid, password, lat, lng, securityType, iconType, description, addedBy, createdAt, isPublic } = req.body;
|
const { id, name, ssid, password, lat, lng, securityType, iconType, description, addedBy, createdAt, isPublic } = req.body;
|
||||||
console.log(`[API] POST /api/markers - Saving marker: ${name} (${ssid}) to SQLite`);
|
if (isDebug) console.log(`[API] POST /api/markers - Saving marker: ${name} (${ssid}) to SQLite`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.run(`
|
await db.run(`
|
||||||
@@ -83,7 +84,7 @@ app.post('/api/markers', async (req, res) => {
|
|||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`, [id, name, ssid, password, lat, lng, securityType, iconType, description || '', addedBy, createdAt, isPublic ? 1 : 0]);
|
`, [id, name, ssid, password, lat, lng, securityType, iconType, description || '', addedBy, createdAt, isPublic ? 1 : 0]);
|
||||||
|
|
||||||
console.log(`[API] Successfully saved marker: ${id}`);
|
if (isDebug) console.log(`[API] Successfully saved marker: ${id}`);
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -93,10 +94,10 @@ app.post('/api/markers', async (req, res) => {
|
|||||||
|
|
||||||
app.delete('/api/markers/:id', async (req, res) => {
|
app.delete('/api/markers/:id', async (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
console.log(`[API] DELETE /api/markers/${id} - Deleting marker from SQLite`);
|
if (isDebug) console.log(`[API] DELETE /api/markers/${id} - Deleting marker from SQLite`);
|
||||||
try {
|
try {
|
||||||
await db.run('DELETE FROM markers WHERE id = ?', [id]);
|
await db.run('DELETE FROM markers WHERE id = ?', [id]);
|
||||||
console.log(`[API] Successfully deleted marker: ${id}`);
|
if (isDebug) console.log(`[API] Successfully deleted marker: ${id}`);
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
import { WiFiHotspot } from '../types';
|
import { WiFiHotspot } from '../types';
|
||||||
|
|
||||||
const API_Base_URL = '/api/markers';
|
const API_Base_URL = '/api/markers';
|
||||||
|
const isDebug = import.meta.env.DEV;
|
||||||
|
|
||||||
export const apiService = {
|
export const apiService = {
|
||||||
getHotspots: async (): Promise<WiFiHotspot[]> => {
|
getHotspots: async (): Promise<WiFiHotspot[]> => {
|
||||||
const fullUrl = `${window.location.origin}${API_Base_URL}`;
|
if (isDebug) console.log(`[API Call] GET ${window.location.origin}${API_Base_URL}`);
|
||||||
console.log(`[API Call] GET ${fullUrl} (Origin: ${window.location.origin})`);
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(API_Base_URL, { cache: 'no-store' }); // 캐시 방지 추가
|
const response = await fetch(API_Base_URL, { cache: 'no-store' });
|
||||||
if (!response.ok) throw new Error('Failed to fetch markers');
|
if (!response.ok) throw new Error('Failed to fetch markers');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log(`[API Response] Received ${data.length} hotspots`, data);
|
if (isDebug) console.log(`[API Response] Received ${data.length} hotspots`, data);
|
||||||
return data;
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to load hotspots from API", e);
|
console.error("Failed to load hotspots from API", e);
|
||||||
@@ -20,7 +20,7 @@ export const apiService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
saveHotspot: async (hotspot: WiFiHotspot): Promise<void> => {
|
saveHotspot: async (hotspot: WiFiHotspot): Promise<void> => {
|
||||||
console.log(`[API Call] POST ${API_Base_URL}`, hotspot);
|
if (isDebug) console.log(`[API Call] POST ${API_Base_URL}`, hotspot);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(API_Base_URL, {
|
const response = await fetch(API_Base_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -31,7 +31,7 @@ export const apiService = {
|
|||||||
});
|
});
|
||||||
if (!response.ok) throw new Error('Failed to save marker');
|
if (!response.ok) throw new Error('Failed to save marker');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log(`[API Response] Save success:`, data);
|
if (isDebug) console.log(`[API Response] Save success:`, data);
|
||||||
// Trigger a storage event to refresh UI if needed (keeping compatibility)
|
// Trigger a storage event to refresh UI if needed (keeping compatibility)
|
||||||
window.dispatchEvent(new Event('storage_updated'));
|
window.dispatchEvent(new Event('storage_updated'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -41,14 +41,14 @@ export const apiService = {
|
|||||||
|
|
||||||
deleteHotspot: async (id: string): Promise<void> => {
|
deleteHotspot: async (id: string): Promise<void> => {
|
||||||
const url = `${API_Base_URL}/${id}`;
|
const url = `${API_Base_URL}/${id}`;
|
||||||
console.log(`[API Call] DELETE ${url}`);
|
if (isDebug) console.log(`[API Call] DELETE ${url}`);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
if (!response.ok) throw new Error('Failed to delete marker');
|
if (!response.ok) throw new Error('Failed to delete marker');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log(`[API Response] Delete success:`, data);
|
if (isDebug) console.log(`[API Response] Delete success:`, data);
|
||||||
window.dispatchEvent(new Event('storage_updated'));
|
window.dispatchEvent(new Event('storage_updated'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to delete hotspot", e);
|
console.error("Failed to delete hotspot", e);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { GoogleGenAI, Type } from "@google/genai";
|
|||||||
|
|
||||||
const apiKey = import.meta.env.VITE_GEMINI_API_KEY || process.env.GEMINI_API_KEY || process.env.API_KEY || '';
|
const apiKey = import.meta.env.VITE_GEMINI_API_KEY || process.env.GEMINI_API_KEY || process.env.API_KEY || '';
|
||||||
if (!apiKey) console.error("API Key is missing!");
|
if (!apiKey) console.error("API Key is missing!");
|
||||||
|
const isDebug = import.meta.env.DEV;
|
||||||
const ai = new GoogleGenAI({ apiKey });
|
const ai = new GoogleGenAI({ apiKey });
|
||||||
|
|
||||||
export interface DetailedSearchResult {
|
export interface DetailedSearchResult {
|
||||||
@@ -15,7 +16,7 @@ export interface DetailedSearchResult {
|
|||||||
export const geminiService = {
|
export const geminiService = {
|
||||||
async searchNearbyWiFi(query: string, location: { lat: number, lng: number }) {
|
async searchNearbyWiFi(query: string, location: { lat: number, lng: number }) {
|
||||||
try {
|
try {
|
||||||
console.log("Stage 1: 정보 검색 시작...");
|
if (isDebug) console.log("Stage 1: 정보 검색 시작...");
|
||||||
|
|
||||||
// Stage 1: Google Search/Maps Grounding을 통해 원시 데이터 확보
|
// Stage 1: Google Search/Maps Grounding을 통해 원시 데이터 확보
|
||||||
const searchResponse = await ai.models.generateContent({
|
const searchResponse = await ai.models.generateContent({
|
||||||
@@ -36,13 +37,13 @@ export const geminiService = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rawText = searchResponse.text || "";
|
const rawText = searchResponse.text || "";
|
||||||
console.log("Stage 1 원문 결과:", rawText);
|
if (isDebug) console.log("Stage 1 원문 결과:", rawText);
|
||||||
|
|
||||||
if (!rawText) {
|
if (!rawText) {
|
||||||
return { text: "검색 결과를 가져오지 못했습니다.", results: [] };
|
return { text: "검색 결과를 가져오지 못했습니다.", results: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Stage 2: 데이터 구조화 추출 시작...");
|
if (isDebug) console.log("Stage 2: 데이터 구조화 추출 시작...");
|
||||||
|
|
||||||
// Stage 2: 획득한 텍스트에서 JSON 형태로 좌표 및 정보 정밀 추출
|
// Stage 2: 획득한 텍스트에서 JSON 형태로 좌표 및 정보 정밀 추출
|
||||||
const parseResponse = await ai.models.generateContent({
|
const parseResponse = await ai.models.generateContent({
|
||||||
@@ -74,7 +75,7 @@ export const geminiService = {
|
|||||||
let results: DetailedSearchResult[] = [];
|
let results: DetailedSearchResult[] = [];
|
||||||
try {
|
try {
|
||||||
results = JSON.parse(parseResponse.text || "[]");
|
results = JSON.parse(parseResponse.text || "[]");
|
||||||
console.log("Stage 2 추출 성공:", results);
|
if (isDebug) console.log("Stage 2 추출 성공:", results);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("JSON 파싱 실패:", e);
|
console.error("JSON 파싱 실패:", e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user