mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
101 lines
3.0 KiB
TypeScript
101 lines
3.0 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { LatLngBounds } from 'leaflet';
|
|
import { useMemo } from 'react';
|
|
import type { BackendSite } from '@/schemas/backend/site';
|
|
import { getNearbySites } from '@/services/sites-api';
|
|
import { calculateDistance } from '@/utils/coordinates.ts';
|
|
|
|
/**
|
|
* Calculate center and radius from map bounds
|
|
*/
|
|
function boundsToCenterAndRadius(bounds: LatLngBounds): {
|
|
lat: number;
|
|
lng: number;
|
|
radius: number;
|
|
} {
|
|
const center = bounds.getCenter();
|
|
const ne = bounds.getNorthEast();
|
|
const sw = bounds.getSouthWest();
|
|
|
|
// Calculate radius as the distance from center to corner
|
|
const radius = Math.max(
|
|
calculateDistance(center.lat, center.lng, ne.lat, ne.lng),
|
|
calculateDistance(center.lat, center.lng, sw.lat, sw.lng)
|
|
);
|
|
|
|
// Add 20% buffer to ensure we get all sites near the edges
|
|
return {
|
|
lat: center.lat,
|
|
lng: center.lng,
|
|
radius: radius * 1.2,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hook to fetch sites within current map bounds
|
|
* This enables viewport-based lazy loading of organizations
|
|
* Optimized with better caching and query key stability
|
|
*/
|
|
export const useSitesByBounds = (bounds: LatLngBounds | null, enabled: boolean = true) => {
|
|
const queryParams = useMemo(() => {
|
|
if (!bounds) return null;
|
|
const params = boundsToCenterAndRadius(bounds);
|
|
// Round coordinates to reduce query key churn (0.001 degrees ≈ 111m)
|
|
return {
|
|
lat: Math.round(params.lat * 1000) / 1000,
|
|
lng: Math.round(params.lng * 1000) / 1000,
|
|
radius: Math.round(params.radius * 10) / 10, // Round to 0.1km
|
|
};
|
|
}, [bounds]);
|
|
|
|
return useQuery({
|
|
queryKey: ['sites', 'nearby', queryParams?.lat, queryParams?.lng, queryParams?.radius],
|
|
queryFn: () => {
|
|
if (!queryParams) return Promise.resolve([]);
|
|
return getNearbySites({
|
|
lat: queryParams.lat,
|
|
lng: queryParams.lng,
|
|
radius: queryParams.radius,
|
|
});
|
|
},
|
|
enabled: enabled && !!queryParams,
|
|
placeholderData: [], // Render immediately with empty array - don't block on API
|
|
staleTime: 60 * 1000, // 1 minute - sites don't change often
|
|
gcTime: 10 * 60 * 1000, // 10 minutes - keep in cache longer
|
|
refetchOnWindowFocus: false, // Don't refetch on window focus
|
|
refetchOnMount: false, // Don't refetch if data exists
|
|
retry: 1, // Only retry once on failure
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Create a map of organization ID -> sites for organizations in viewport
|
|
*/
|
|
export const useOrganizationSitesByBounds = (
|
|
bounds: LatLngBounds | null,
|
|
enabled: boolean = true
|
|
) => {
|
|
const { data: sites, isLoading } = useSitesByBounds(bounds, enabled);
|
|
|
|
const orgSitesMap = useMemo(() => {
|
|
const map = new Map<string, BackendSite[]>();
|
|
if (!sites) return map;
|
|
|
|
sites.forEach((site) => {
|
|
const orgId = site.OwnerOrganizationID;
|
|
if (!orgId) return;
|
|
|
|
const existing = map.get(orgId) || [];
|
|
map.set(orgId, [...existing, site]);
|
|
});
|
|
|
|
return map;
|
|
}, [sites]);
|
|
|
|
return {
|
|
orgSitesMap,
|
|
sites: sites || [],
|
|
isLoading,
|
|
};
|
|
};
|