diff --git a/apps/core-admin/src/controllers/registration.ts b/apps/core-admin/src/controllers/registration.ts
index f479fc50..1793c93f 100644
--- a/apps/core-admin/src/controllers/registration.ts
+++ b/apps/core-admin/src/controllers/registration.ts
@@ -10,12 +10,17 @@ export const orgAndEventVerification = async (req: Request, res: Response) => {
where: {
id: eventId,
},
+ select: {
+ organizationId: true,
+ isRegistrationClosed: true,
+ },
});
if (!event) {
return res.status(404).json({ error: 'Event not found' });
- }
- if (event.organizationId != orgId) {
+ } else if (event.organizationId != orgId) {
return res.status(404).json({ error: "Organisation and event don't match" });
+ } else if (event.isRegistrationClosed) {
+ return res.status(403).json({ error: 'Registration currently unavailable' });
}
return res.status(200).json({ msg: 'Event corresponds to the given org and both exists' });
} catch (err: any) {
@@ -29,6 +34,19 @@ export const addFormResponse = async (req: Request, res: Response) => {
const { orgId, eventId } = req?.params;
const data = req?.body;
+ const event = await prisma.event.findFirst({
+ where: {
+ id: eventId,
+ },
+ select: {
+ isShortlisting: true,
+ },
+ });
+
+ if (!event) {
+ return res.status(404).json({ error: 'Event not found' });
+ }
+
const defaultKeys = ['firstName', 'lastName', 'email', 'phone'];
const defaultData: { [key: string]: string } = {};
const attrData: { attributeId: string; value: string }[] = [];
@@ -44,21 +62,35 @@ export const addFormResponse = async (req: Request, res: Response) => {
}
}
- const newRegistrant = await prisma.registrant.create({
- data: {
- firstName: defaultData['firstName'],
- lastName: defaultData['lastName'] || null,
- email: defaultData['email'],
- phone: defaultData['phone'] || null,
- eventId: eventId,
- organizationId: orgId,
- registrantAttributes: {
- create: attrData,
- },
- },
- });
+ const newAttendee = event.isShortlisting
+ ? await prisma.registrant.create({
+ data: {
+ firstName: defaultData['firstName'],
+ lastName: defaultData['lastName'] || null,
+ email: defaultData['email'],
+ phone: defaultData['phone'] || null,
+ eventId: eventId,
+ organizationId: orgId,
+ registrantAttributes: {
+ create: attrData,
+ },
+ },
+ })
+ : await prisma.participant.create({
+ data: {
+ firstName: defaultData['firstName'],
+ lastName: defaultData['lastName'] || null,
+ email: defaultData['email'],
+ phone: defaultData['phone'] || null,
+ eventId: eventId,
+ organizationId: orgId,
+ participantAttributes: {
+ create: attrData,
+ },
+ },
+ });
- return res.status(200).json({ newRegistrant });
+ return res.status(200).json({ newAttendee });
} catch (err: any) {
console.error(err);
return res.status(500).json({ error: 'Something went wrong' });
@@ -105,3 +137,41 @@ export const getFormAttributes = async (req: Request, res: Response) => {
return res.status(500).json({ error: 'Something went wrong' });
}
};
+
+export const getAllRegistrations = async (req: Request, res: Response) => {
+ try {
+ const { orgId, eventId } = req?.params;
+ let registrants = await prisma.registrant.findMany({
+ where: {
+ organizationId: orgId,
+ eventId,
+ },
+ include: {
+ registrantAttributes: true,
+ registrantExtras: true,
+ },
+ });
+
+ if (!registrants) {
+ return res.status(500).json({ error: 'Something went wrong' });
+ }
+
+ registrants = registrants.map((registrant: any) => {
+ return {
+ id: registrant.id,
+ addedAt: registrant.createdAt,
+ firstName: registrant.firstName,
+ lastName: registrant.lastName,
+ phone: registrant.phone,
+ email: registrant.email,
+ numberOfAttributesAssigned: registrant.registrantAttributes.length,
+ numnerOfExtrasAssigned: registrant.registrantExtras.length,
+ };
+ });
+
+ return res.status(200).json({ registrants });
+ } catch (err: any) {
+ console.error(err);
+ return res.status(500).json({ error: 'Something went wrong' });
+ }
+};
diff --git a/apps/core-admin/src/routes.ts b/apps/core-admin/src/routes.ts
index 807bab33..3ef30c19 100644
--- a/apps/core-admin/src/routes.ts
+++ b/apps/core-admin/src/routes.ts
@@ -20,6 +20,7 @@ import {
updateParticipantAttribute,
getParticipantBycheckInKey,
} from './controllers/participants';
+import { getAllRegistrations } from './controllers/registration';
import {
addNewAttribute,
editAttribute,
@@ -79,6 +80,7 @@ router.get('/organizations/:orgId/events/:eventId', getEventStats); //midhun //m
router.post('/organizations/:orgId/events', createNewEvent); //midhun
router.get('/organizations/:orgId/events/:eventId/participants', getAllParticipants); //midhun //midhun - done
+router.get('/organizations/:orgId/events/:eventId/registrations', getAllRegistrations);
router.post('/organizations/:orgId/events/:eventId/participants', addNewParticipant);
router.put('/organizations/:orgId/events/:eventId/participants/:participantId', editParticipant);
diff --git a/apps/registration-admin/src/App.tsx b/apps/registration-admin/src/App.tsx
index 1916ba08..a495177a 100644
--- a/apps/registration-admin/src/App.tsx
+++ b/apps/registration-admin/src/App.tsx
@@ -3,6 +3,7 @@ import { ChakraProvider } from '@chakra-ui/react';
import Form from './pages/Form';
import NotFound from './pages/NotFound';
import Registered from './pages/Registered';
+import RegistrationClosed from './pages/RegistrationClosed';
const App = () => {
return (
@@ -11,6 +12,7 @@ const App = () => {
} />
} />
+ } />
} />
diff --git a/apps/registration-admin/src/hooks/useFetch.tsx b/apps/registration-admin/src/hooks/useFetch.tsx
index 2bbeebf3..686af4f6 100644
--- a/apps/registration-admin/src/hooks/useFetch.tsx
+++ b/apps/registration-admin/src/hooks/useFetch.tsx
@@ -16,7 +16,13 @@ export const useFetch = () => {
} catch (err) {
console.error(err);
setLoading(false);
- return null;
+ if (axios.isAxiosError(err) && err.response) {
+ console.error(`Error: ${err.response.status} - ${err.response.statusText}`);
+ return { data: err.response.data, status: err.response.status };
+ } else {
+ console.error('Error: Unable to process the request.');
+ return null;
+ }
}
};
diff --git a/apps/registration-admin/src/pages/Form.tsx b/apps/registration-admin/src/pages/Form.tsx
index 3bf8f1ab..07cc771f 100644
--- a/apps/registration-admin/src/pages/Form.tsx
+++ b/apps/registration-admin/src/pages/Form.tsx
@@ -31,6 +31,8 @@ const Form = () => {
status: 'error',
});
}
+ } else if (checkResponse?.status === 403) {
+ navigate('/registrationclosed');
} else {
navigate('/');
}
@@ -58,7 +60,7 @@ const Form = () => {
description: 'Form submitted successfully!',
status: 'success',
});
- navigate('/');
+ navigate('/already-registered');
} else {
showAlert({
title: 'Error',
diff --git a/apps/registration-admin/src/pages/NotFound.tsx b/apps/registration-admin/src/pages/NotFound.tsx
index 292c61e4..7e8a2484 100644
--- a/apps/registration-admin/src/pages/NotFound.tsx
+++ b/apps/registration-admin/src/pages/NotFound.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Box, Heading, Text, Center } from '@chakra-ui/react';
-const NotFound: React.FC = () => {
+const NotFound: React.FC<{ msg?: String }> = ({ msg }) => {
return (
@@ -9,7 +9,7 @@ const NotFound: React.FC = () => {
404
- Sorry, the page you are looking for does not exist.
+ {msg || 'Sorry, the page you are looking for does not exist.'}
diff --git a/apps/registration-admin/src/pages/RegistrationClosed.tsx b/apps/registration-admin/src/pages/RegistrationClosed.tsx
new file mode 100644
index 00000000..4bb580de
--- /dev/null
+++ b/apps/registration-admin/src/pages/RegistrationClosed.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { Box, Heading, Text, Center } from '@chakra-ui/react';
+
+const RegistrationClosed: React.FC = () => {
+ return (
+
+
+
+ Registration Closed
+
+
+ The registrations for this event is not currently active
+
+
+
+ );
+};
+
+export default RegistrationClosed;
diff --git a/apps/registration-admin/tsconfig.app.tsbuildinfo b/apps/registration-admin/tsconfig.app.tsbuildinfo
index 5f74bc25..ae2e42d7 100644
--- a/apps/registration-admin/tsconfig.app.tsbuildinfo
+++ b/apps/registration-admin/tsconfig.app.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/hooks/usealert.tsx","./src/hooks/usefetch.tsx","./src/pages/form.tsx","./src/pages/notfound.tsx","./src/pages/registered.tsx"],"version":"5.7.2"}
\ No newline at end of file
+{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/hooks/usealert.tsx","./src/hooks/usefetch.tsx","./src/pages/form.tsx","./src/pages/notfound.tsx","./src/pages/registered.tsx","./src/pages/registrationclosed.tsx"],"version":"5.7.2"}
\ No newline at end of file
diff --git a/apps/web-admin/src/contexts/MyContext.jsx b/apps/web-admin/src/contexts/MyContext.jsx
index b6e14355..85979287 100644
--- a/apps/web-admin/src/contexts/MyContext.jsx
+++ b/apps/web-admin/src/contexts/MyContext.jsx
@@ -13,6 +13,7 @@ const MyContext = ({ children }) => {
const { user, isAuthenticated, isLoading, loginWithRedirect } = useAuth0();
const [participants, setParticipants] = useState([]);
const [userDetails, setUserDetails] = useState([]);
+ const [eventDetails, setEventDetails] = useState({});
const { loading, get, put } = useFetch();
const showAlert = useAlert();
@@ -76,6 +77,8 @@ const MyContext = ({ children }) => {
updateAccountDetails,
participants,
setParticipants,
+ eventDetails,
+ setEventDetails,
}}
>
{children}
diff --git a/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx b/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx
index b7a7d060..557b7d49 100644
--- a/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx
+++ b/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx
@@ -50,13 +50,22 @@ const NavigationMenu = ({ orgId, eventId }) => {
width: { base: '100%', md: 'auto' },
});
const router = useRouter();
- const navItems = [
- { link: 'participants', name: 'Participants' },
- { link: 'check-in', name: 'Participants Check In' },
- { link: 'attributes', name: 'Attributes' },
- { link: 'extras', name: 'Extras' },
- ];
- const { activeTab, setActiveTab } = useContext(account);
+ const { activeTab, setActiveTab, eventDetails } = useContext(account);
+ console.log('trial', eventDetails.isShortlisting);
+ const navItems =
+ eventDetails.isShortlisting && router.asPath.endsWith('/participants')
+ ? [
+ { link: 'registrants', name: 'Registrants' },
+ { link: 'check-in', name: 'Participants Check In' },
+ { link: 'attributes', name: 'Attributes' },
+ { link: 'extras', name: 'Extras' },
+ ]
+ : [
+ { link: 'participants', name: 'Participants' },
+ { link: 'check-in', name: 'Participants Check In' },
+ { link: 'attributes', name: 'Attributes' },
+ { link: 'extras', name: 'Extras' },
+ ];
useEffect(() => {
//console.log(activeTab);
}, [activeTab]);
@@ -94,24 +103,27 @@ const NavigationMenu = ({ orgId, eventId }) => {
width="100%"
display={{ base: 'none', md: 'flex' }} // Horizontal layout on desktop
>
- {['participants', 'check-in', 'attributes', 'extras'].map((tab) => (
- {
- setActiveTab(tab);
- const element = tab === 'check-in' ? 'participants/check-in' : tab;
- router.push(
- `/${orgId}/events/${eventId}/${element}
+ {navItems.map((content) => {
+ const tab = content.link;
+ return (
+ {
+ setActiveTab(tab);
+ const element = tab === 'check-in' ? 'participants/check-in' : tab;
+ router.push(
+ `/${orgId}/events/${eventId}/${element}
`,
- );
- }}
- >
- {tab === 'check-in'
- ? 'Participant Check In'
- : tab.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase())}
-
- ))}
+ );
+ }}
+ >
+ {tab === 'check-in'
+ ? 'Participant Check In'
+ : tab.replace(/(^\w|\s\w)/g, (m) => m.toUpperCase())}
+
+ );
+ })}
);
diff --git a/apps/web-admin/src/pages/[orgId]/events/[eventId]/registrants/index.jsx b/apps/web-admin/src/pages/[orgId]/events/[eventId]/registrants/index.jsx
new file mode 100644
index 00000000..b5071a0d
--- /dev/null
+++ b/apps/web-admin/src/pages/[orgId]/events/[eventId]/registrants/index.jsx
@@ -0,0 +1,193 @@
+import { useState, useEffect } from 'react';
+import { Button, useDisclosure } from '@chakra-ui/react';
+import { StyledBox, StyledText } from '@/components/ui/StyledComponents';
+import { useRouter } from 'next/router';
+import DashboardLayout from '@/layouts/DashboardLayout';
+import DataDisplay from '@/components/DataDisplay';
+import { useAlert } from '@/hooks/useAlert';
+import { useFetch } from '@/hooks/useFetch';
+import { CSVLink } from 'react-csv';
+import AddParticipant from '@/components/AddParticipant';
+import MultiStepModal from '@/components/MultiFormEmail';
+import { useContext } from 'react';
+import { account } from '@/contexts/MyContext';
+import axios from 'axios';
+import useWrapper from '@/hooks/useWrapper';
+import NavigationMenu from '../navigationmenu';
+
+const columns = [
+ { field: 'firstName', headerName: 'First Name', width: 200 },
+ { field: 'lastName', headerName: 'Last Name', width: 200 },
+ { field: 'email', headerName: 'Email', width: 200 },
+ { field: 'phone', headerName: 'Phone', width: 200 },
+ { field: 'numberOfAttributesAssigned', headerName: 'Attributes Assigned', width: 200 },
+ { field: 'numnerOfExtrasAssigned', headerName: 'Extras Assigned', width: 200 },
+ { field: 'addedAt', headerName: 'Added At', width: 200 },
+];
+
+export default function Registrants() {
+ const { participants, setParticipants, accountDetails } = useContext(account);
+ const [formData, setFormData] = useState({
+ firstName: '',
+ lastName: '',
+ email: '',
+ phone: '',
+ checkInKey: '',
+ });
+
+ //console.log("test",accountDetails);
+
+ const { isOpen, onOpen, onClose } = useDisclosure();
+ const router = useRouter();
+ const showAlert = useAlert();
+ const { orgId, eventId } = router.query;
+ // const { loading, get, post } = useFetch();
+ const { useGetQuery, usePostMutation } = useWrapper();
+
+ // const { accountDetails } = useContext(account);
+
+ const {
+ data,
+ status,
+ error,
+ isLoading: loading,
+ } = useGetQuery(
+ `/core/organizations/${orgId}/events/${eventId}/registrations`,
+ `/core/organizations/${orgId}/events/${eventId}/registrations`,
+ {},
+ {},
+ (data) => {
+ setParticipants(data.data.registrants || []);
+ },
+ );
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prevData) => ({ ...prevData, [name]: value }));
+ };
+ const [emailContent, setEmailContent] = useState('');
+ const { mutate: addParticipantsMutation } = usePostMutation(
+ `/core/organizations/${orgId}/events/${eventId}/participants`,
+ {},
+ {
+ onSuccess: (response) => {
+ const value = {
+ addedAt: response.data.newParticipant.createdAt,
+ id: response.data.newParticipant.id,
+ checkInKey: response.data.newParticipant.checkInKey,
+ email: response.data.newParticipant.email,
+ firstName: response.data.newParticipant.firstName,
+ lastName: response.data.newParticipant.lastName,
+ numberOfAttributesAssigned: 0,
+ numnerOfExtrasAssigned: 0,
+ phone: response.data.newParticipant.phone,
+ };
+ setParticipants((prevValue) => [...prevValue, value]);
+ showAlert({
+ title: 'Success',
+ description: 'Added participant!!',
+ status: 'success',
+ });
+ },
+ invalidatelKeys: [`/core/organizations/${orgId}/events/${eventId}/registrations`],
+ },
+ );
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ addParticipantsMutation({
+ firstName: formData.firstName,
+ lastName: formData.lastName,
+ attributes: [],
+ phone: formData.phone,
+ email: formData.email,
+ checkInKey: formData.checkInKey,
+ });
+ setFormData({
+ firstName: '',
+ lastName: '',
+ email: '',
+ phone: '',
+ checkInKey: '',
+ });
+ onClose();
+ };
+ const { isOpen: qrIsOpen, onOpen: qROnOpen, onClose: qROnClose } = useDisclosure();
+
+ const exportToCsv = () => {
+ const csvData = participants.map((participant) => ({
+ firstName: participant.firstName,
+ lastName: participant.lastName,
+ email: participant.email,
+ phone: participant.phone,
+ checkInKey: participant.checkInKey,
+ checkedIn: participant.checkedIn,
+ numberOfAttributesAssigned: participant.numberOfAttributesAssigned,
+ numberOfExtrasAssigned: participant.numberOfExtrasAssigned,
+ addedAt: participant.addedAt,
+ }));
+
+ return (
+
+
+ Export to CSV
+
+
+ );
+ };
+
+ return (
+
+
+ Add Participant
+
+ router.push(`/${orgId}/events/${eventId}/participants/new/upload-csv`)}
+ isLoading={loading}
+ >
+ Upload CSV
+
+ {exportToCsv()}
+ Send Emails with QR
+ >
+ }
+ debugInfo={participants}
+ >
+
+
+ {!loading && participants.length === 0 ? (
+
+
+ No participants
+
+
+ Add participants for the event to see details
+
+
+ ) : (
+ <>>
+ )}
+
+
+
+ );
+}
diff --git a/apps/web-admin/src/pages/[orgId]/events/index.jsx b/apps/web-admin/src/pages/[orgId]/events/index.jsx
index af89fb2b..fd9cac4a 100644
--- a/apps/web-admin/src/pages/[orgId]/events/index.jsx
+++ b/apps/web-admin/src/pages/[orgId]/events/index.jsx
@@ -156,7 +156,7 @@ export default function Events() {
const { isOpen, onOpen, onClose } = useDisclosure();
// const { loading, get } = useFetch();
const { useGetQuery } = useWrapper();
- const { accountDetails, setAccountDetails, allAccounts, setAllAccounts } = useContext(account);
+ const { accountDetails, setAccountDetails, setEventDetails } = useContext(account);
// console.log(accountDetails.Event);
const links = [
@@ -300,7 +300,10 @@ export default function Events() {
columns={columns}
rows={mergedEvents}
onRowClick={(row) => {
- router.push(`/${orgId}/events/${row.id}/participants`);
+ setEventDetails(row);
+ row.isShortlisting
+ ? router.push(`/${orgId}/events/${row.id}/registrants`)
+ : router.push(`/${orgId}/events/${row.id}/participants`);
}}
/>
{!loading && events.length === 0 ? (
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 95be7789..da7943f6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -124,7 +124,7 @@ importers:
version: 0.0.0(eslint@8.56.0)(typescript@5.7.2)
eslint-config-standard-with-typescript:
specifier: ^43.0.0
- version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0)(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2)
+ version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0))(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2)
eslint-plugin-import:
specifier: ^2.27.5
version: 2.31.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)
@@ -212,7 +212,7 @@ importers:
version: 0.0.0(eslint@8.56.0)(typescript@5.7.2)
eslint-config-standard-with-typescript:
specifier: ^43.0.0
- version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0)(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2)
+ version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0))(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2)
eslint-plugin-import:
specifier: ^2.27.5
version: 2.31.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)
@@ -13926,7 +13926,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-config-standard-with-typescript@43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0)(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2):
+ eslint-config-standard-with-typescript@43.0.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0))(eslint-plugin-n@16.6.2(eslint@8.56.0))(eslint-plugin-promise@6.6.0(eslint@8.56.0))(eslint@8.56.0)(typescript@5.7.2):
dependencies:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.0.0(eslint@8.56.0)(typescript@5.7.2))(eslint@8.56.0)(typescript@5.7.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.7.2)