Extract components
This commit is contained in:
parent
a48eb945e0
commit
fe46cb3379
30 changed files with 4075 additions and 2610 deletions
138
frontend/src/components/map/map-page/effects.ts
Normal file
138
frontend/src/components/map/map-page/effects.ts
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
import { useEffect } from 'react';
|
||||
import type { MutableRefObject } from 'react';
|
||||
|
||||
import type { PostcodeGeometry, ViewState } from '../../../types';
|
||||
import type { useMapData } from '../../../hooks/useMapData';
|
||||
import { authHeaders } from '../../../lib/api';
|
||||
import { canWheelScrollInsideTarget } from '../../../lib/dom-scroll';
|
||||
import type { MapFlyTo } from './types';
|
||||
|
||||
type MapData = ReturnType<typeof useMapData>;
|
||||
type RightPaneTab = 'properties' | 'area';
|
||||
|
||||
export function useInitialMapPageView(
|
||||
mapData: MapData,
|
||||
initialViewState: ViewState,
|
||||
initialTab: RightPaneTab,
|
||||
setRightPaneTab: (tab: RightPaneTab) => void
|
||||
) {
|
||||
useEffect(() => {
|
||||
mapData.setInitialView(initialViewState);
|
||||
setRightPaneTab(initialTab);
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
|
||||
interface UseInitialPostcodeSelectionOptions {
|
||||
initialPostcode?: string;
|
||||
isMobile: boolean;
|
||||
flyTo: MutableRefObject<MapFlyTo | null>;
|
||||
onLocationSearch: (
|
||||
postcode: string,
|
||||
geometry: PostcodeGeometry,
|
||||
lat?: number,
|
||||
lng?: number
|
||||
) => void;
|
||||
onOpenMobileDrawer: () => void;
|
||||
}
|
||||
|
||||
export function useInitialPostcodeSelection({
|
||||
initialPostcode,
|
||||
isMobile,
|
||||
flyTo,
|
||||
onLocationSearch,
|
||||
onOpenMobileDrawer,
|
||||
}: UseInitialPostcodeSelectionOptions) {
|
||||
useEffect(() => {
|
||||
if (!initialPostcode) return;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.delete('pc');
|
||||
const newUrl = params.toString() ? `/dashboard?${params}` : '/dashboard';
|
||||
window.history.replaceState(window.history.state, '', newUrl);
|
||||
|
||||
fetch(`/api/postcode/${encodeURIComponent(initialPostcode)}`, authHeaders())
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error('Postcode not found');
|
||||
return res.json();
|
||||
})
|
||||
.then(
|
||||
(data: {
|
||||
postcode: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
geometry: PostcodeGeometry;
|
||||
}) => {
|
||||
flyTo.current?.(data.latitude, data.longitude, 16);
|
||||
onLocationSearch(data.postcode, data.geometry, data.latitude, data.longitude);
|
||||
if (isMobile) onOpenMobileDrawer();
|
||||
}
|
||||
)
|
||||
.catch(() => {
|
||||
// Silently fail because the postcode might no longer exist.
|
||||
});
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
|
||||
export function useHorizontalSwipeNavigationGuard() {
|
||||
useEffect(() => {
|
||||
const handleWheel = (e: WheelEvent) => {
|
||||
if (
|
||||
Math.abs(e.deltaX) > Math.abs(e.deltaY) &&
|
||||
!canWheelScrollInsideTarget(e.target, e.deltaX, e.deltaY)
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
document.addEventListener('wheel', handleWheel, { passive: false });
|
||||
return () => document.removeEventListener('wheel', handleWheel);
|
||||
}, []);
|
||||
}
|
||||
|
||||
export function useMobileBackNavigationGuard(isMobile: boolean) {
|
||||
useEffect(() => {
|
||||
if (!isMobile) return;
|
||||
window.history.pushState({ dashboardGuard: true }, '');
|
||||
const handlePopState = () => {
|
||||
window.history.pushState({ dashboardGuard: true }, '');
|
||||
};
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
return () => window.removeEventListener('popstate', handlePopState);
|
||||
}, [isMobile]);
|
||||
}
|
||||
|
||||
interface UseScreenshotReadySignalOptions {
|
||||
screenshotMode?: boolean;
|
||||
loading: boolean;
|
||||
dataLength: number;
|
||||
postcodeDataLength: number;
|
||||
usePostcodeView: boolean;
|
||||
}
|
||||
|
||||
export function useScreenshotReadySignal({
|
||||
screenshotMode,
|
||||
loading,
|
||||
dataLength,
|
||||
postcodeDataLength,
|
||||
usePostcodeView,
|
||||
}: UseScreenshotReadySignalOptions) {
|
||||
useEffect(() => {
|
||||
if (screenshotMode && !loading) {
|
||||
const hasData = usePostcodeView ? postcodeDataLength > 0 : dataLength > 0;
|
||||
if (hasData) {
|
||||
// Wait for both deck.gl data and MapLibre base map tile rendering.
|
||||
const waitAndSignal = () => {
|
||||
if (window.__map_idle) {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
window.__screenshot_ready = true;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(waitAndSignal);
|
||||
}
|
||||
};
|
||||
waitAndSignal();
|
||||
}
|
||||
}
|
||||
}, [screenshotMode, loading, dataLength, postcodeDataLength, usePostcodeView]);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue