mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
Some checks failed
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / backend-lint (push) Failing after 31s
CI/CD Pipeline / frontend-lint (push) Failing after 1m26s
CI/CD Pipeline / frontend-build (push) Has been skipped
CI/CD Pipeline / e2e-test (push) Has been skipped
- Fix prettier formatting issues in multiple components - Fix React Compiler memoization issues in ProductServiceMarkers.tsx - Replace literal strings with i18n keys across components - Address i18n issues in heritage, network graph, and match components - Fix dependency arrays in useMemo hooks to match React Compiler expectations
110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import { LatLngTuple } from 'leaflet';
|
|
import React, { useMemo } from 'react';
|
|
import { Polyline, Popup } from 'react-leaflet';
|
|
import { useOrganizationSites } from '@/hooks/map/useOrganizationSites.ts';
|
|
import { Organization, SymbiosisMatch } from '@/types.ts';
|
|
|
|
interface SymbiosisLinesProps {
|
|
matches: SymbiosisMatch[];
|
|
hoveredOrgId: string | null;
|
|
selectedOrg: Organization;
|
|
}
|
|
|
|
/**
|
|
* Individual symbiosis line component memoized to prevent unnecessary re-renders
|
|
*/
|
|
const SymbiosisLine = React.memo<{
|
|
match: SymbiosisMatch;
|
|
selectedOrgSite: { Latitude: number; Longitude: number };
|
|
matchOrgSite: { Latitude: number; Longitude: number };
|
|
isHovered: boolean;
|
|
}>(({ match, selectedOrgSite, matchOrgSite, isHovered }) => {
|
|
const positions: LatLngTuple[] = useMemo(
|
|
() => [
|
|
[selectedOrgSite.Latitude, selectedOrgSite.Longitude],
|
|
[matchOrgSite.Latitude, matchOrgSite.Longitude],
|
|
],
|
|
[selectedOrgSite, matchOrgSite]
|
|
);
|
|
|
|
return (
|
|
<Polyline
|
|
positions={positions}
|
|
pathOptions={{
|
|
color: 'hsl(var(--primary))',
|
|
weight: isHovered ? 4 : 2,
|
|
opacity: isHovered ? 1 : 0.5,
|
|
}}
|
|
>
|
|
<Popup>
|
|
<div>
|
|
<p className="text-sm">
|
|
{t('symbiosis.connectionTo', { name: match.org?.Name || 'Unknown' })}
|
|
</p>
|
|
</div>
|
|
</Popup>
|
|
</Polyline>
|
|
);
|
|
});
|
|
|
|
SymbiosisLine.displayName = 'SymbiosisLine';
|
|
|
|
const SymbiosisLines: React.FC<SymbiosisLinesProps> = ({ matches, hoveredOrgId, selectedOrg }) => {
|
|
// Get sites for selected org and matched orgs
|
|
const allOrgs = useMemo(
|
|
() => [selectedOrg, ...matches.map((m) => m.org).filter(Boolean)],
|
|
[selectedOrg, matches]
|
|
);
|
|
const { orgSitesMap } = useOrganizationSites(allOrgs);
|
|
|
|
const selectedOrgSite = orgSitesMap.get(selectedOrg.ID);
|
|
|
|
// Memoize valid matches with sites to prevent unnecessary recalculations
|
|
const validMatches = useMemo(() => {
|
|
if (!selectedOrgSite) return [];
|
|
|
|
return matches
|
|
.map((match) => {
|
|
if (!match.org) return null;
|
|
|
|
const matchOrgSite = orgSitesMap.get(match.org.ID);
|
|
if (!matchOrgSite) return null;
|
|
|
|
return {
|
|
match,
|
|
matchOrgSite,
|
|
};
|
|
})
|
|
.filter(
|
|
(
|
|
item
|
|
): item is {
|
|
match: SymbiosisMatch;
|
|
matchOrgSite: NonNullable<typeof item>['matchOrgSite'];
|
|
} => item !== null
|
|
);
|
|
}, [matches, orgSitesMap, selectedOrgSite]);
|
|
|
|
if (!selectedOrgSite) return null;
|
|
|
|
return (
|
|
<>
|
|
{validMatches.map(({ match, matchOrgSite }) => {
|
|
const isHovered = hoveredOrgId === match.id;
|
|
|
|
return (
|
|
<SymbiosisLine
|
|
key={match.id}
|
|
match={match}
|
|
selectedOrgSite={selectedOrgSite}
|
|
matchOrgSite={matchOrgSite}
|
|
isHovered={isHovered}
|
|
/>
|
|
);
|
|
})}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default React.memo(SymbiosisLines);
|