feat: Add real-time visitor map with IP geolocation

- Add latitude/longitude columns to visitor_logs model
- Update visitor_service to fetch and store coordinates from ip-api.com
- Add /admin/map-data API endpoint for map visualization
- Create VisitorMap component using Leaflet/OpenStreetMap
- Integrate map into visitor-stats admin page
- 30-second auto-refresh with animation for new visitors
- Color-coded markers (red: active, blue: recent)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AutonetSellCar Deploy
2026-01-05 18:31:22 +09:00
parent 4858965087
commit b8f0ae4d28
7 changed files with 469 additions and 3 deletions

View File

@@ -1,8 +1,22 @@
'use client';
import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
import { visitorApi, VisitorStatsOverview, TopPage, TopReferrer, ChartData, RealtimeStats } from '@/lib/api';
// Dynamic import for VisitorMap (no SSR - Leaflet requires browser)
const VisitorMap = dynamic(() => import('@/components/VisitorMap'), {
ssr: false,
loading: () => (
<div className="bg-white rounded-lg shadow p-6">
<div className="animate-pulse">
<div className="h-6 bg-gray-200 rounded w-48 mb-4"></div>
<div className="h-96 bg-gray-200 rounded"></div>
</div>
</div>
),
});
// Country code to name and flag mapping
const countryInfo: Record<string, { name: string; flag: string }> = {
MN: { name: 'Mongolia', flag: '🇲🇳' },
@@ -390,6 +404,9 @@ export default function VisitorStatsPage() {
{/* Country Stats - Full Width */}
<CountryStatsCard data={overview?.country_breakdown || {}} />
{/* Real-time Visitor Map */}
<VisitorMap refreshInterval={30} />
{/* Device & Browser Breakdowns */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<BreakdownCard