fuzzyworld

when-am-i / commit

refactor: remove dead duplicates and fix MapPicker render bug

9a0109d5a22f4731a1de4dab0ca0731abb8dd90d · Pavel Safronov · 2026-06-16 23:31:57 -0700 · parents 60741172d8ae

refactor: remove dead duplicates and fix MapPicker render bug

- Delete src/MapPicker.tsx: an unused, slightly-broken duplicate of the live
  src/components/MapPicker.tsx (App imports the latter).
- Fix a real bug in src/components/MapPicker.tsx: LocationMarker was defined
  inside render, so it was recreated every render and remounted the Leaflet
  click handler. Hoist it out and type the event via leaflet's
  LeafletMouseEvent (was an undeclared `L` namespace).
- Drop empty placeholder stubs src/hooks/index.ts and src/utils/index.ts.
- Rename react-app-env.d.ts -> vite-env.d.ts and reference vite/client, which
  provides asset-import and import.meta.glob typings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
 src/MapPicker.tsx            | 35 -----------------------------------
 src/components/MapPicker.tsx | 33 +++++++++++++++++++++++----------
 src/hooks/index.ts           |  2 --
 src/react-app-env.d.ts       |  4 ----
 src/utils/index.ts           |  2 --
 src/vite-env.d.ts            |  4 ++++
 6 files changed, 27 insertions(+), 53 deletions(-)

diff --git a/src/MapPicker.tsx b/src/MapPicker.tsx
deleted file mode 100644
index e082e59..0000000
--- a/src/MapPicker.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, { useState } from 'react';
-import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet';
-import 'leaflet/dist/leaflet.css';
-
-interface MapPickerProps {
-    onPick: (lat: number, lng: number) => void;
-}
-
-const MapPicker: React.FC<MapPickerProps> = ({ onPick }) => {
-    const [position, setPosition] = useState<[number, number] | null>(null);
-
-    function LocationMarker() {
-        useMapEvents({
-            click(e: { latlng: { lat: number; lng: number; }; }) {
-                setPosition([e.latlng.lat, e.latlng.lng]);
-                onPick(e.latlng.lat, e.latlng.lng);
-            },
-        });
-        return position ? <Marker position={position} /> : null;
-    }
-
-    const tileLayerProps = {
-        attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
-        url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
-    };
-
-    return (
-        <MapContainer style={{ height: '400px', width: '100%' }} >
-            <TileLayer {...tileLayerProps} />
-            <LocationMarker />
-        </MapContainer>
-    );
-};
-
-export default MapPicker;
diff --git a/src/components/MapPicker.tsx b/src/components/MapPicker.tsx
index 6c22c74..11664c5 100644
--- a/src/components/MapPicker.tsx
+++ b/src/components/MapPicker.tsx
@@ -1,23 +1,36 @@
 import React, { useState } from 'react';
 import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet';
+import type { LeafletMouseEvent } from 'leaflet';
 import 'leaflet/dist/leaflet.css';
 
 interface MapPickerProps {
     onPick: (lat: number, lng: number) => void;
 }
 
+// Hoisted out of MapPicker so it isn't recreated on every render (which would
+// remount the Leaflet click handler). Renders the marker at the picked spot.
+function LocationMarker({
+    position,
+    onSelect,
+}: {
+    position: [number, number] | null;
+    onSelect: (lat: number, lng: number) => void;
+}) {
+    useMapEvents({
+        click(e: LeafletMouseEvent) {
+            onSelect(e.latlng.lat, e.latlng.lng);
+        },
+    });
+    return position ? <Marker position={position} /> : null;
+}
+
 const MapPicker: React.FC<MapPickerProps> = ({ onPick }) => {
     const [position, setPosition] = useState<[number, number] | null>(null);
 
-    function LocationMarker() {
-        useMapEvents({
-            click(e: L.LeafletMouseEvent) {
-                setPosition([e.latlng.lat, e.latlng.lng]);
-                onPick(e.latlng.lat, e.latlng.lng);
-            },
-        });
-        return position ? <Marker position={position} /> : null;
-    }
+    const handleSelect = (lat: number, lng: number) => {
+        setPosition([lat, lng]);
+        onPick(lat, lng);
+    };
 
     return (
         <MapContainer center={[20, 0]} zoom={2} style={{ height: '400px', width: '100%' }}>
@@ -25,7 +38,7 @@ const MapPicker: React.FC<MapPickerProps> = ({ onPick }) => {
                 attribution='&copy; OpenStreetMap contributors'
                 url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
             />
-            <LocationMarker />
+            <LocationMarker position={position} onSelect={handleSelect} />
         </MapContainer>
     );
 };
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
deleted file mode 100644
index 638fa71..0000000
--- a/src/hooks/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// Custom hooks will go here
-export { };
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
deleted file mode 100644
index 0357e4f..0000000
--- a/src/react-app-env.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module "*.png";
-declare module "*.svg";
-declare module "*.jpeg";
-declare module "*.jpg";
diff --git a/src/utils/index.ts b/src/utils/index.ts
deleted file mode 100644
index e20b017..0000000
--- a/src/utils/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// Utility functions will go here
-export { };
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..8379221
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,4 @@
+/// <reference types="vite/client" />
+
+// vite/client already declares asset imports (*.png, *.svg, …) and the typings
+// for import.meta.glob used by the calendar data loader.