File size: 2,851 Bytes
4851501
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"use client";

import dynamic from "next/dynamic";
import ChatPanel from "@/components/ChatPanel";
import { useState } from "react";
import type { MapLayer } from "@/components/MapViewer";

// Dynamic import for MapViewer (client-side only)
const MapViewer = dynamic(() => import("@/components/MapViewer"), {
  ssr: false,
  loading: () => <div className="w-full h-full bg-slate-100 flex items-center justify-center">Loading Map...</div>
});

export default function Home() {
  const [layers, setLayers] = useState<MapLayer[]>([]);

  const handleMapUpdate = (newGeojson: any) => {
    // Unique ID generation
    const id = Date.now().toString() + Math.random().toString(36).substr(2, 9);

    // Extract metadata from backend response
    const name = newGeojson.properties?.layer_name || `Layer ${layers.length + 1}`;
    const recommendedStyle = newGeojson.properties?.style || {};
    const choroplethConfig = newGeojson.properties?.choropleth || null;

    // Construct new layer with defaults if style is missing
    const newLayer: MapLayer = {
      id,
      name,
      data: newGeojson,
      visible: true,
      style: {
        color: recommendedStyle.color || "#6366f1",
        fillColor: recommendedStyle.fillColor || recommendedStyle.color || "#6366f1",
        fillOpacity: recommendedStyle.fillOpacity || 0.3,
        weight: recommendedStyle.weight || 1
      },
      // Pass choropleth config if present
      ...(choroplethConfig && { choropleth: choroplethConfig }),

      // Point marker config
      pointMarker: newGeojson.properties?.pointMarker
    };

    // Add to layers (newest on top)
    setLayers(prev => [...prev, newLayer]);
  };

  const handleLayerUpdate = (id: string, updates: Partial<MapLayer>) => {
    setLayers(prev => prev.map(layer =>
      layer.id === id ? { ...layer, ...updates } : layer
    ));
  };

  const handleLayerRemove = (id: string) => {
    setLayers(prev => prev.filter(layer => layer.id !== id));
  };

  const handleLayerReorder = (fromIndex: number, toIndex: number) => {
    setLayers(prev => {
      const newLayers = [...prev];
      const [movedLayer] = newLayers.splice(fromIndex, 1);
      newLayers.splice(toIndex, 0, movedLayer);
      return newLayers;
    });
  };

  return (
    <main className="flex h-screen w-full overflow-hidden">
      {/* Left Panel: Chat (30-40% width) */}
      <div className="w-[400px] md:w-[450px] lg:w-[30%] shrink-0 h-full relative z-10">
        <ChatPanel onMapUpdate={handleMapUpdate} layers={layers} />
      </div>

      {/* Right Panel: Map (Remaining width) */}
      <div className="flex-1 h-full relative">
        <MapViewer
          layers={layers}
          onLayerUpdate={handleLayerUpdate}
          onLayerRemove={handleLayerRemove}
          onLayerReorder={handleLayerReorder}
        />
      </div>
    </main>
  );
}