mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
Norms filter
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
rapidAtom,
|
||||
blitzAtom,
|
||||
otherAtom,
|
||||
normsOnlyAtom,
|
||||
} from "@/app/atoms";
|
||||
|
||||
import Legend from "./Legend";
|
||||
@@ -93,6 +94,8 @@ const stopBouncingMarkers = () => {
|
||||
|
||||
const TimeControlGroup = ({ timeControl, colour }: TimeControlGroupProps) => {
|
||||
const tournaments = useAtomValue(tournamentsAtom);
|
||||
const normsOnly = useAtomValue(normsOnlyAtom);
|
||||
|
||||
const markerRefs = useRef<Record<string, L.Marker<any> | null>>({});
|
||||
const clusterRef = useRef<L.MarkerClusterGroup | null>(null);
|
||||
const expandedClusterMarkerRef = useRef<L.MarkerCluster | null>(null);
|
||||
|
||||
@@ -6,6 +6,7 @@ import L from "leaflet";
|
||||
import { Marker, Popup, MarkerProps } from "react-leaflet";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { FaTrophy } from "react-icons/fa";
|
||||
|
||||
import { debouncedHoveredMapTournamentIdAtom } from "@/app/atoms";
|
||||
|
||||
@@ -63,14 +64,20 @@ export const TournamentMarker = forwardRef<
|
||||
{...markerProps}
|
||||
>
|
||||
<Popup>
|
||||
<p>
|
||||
{tournament.date}
|
||||
<br />
|
||||
<div className="flex flex-col gap-3">
|
||||
<b>{tournament.date}</b>
|
||||
|
||||
<a href={tournament.url} target="_blank" rel="noopener noreferrer">
|
||||
{tournament.tournament}
|
||||
</a>
|
||||
</p>
|
||||
{t("approx")}
|
||||
{tournament.norm && (
|
||||
<div className="flex items-center">
|
||||
<FaTrophy className="mr-3 h-4 w-4" />
|
||||
{t("norm")}
|
||||
</div>
|
||||
)}
|
||||
{t("approx")}
|
||||
</div>
|
||||
</Popup>
|
||||
</Marker>
|
||||
);
|
||||
|
||||
@@ -5,10 +5,13 @@ import { useTranslations } from "next-intl";
|
||||
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { FaExternalLinkAlt } from "react-icons/fa";
|
||||
import { FaTrophy } from "react-icons/fa";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
|
||||
import {
|
||||
filteredTournamentsListAtom,
|
||||
syncVisibleAtom,
|
||||
normsOnlyAtom,
|
||||
hoveredMapTournamentIdAtom,
|
||||
debouncedHoveredMapTournamentIdAtom,
|
||||
debouncedHoveredListTournamentIdAtom,
|
||||
@@ -24,6 +27,7 @@ export default function TournamentTable() {
|
||||
|
||||
const filteredTournaments = useAtomValue(filteredTournamentsListAtom);
|
||||
const [syncVisible, setSyncVisible] = useAtom(syncVisibleAtom);
|
||||
const [normsOnly, setNormsOnly] = useAtom(normsOnlyAtom);
|
||||
const hoveredMapTournamentId = useAtomValue(hoveredMapTournamentIdAtom);
|
||||
const debouncedHoveredMapTournamentId = useAtomValue(
|
||||
debouncedHoveredMapTournamentIdAtom,
|
||||
@@ -52,7 +56,8 @@ export default function TournamentTable() {
|
||||
>
|
||||
<div className="z-10 flex w-full flex-wrap items-center justify-between gap-3 p-3">
|
||||
<SearchBar />
|
||||
<div className="text-gray-900 dark:text-white">
|
||||
|
||||
<div className="flex flex-col gap-0 text-gray-900 dark:text-white">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -62,6 +67,16 @@ export default function TournamentTable() {
|
||||
/>
|
||||
{t("syncWithMapCheckbox")}
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mr-2"
|
||||
checked={normsOnly}
|
||||
onChange={() => setNormsOnly(!normsOnly)}
|
||||
/>
|
||||
{t("normsOnly")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="hidden lg:block">
|
||||
@@ -115,7 +130,17 @@ export default function TournamentTable() {
|
||||
>
|
||||
<td className="p-3">{tournament.date}</td>
|
||||
<td className="p-3">{tournament.town}</td>
|
||||
<td className="p-3">{tournament.tournament}</td>
|
||||
<td className="p-3">
|
||||
<span>
|
||||
{tournament.norm && (
|
||||
<FaTrophy
|
||||
className="mr-2 inline-block h-4 w-4"
|
||||
data-norm="norm"
|
||||
/>
|
||||
)}
|
||||
{tournament.tournament}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-3">
|
||||
{t("timeControlEnum", { tc: tournament.timeControl })}
|
||||
</td>
|
||||
@@ -129,6 +154,13 @@ export default function TournamentTable() {
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<Tooltip anchorSelect="[data-norm='norm']">
|
||||
<div className="flex items-center">
|
||||
<FaTrophy className="mr-3 h-4 w-4" />
|
||||
{t("norm")}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface TournamentData {
|
||||
tournament: string;
|
||||
url: string;
|
||||
time_control: "Cadence Lente" | "Rapide" | "Blitz" | string;
|
||||
norm_tournament: boolean;
|
||||
date: string;
|
||||
coordinates: [number, number];
|
||||
}
|
||||
@@ -58,6 +59,7 @@ const getTournaments = async () => {
|
||||
_id: t._id.toString(),
|
||||
timeControl: tcMap[t.time_control] ?? TimeControl.Other,
|
||||
latLng: { lat: t.coordinates[0], lng: t.coordinates[1] },
|
||||
norm: t.norm_tournament,
|
||||
}));
|
||||
} catch (error) {
|
||||
errorLog(error);
|
||||
|
||||
+9
-4
@@ -7,6 +7,7 @@ import atomWithDebounce from "@/utils/atomWithDebounce";
|
||||
export const tournamentsAtom = atom<Tournament[]>([]);
|
||||
export const mapBoundsAtom = atom<LatLngBounds | null>(null);
|
||||
export const syncVisibleAtom = atom(true);
|
||||
export const normsOnlyAtom = atom(false);
|
||||
|
||||
export const searchStringAtom = atom("");
|
||||
export const classicAtom = atom(true);
|
||||
@@ -43,20 +44,24 @@ export const filteredTournamentsListAtom = atom((get) => {
|
||||
const tournaments = get(filteredTournamentsByTimeControlAtom);
|
||||
const mapBounds = get(mapBoundsAtom);
|
||||
const syncVisible = get(syncVisibleAtom);
|
||||
|
||||
const normsOnly = get(normsOnlyAtom);
|
||||
const searchString = get(searchStringAtom).trim();
|
||||
|
||||
const filteredByNorm = normsOnly
|
||||
? tournaments.filter((t) => t.norm)
|
||||
: tournaments;
|
||||
|
||||
// When searching, we search all the tournament, regardless of the map display
|
||||
if (searchString !== "")
|
||||
return tournaments.filter((t) =>
|
||||
return filteredByNorm.filter((t) =>
|
||||
t.town.includes(searchString.toUpperCase()),
|
||||
);
|
||||
|
||||
// If we not syncing to the map, return all tournaments
|
||||
if (mapBounds === null || !syncVisible) return tournaments;
|
||||
if (mapBounds === null || !syncVisible) return filteredByNorm;
|
||||
|
||||
// Filter by those in the current map bounds
|
||||
return tournaments.filter((tournament) =>
|
||||
return filteredByNorm.filter((tournament) =>
|
||||
mapBounds.contains(tournament.latLng),
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user