Group tournaments into a single map marker based on position & date (#105)

This commit is contained in:
Timothy Armes
2023-07-18 11:52:19 +02:00
committed by GitHub
parent 1e7b5bf50e
commit b305b0578b
9 changed files with 234 additions and 58 deletions
+57 -7
View File
@@ -2,6 +2,8 @@ import clientPromise from "@/lib/mongodb";
import { errorLog } from "@/utils/logger";
import { Tournament, TimeControl } from "@/types";
import { groupBy } from "lodash";
import { parse, differenceInDays, isSameDay } from "date-fns";
import TournamentsDisplay from "./TournamentsDisplay";
import { ObjectId } from "mongodb";
@@ -54,13 +56,61 @@ const getTournaments = async () => {
])
.toArray();
return data.map<Tournament>((t) => ({
...t,
_id: t._id.toString(),
timeControl: tcMap[t.time_control] ?? TimeControl.Other,
latLng: { lat: t.coordinates[0], lng: t.coordinates[1] },
norm: t.norm_tournament,
}));
// Group the tournaments by their location
const groupedByLocation = groupBy(
data,
(t) => `${t.coordinates[0]}_${t.coordinates[1]}`,
);
// For each location, create an array of arrays of contiguous dates for this location
const dateRangesByLocation: Record<string, Date[][]> = {};
for (const location in groupedByLocation) {
const tournaments = groupedByLocation[location];
// Note that this works since the tournaments are sorted by date
const dateRanges = tournaments.reduce<Date[][]>(
(acc, tournament) => {
const group = acc[acc.length - 1];
const date = parse(tournament.date, "dd/MM/yyyy", new Date());
const diff = differenceInDays(date, group[group.length - 1] ?? date);
if (diff > 1) {
acc.push([date]);
} else if (group.length === 0 || diff === 1) {
group.push(date);
}
return acc;
},
[[]],
);
dateRangesByLocation[location] = dateRanges;
}
return data.map<Tournament>((t) => {
const location = `${t.coordinates[0]}_${t.coordinates[1]}`;
const date = parse(t.date, "dd/MM/yyyy", new Date());
const dateRanges = dateRangesByLocation[location];
const rangeIndex = dateRanges.findIndex((ranges) =>
ranges.some((d) => isSameDay(d, date)),
);
// We place each tournament into a group based on location and date, so that
// we can display a single map marker.
const groupId = `${location}_${rangeIndex}`;
return {
id: t._id.toString(),
groupId,
tournament: t.tournament,
town: t.town,
department: t.department,
date: t.date,
url: t.url,
timeControl: tcMap[t.time_control] ?? TimeControl.Other,
latLng: { lat: t.coordinates[0], lng: t.coordinates[1] },
norm: t.norm_tournament,
};
});
} catch (error) {
errorLog(error);
throw new Error("Error fetching tournament data");