Skip to content

Commit 5d55d06

Browse files
committed
Click-to-filter in series table
Allows users to click on organizers, contributors and creation dates in the series table to filter the table by the value that was clicked on, similar to how it works in the events table. Requires backend changes to work. Should not break anything without the backend changes, the buttons will simply not be responsive.
1 parent fa48c7a commit 5d55d06

11 files changed

Lines changed: 205 additions & 110 deletions

File tree

src/components/events/partials/EventsDateCell.tsx

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import React from "react";
2-
import { useTranslation } from "react-i18next";
3-
import { editFilterValue } from "../../../slices/tableFilterSlice";
42
import { loadEventsIntoTable } from "../../../thunks/tableThunks";
5-
import { getFilters } from "../../../selectors/tableFilterSelectors";
6-
import { useAppDispatch, useAppSelector } from "../../../store";
73
import { fetchEvents } from "../../../slices/eventSlice";
8-
import { renderValidDate } from "../../../utils/dateUtils";
94
import { Event } from "../../../slices/eventSlice";
10-
import { IconButton } from "../../shared/IconButton";
5+
import DateTimeCell from "../../shared/DateTimeCell";
116

127
/**
138
* This component renders the start date cells of events in the table view
@@ -17,39 +12,15 @@ const EventsDateCell = ({
1712
}: {
1813
row: Event
1914
}) => {
20-
const { t } = useTranslation();
21-
const dispatch = useAppDispatch();
22-
23-
const filterMap = useAppSelector(state => getFilters(state, "events"));
24-
25-
// Filter with value of current cell
26-
const addFilter = async (date: string) => {
27-
let filter = filterMap.find(({ name }) => name === "startDate");
28-
if (!!filter) {
29-
let startDate = new Date(date);
30-
startDate.setHours(0);
31-
startDate.setMinutes(0);
32-
startDate.setSeconds(0);
33-
let endDate = new Date(date);
34-
endDate.setHours(23);
35-
endDate.setMinutes(59);
36-
endDate.setSeconds(59);
37-
38-
await dispatch(editFilterValue({filterName: filter.name, value: startDate.toISOString() + "/" + endDate.toISOString()}));
39-
await dispatch(fetchEvents());
40-
dispatch(loadEventsIntoTable());
41-
}
42-
};
43-
4415
return (
45-
// Link template for start date of event
46-
<IconButton
47-
callback={() => addFilter(row.date)}
48-
iconClassname={"crosslink"}
49-
tooltipText={"EVENTS.EVENTS.TABLE.TOOLTIP.START"}
50-
>
51-
{t("dateFormats.date.short", { date: renderValidDate(row.date) })}
52-
</IconButton>
16+
<DateTimeCell
17+
resource="events"
18+
date={row.date}
19+
filterName="startDate"
20+
fetchResource={fetchEvents}
21+
loadResourceIntoTable={loadEventsIntoTable}
22+
tooltipText="EVENTS.EVENTS.TABLE.TOOLTIP.START"
23+
/>
5324
);
5425
};
5526

src/components/events/partials/EventsPresentersCell.tsx

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import React from "react";
2-
import { getFilters } from "../../../selectors/tableFilterSelectors";
3-
import { editFilterValue } from "../../../slices/tableFilterSlice";
42
import { loadEventsIntoTable } from "../../../thunks/tableThunks";
5-
import { useAppDispatch, useAppSelector } from "../../../store";
63
import { fetchEvents } from "../../../slices/eventSlice";
74
import { Event } from "../../../slices/eventSlice";
8-
import { IconButton } from "../../shared/IconButton";
5+
import MultiValueCell from "../../shared/MultiValueCell";
96

107
/**
118
* This component renders the presenters cells of events in the table view
@@ -15,35 +12,15 @@ const EventsPresentersCell = ({
1512
}: {
1613
row: Event
1714
}) => {
18-
const dispatch = useAppDispatch();
19-
20-
const filterMap = useAppSelector(state => getFilters(state, "events"));
21-
22-
// Filter with value of current cell
23-
const addFilter = async (presenter: string) => {
24-
let filter = filterMap.find(
25-
({ name }) => name === "presentersBibliographic"
26-
);
27-
if (!!filter) {
28-
await dispatch(editFilterValue({filterName: filter.name, value: presenter}));
29-
await dispatch(fetchEvents());
30-
dispatch(loadEventsIntoTable());
31-
}
32-
};
33-
3415
return (
35-
// Link template for presenter of event
36-
// Repeat for each presenter
37-
row.presenters.map((presenter, key) => (
38-
<IconButton
39-
key={key}
40-
callback={() => addFilter(presenter)}
41-
iconClassname={"metadata-entry"}
42-
tooltipText={"EVENTS.EVENTS.TABLE.TOOLTIP.PRESENTER"}
43-
>
44-
{presenter}
45-
</IconButton>
46-
))
16+
<MultiValueCell
17+
resource="events"
18+
values={row.presenters}
19+
filterName="presentersBibliographic"
20+
fetchResource={fetchEvents}
21+
loadResourceIntoTable={loadEventsIntoTable}
22+
tooltipText="EVENTS.EVENTS.TABLE.TOOLTIP.PRESENTER"
23+
/>
4724
);
4825
};
4926

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React from "react";
2-
import { Series } from "../../../slices/seriesSlice";
2+
import { fetchSeries, Series } from "../../../slices/seriesSlice";
3+
import { loadSeriesIntoTable } from "../../../thunks/tableThunks";
4+
import MultiValueCell from "../../shared/MultiValueCell";
35

46
/**
57
* This component renders the contributors cells of series in the table view
@@ -9,11 +11,16 @@ const SeriesContributorsCell = ({
911
}: {
1012
row: Series
1113
}) => {
12-
return row.contributors.map((contributor, key) => (
13-
<span key={key} className="metadata-entry">
14-
{contributor}
15-
</span>
16-
));
14+
return (
15+
<MultiValueCell
16+
resource="series"
17+
values={row.contributors}
18+
filterName="contributors"
19+
fetchResource={fetchSeries}
20+
loadResourceIntoTable={loadSeriesIntoTable}
21+
tooltipText="EVENTS.SERIES.TABLE.TOOLTIP.CONTRIBUTORS"
22+
/>
23+
);
1724
};
1825

1926
export default SeriesContributorsCell;

src/components/events/partials/SeriesCreatorsCell.tsx

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/components/events/partials/SeriesDateTimeCell.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
2-
import { useTranslation } from "react-i18next";
3-
import { renderValidDate } from "../../../utils/dateUtils";
4-
import { Series } from "../../../slices/seriesSlice";
2+
import { fetchSeries, Series } from "../../../slices/seriesSlice";
3+
import { loadSeriesIntoTable } from "../../../thunks/tableThunks";
4+
import DateTimeCell from "../../shared/DateTimeCell";
55

66
/**
77
* This component renders the creation date cells of series in the table view
@@ -11,15 +11,22 @@ const SeriesDateTimeCell = ({
1111
}: {
1212
row: Series
1313
}) => {
14-
const { t } = useTranslation();
15-
1614
return (
17-
// Link template for creation date of series
18-
<span>
19-
{t("dateFormats.date.short", {
20-
date: row.creation_date ? renderValidDate(row.creation_date) : "",
21-
})}
22-
</span>
15+
<>
16+
{row.creation_date !== undefined && (() => {
17+
const creationDate = row.creation_date;
18+
return (
19+
<DateTimeCell
20+
resource="series"
21+
date={creationDate}
22+
filterName="CreationDate"
23+
fetchResource={fetchSeries}
24+
loadResourceIntoTable={loadSeriesIntoTable}
25+
tooltipText="EVENTS.SERIES.TABLE.TOOLTIP.CREATION"
26+
/>
27+
);
28+
})()}
29+
</>
2330
);
2431
};
2532

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from "react";
2+
import { fetchSeries, Series } from "../../../slices/seriesSlice";
3+
import { loadSeriesIntoTable } from "../../../thunks/tableThunks";
4+
import MultiValueCell from "../../shared/MultiValueCell";
5+
6+
/**
7+
* This component renders the creators cells of series in the table view
8+
*/
9+
const SeriesOrganizersCell = ({
10+
row
11+
}: {
12+
row: Series
13+
}) => {
14+
return (
15+
<MultiValueCell
16+
resource="series"
17+
values={row.organizers}
18+
filterName="organizers"
19+
fetchResource={fetchSeries}
20+
loadResourceIntoTable={loadSeriesIntoTable}
21+
tooltipText="EVENTS.SERIES.TABLE.TOOLTIP.ORGANIZER"
22+
/>
23+
);
24+
};
25+
26+
export default SeriesOrganizersCell;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from "react";
2+
import { useTranslation } from "react-i18next";
3+
import { editFilterValue } from "../../slices/tableFilterSlice";
4+
import { getFilters } from "../../selectors/tableFilterSelectors";
5+
import { AppThunk, useAppDispatch, useAppSelector } from "../../store";
6+
import { renderValidDate } from "../../utils/dateUtils";
7+
import { IconButton } from "../shared/IconButton";
8+
import { ParseKeys } from "i18next";
9+
import { AsyncThunk } from "@reduxjs/toolkit";
10+
11+
/**
12+
* This component renders the start date cells of events in the table view
13+
*/
14+
const DateTimeCell = ({
15+
resource,
16+
date,
17+
filterName,
18+
fetchResource,
19+
loadResourceIntoTable,
20+
tooltipText,
21+
}: {
22+
resource: string
23+
date: string
24+
filterName: string
25+
fetchResource: AsyncThunk<any, void, any>
26+
loadResourceIntoTable: () => AppThunk
27+
tooltipText: ParseKeys
28+
}) => {
29+
const { t } = useTranslation();
30+
const dispatch = useAppDispatch();
31+
32+
const filterMap = useAppSelector(state => getFilters(state, resource));
33+
34+
// Filter with value of current cell
35+
const addFilter = async (date: string) => {
36+
let filter = filterMap.find(({ name }) => name === filterName);
37+
if (!!filter) {
38+
let startDate = new Date(date);
39+
startDate.setHours(0);
40+
startDate.setMinutes(0);
41+
startDate.setSeconds(0);
42+
let endDate = new Date(date);
43+
endDate.setHours(23);
44+
endDate.setMinutes(59);
45+
endDate.setSeconds(59);
46+
47+
await dispatch(editFilterValue({filterName: filter.name, value: startDate.toISOString() + "/" + endDate.toISOString()}));
48+
await dispatch(fetchResource());
49+
dispatch(loadResourceIntoTable());
50+
}
51+
};
52+
53+
return (
54+
// Link template for start date of event
55+
<IconButton
56+
callback={() => addFilter(date)}
57+
iconClassname={"crosslink"}
58+
tooltipText={tooltipText}
59+
>
60+
{t("dateFormats.date.short", { date: renderValidDate(date) })}
61+
</IconButton>
62+
);
63+
};
64+
65+
export default DateTimeCell;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from "react";
2+
import { getFilters } from "../../selectors/tableFilterSelectors";
3+
import { editFilterValue } from "../../slices/tableFilterSlice";
4+
import { AppThunk, useAppDispatch, useAppSelector } from "../../store";
5+
import { IconButton } from "../shared/IconButton";
6+
import { AsyncThunk } from "@reduxjs/toolkit";
7+
import { ParseKeys } from "i18next";
8+
9+
/**
10+
* This component renders the presenters cells of events in the table view
11+
*/
12+
const MultiValueCell = ({
13+
resource,
14+
values,
15+
filterName,
16+
fetchResource,
17+
loadResourceIntoTable,
18+
tooltipText,
19+
}: {
20+
resource: string
21+
values: string[]
22+
filterName: string
23+
fetchResource: AsyncThunk<any, void, any>
24+
loadResourceIntoTable: () => AppThunk
25+
tooltipText: ParseKeys,
26+
}) => {
27+
const dispatch = useAppDispatch();
28+
29+
const filterMap = useAppSelector(state => getFilters(state, resource));
30+
31+
// Filter with value of current cell
32+
const addFilter = async (presenter: string) => {
33+
let filter = filterMap.find(
34+
({ name }) => name === filterName
35+
);
36+
if (!!filter) {
37+
await dispatch(editFilterValue({filterName: filter.name, value: presenter}));
38+
await dispatch(fetchResource());
39+
dispatch(loadResourceIntoTable());
40+
}
41+
};
42+
43+
return (
44+
// Link template for each value
45+
values.map((value, key) => (
46+
<IconButton
47+
key={key}
48+
callback={() => addFilter(value)}
49+
iconClassname={"metadata-entry"}
50+
tooltipText={tooltipText}
51+
>
52+
{value}
53+
</IconButton>
54+
))
55+
);
56+
};
57+
58+
export default MultiValueCell;

src/configs/tableConfigs/seriesTableConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const seriesTableConfig: TableConfig = {
1919
sortable: true,
2020
},
2121
{
22-
template: "SeriesCreatorsCell",
22+
template: "SeriesOrganizersCell",
2323
name: "organizers",
2424
label: "EVENTS.SERIES.TABLE.ORGANIZERS",
2525
sortable: true,

src/configs/tableConfigs/seriesTableMap.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import SeriesTitleCell from "../../components/events/partials/SeriesTitleCell";
2-
import SeriesCreatorsCell from "../../components/events/partials/SeriesCreatorsCell";
2+
import SeriesOrganizersCell from "../../components/events/partials/SeriesOrganizersCell";
33
import SeriesContributorsCell from "../../components/events/partials/SeriesContributorsCell";
44
import SeriesDateTimeCell from "../../components/events/partials/SeriesDateTimeCell";
55
import SeriesActionsCell from "../../components/events/partials/SeriesActionsCell";
@@ -10,7 +10,7 @@ import SeriesActionsCell from "../../components/events/partials/SeriesActionsCel
1010
*/
1111
export const seriesTemplateMap = {
1212
SeriesTitleCell: SeriesTitleCell,
13-
SeriesCreatorsCell: SeriesCreatorsCell,
13+
SeriesOrganizersCell: SeriesOrganizersCell,
1414
SeriesContributorsCell: SeriesContributorsCell,
1515
SeriesDateTimeCell: SeriesDateTimeCell,
1616
SeriesActionsCell: SeriesActionsCell,

0 commit comments

Comments
 (0)