From dd5eb660bfd86ec3fe1c848242031f622bc967af Mon Sep 17 00:00:00 2001 From: ferishili Date: Wed, 14 May 2025 09:12:24 +0200 Subject: [PATCH] Event Cell Filtering: enhance event cell components with debounced filter application --- .../events/partials/EventsDateCell.tsx | 33 +++++++++++++++-- .../events/partials/EventsLocationCell.tsx | 37 ++++++++++++++++--- .../events/partials/EventsPresentersCell.tsx | 33 +++++++++++++++-- .../events/partials/EventsSeriesCell.tsx | 33 +++++++++++++++-- .../partials/EventsTechnicalDateCell.tsx | 33 +++++++++++++++-- 5 files changed, 152 insertions(+), 17 deletions(-) diff --git a/src/components/events/partials/EventsDateCell.tsx b/src/components/events/partials/EventsDateCell.tsx index 6d1ae9127f..3a5c7b0059 100644 --- a/src/components/events/partials/EventsDateCell.tsx +++ b/src/components/events/partials/EventsDateCell.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { editFilterValue } from "../../../slices/tableFilterSlice"; import { loadEventsIntoTable } from "../../../thunks/tableThunks"; @@ -8,6 +8,9 @@ import { fetchEvents } from "../../../slices/eventSlice"; import { renderValidDate } from "../../../utils/dateUtils"; import { Event } from "../../../slices/eventSlice"; import { IconButton } from "../../shared/IconButton"; +import { + goToPage, +} from "../../../thunks/tableThunks"; /** * This component renders the start date cells of events in the table view @@ -17,6 +20,8 @@ const EventsDateCell = ({ }: { row: Event }) => { + // Using itemValue with useState in order to use as flag in useEffect as watcher! + const [itemValue, setItemValue] = useState(''); const { t } = useTranslation(); const dispatch = useAppDispatch(); @@ -24,6 +29,7 @@ const EventsDateCell = ({ // Filter with value of current cell const addFilter = async (date: string) => { + let mustApplyChanges = false; let filter = filterMap.find(({ name }) => name === "startDate"); if (!!filter) { let startDate = new Date(date); @@ -36,11 +42,32 @@ const EventsDateCell = ({ endDate.setSeconds(59); await dispatch(editFilterValue({filterName: filter.name, value: startDate.toISOString() + "/" + endDate.toISOString()})); - await dispatch(fetchEvents()); - dispatch(loadEventsIntoTable()); + mustApplyChanges = true; } + if (mustApplyChanges) { + setItemValue(date); + } + }; + + const applyFilterChangesDebounced = async () => { + // No matter what, we go to page one. + dispatch(goToPage(0)) + // Reload of resource + await dispatch(fetchEvents()); + dispatch(loadEventsIntoTable()); + setItemValue(''); }; + useEffect(() => { + if (itemValue) { + // Call to apply filter changes with 500MS debounce! + let applyFilterChangesDebouncedTimeoutId = setTimeout(applyFilterChangesDebounced, 500); + + return () => clearTimeout(applyFilterChangesDebouncedTimeoutId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [itemValue]); + return ( // Link template for start date of event { + // Using itemValue with useState in order to use as flag in useEffect as watcher! + const [itemValue, setItemValue] = useState(''); const dispatch = useAppDispatch(); const filterMap = useAppSelector(state => getFilters(state, "events")); // Filter with value of current cell - const addFilter = (location: string) => { + const addFilter = async (location: string) => { + let mustApplyChanges = false; let filter = filterMap.find(({ name }) => name === "location"); if (!!filter) { - dispatch(editFilterValue({filterName: filter.name, value: location})); - dispatch(fetchEvents()); - dispatch(loadEventsIntoTable()); + await dispatch(editFilterValue({filterName: filter.name, value: location})); + mustApplyChanges = true; } + if (mustApplyChanges) { + setItemValue(location); + } + }; + + const applyFilterChangesDebounced = async () => { + // No matter what, we go to page one. + dispatch(goToPage(0)) + // Reload of resource + await dispatch(fetchEvents()); + dispatch(loadEventsIntoTable()); + setItemValue(''); }; + useEffect(() => { + if (itemValue) { + // Call to apply filter changes with 500MS debounce! + let applyFilterChangesDebouncedTimeoutId = setTimeout(applyFilterChangesDebounced, 500); + + return () => clearTimeout(applyFilterChangesDebouncedTimeoutId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [itemValue]); + return ( // Link template for location of event { + // Using itemValue with useState in order to use as flag in useEffect as watcher! + const [itemValue, setItemValue] = useState(''); const dispatch = useAppDispatch(); const filterMap = useAppSelector(state => getFilters(state, "events")); // Filter with value of current cell const addFilter = async (presenter: string) => { + let mustApplyChanges = false; let filter = filterMap.find( ({ name }) => name === "presentersBibliographic" ); if (!!filter) { await dispatch(editFilterValue({filterName: filter.name, value: presenter})); - await dispatch(fetchEvents()); - dispatch(loadEventsIntoTable()); + mustApplyChanges = true; } + if (mustApplyChanges) { + setItemValue(presenter); + } + }; + + const applyFilterChangesDebounced = async () => { + // No matter what, we go to page one. + dispatch(goToPage(0)) + // Reload of resource + await dispatch(fetchEvents()); + dispatch(loadEventsIntoTable()); + setItemValue(''); }; + useEffect(() => { + if (itemValue) { + // Call to apply filter changes with 500MS debounce! + let applyFilterChangesDebouncedTimeoutId = setTimeout(applyFilterChangesDebounced, 500); + + return () => clearTimeout(applyFilterChangesDebouncedTimeoutId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [itemValue]); + return ( // Link template for presenter of event // Repeat for each presenter diff --git a/src/components/events/partials/EventsSeriesCell.tsx b/src/components/events/partials/EventsSeriesCell.tsx index 2680d425ab..a94b5282fe 100644 --- a/src/components/events/partials/EventsSeriesCell.tsx +++ b/src/components/events/partials/EventsSeriesCell.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import { getFilters } from "../../../selectors/tableFilterSelectors"; import { editFilterValue } from "../../../slices/tableFilterSlice"; import { loadEventsIntoTable } from "../../../thunks/tableThunks"; @@ -6,6 +6,9 @@ import { useAppDispatch, useAppSelector } from "../../../store"; import { fetchEvents } from "../../../slices/eventSlice"; import { Event } from "../../../slices/eventSlice"; import { IconButton } from "../../shared/IconButton"; +import { + goToPage, +} from "../../../thunks/tableThunks"; /** * This component renders the series cells of events in the table view @@ -15,20 +18,44 @@ const EventsSeriesCell = ({ }: { row: Event }) => { + // Using itemValue with useState in order to use as flag in useEffect as watcher! + const [itemValue, setItemValue] = useState(''); const dispatch = useAppDispatch(); const filterMap = useAppSelector(state => getFilters(state, "events")); // Filter with value of current cell const addFilter = async (seriesId: string) => { + let mustApplyChanges = false; let filter = filterMap.find(({ name }) => name === "series"); if (!!filter) { await dispatch(editFilterValue({filterName: filter.name, value: seriesId})); - await dispatch(fetchEvents()); - dispatch(loadEventsIntoTable()); + mustApplyChanges = true; } + if (mustApplyChanges) { + setItemValue(seriesId); + } + }; + + const applyFilterChangesDebounced = async () => { + // No matter what, we go to page one. + dispatch(goToPage(0)) + // Reload of resource + await dispatch(fetchEvents()); + dispatch(loadEventsIntoTable()); + setItemValue(''); }; + useEffect(() => { + if (itemValue) { + // Call to apply filter changes with 500MS debounce! + let applyFilterChangesDebouncedTimeoutId = setTimeout(applyFilterChangesDebounced, 500); + + return () => clearTimeout(applyFilterChangesDebouncedTimeoutId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [itemValue]); + return ( !!row.series ? ( // Link template for series of event diff --git a/src/components/events/partials/EventsTechnicalDateCell.tsx b/src/components/events/partials/EventsTechnicalDateCell.tsx index 585e2f711e..de17d6c9f0 100644 --- a/src/components/events/partials/EventsTechnicalDateCell.tsx +++ b/src/components/events/partials/EventsTechnicalDateCell.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { getFilters } from "../../../selectors/tableFilterSelectors"; import { editFilterValue } from "../../../slices/tableFilterSlice"; @@ -8,6 +8,9 @@ import { fetchEvents } from "../../../slices/eventSlice"; import { renderValidDate } from "../../../utils/dateUtils"; import { Event } from "../../../slices/eventSlice"; import { IconButton } from "../../shared/IconButton"; +import { + goToPage, +} from "../../../thunks/tableThunks"; /** * This component renders the technical date cells of events in the table view @@ -17,6 +20,8 @@ const EventsTechnicalDateCell = ({ }: { row: Event }) => { + // Using itemValue with useState in order to use as flag in useEffect as watcher! + const [itemValue, setItemValue] = useState(''); const { t } = useTranslation(); const dispatch = useAppDispatch(); @@ -24,14 +29,36 @@ const EventsTechnicalDateCell = ({ // Filter with value of current cell const addFilter = async (date: string) => { + let mustApplyChanges = false; let filter = filterMap.find(({ name }) => name === "technicalStart"); if (!!filter) { await dispatch(editFilterValue({filterName: filter.name, value: date + "/" + date})); - await dispatch(fetchEvents()); - dispatch(loadEventsIntoTable()); + mustApplyChanges = true; } + if (mustApplyChanges) { + setItemValue(date); + } + }; + + const applyFilterChangesDebounced = async () => { + // No matter what, we go to page one. + dispatch(goToPage(0)) + // Reload of resource + await dispatch(fetchEvents()); + dispatch(loadEventsIntoTable()); + setItemValue(''); }; + useEffect(() => { + if (itemValue) { + // Call to apply filter changes with 500MS debounce! + let applyFilterChangesDebouncedTimeoutId = setTimeout(applyFilterChangesDebounced, 500); + + return () => clearTimeout(applyFilterChangesDebouncedTimeoutId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [itemValue]); + return ( // Link template for technical date of event