infoalloggi-monorepo/apps/infoalloggi/src/components/map/Map.tsx
Marco Pedone f85ea22215 chore: update biome schema and dependencies, refactor key usage in components
- Updated biome schema version from 2.2.2 to 2.3.1 in biome.json.
- Removed experimentalScannerIgnores from files section and replaced with ignore patterns.
- Added CSS parser configuration for Tailwind directives.
- Updated linter rules for better code quality.
- Refactored key usage in various components to use unique identifiers instead of array indices.
- Updated package-lock.json and package.json to reflect new biome version.
- General code cleanup and improvements across multiple components for better maintainability.
2025-10-28 11:55:01 +01:00

295 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import {
Circle,
MapContainer,
Marker,
Popup,
TileLayer,
useMapEvents,
} from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
import { Home } from "lucide-react";
import { Marker as CustomMarker } from "~/components/map/custom_marker";
import MapMarker from "~/components/map/map_marker";
import { cn } from "~/lib/utils";
type LatLon = {
lat: number;
lng: number;
alt?: number;
};
type posData = {
pos: LatLon;
popupTxt?: string;
onClick?: () => void;
markerTxt?: string;
};
type GroupProps = {
isGroup: true;
groupData: posData[];
};
type SingleProps = {
isGroup?: false;
groupData?: never;
};
type MapProps = {
posix: posData;
autocenter?: boolean;
zoom?: number;
markerType: "precise" | "circle" | "price" | "home";
markerRadius?: number;
scrollWheelZoom?: boolean;
width?: string;
height?: string;
onMapClick?: () => void;
} & (GroupProps | SingleProps);
const defaults = {
height: "500px",
width: "500px",
zoom: 15,
};
const MedianPoint = (pos: posData[]) => {
const lat = pos.map((p) => p.pos.lat).reduce((a, b) => a + b) / pos.length;
const lng = pos.map((p) => p.pos.lng).reduce((a, b) => a + b) / pos.length;
return { lat, lng };
};
const MapComp = ({
posix,
autocenter,
zoom = defaults.zoom,
markerType,
markerRadius,
scrollWheelZoom = false,
width = defaults.width,
height = defaults.height,
isGroup,
groupData,
onMapClick,
}: MapProps) => {
const APIs = () => {
useMapEvents({
click: () => {
if (onMapClick) {
onMapClick();
}
},
});
return null;
};
const MarkerComp = ({ pos }: { pos: posData }) => {
switch (markerType) {
case "price":
return (
<CustomMarker
eventHandlers={pos.onClick && { click: pos.onClick }}
icon={
<MapMarker
color="primary"
label={
<span className="inline-block whitespace-nowrap">
{pos.markerTxt}
</span>
}
size="sm"
/>
}
position={pos.pos}
title={pos.markerTxt}
>
{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
</CustomMarker>
);
case "precise":
return (
<Marker
eventHandlers={pos.onClick && { click: pos.onClick }}
position={pos.pos}
title={pos.markerTxt}
>
{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
</Marker>
);
case "circle":
return (
<Circle
center={pos.pos}
eventHandlers={pos.onClick && { click: pos.onClick }}
pathOptions={{ color: "red" }}
radius={markerRadius || 100}
>
{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
</Circle>
);
case "home":
return (
<>
<Circle
center={pos.pos}
eventHandlers={pos.onClick && { click: pos.onClick }}
fillOpacity={1}
pathOptions={{ color: "#ec4899" }}
radius={markerRadius || 100}
>
{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
</Circle>
<CustomMarker
eventHandlers={pos.onClick && { click: pos.onClick }}
icon={
<div className="relative flex size-10 items-center justify-center rounded-full bg-pink-500 p-2">
<Home className="absolute size-3/4 stroke-white" />
</div>
}
position={pos.pos}
title={pos.markerTxt}
>
{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
</CustomMarker>
</>
);
}
};
const hashKey = JSON.stringify(
groupData ? groupData.map((p) => p.pos) : posix.pos,
);
return (
<MapContainer
center={
autocenter ? MedianPoint(isGroup ? groupData : [posix]) : posix.pos
}
className={cn("")}
key={hashKey}
scrollWheelZoom={scrollWheelZoom}
style={{
borderRadius: "8px",
height: height,
width: width,
}}
zoom={zoom}
>
<APIs />
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
//url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
url="/api/tiles/{s}/{z}/{x}/{y}"
/>
{isGroup ? (
// biome-ignore lint/suspicious/noArrayIndexKey: <index is acceptable here>
groupData.map((pos, i) => <MarkerComp key={i} pos={pos} />)
) : (
<MarkerComp pos={posix} />
)}
</MapContainer>
);
};
export default MapComp;
/*
const PuntiInteresse: {
title: string;
lat: number;
lng: number;
icon: IconType;
}[] = [
{
title: "PIAZZA LIBERTA",
lat: 45.766706,
lng: 11.733919,
icon: "milestone",
},
{ title: "PONTE VECCHIO", lat: 45.76752, lng: 11.731148, icon: "milestone" },
{ title: "INFOALLOGGI", lat: 45.764886, lng: 11.736019, icon: "info" },
{ title: "PRATO 1", lat: 45.770066, lng: 11.736306, icon: "parking" },
{ title: "PRATO 2", lat: 45.771495, lng: 11.734107, icon: "parking" },
{
title: "STAZIONE FERROVIARIA/BUS",
lat: 45.766709,
lng: 11.741204,
icon: "milestone",
},
{ title: "GIARDINI PAROLINI", lat: 45.764804, lng: 11.738355, icon: "park" },
{ title: "BIBLIOTECA", lat: 45.765801, lng: 11.735987, icon: "school" },
{ title: "CENTRO STUDIO", lat: 45.754266, lng: 11.733066, icon: "school" },
{ title: "OSPEDALE", lat: 45.747444, lng: 11.744371, icon: "cross" },
{
title: "PALARENA CMP",
lat: 45.747374,
lng: 11.740302,
icon: "entertainment",
},
{ title: "PONTE NUOVO", lat: 45.764594, lng: 11.729995, icon: "milestone" },
{ title: "OSSARIO ", lat: 45.763568, lng: 11.733449, icon: "milestone" },
{ title: "CINEMA METROPOLIS", lat: 45.742997, lng: 11.735622, icon: "film" },
{
title: "CENTRO COMMERCIALE GRIFONE",
lat: 45.744988,
lng: 11.751847,
icon: "cart",
},
{
title: "CENTRO COMMERCIALE EMISFERO",
lat: 45.742368,
lng: 11.728874,
icon: "cart",
},
{
title: "SUPERMERCATO Alì s. vito",
lat: 45.775167,
lng: 11.750929,
icon: "cart",
},
{
title: "SUPERMERCATO Alì cà baroncello ",
lat: 45.758659,
lng: 11.751037,
icon: "cart",
},
{
title: "CONAD via passalacqua",
lat: 45.771366,
lng: 11.742604,
icon: "cart",
},
{
title: "CONAD VIALE PECORI GIRARDI",
lat: 45.764649,
lng: 11.720416,
icon: "cart",
},
{
title: "BIOSAPORI VIALE DE GASPERI",
lat: 45.761377,
lng: 11.732186,
icon: "cart",
},
{ title: "SUPERMERCATO ALDI ", lat: 45.743694, lng: 11.755435, icon: "cart" },
{
title: "SUPERMERCATO TOSANO",
lat: 45.764982,
lng: 11.766572,
icon: "cart",
},
{
title: "POSTE CENTRALI BASSANO",
lat: 45.762758,
lng: 11.735091,
icon: "mail",
},
{ title: "POSTE VIA ANGARANO", lat: 45.767573, lng: 11.726599, icon: "mail" },
];
*/