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/travelsStore';
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 // Set event bounds
83 const {latitude, longitude} = event || {};
84 if (latitude && longitude) bounds.push([latitude, longitude]);
85
86 if (meetingFilter?.latitude && meetingFilter?.longitude) {
87 bounds.push([meetingFilter.latitude, meetingFilter.longitude]);
88
89 // Set travels bounds
90 const travelCoords = travelsWithGeoloc
91 .map(travel => ({
92 ...travel,
93 distance: calculateHaversineDistance(
94 [meetingFilter.latitude, meetingFilter.longitude],
95 [
96 travel.attributes.meeting_latitude,
97 travel.attributes.meeting_longitude,
98 ]
99 ),
100 }))
101 .sort((a, b) => a.distance - b.distance)
102 .slice(0, 3)
103 .map(travel => [
104 travel.attributes.meeting_latitude,
105 travel.attributes.meeting_longitude,
106 ]);
107 bounds.push(...travelCoords);
108 } else {
109 // Set travels bounds
110 const travelCoords = travelsWithGeoloc.map(travel => [
111 travel.attributes.meeting_latitude,
112 travel.attributes.meeting_longitude,
113 ]);
114 bounds.push(...travelCoords);
115 }
116
117 setBounds(bounds);
118 }, [event, travelsWithGeoloc, setBounds, meetingFilter]);
119};
120
121export default useDisplayMarkers;