frontend/containers/TravelColumns/useDisplayMarkers.tsx (view raw)
1import moment from 'moment';
2import {useEffect, useMemo} from 'react';
3import useMapStore from '../../stores/useMapStore';
4import dynamic from 'next/dynamic';
5import {Event} from '../../generated/graphql';
6import useTravelsStore from '../../stores/useTravelsStore';
7import {calculateHaversineDistance} from '../../lib/geography';
8
9const EventMarker = dynamic(() => import('../Markers/EventMarker'), {
10 ssr: false,
11});
12const TravelMarker = dynamic(() => import('../Markers/TravelMarker'), {
13 ssr: false,
14});
15const MeetingFilterMarker = dynamic(
16 () => import('../Markers/MeetingFilterMarker'),
17 {ssr: false}
18);
19
20interface Props {
21 event: Event & {id: string};
22}
23
24const useDisplayMarkers = ({event}: Props) => {
25 const setMarkers = useMapStore(s => s.setMarkers);
26 const setBounds = useMapStore(s => s.setBounds);
27 const focusedTravel = useMapStore(s => s.focusedTravel);
28 const datesFilters = useTravelsStore(s => s.datesFilter);
29 const meetingFilter = useTravelsStore(s => s.meetingFilter);
30
31 const travelsWithGeoloc = useMemo(() => {
32 const travels = event?.travels?.data || [];
33 const filteredTravels =
34 datesFilters.length >= 1
35 ? travels.filter(travel => {
36 const departureDate = moment(travel?.attributes?.departureDate);
37 return datesFilters.some(date => date.isSame(departureDate, 'day'));
38 })
39 : travels;
40
41 return filteredTravels.filter(
42 travel =>
43 travel.attributes.meeting_latitude &&
44 travel.attributes.meeting_longitude
45 );
46 }, [event, datesFilters]);
47
48 // Set markers
49 useEffect(() => {
50 let markers = [];
51
52 // Set event marker
53 const {latitude, longitude} = event || {};
54 if (latitude && longitude)
55 markers.push(<EventMarker key="event" event={event} />);
56
57 // Set meeting filter marker
58 if (meetingFilter?.latitude && meetingFilter?.longitude)
59 markers.push(
60 <MeetingFilterMarker
61 center={[meetingFilter.latitude, meetingFilter.longitude]}
62 />
63 );
64
65 // Set travels markers
66 const travelMarkers = travelsWithGeoloc.map(travel => (
67 <TravelMarker
68 key={travel.id}
69 travel={travel}
70 focused={focusedTravel === travel.id}
71 />
72 ));
73 markers.push(...travelMarkers);
74
75 setMarkers(markers);
76 }, [event, travelsWithGeoloc, focusedTravel, setMarkers, meetingFilter]);
77
78 // Set bounds
79 useEffect(() => {
80 let bounds = [];
81
82 if (meetingFilter?.latitude && meetingFilter?.longitude) {
83 bounds.push([meetingFilter.latitude, meetingFilter.longitude]);
84
85 // Set travels bounds
86 const travelCoords = travelsWithGeoloc
87 .map(travel => ({
88 ...travel,
89 distance: calculateHaversineDistance(
90 [meetingFilter.latitude, meetingFilter.longitude],
91 [
92 travel.attributes.meeting_latitude,
93 travel.attributes.meeting_longitude,
94 ]
95 ),
96 }))
97 .sort((a, b) => a.distance - b.distance)
98 .slice(0, 3)
99 .map(travel => [
100 travel.attributes.meeting_latitude,
101 travel.attributes.meeting_longitude,
102 ]);
103 bounds.push(...travelCoords);
104 } else {
105 // Set event bounds
106 const {latitude, longitude} = event || {};
107 if (latitude && longitude) bounds.push([latitude, longitude]);
108 // Set travels bounds
109 const travelCoords = travelsWithGeoloc.map(travel => [
110 travel.attributes.meeting_latitude,
111 travel.attributes.meeting_longitude,
112 ]);
113 bounds.push(...travelCoords);
114 }
115
116 setBounds(bounds);
117 }, [event, travelsWithGeoloc, setBounds, meetingFilter]);
118};
119
120export default useDisplayMarkers;