diff --git a/apps/core-admin/src/controllers/attributes.ts b/apps/core-admin/src/controllers/attributes.ts index 0c5d9216..63fe034a 100644 --- a/apps/core-admin/src/controllers/attributes.ts +++ b/apps/core-admin/src/controllers/attributes.ts @@ -153,3 +153,75 @@ export const getAttributeParticipants = async (req: Request, res: Response) => { return res.status(500).json({ error: 'Something went wrong' }); } }; + +// Temporary controllers + +export const setPaymentStatus = async (req: Request, res: Response) => { + try { + const { orgId, eventId } = req?.params; + const { participantId, paymentStatus } = req?.body; + + if (paymentStatus !== 'yes' && paymentStatus !== 'no') { + return res.status(400).json({ error: 'Invalid payment status' }); + } + + const attribute = await prisma.attributes.findFirst({ + where: { + organizationId: orgId, + eventId: eventId, + name: 'Paid', + }, + }); + + if (!attribute) { + return res.status(404).json({ error: 'No attribute for payment status found' }); + } + + const participant = await prisma.participant.findFirst({ + where: { + id: participantId, + eventId, + organizationId: orgId, + }, + }); + + if (!participant) { + return res.status(404).json({ error: 'Participant not found' }); + } + + const participantAttribute = await prisma.participantAttributes.findFirst({ + where: { + participantId, + attributeId: attribute.id, + }, + }); + + if (!participantAttribute) { + return res.status(400).json({ error: 'Payment attribute not assigned to participant' }); + } + + if (participantAttribute.value === paymentStatus) { + return res + .status(400) + .json({ error: `Participant already payment status set as ${paymentStatus}` }); + } + + const updatedParticipantAttribute = await prisma.participantAttributes.update({ + where: { + id: participantAttribute.id, + }, + data: { + value: paymentStatus, + }, + }); + + if (!updatedParticipantAttribute) { + return res.status(500).json({ error: 'Failed to update payment status' }); + } + + return res.status(200).json({ updatedParticipantAttribute }); + } catch (err: any) { + console.error(err); + return res.status(500).json({ error: 'Something went wrong' }); + } +}; diff --git a/apps/core-admin/src/controllers/organizations.ts b/apps/core-admin/src/controllers/organizations.ts index 88342557..0dee77d9 100644 --- a/apps/core-admin/src/controllers/organizations.ts +++ b/apps/core-admin/src/controllers/organizations.ts @@ -5,26 +5,64 @@ import prisma from '../utils/database'; export const createNewOrganization = async (req: Request, res: Response) => { try { const userId = req?.auth?.payload?.sub; - const { id, name } = req.body; - //console.log(id, name); - const newOrganization = await prisma.organization.create({ - data: { - id, - name, - OrganizationUser: { - create: { - userId, - role: 'ADMIN', + const { id, name, email } = req.body; + console.log(id, name); + console.log(userId); + + const existingUser = await prisma.user.findUnique({ + where: { id: userId }, + }); + + if (!existingUser) { + // throw new Error(`User with ID ${userId} not found`); + + const newUser = await prisma.user.create({ + data: { + email: email, + id: userId, + }, + }); + if (!newUser) { + return res.status(500).json({ error: 'Something went wrong' }); + } + const newOrganization = await prisma.organization.create({ + data: { + id, + name, + OrganizationUser: { + create: { + userId: userId, + role: 'ADMIN', + }, }, }, - }, - }); + }); - if (!newOrganization) { - return res.status(500).json({ error: 'Something went wrong' }); - } + if (!newOrganization) { + return res.status(500).json({ error: 'Something went wrong' }); + } - return res.status(200).json(newOrganization); + return res.status(200).json(newOrganization); + } else { + const newOrganization = await prisma.organization.create({ + data: { + id, + name, + OrganizationUser: { + create: { + userId: userId, + role: 'ADMIN', + }, + }, + }, + }); + + if (!newOrganization) { + return res.status(500).json({ error: 'Something went wrong' }); + } + + return res.status(200).json(newOrganization); + } } catch (err: any) { console.error(err); if (err.code === 'P2002') { diff --git a/apps/core-admin/src/controllers/participants.ts b/apps/core-admin/src/controllers/participants.ts index a84583c1..717d7d6d 100644 --- a/apps/core-admin/src/controllers/participants.ts +++ b/apps/core-admin/src/controllers/participants.ts @@ -299,6 +299,7 @@ export const getAllParticipantsCheckInDetails = async (req: Request, res: Respon eventId, }, include: { + participantAttributes: true, participantCheckIn: { select: { id: true, @@ -322,6 +323,9 @@ export const getAllParticipantsCheckInDetails = async (req: Request, res: Respon phone: participant.phone, email: participant.email, checkInKey: participant.checkInKey, + paymentStatus: participant.participantAttributes.filter( + (attr: any) => attr.value === 'yes' || attr.value === 'no', + )[0].value, checkIn: { status: participant.participantCheckIn.length > 0 ? true : false, checkedInAt: diff --git a/apps/core-admin/src/routes.ts b/apps/core-admin/src/routes.ts index 55e2f64d..253708cf 100644 --- a/apps/core-admin/src/routes.ts +++ b/apps/core-admin/src/routes.ts @@ -27,6 +27,7 @@ import { getAllAttributes, getAttributeById, getAttributeParticipants, + setPaymentStatus, } from './controllers/attributes'; import { fetchAccountDetails, myCredential, updateAccountDetails } from './controllers/users'; import { validateOrganizationUser, validateOrganizationAdmin } from './middlewares/authorization'; @@ -111,6 +112,9 @@ router.put( updateParticipantAttribute, ); +// Temp routes +router.post('/organizations/:orgId/events/:eventId/participants/payment-status', setPaymentStatus); + router.post('/organizations/update', updateOrganizationDetails); //ajay router.get('/organizations/:orgId/events/:eventId/attributes', getAllAttributes); // done diff --git a/apps/web-admin/src/components/DataDisplay.jsx b/apps/web-admin/src/components/DataDisplay.jsx index 55ae1c5b..546cba6f 100644 --- a/apps/web-admin/src/components/DataDisplay.jsx +++ b/apps/web-admin/src/components/DataDisplay.jsx @@ -189,6 +189,17 @@ export default function DataDisplay({ Open + ) : column.field == 'paymentStatus' ? ( + + {row[column.field]} + { + e.stopPropagation(); + column.togglePaymentStatus(row.id, e.target.checked ? 'yes' : 'no'); + }} + /> + ) : ( // {row[column.field]} diff --git a/apps/web-admin/src/components/ProtectedRoute.jsx b/apps/web-admin/src/components/ProtectedRoute.jsx index a5b219f5..b4b7ef6a 100644 --- a/apps/web-admin/src/components/ProtectedRoute.jsx +++ b/apps/web-admin/src/components/ProtectedRoute.jsx @@ -54,7 +54,8 @@ export const ProtectedRoute = ({ children }) => { async function postOrg() { const id = user.sub.substring(6); const name = user.nickname; - const response = await post(`/core/organizations`, {}, { id, name }); + const email = user.email; + const response = await post(`/core/organizations`, {}, { id, name, email }); if (response) { const { data, mystatus } = response; //console.log('created'); @@ -77,7 +78,12 @@ export const ProtectedRoute = ({ children }) => { async function checkOrg() { let myResponse = await get('/core/users/mycreds'); // //console.log(myResponse.data.data); - if (myResponse && myResponse.status === 200) { + if ( + myResponse && + myResponse.status === 200 && + myResponse.data.data && + myResponse.data.data.length !== 0 + ) { console.log('Hello world'); setAllAccounts( myResponse.data.data.map((value) => ({ @@ -95,7 +101,7 @@ export const ProtectedRoute = ({ children }) => { }); //console.log('final: ', data); setAccountDetails(data[0]); - router.replace(`/${data[0].orgId}/events`); + // router.replace(`/${data[0].orgId}/events`); return data; }); } 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 1fc53bbc..a750da8a 100644 --- a/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx +++ b/apps/web-admin/src/pages/[orgId]/events/[eventId]/navigationmenu.jsx @@ -27,6 +27,10 @@ const NavigationMenu = ({ orgId, eventId, navButton }) => { name: 'Participants Check-in Details', path: `/${orgId}/events/${eventId}/participants/check-in`, }, + { + name: 'Participants Payment Status', + path: `/${orgId}/events/${eventId}/paymentstatus`, + }, { name: 'Attributes Details', path: `/${orgId}/events/${eventId}/attributes`, diff --git a/apps/web-admin/src/pages/[orgId]/events/[eventId]/participants/new/upload-csv/index.jsx b/apps/web-admin/src/pages/[orgId]/events/[eventId]/participants/new/upload-csv/index.jsx index 989daac1..adb134db 100644 --- a/apps/web-admin/src/pages/[orgId]/events/[eventId]/participants/new/upload-csv/index.jsx +++ b/apps/web-admin/src/pages/[orgId]/events/[eventId]/participants/new/upload-csv/index.jsx @@ -116,8 +116,7 @@ export default function NewParticipantByCSVUpload() { if (extraColumns.length > 0) { showAlert({ title: 'Info', - description: - 'Extra columns detected. Using _ for attributes and & for check-in extras.', + description: 'Extra columns detected. Using _ for attributes and & for extras.', status: 'info', duration: 5000, }); @@ -267,8 +266,7 @@ export default function NewParticipantByCSVUpload() { fontSize="lg" color={colorMode === 'light' ? 'gray.600' : 'gray.100'} > - Prefix extra attributes with underscore (_) and check-in attributes with ampersand - (&) + Prefix Attributes with underscore ( _ ) and Extra Details with ampersand ( & ) diff --git a/apps/web-admin/src/pages/[orgId]/events/[eventId]/paymentstatus/index.jsx b/apps/web-admin/src/pages/[orgId]/events/[eventId]/paymentstatus/index.jsx new file mode 100644 index 00000000..86559bdf --- /dev/null +++ b/apps/web-admin/src/pages/[orgId]/events/[eventId]/paymentstatus/index.jsx @@ -0,0 +1,183 @@ +import { useRouter } from 'next/router'; +import { useState } from 'react'; +import { StyledBox, StyledButton, StyledText } from '@/components/ui/StyledComponents'; +import DashboardLayout from '@/layouts/DashboardLayout'; +import DataDisplay from '@/components/DataDisplay'; +import { useAlert } from '@/hooks/useAlert'; +import useWrapper from '@/hooks/useWrapper'; +import NavigationMenu from '../navigationmenu'; + +import { useDisclosure } from '@chakra-ui/react'; +import CheckInParticipantWithMultiScanner from '@/components/modals/MultiStageScanner/index'; +import CheckInParticipant from '@/components/modals/Check-inParticipant/index'; +import CheckInParticipantWithScanner from '@/components/modals/Check-in-Scanner/index'; +import CheckOutParticipant from '@/components/modals/Check-OutParticipant/index'; +import CheckOutParticipantWithScanner from '@/components/modals/Check-Out-Scanner/index'; + +export default function ParticipantsCheckIn() { + const router = useRouter(); + const showAlert = useAlert(); + const { orgId, eventId } = router.query; + const [participantsCheckIn, setParticipantsCheckIn] = useState([]); + const { useGetQuery, usePostMutation } = useWrapper(); + + const { + data, + status, + error, + isFetching: loading, + } = useGetQuery( + `/core/organizations/${orgId}/events/${eventId}/participants/check-in`, + `/core/organizations/${orgId}/events/${eventId}/participants/check-in`, + {}, + {}, + (data) => { + setParticipantsCheckIn(data.data.participantsCheckIn || []); + }, + ); + + const { + isOpen: isMultiScannerModalOpen, + onOpen: onMultiScannerModalOpen, + onClose: onMultiScannerModalClose, + } = useDisclosure(); + const { + isOpen: isCheckInModalOpen, + onOpen: onCheckInModalOpen, + onClose: onCheckInModalClose, + } = useDisclosure(); + const { + isOpen: isScanner1ModalOpen, + onOpen: onScanner1ModalOpen, + onClose: onScanner1ModalClose, + } = useDisclosure(); + const { + isOpen: isScanner2ModalOpen, + onOpen: onScanner2ModalOpen, + onClose: onScanner2ModalClose, + } = useDisclosure(); + const { + isOpen: isCheckOutModalOpen, + onOpen: onCheckOutModalOpen, + onClose: onCheckOutModalClose, + } = useDisclosure(); + + const { mutate: handlePaymentStatusMutation } = usePostMutation( + `/core/organizations/${orgId}/events/${eventId}/participants/payment-status`, + {}, + { + onSuccess: (response) => { + showAlert({ + title: 'Success', + description: 'Payment status for participant has been updated successfully.', + status: 'success', + }); + }, + onError: (error) => { + showAlert({ + title: 'Error', + description: error.message, + status: 'error', + }); + }, + }, + ); + + 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: 'checkInKey', headerName: 'Check In Key', width: 200 }, + { + field: 'paymentStatus', + headerName: 'Payment Status', + width: 150, + togglePaymentStatus: (id, status) => { + handlePaymentStatusMutation({ + participantId: id, + paymentStatus: status, + }); + setParticipantsCheckIn((prevParticipants) => + prevParticipants.map((participant) => + participant.id === id ? { ...participant, paymentStatus: status } : participant, + ), + ); + }, + }, + { + field: 'checkedInAt', + headerName: 'Check-In At', + width: 200, + valueGetter: (params) => params.row?.checkIn?.checkedInAt || 'Not Checked In', + }, + { + field: 'checkedInByEmail', + headerName: 'Checked In By', + width: 200, + valueGetter: (params) => params.row?.checkIn?.checkedInByEmail, + }, + ]; + + return ( + + + + Multi-Stage Scanner + + + Check-In Participant + + + Open Scanner + + + Check-Out Participant + + + Open Scanner + + + } + /> + + { + // router.push(`/${orgId}/events/${eventId}/participants/${row.id}`); + // }} + /> + + {!loading && participantsCheckIn.length === 0 ? ( + + + No participants checked-in + + + Add details about the checked-in participants + + + ) : ( + <> + )} + + + + + + + ); +}