From a48d62a14538ac3c04334a9a852590636b32c4d4 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:01:32 +0200 Subject: [PATCH 1/9] Add event list page --- src/features/calendar/l10n/messageIds.ts | 1 + src/features/campaigns/l10n/messageIds.ts | 1 + .../events/components/SelectionBar/index.tsx | 44 +++++++++- src/locale/en.yml | 1 + .../[orgId]/projects/eventlist/index.tsx | 85 +++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/pages/organize/[orgId]/projects/eventlist/index.tsx diff --git a/src/features/calendar/l10n/messageIds.ts b/src/features/calendar/l10n/messageIds.ts index 20dac78274..ee9d375fee 100644 --- a/src/features/calendar/l10n/messageIds.ts +++ b/src/features/calendar/l10n/messageIds.ts @@ -108,6 +108,7 @@ export default makeMessages('feat.calendar', { nextDay: m<{ dates: ReactElement }>('Next day {dates}'), nextWeek: m<{ dates: ReactElement }>('Next week {dates}'), }, + openEventList: m('Make questionnaire'), }, shortWeek: m<{ weekNumber: number }>('w {weekNumber}'), showMore: m('Show'), diff --git a/src/features/campaigns/l10n/messageIds.ts b/src/features/campaigns/l10n/messageIds.ts index 762fede54b..e97eb1aef6 100644 --- a/src/features/campaigns/l10n/messageIds.ts +++ b/src/features/campaigns/l10n/messageIds.ts @@ -123,6 +123,7 @@ export default makeMessages('feat.campaigns', { allCampaigns: m('All Projects & Activities'), archive: m('Archive'), calendar: m('Calendar'), + eventList: m('Event List'), insights: m('Insights'), overview: m('Overview'), }, diff --git a/src/features/events/components/SelectionBar/index.tsx b/src/features/events/components/SelectionBar/index.tsx index 44937aff63..e0eb9fd752 100644 --- a/src/features/events/components/SelectionBar/index.tsx +++ b/src/features/events/components/SelectionBar/index.tsx @@ -10,15 +10,53 @@ import { resetSelection } from 'features/events/store'; import { RootState } from 'core/store'; import SelectionBarEllipsis from '../SelectionBarEllipsis'; import useParticipantPool from 'features/events/hooks/useParticipantPool'; -import { useAppDispatch, useAppSelector } from 'core/hooks'; +import { + useAppDispatch, + useAppSelector, + useNumericRouteParams, +} from 'core/hooks'; const SelectionBar = () => { const dispatch = useAppDispatch(); const [participantsDialogOpen, setParticipantsDialogOpen] = useState(false); const { affectedParticipantIds } = useParticipantPool(); + const eventList = useAppSelector((state) => state.events.eventList); const selectedEventIds = useAppSelector( (state: RootState) => state.events.selectedEventIds ); + const { orgId } = useNumericRouteParams(); + + const handleOpenEventList = () => { + const filteredEvents = eventList.items + .filter( + (item) => item.data?.id && selectedEventIds.includes(item.data.id) + ) + .map((x) => x.data); + + const endDates = filteredEvents.map((x) => x?.end_time); + const startDates = filteredEvents.map((x) => x?.start_time); + + const minDate = startDates.reduce((min, current) => { + const currentDate = new Date(current || ''); + const minDate = new Date(min || ''); + return currentDate < minDate ? current : min; + }); + + const maxDate = endDates.reduce((min, current) => { + const currentDate = new Date(current || ''); + const minDate = new Date(min || ''); + return currentDate < minDate ? current : min; + }); + + window + .open( + `/organize/${orgId}/projects/eventlist?minDate=${minDate}&maxDate=${maxDate}&ids=${selectedEventIds.join( + ',' + )}`, + '_blank' + ) + ?.focus(); + }; const handleDeselect = () => { dispatch(resetSelection()); @@ -68,6 +106,10 @@ const SelectionBar = () => { gap={1} justifyContent="center" > + + = ({ orgId }) => { + const router = useRouter(); + const messages = useMessages(messageIds); + + const [selectedEventIds, setSelectedEventIds] = useState([]); + + // const endDate = new Date( + // typeof router.query.maxDate === 'string' ? router.query.maxDate : '' + // ); + // const startDate = new Date( + // typeof router.query.minDate === 'string' ? router.query.minDate : '' + // ); + + const endDate = new Date('2024-12-31'); + const startDate = new Date('2020-12-31'); + + useEffect(() => { + const { ids } = router.query; + if (typeof ids !== 'string') { + return; + } + + const parsedIds = ids.split(',').map((x) => Number(x)); + + setSelectedEventIds(parsedIds); + }, [router.query]); + + const stuff = useEventsFromDateRange(startDate, endDate, orgId); + + const filteredEvents = stuff.filter((x) => + selectedEventIds.includes(x.data.id) + ); + + return ( + <> + + {messages.layout.eventList()} + + + + + + + + + + + + + {filteredEvents.map((item) => ( + + + + + + ))} + +
DateActivityPlace
{new Date(item.data.end_time).toLocaleDateString()}{item.data.activity?.title} + {item.data.location?.lat} {item.data.location?.lng} +
+ + {selectedEventIds.length === 0 &&

No events selected.

} + + ); +}; + +const Wrapper = () => { + const { orgId } = useNumericRouteParams(); + if (!orgId) { + return; + } + + return ; +}; + +export default Wrapper; From d72c053c43b84ea2b6263ed8412a04fe91b88ec3 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:20:24 +0200 Subject: [PATCH 2/9] Cleanup code --- .../events/components/SelectionBar/index.tsx | 17 +++++----- .../events/hooks/useDateRouterParam.ts | 22 +++++++++++++ .../[orgId]/projects/eventlist/index.tsx | 33 ++++++++----------- 3 files changed, 44 insertions(+), 28 deletions(-) create mode 100644 src/features/events/hooks/useDateRouterParam.ts diff --git a/src/features/events/components/SelectionBar/index.tsx b/src/features/events/components/SelectionBar/index.tsx index e0eb9fd752..dbc91124d9 100644 --- a/src/features/events/components/SelectionBar/index.tsx +++ b/src/features/events/components/SelectionBar/index.tsx @@ -33,8 +33,8 @@ const SelectionBar = () => { ) .map((x) => x.data); - const endDates = filteredEvents.map((x) => x?.end_time); - const startDates = filteredEvents.map((x) => x?.start_time); + const endDates = filteredEvents.map((x) => x?.end_time.slice(0, 10)); + const startDates = filteredEvents.map((x) => x?.start_time.slice(0, 10)); const minDate = startDates.reduce((min, current) => { const currentDate = new Date(current || ''); @@ -42,17 +42,18 @@ const SelectionBar = () => { return currentDate < minDate ? current : min; }); - const maxDate = endDates.reduce((min, current) => { + const maxDate = endDates.reduce((max, current) => { const currentDate = new Date(current || ''); - const minDate = new Date(min || ''); - return currentDate < minDate ? current : min; + const maxDate = new Date(max || ''); + + return maxDate > currentDate ? max : current; }); window .open( - `/organize/${orgId}/projects/eventlist?minDate=${minDate}&maxDate=${maxDate}&ids=${selectedEventIds.join( - ',' - )}`, + `/organize/${orgId}/projects/eventlist?minDate=${ + minDate || '' + }&maxDate=${maxDate || ''}&ids=${selectedEventIds.join(',')}`, '_blank' ) ?.focus(); diff --git a/src/features/events/hooks/useDateRouterParam.ts b/src/features/events/hooks/useDateRouterParam.ts new file mode 100644 index 0000000000..2fa76273bb --- /dev/null +++ b/src/features/events/hooks/useDateRouterParam.ts @@ -0,0 +1,22 @@ +import { useRouter } from 'next/router'; +import { useMemo } from 'react'; + +export default function useDateRouterParam(paramName: string): Date | null { + const router = useRouter(); + + return useMemo(() => { + const rawValue = router.query[paramName]; + + if (typeof rawValue !== 'string') { + return null; + } + + const date = new Date(rawValue); + + if (isNaN(date.valueOf())) { + return null; + } + + return date; + }, [router.query]); +} diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index 25ecbaa5b6..6055dd6d25 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -1,44 +1,37 @@ import Head from 'next/head'; import { useRouter } from 'next/router'; -import { FC, useEffect, useState } from 'react'; +import { FC, useMemo } from 'react'; import { useMessages } from 'core/i18n'; import messageIds from 'features/campaigns/l10n/messageIds'; import useEventsFromDateRange from 'features/events/hooks/useEventsFromDateRange'; import { useNumericRouteParams } from 'core/hooks'; +import useDateRouterParam from 'features/events/hooks/useDateRouterParam'; const EventList: FC<{ orgId: number }> = ({ orgId }) => { const router = useRouter(); const messages = useMessages(messageIds); - const [selectedEventIds, setSelectedEventIds] = useState([]); - - // const endDate = new Date( - // typeof router.query.maxDate === 'string' ? router.query.maxDate : '' - // ); - // const startDate = new Date( - // typeof router.query.minDate === 'string' ? router.query.minDate : '' - // ); - - const endDate = new Date('2024-12-31'); - const startDate = new Date('2020-12-31'); - - useEffect(() => { + const selectedEventIds = useMemo(() => { const { ids } = router.query; if (typeof ids !== 'string') { - return; + return []; } const parsedIds = ids.split(',').map((x) => Number(x)); - setSelectedEventIds(parsedIds); + return parsedIds; }, [router.query]); - const stuff = useEventsFromDateRange(startDate, endDate, orgId); + // TODO: Date parsing is not correct + const endDate = useDateRouterParam('minDate') || new Date(); + const startDate = useDateRouterParam('maxDate') || new Date(); - const filteredEvents = stuff.filter((x) => - selectedEventIds.includes(x.data.id) - ); + const filteredEvents = useEventsFromDateRange( + startDate, + endDate, + orgId + ).filter((x) => selectedEventIds.includes(x.data.id)); return ( <> From d1f19f8190270033eada933a844160ad2075250a Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 12:10:32 +0200 Subject: [PATCH 3/9] Fix typo --- src/pages/organize/[orgId]/projects/eventlist/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index 6055dd6d25..c2db75a9eb 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -23,9 +23,8 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { return parsedIds; }, [router.query]); - // TODO: Date parsing is not correct - const endDate = useDateRouterParam('minDate') || new Date(); - const startDate = useDateRouterParam('maxDate') || new Date(); + const endDate = useDateRouterParam('maxDate') || new Date(); + const startDate = useDateRouterParam('minDate') || new Date(); const filteredEvents = useEventsFromDateRange( startDate, From fdbbf28392ee9b349db2447464aba91e168769f7 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 12:14:44 +0200 Subject: [PATCH 4/9] Add column --- .../[orgId]/projects/eventlist/index.tsx | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index c2db75a9eb..75ce0d994a 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -1,3 +1,11 @@ +import { + Checkbox, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; import Head from 'next/head'; import { useRouter } from 'next/router'; import { FC, useMemo } from 'react'; @@ -38,27 +46,31 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { {messages.layout.eventList()} - - - - - - - - +
DateActivityPlace
+ + + + Date + Title + Coordinates + + - - {filteredEvents.map((item) => ( - - - - - + + {filteredEvents.map((event) => ( + + + + {new Date(event.data.end_time).toLocaleDateString()} + + {event.data.title} + + {event.data.location?.lat} {event.data.location?.lng} + + ))} - -
{new Date(item.data.end_time).toLocaleDateString()}{item.data.activity?.title} - {item.data.location?.lat} {item.data.location?.lng} -
+ + {selectedEventIds.length === 0 &&

No events selected.

} From dc7d3bc367326bdd91f8761039ab93386ac6b4bb Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 12:32:17 +0200 Subject: [PATCH 5/9] feat: add name field --- .../[orgId]/projects/eventlist/index.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index 75ce0d994a..6d2df8cb8d 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -46,27 +46,25 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { {messages.layout.eventList()} - +
- - Date + + Date Title - Coordinates {filteredEvents.map((event) => ( - - + + + + {new Date(event.data.end_time).toLocaleDateString()} {event.data.title} - - {event.data.location?.lat} {event.data.location?.lng} - ))} From ba22b4a3477d170fb432a350f2ea4854cb4f3473 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 13:55:15 +0200 Subject: [PATCH 6/9] Add name field to event list --- .../organize/[orgId]/projects/eventlist/index.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index 6d2df8cb8d..9dcbfe9fb0 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -5,6 +5,7 @@ import { TableCell, TableHead, TableRow, + TextField, } from '@mui/material'; import Head from 'next/head'; import { useRouter } from 'next/router'; @@ -15,6 +16,7 @@ import messageIds from 'features/campaigns/l10n/messageIds'; import useEventsFromDateRange from 'features/events/hooks/useEventsFromDateRange'; import { useNumericRouteParams } from 'core/hooks'; import useDateRouterParam from 'features/events/hooks/useDateRouterParam'; +import { Box } from '@mui/system'; const EventList: FC<{ orgId: number }> = ({ orgId }) => { const router = useRouter(); @@ -46,6 +48,16 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { {messages.layout.eventList()} + + + +
From cbc6960063091de584cc9db5abc89c0b240bf903 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 14:58:53 +0200 Subject: [PATCH 7/9] Add styling fixes --- .../[orgId]/projects/eventlist/index.tsx | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index 9dcbfe9fb0..a311a71ef3 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -7,16 +7,16 @@ import { TableRow, TextField, } from '@mui/material'; +import { Box } from '@mui/system'; import Head from 'next/head'; import { useRouter } from 'next/router'; import { FC, useMemo } from 'react'; +import { useNumericRouteParams } from 'core/hooks'; import { useMessages } from 'core/i18n'; import messageIds from 'features/campaigns/l10n/messageIds'; import useEventsFromDateRange from 'features/events/hooks/useEventsFromDateRange'; -import { useNumericRouteParams } from 'core/hooks'; import useDateRouterParam from 'features/events/hooks/useDateRouterParam'; -import { Box } from '@mui/system'; const EventList: FC<{ orgId: number }> = ({ orgId }) => { const router = useRouter(); @@ -48,7 +48,7 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { {messages.layout.eventList()} - + = ({ orgId }) => { /> -
+
- - Date + + Date Title @@ -70,10 +78,10 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { {filteredEvents.map((event) => ( - + - + {new Date(event.data.end_time).toLocaleDateString()} {event.data.title} From 60204a8488b8d46493b15c579777ae716eb0cbb8 Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:16:18 +0200 Subject: [PATCH 8/9] Split event list into multiple pages --- .../[orgId]/projects/eventlist/index.tsx | 103 +++++++++++------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx index a311a71ef3..db83d9b0af 100644 --- a/src/pages/organize/[orgId]/projects/eventlist/index.tsx +++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx @@ -18,6 +18,21 @@ import messageIds from 'features/campaigns/l10n/messageIds'; import useEventsFromDateRange from 'features/events/hooks/useEventsFromDateRange'; import useDateRouterParam from 'features/events/hooks/useDateRouterParam'; +function batchArray(items: T[], batchSize: number): T[][] { + const batches: T[][] = []; + + const numBatches = Math.ceil(items.length / batchSize); + + for (let batchIndex = 0; batchIndex < numBatches; batchIndex++) { + batches[batchIndex] = items.slice( + batchIndex * batchSize, + Math.min(items.length, (batchIndex + 1) * batchSize) + ); + } + + return batches; +} + const EventList: FC<{ orgId: number }> = ({ orgId }) => { const router = useRouter(); const messages = useMessages(messageIds); @@ -42,53 +57,59 @@ const EventList: FC<{ orgId: number }> = ({ orgId }) => { orgId ).filter((x) => selectedEventIds.includes(x.data.id)); + const batches = batchArray(filteredEvents, 30); + return ( <> {messages.layout.eventList()} - - - - -
- - - - Date - Title - - - - - {filteredEvents.map((event) => ( - - - - - - {new Date(event.data.end_time).toLocaleDateString()} - - {event.data.title} - - ))} - -
+ {batches.map((batch, index) => ( + + + + + + + + + + Date + Title + + + + + {batch.map((event) => ( + + + + + + {new Date(event.data.end_time).toLocaleDateString()} + + {event.data.title} + + ))} + +
+
+ ))} {selectedEventIds.length === 0 &&

No events selected.

} From e52aa3c66c71dae7d4aea392df7f06c2908a0d4e Mon Sep 17 00:00:00 2001 From: Johan Book <{ID}+{username}@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:21:56 +0200 Subject: [PATCH 9/9] Add translation --- src/locale/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locale/en.yml b/src/locale/en.yml index da89119a79..ab412b8e59 100644 --- a/src/locale/en.yml +++ b/src/locale/en.yml @@ -319,6 +319,7 @@ feat: allCampaigns: All Projects & Activities archive: Archive calendar: Calendar + eventList: Event List insights: Insights overview: Overview linkGroup: