Feature/date picker (#238)

- Date range picker for tournaments.

- Resets date when closing picker

- tRPC and Jotai update
This commit is contained in:
Owen Rees
2024-01-16 12:28:08 +01:00
committed by GitHub
parent a3ec663384
commit efa9088336
10 changed files with 1058 additions and 775 deletions
@@ -0,0 +1,34 @@
"use client";
import { useAtom, useAtomValue } from "jotai";
import { DateRange } from "react-date-range";
import "react-date-range/dist/styles.css";
import "react-date-range/dist/theme/default.css";
import { dateRangeAtom, maxDateAtom } from "@/atoms";
import { DatePickerDirection } from "@/types";
const DatePicker = ({
datePickerDirection,
}: {
datePickerDirection: DatePickerDirection;
}) => {
const [dateRange, setDateRange] = useAtom(dateRangeAtom);
const maxDate = useAtomValue(maxDateAtom);
return (
<DateRange
onChange={(item) => setDateRange([item.selection])}
minDate={new Date()}
maxDate={maxDate}
months={2}
moveRangeOnFirstSelection={true}
preventSnapRefocus={true}
ranges={dateRange}
direction={datePickerDirection}
showDateDisplay={false}
/>
);
};
export default DatePicker;
@@ -1,15 +1,18 @@
"use client";
import { useEffect } from "react";
import { useEffect, useRef, useState } from "react";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { useTranslations } from "next-intl";
import { FaExternalLinkAlt } from "react-icons/fa";
import { FaTrophy } from "react-icons/fa";
import { BsCalendar2Date } from "react-icons/bs";
import { FaExternalLinkAlt, FaTrophy } from "react-icons/fa";
import { Tooltip } from "react-tooltip";
import { twMerge } from "tailwind-merge";
import DatePicker from "@/app/[locale]/tournaments/DatePicker";
import {
datePickerIsOpenAtom,
dateRangeAtom,
debouncedHoveredListIdAtom,
debouncedHoveredMapIdAtom,
filteredTournamentsListAtom,
@@ -20,6 +23,8 @@ import {
import ScrollToTopButton from "@/components/ScrollToTopButton";
import SearchBar from "@/components/SearchBar";
import { useBreakpoint } from "@/hooks/tailwind";
import useDatePickerWidth from "@/hooks/useDatePickerWidth";
import { DatePickerDirection } from "@/types";
import TimeControlFilters from "./TimeControlFilters";
@@ -27,14 +32,26 @@ const TournamentTable = () => {
const t = useTranslations("Tournaments");
const at = useTranslations("App");
const isLg = useBreakpoint("lg");
const datePickerRef = useRef<HTMLDivElement>(null);
const filteredTournaments = useAtomValue(filteredTournamentsListAtom);
const [syncVisible, setSyncVisible] = useAtom(syncVisibleAtom);
const [normsOnly, setNormsOnly] = useAtom(normsOnlyAtom);
const hoveredMapId = useAtomValue(hoveredMapIdAtom);
const debouncedHoveredMapId = useAtomValue(debouncedHoveredMapIdAtom);
const setHoveredListId = useSetAtom(debouncedHoveredListIdAtom);
const isLg = useBreakpoint("lg");
const setDateRange = useSetAtom(dateRangeAtom);
const [datePickerIsOpen, setDatePickerIsOpen] = useAtom(datePickerIsOpenAtom);
const [dateDirectionState, setDateDirectionState] =
useState<DatePickerDirection>("horizontal");
const datePickerColour = datePickerIsOpen
? "text-primary-600"
: "text-gray-500";
useDatePickerWidth({ datePickerRef, setDateDirectionState });
useEffect(() => {
if (!isLg || debouncedHoveredMapId === null) return;
@@ -45,14 +62,31 @@ const TournamentTable = () => {
tournamentRow?.scrollIntoView({ behavior: "smooth" });
}, [debouncedHoveredMapId, isLg]);
const handleDatePickerClick = () => {
// reset date range today -> max date
setDateRange([
{
startDate: new Date(),
endDate: undefined,
key: "selection",
},
]);
setDatePickerIsOpen(!datePickerIsOpen);
};
return (
<section
className="grid w-full auto-rows-max pb-20 lg:col-start-2 lg:col-end-3 lg:h-content lg:overflow-y-scroll lg:pb-0"
id="listing"
>
<div className="z-10 flex w-full flex-wrap items-center justify-between gap-3 p-3">
<div className="z-10 flex w-full flex-wrap items-center justify-start gap-3 p-3">
<SearchBar />
<BsCalendar2Date
className={`cursor-pointer text-3xl ${datePickerColour}`}
onClick={handleDatePickerClick}
/>
<div className="flex flex-col gap-0 text-gray-900 dark:text-white">
<label>
<input
@@ -80,6 +114,12 @@ const TournamentTable = () => {
</div>
</div>
<div className="flex justify-center" ref={datePickerRef}>
{datePickerIsOpen && (
<DatePicker datePickerDirection={dateDirectionState} />
)}
</div>
<ScrollToTopButton />
<div className="overflow-x-scroll">
+11 -1
View File
@@ -1,4 +1,11 @@
import { differenceInDays, isSameDay, parse } from "date-fns";
import {
differenceInDays,
formatISO,
isSameDay,
parse,
setDefaultOptions,
} from "date-fns";
import { fr } from "date-fns/locale";
import { groupBy } from "lodash";
import { unstable_cache } from "next/cache";
@@ -9,6 +16,8 @@ import { errorLog } from "@/utils/logger";
import TournamentsDisplay from "./TournamentsDisplay";
setDefaultOptions({ locale: fr });
const getTournaments = async () => {
try {
const client = await clientPromise;
@@ -129,6 +138,7 @@ const getTournaments = async () => {
town: t.town,
department: t.department,
date: t.date,
isoDate: formatISO(date),
url: t.url,
timeControl,
latLng: { lat: t.coordinates[0], lng: t.coordinates[1] },