Skip to content

Commit

Permalink
feat: UUID validator middleware and edit Participant (#328)
Browse files Browse the repository at this point in the history
* validateUUID

* fix UUID checks

* feat - edit participant

* Revert "feat - edit participant"

This reverts commit 1e38f17.

* Revert "Revert "feat - edit participant""

This reverts commit 86b99e9.

* participant attribute display

* Removed console.log
  • Loading branch information
vaidyanath-b authored Mar 1, 2024
1 parent 28ca086 commit 6a47211
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 10 deletions.
2 changes: 2 additions & 0 deletions apps/core-admin/src/controllers/attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export const getAttributeById = async (req: Request, res: Response) => {
addedAt: participantAttribute.createdAt,
firstName: participantAttribute.participant.firstName,
lastName: participantAttribute.participant.lastName,
email: participantAttribute.participant.email,
phone: participantAttribute.participant.phone,
};
},
),
Expand Down
31 changes: 29 additions & 2 deletions apps/core-admin/src/controllers/participants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export const addNewParticipant = async (req: Request, res: Response) => {
export const editParticipant = async (req: Request, res: Response) => {
try {
const { orgId, eventId, participantId } = req?.params;
const { firstName, lastName, phone, email, checkInKey } = req?.body;
const { firstName, lastName, phone, email, checkInKey, attributes } = req?.body;

if (!firstName || !lastName) {
return res.status(400).json({ error: 'First name and last name are required' });
Expand All @@ -196,10 +196,37 @@ export const editParticipant = async (req: Request, res: Response) => {
},
});

const awaitAttributes = attributes?.map(async (attribute: any) => {
try {
const participantAttribute = await prisma.participantAttributes.updateMany({
where: {
attributeId: attribute.id,
participantId: participantId,
},
data: {
value: attribute.value,
},
});
if (participantAttribute.count === 0) {
const newParticipantAttribute = await prisma.participantAttributes.create({
data: {
participantId,
attributeId: attribute.id,
value: attribute.value,
},
});
return newParticipantAttribute;
}
return participantAttribute;
} catch (err: any) {
console.error(err);
return res.status(500).json({ error: 'Something went wrong' });
}
});

if (!updatedParticipant) {
return res.status(500).json({ error: 'Something went wrong' });
}

return res.status(200).json({ updatedParticipant });
} catch (err: any) {
console.error(err);
Expand Down
6 changes: 6 additions & 0 deletions apps/core-admin/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ import {
import { fetchAccountDetails, updateAccountDetails } from './controllers/users';
import { validateOrganizationUser, validateOrganizationAdmin } from './middlewares/authorization';
import { addNewExtra, checkInExtra, getAllExtras, getExtraById } from './controllers/extras';
import { validateUUID } from './middlewares/validateParams';

const router: Router = express.Router();

router.param('eventId', validateUUID);
router.param('attributeId', validateUUID);
router.param('participantId', validateUUID);
router.param('extraId', validateUUID);

router.get('/', (req: any, res: any) => {
try {
return res.send('Hello World!');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';

import { Button, FormControl, FormLabel, Input } from '@chakra-ui/react';

import DashboardLayout from '@/layouts/DashboardLayout';

import { useAlert } from '@/hooks/useAlert';
import { useFetch } from '@/hooks/useFetch';

export default function EditParticipant() {
const { loading, put, get } = useFetch();
const showAlert = useAlert();

const router = useRouter();
const { orgId, eventId, participantId } = router.query;

const [participant, setParticipant] = useState(null);
const [attributes, setAttributes] = useState([]);
const [attributeValues, setAttributeValues] = useState([]);

const handleSubmit = async (e) => {
e.preventDefault();

const { data, status } = await put(
`/core/organizations/${orgId}/events/${eventId}/participants/${participantId}`,
{},
{
firstName: participant.firstName,
lastName: participant.lastName,
email: participant.email,
phone: participant.phone,
checkInKey: participant.checkInKey,
checkedIn: participant.checkedIn,
attributes: attributeValues,
},
);

if (status === 200) {
showAlert({
title: 'Success',
description: 'Participant has been updated successfully.',
status: 'success',
});
router.push(`/organizations/${orgId}/events/${eventId}/participants`);
} else {
showAlert({
title: 'Error',
description: data.error,
status: 'error',
});
}
};

useEffect(() => {
const fetchParticipant = async () => {
const { data, status } = await get(
`/core/organizations/${orgId}/events/${eventId}/participants/${participantId}`,
);

if (status === 200) {
setParticipant(data.participant);
setAttributeValues(data.participant.attributes);
}
};
}, [orgId, eventId, participantId]);

if (!participant) {
return null;
}

return (
participant && (
<DashboardLayout
pageTitle="Edit Participant"
previousPage={`/organizations/${orgId}/events/${eventId}/participants`}
style={{ overflow: 'auto' }}
>
<form onSubmit={handleSubmit}>
<FormControl isRequired my={2}>
<FormLabel>First Name</FormLabel>
<Input
type="text"
name="firstName"
value={participant.firstName}
onChange={(e) => {
setParticipant({ ...participant, firstName: e.target.value });
}}
/>
</FormControl>
<FormControl isRequired my={2}>
<FormLabel>Last Name</FormLabel>
<Input
type="text"
name="lastName"
value={participant.lastName}
onChange={(e) => {
setParticipant({ ...participant, lastName: e.target.value });
}}
/>
</FormControl>
<FormControl my={2}>
<FormLabel>Check In</FormLabel>
<Input
type="text"
name="checkInKey"
value={participant.checkInKey}
onChange={(e) => {
setParticipant({ ...participant, checkInKey: e.target.value });
}}
/>
</FormControl>
<FormControl my={2}>
<FormLabel>mail</FormLabel>
<Input
type="text"
name="email"
value={participant.email}
onChange={(e) => {
setParticipant({ ...participant, email: e.target.value });
}}
/>
</FormControl>
<FormControl my={2}>
<FormLabel>Phone</FormLabel>
<Input
type="text"
name="phone"
value={participant.phone}
onChange={(e) => {
setParticipant({ ...participant, phone: e.target.value });
}}
/>
</FormControl>

{attributeValues.map((attribute) => (
<FormControl my={2} key={attribute.id}>
<FormLabel>{attribute.name}</FormLabel>
<Input
type="text"
name={attribute.name}
value={attributeValues.find((value) => value.id === attribute.id)?.value || ''}
onChange={(e) => {
setAttributeValues((prev) => {
const index = prev.findIndex((value) => value.id === attribute.id);
if (index === -1) {
return [
...prev,
{
id: attribute.id,
value: e.target.value,
},
];
}
return prev.map((value) => {
if (value.id === attribute.id) {
return {
...value,
value: e.target.value,
};
}
return value;
});
});
}}
/>
</FormControl>
))}

{/* Add more form fields as needed */}
<Button type="submit" width="100%" my="4" isLoading={loading} loadingText="Please Wait">
Update
</Button>
</form>
</DashboardLayout>
)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import DataDisplay from '@/components/DataDisplay';

import { useAlert } from '@/hooks/useAlert';
import { useFetch } from '@/hooks/useFetch';
import { EditIcon, ViewIcon } from '@chakra-ui/icons';

const columns = [
{ field: 'firstName', headerName: 'First Name', width: 200, editable: true },
Expand All @@ -23,6 +24,53 @@ const columns = [
];

export default function Participants() {
const columns = [
{ field: 'firstName', headerName: 'First Name', width: 125 },
{ field: 'lastName', headerName: 'Last Name', width: 125 },
{
field: 'edit',
headerName: '',
sortable: false,
width: 50,
renderCell: (params) => (
<Button
variant="contained"
color="primary"
onClick={() => {
router.push(
`/organizations/${orgId}/events/${eventId}/participants/${params.row.id}/edit`,
);
}}
>
<EditIcon />
</Button>
),
},
{
field: 'view',
headerName: '',
sortable: false,
width: 50,
renderCell: (params) => (
<Button
variant="contained"
color="primary"
onClick={() => {
router.push(`/organizations/${orgId}/events/${eventId}/participants/${params.row.id}`);
}}
>
<ViewIcon />
</Button>
),
},
{ field: 'email', headerName: 'Email', width: 200 },
{ field: 'phone', headerName: 'Phone', width: 125 },
{ field: 'checkInKey', headerName: 'Check In Key', width: 125 },
{ field: 'checkedIn', headerName: 'CheckedIn', width: 125 },
{ field: 'numberOfAttributesAssigned', headerName: 'Attributes Assigned', width: 125 },
{ field: 'numnerOfExtrasAssigned', headerName: 'Extras Assigned', width: 125 },
{ field: 'addedAt', headerName: 'Added At', width: 125 },
];
const router = useRouter();
const showAlert = useAlert();

Expand Down Expand Up @@ -75,14 +123,7 @@ export default function Participants() {
}
debugInfo={participants}
>
<DataDisplay
loading={loading}
rows={participants}
columns={columns}
onRowClick={(row) => {
router.push(`/organizations/${orgId}/events/${eventId}/participants/${row.id}`);
}}
/>
<DataDisplay loading={loading} rows={participants} columns={columns} />
</DashboardLayout>
);
}

0 comments on commit 6a47211

Please sign in to comment.