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..dbc91124d9 100644
--- a/src/features/events/components/SelectionBar/index.tsx
+++ b/src/features/events/components/SelectionBar/index.tsx
@@ -10,15 +10,54 @@ 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.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 || '');
+ const minDate = new Date(min || '');
+ return currentDate < minDate ? current : min;
+ });
+
+ const maxDate = endDates.reduce((max, current) => {
+ const currentDate = new Date(current || '');
+ const maxDate = new Date(max || '');
+
+ return maxDate > currentDate ? max : current;
+ });
+
+ window
+ .open(
+ `/organize/${orgId}/projects/eventlist?minDate=${
+ minDate || ''
+ }&maxDate=${maxDate || ''}&ids=${selectedEventIds.join(',')}`,
+ '_blank'
+ )
+ ?.focus();
+ };
const handleDeselect = () => {
dispatch(resetSelection());
@@ -68,6 +107,10 @@ const SelectionBar = () => {
gap={1}
justifyContent="center"
>
+
+
{
+ 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/locale/en.yml b/src/locale/en.yml
index 1f5714467f..ab412b8e59 100644
--- a/src/locale/en.yml
+++ b/src/locale/en.yml
@@ -126,6 +126,7 @@ feat:
moveMenuHeader: Move {numberOfEvents} events to
nextDay: Next day {dates}
nextWeek: Next week {dates}
+ openEventList: Make questionnaire
shortWeek: w {weekNumber}
showMore: Show
today: Today
@@ -318,6 +319,7 @@ feat:
allCampaigns: All Projects & Activities
archive: Archive
calendar: Calendar
+ eventList: Event List
insights: Insights
overview: Overview
linkGroup:
diff --git a/src/pages/organize/[orgId]/projects/eventlist/index.tsx b/src/pages/organize/[orgId]/projects/eventlist/index.tsx
new file mode 100644
index 0000000000..db83d9b0af
--- /dev/null
+++ b/src/pages/organize/[orgId]/projects/eventlist/index.tsx
@@ -0,0 +1,128 @@
+import {
+ Checkbox,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ 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 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);
+
+ const selectedEventIds = useMemo(() => {
+ const { ids } = router.query;
+ if (typeof ids !== 'string') {
+ return [];
+ }
+
+ const parsedIds = ids.split(',').map((x) => Number(x));
+
+ return parsedIds;
+ }, [router.query]);
+
+ const endDate = useDateRouterParam('maxDate') || new Date();
+ const startDate = useDateRouterParam('minDate') || new Date();
+
+ const filteredEvents = useEventsFromDateRange(
+ startDate,
+ endDate,
+ orgId
+ ).filter((x) => selectedEventIds.includes(x.data.id));
+
+ const batches = batchArray(filteredEvents, 30);
+
+ return (
+ <>
+
+ {messages.layout.eventList()}
+
+
+ {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.
}
+ >
+ );
+};
+
+const Wrapper = () => {
+ const { orgId } = useNumericRouteParams();
+ if (!orgId) {
+ return;
+ }
+
+ return ;
+};
+
+export default Wrapper;