diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/Map.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/Map.tsx index fa3dd29..b5f4673 100644 --- a/src/components/assets/missing-location/TagMissingLocationDialog/Map.tsx +++ b/src/components/assets/missing-location/TagMissingLocationDialog/Map.tsx @@ -11,6 +11,8 @@ import { MapContainer, TileLayer, useMapEvents } from "react-leaflet"; import { useState } from "react"; import { IPlace } from "@/types/common"; import CustomMarker from "./CustomMarker"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; interface MapComponentProps { location: IPlace; @@ -33,6 +35,7 @@ const MapMouseHandler = ({ onMouseDown }: MapMouseHandlerProps) => { export default function Map({ location, onLocationChange }: MapComponentProps) { const [position, setPosition] = useState([location.latitude, location.longitude]); + const [locationName, setLocationName] = useState(location.name || ""); const handleClick = (coords: LatLngExpression) => { const normalized = L.latLng(coords); @@ -41,23 +44,41 @@ export default function Map({ location, onLocationChange }: MapComponentProps) { onLocationChange({ latitude: normalized.lat, longitude: normalized.lng, - name: "" + name: locationName }); }; + const handleNameChange = (name: string) => { + setLocationName(name); + onLocationChange({ + latitude: location.latitude, + longitude: location.longitude, + name: name + }); + }; return ( - - - - - +
+
+ + handleNameChange(e.target.value)} + /> +
+ + + + + +
); } \ No newline at end of file diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/RecentSearches.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/RecentSearches.tsx new file mode 100644 index 0000000..7c12eeb --- /dev/null +++ b/src/components/assets/missing-location/TagMissingLocationDialog/RecentSearches.tsx @@ -0,0 +1,79 @@ +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { getRecentSearchesByType, RecentSearch } from "@/lib/utils"; +import { IPlace } from "@/types/common"; +import { Clock, MapPin } from "lucide-react"; +import React from "react"; + +interface RecentSearchesProps { + searchType: RecentSearch['searchType']; + onSelect: (place: IPlace) => void; + selectedPlace?: IPlace | null; +} + +export default function RecentSearches({ searchType, onSelect, selectedPlace }: RecentSearchesProps) { + const recentSearches = getRecentSearchesByType(searchType); + + if (recentSearches.length === 0) { + return null; + } + + const formatTimeAgo = (timestamp: number) => { + const now = Date.now(); + const diff = now - timestamp; + const minutes = Math.floor(diff / (1000 * 60)); + const hours = Math.floor(diff / (1000 * 60 * 60)); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (days > 0) return `${days}d ago`; + if (hours > 0) return `${hours}h ago`; + if (minutes > 0) return `${minutes}m ago`; + return 'Just now'; + }; + + return ( +
+
+ +

Recent Searches

+
+
+ {recentSearches.map((search, index) => ( +
onSelect({ + name: search.name, + latitude: search.latitude, + longitude: search.longitude + })} + className={cn( + "hover:bg-zinc-200 dark:hover:bg-zinc-800 flex justify-between items-center px-3 py-2 rounded-lg cursor-pointer border", + { + "bg-zinc-200 dark:bg-zinc-800 border-primary": + selectedPlace && + selectedPlace.name === search.name && + selectedPlace.latitude === search.latitude && + selectedPlace.longitude === search.longitude, + } + )} + > +
+
+ +

{search.name}

+
+
+ + {search.latitude.toFixed(4)}, {search.longitude.toFixed(4)} + + + {formatTimeAgo(search.timestamp)} + +
+
+
+ ))} +
+
+ ); +} \ No newline at end of file diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationDialog.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationDialog.tsx index d8eb4a9..374550d 100644 --- a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationDialog.tsx +++ b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationDialog.tsx @@ -15,6 +15,8 @@ import TagMissingLocationSearchLatLong from "./TagMissingLocationSearchLatLong"; import TagMissingLocationOSMSearchAndAdd from "./TagMissingLocationOSMSearchAndAdd"; import dynamic from "next/dynamic"; import { usePhotoSelectionContext } from "@/contexts/PhotoSelectionContext"; +import { addRecentSearch } from "@/lib/utils"; +import RecentSearches from "./RecentSearches"; const LazyMap = dynamic(() => import("./Map"), { ssr: false @@ -31,9 +33,15 @@ export default function TagMissingLocationDialog({ const [mapPosition, setMapPosition] = useState({ latitude: 48.210033, longitude: 16.363449, - name: "Vienna, Austria" + name: "" }); + const handleMapSubmit = async (place: IPlace) => { + // Save to recent searches + addRecentSearch(place, 'map'); + return onSubmit(place); + }; + return ( @@ -64,11 +72,39 @@ export default function TagMissingLocationDialog({
+ {/* Recent Searches */} + { + setMapPosition(place); + }} + selectedPlace={mapPosition.name ? mapPosition : null} + /> + +
+ + +
diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationOSMSearchAndAdd.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationOSMSearchAndAdd.tsx index 9f74c1d..d5ffe1f 100644 --- a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationOSMSearchAndAdd.tsx +++ b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationOSMSearchAndAdd.tsx @@ -4,11 +4,12 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import Loader from "@/components/ui/loader"; import { useToast } from "@/components/ui/use-toast"; -import { cn } from "@/lib/utils"; +import { cn, addRecentSearch } from "@/lib/utils"; import { IPlace } from "@/types/common"; import axios from "axios"; import { Check } from "lucide-react"; import React, { useRef, useState } from "react"; +import RecentSearches from "./RecentSearches"; interface ITagMissingLocationSearchAndAddProps { onSubmit: (place: IPlace) => Promise; @@ -107,6 +108,8 @@ export default function TagMissingLocationOSMSearchAndAdd( setSubmitting(true); onSubmit(selectedPlace) .then(() => { + // Save to recent searches + addRecentSearch(selectedPlace, 'osm'); toast({ title: "Location updated", description: "Location updated successfully", @@ -136,6 +139,19 @@ export default function TagMissingLocationOSMSearchAndAdd( handleSearch(e.target.value); }} /> + + {/* Recent Searches */} + {!loading && !searchedPlaces && ( + { + setSelectedPlace(place); + onLocationChange(place); + }} + selectedPlace={selectedPlace} + /> + )} +
{loading && } {!loading && searchedPlaces && searchedPlaces.length === 0 && ( diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchAndAdd.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchAndAdd.tsx index 85e455c..0e1df55 100644 --- a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchAndAdd.tsx +++ b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchAndAdd.tsx @@ -5,10 +5,11 @@ import { Input } from "@/components/ui/input"; import Loader from "@/components/ui/loader"; import { useToast } from "@/components/ui/use-toast"; import { searchPlaces } from "@/handlers/api/common.handler"; -import { cn } from "@/lib/utils"; +import { cn, addRecentSearch } from "@/lib/utils"; import { IPlace } from "@/types/common"; import { Check } from "lucide-react"; import React, { useRef, useState } from "react"; +import RecentSearches from "./RecentSearches"; interface ITagMissingLocationSearchAndAddProps { onSubmit: (place: IPlace) => Promise; @@ -70,6 +71,8 @@ export default function TagMissingLocationSearchAndAdd( setSubmitting(true); onSubmit(selectedPlace) .then(() => { + // Save to recent searches + addRecentSearch(selectedPlace, 'immich'); toast({ title: "Location updated", description: "Location updated successfully", @@ -101,6 +104,18 @@ export default function TagMissingLocationSearchAndAdd( }} />
+ + {/* Recent Searches */} + {!loading && !searchedPlaces && ( + { + setSelectedPlace(place); + }} + selectedPlace={selectedPlace} + /> + )} +
{loading && } {!loading && searchedPlaces && searchedPlaces.length === 0 && ( @@ -113,9 +128,9 @@ export default function TagMissingLocationSearchAndAdd( key={place.name} onClick={() => handleSelect(place)} className={cn( - "hover:bg-zinc-200 dark:hover:bg-zinc-800 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer", + "hover:bg-gray-300 dark:hover:bg-gray-700 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer", { - "bg-zinc-900 dark:bg-zinc-200": + "bg-gray-300 dark:bg-gray-700": selectedPlace && selectedPlace.name === place.name, } )} diff --git a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchLatLong.tsx b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchLatLong.tsx index 81b222c..9ac6183 100644 --- a/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchLatLong.tsx +++ b/src/components/assets/missing-location/TagMissingLocationDialog/TagMissingLocationSearchLatLong.tsx @@ -4,8 +4,10 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useToast } from "@/components/ui/use-toast"; +import { addRecentSearch } from "@/lib/utils"; import { IPlace } from "@/types/common"; import React, { useEffect, useMemo, useState } from "react"; +import RecentSearches from "./RecentSearches"; interface TagMissingLocationSearchLatLongProps { onSubmit: (place: IPlace) => Promise; @@ -52,6 +54,8 @@ export default function TagMissingLocationSearchLatLong( setSubmitting(true); onSubmit(formData) .then(() => { + // Save to recent searches + addRecentSearch(formData, 'latlong'); toast({ title: "Location updated", description: "Location updated successfully", @@ -119,6 +123,17 @@ export default function TagMissingLocationSearchLatLong(
+ {/* Recent Searches */} + { + setFormData(place); + onLocationChange(place); + setLatLong(`${place.latitude}, ${place.longitude}`); + }} + selectedPlace={formData.name ? formData : null} + /> +