refactor: rename TopNavigation to TopControl and update related imports in CrimeMap
style: update MapLegend text color for better visibility
This commit is contained in:
parent
75df66a621
commit
5d13ff532b
|
@ -1,126 +0,0 @@
|
||||||
import { Checkbox } from "../../ui/checkbox";
|
|
||||||
import { Label } from "../../ui/label";
|
|
||||||
import { RadioGroup, RadioGroupItem } from "../../ui/radio-group";
|
|
||||||
import { ControlPosition, IControl, Map } from "mapbox-gl"
|
|
||||||
import { useControl } from "react-map-gl/mapbox"
|
|
||||||
import React, { useEffect } from "react"
|
|
||||||
import { createRoot } from "react-dom/client"
|
|
||||||
|
|
||||||
interface MapLayerControlProps {
|
|
||||||
position?: ControlPosition
|
|
||||||
isFullscreen?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// React component for layer control content
|
|
||||||
const LayerControlContent = () => {
|
|
||||||
return (
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="text-sm font-medium">Lapisan peta</div>
|
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Checkbox id="sambaran-petir" />
|
|
||||||
<Label htmlFor="sambaran-petir" className="text-xs text-white">
|
|
||||||
Sambaran petir
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Checkbox id="jalur-badai" defaultChecked />
|
|
||||||
<Label htmlFor="jalur-badai" className="text-xs text-white">
|
|
||||||
Jalur badai guntur
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4">
|
|
||||||
<div className="text-sm font-medium mb-2">Waktu</div>
|
|
||||||
<RadioGroup defaultValue="4jam">
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem value="4jam" id="4jam" />
|
|
||||||
<Label htmlFor="4jam" className="text-xs text-white">
|
|
||||||
4 Jam
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem value="10hari" id="10hari" />
|
|
||||||
<Label htmlFor="10hari" className="text-xs text-white">
|
|
||||||
10 Hari
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
</RadioGroup>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class LayerControlMapboxControl implements IControl {
|
|
||||||
private container: HTMLElement;
|
|
||||||
private map?: Map;
|
|
||||||
private props: MapLayerControlProps;
|
|
||||||
private root: ReturnType<typeof createRoot> | null = null;
|
|
||||||
private isUnmounting: boolean = false;
|
|
||||||
|
|
||||||
constructor(props: MapLayerControlProps) {
|
|
||||||
this.props = props;
|
|
||||||
this.container = document.createElement("div");
|
|
||||||
this.container.className = "mapboxgl-ctrl";
|
|
||||||
}
|
|
||||||
|
|
||||||
onAdd(map: Map): HTMLElement {
|
|
||||||
this.map = map;
|
|
||||||
this.container.className = 'mapboxgl-ctrl mapboxgl-ctrl-layer absolute bottom-36 left-0 z-20 bg-black/70 text-white p-3 rounded-tr-lg';
|
|
||||||
this.render();
|
|
||||||
return this.container;
|
|
||||||
}
|
|
||||||
|
|
||||||
onRemove(): void {
|
|
||||||
if (this.isUnmounting) return;
|
|
||||||
|
|
||||||
this.isUnmounting = true;
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
if (this.root) {
|
|
||||||
this.root.unmount();
|
|
||||||
this.root = null;
|
|
||||||
}
|
|
||||||
if (this.container.parentNode) {
|
|
||||||
this.container.parentNode.removeChild(this.container);
|
|
||||||
}
|
|
||||||
this.map = undefined;
|
|
||||||
this.isUnmounting = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProps(props: MapLayerControlProps): void {
|
|
||||||
this.props = props;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): void {
|
|
||||||
if (this.props.isFullscreen === false) {
|
|
||||||
if (this.container.style.display !== 'none') {
|
|
||||||
this.container.style.display = 'none';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.container.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.root) {
|
|
||||||
this.root = createRoot(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.root.render(<LayerControlContent />);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MapLayerControl({ position = 'bottom-left', isFullscreen }: MapLayerControlProps) {
|
|
||||||
const control = useControl<LayerControlMapboxControl>(
|
|
||||||
() => new LayerControlMapboxControl({ position, isFullscreen }),
|
|
||||||
{ position }
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
control.updateProps({ position, isFullscreen });
|
|
||||||
}, [control, position, isFullscreen]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ interface MapLegendProps {
|
||||||
export default function MapLegend({ position = "bottom-right" }: MapLegendProps) {
|
export default function MapLegend({ position = "bottom-right" }: MapLegendProps) {
|
||||||
return (
|
return (
|
||||||
// <Overlay position={position}>
|
// <Overlay position={position}>
|
||||||
<div className="flex flex-row text-xs font-semibold font-sans text-white">
|
<div className="flex flex-row text-xs font-semibold font-sans text-background">
|
||||||
<div className={`flex items-center gap-1.5 py-0 px-8 rounded-l-md border-y border-1 `} style={{ backgroundColor: `${CRIME_RATE_COLORS.low}` }}>
|
<div className={`flex items-center gap-1.5 py-0 px-8 rounded-l-md border-y border-1 `} style={{ backgroundColor: `${CRIME_RATE_COLORS.low}` }}>
|
||||||
<span>Low</span>
|
<span>Low</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { ITopTooltipsMapId } from "./map-tooltips"
|
import { ITopTooltipsMapId } from "./map-tooltips"
|
||||||
|
|
||||||
interface TopNavigationProps {
|
interface TopControlProps {
|
||||||
onControlChange?: (controlId: ITopTooltipsMapId) => void
|
onControlChange?: (controlId: ITopTooltipsMapId) => void
|
||||||
activeControl?: string
|
activeControl?: string
|
||||||
selectedYear: number
|
selectedYear: number
|
||||||
|
@ -41,7 +41,7 @@ interface TopNavigationProps {
|
||||||
categories?: string[]
|
categories?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TopNavigation({
|
export default function TopControl({
|
||||||
onControlChange,
|
onControlChange,
|
||||||
activeControl,
|
activeControl,
|
||||||
selectedYear,
|
selectedYear,
|
||||||
|
@ -52,7 +52,7 @@ export default function TopNavigation({
|
||||||
setSelectedCategory,
|
setSelectedCategory,
|
||||||
availableYears = [2022, 2023, 2024],
|
availableYears = [2022, 2023, 2024],
|
||||||
categories = [],
|
categories = [],
|
||||||
}: TopNavigationProps) {
|
}: TopControlProps) {
|
||||||
const [showSelectors, setShowSelectors] = useState(false)
|
const [showSelectors, setShowSelectors] = useState(false)
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export default function TopNavigation({
|
||||||
{ id: "heatmap" as ITopTooltipsMapId, icon: <Map size={20} />, label: "Crime Heatmap" },
|
{ id: "heatmap" as ITopTooltipsMapId, icon: <Map size={20} />, label: "Crime Heatmap" },
|
||||||
{ id: "trends" as ITopTooltipsMapId, icon: <BarChart2 size={20} />, label: "Crime Trends" },
|
{ id: "trends" as ITopTooltipsMapId, icon: <BarChart2 size={20} />, label: "Crime Trends" },
|
||||||
{ id: "patrol" as ITopTooltipsMapId, icon: <Shield size={20} />, label: "Patrol Areas" },
|
{ id: "patrol" as ITopTooltipsMapId, icon: <Shield size={20} />, label: "Patrol Areas" },
|
||||||
{ id: "clusters" as ITopTooltipsMapId, icon: <Users size={20} />, label: "Offender Clusters" },
|
{ id: "clusters" as ITopTooltipsMapId, icon: <Users size={20} />, label: "Clusters" },
|
||||||
{ id: "timeline" as ITopTooltipsMapId, icon: <Clock size={20} />, label: "Time Analysis" },
|
{ id: "timeline" as ITopTooltipsMapId, icon: <Clock size={20} />, label: "Time Analysis" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,14 @@ import MapLegend from "./controls/map-legend"
|
||||||
import { useGetAvailableYears, useGetCrimeCategories, useGetCrimes } from "@/app/(pages)/(admin)/dashboard/crime-management/crime-overview/_queries/queries"
|
import { useGetAvailableYears, useGetCrimeCategories, useGetCrimes } from "@/app/(pages)/(admin)/dashboard/crime-management/crime-overview/_queries/queries"
|
||||||
import { ITopTooltipsMapId } from "./controls/map-tooltips"
|
import { ITopTooltipsMapId } from "./controls/map-tooltips"
|
||||||
import MapSelectors from "./controls/map-selector"
|
import MapSelectors from "./controls/map-selector"
|
||||||
import TopNavigation from "./controls/map-navigations"
|
|
||||||
import CrimeSidebar from "./sidebar/map-sidebar"
|
import CrimeSidebar from "./sidebar/map-sidebar"
|
||||||
import SidebarToggle from "./sidebar/sidebar-toggle"
|
import SidebarToggle from "./sidebar/sidebar-toggle"
|
||||||
import { cn } from "@/app/_lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
import CrimePopup from "./pop-up/crime-popup"
|
import CrimePopup from "./pop-up/crime-popup"
|
||||||
import { $Enums, crime_categories, crime_incidents, crimes, demographics, districts, geographics, locations } from "@prisma/client"
|
import { $Enums, crime_categories, crime_incidents, crimes, demographics, districts, geographics, locations } from "@prisma/client"
|
||||||
import { CrimeTimelapse } from "./controls/crime-timelapse"
|
import { CrimeTimelapse } from "./controls/crime-timelapse"
|
||||||
|
import TopControl from "./controls/map-navigations"
|
||||||
|
|
||||||
// Updated CrimeIncident type to match the structure in crime_incidents
|
// Updated CrimeIncident type to match the structure in crime_incidents
|
||||||
interface CrimeIncident {
|
interface CrimeIncident {
|
||||||
|
@ -281,7 +282,7 @@ export default function CrimeMap() {
|
||||||
<>
|
<>
|
||||||
<Overlay position="top" className="m-0 bg-transparent shadow-none p-0 border-none">
|
<Overlay position="top" className="m-0 bg-transparent shadow-none p-0 border-none">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<TopNavigation
|
<TopControl
|
||||||
activeControl={activeControl}
|
activeControl={activeControl}
|
||||||
onControlChange={setActiveControl}
|
onControlChange={setActiveControl}
|
||||||
selectedYear={selectedYear}
|
selectedYear={selectedYear}
|
||||||
|
|
Loading…
Reference in New Issue