Skip to content

Commit c9f618d

Browse files
committed
feat: add guest group management for sub-events with new routes and service functions
1 parent 67959d0 commit c9f618d

File tree

4 files changed

+534
-21
lines changed

4 files changed

+534
-21
lines changed

prisma/schema.prisma

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,20 @@ model SubEvent {
207207
208208
guests String[]
209209
messages String[]
210+
211+
// Add this relation
212+
guestGroups SubEventGuestGroup[]
213+
}
214+
215+
// Add this new model
216+
model SubEventGuestGroup {
217+
sub_event_id String
218+
guest_group_id String
219+
220+
subEvent SubEvent @relation(fields: [sub_event_id], references: [id], onDelete: Cascade)
221+
guestGroup GuestGroup @relation(fields: [guest_group_id], references: [id], onDelete: Cascade)
222+
223+
@@id([sub_event_id, guest_group_id])
210224
}
211225

212226
model Guest {
@@ -248,12 +262,13 @@ model GuestGroup {
248262
name String
249263
createdBy String
250264
251-
creator User @relation("CreatedGuestGroups", fields: [createdBy], references: [id])
265+
creator User @relation("CreatedGuestGroups", fields: [createdBy], references: [id])
252266
members GuestGroupUsers[]
253267
guests Guest[]
254268
inviteLinks InviteLink[]
255269
invites Invite[]
256270
events EventGuestGroup[]
271+
subEvents SubEventGuestGroup[] // Add this line
257272
}
258273

259274
model EventGuestGroup {

src/routes/subEventRoutes.ts

Lines changed: 142 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import express, { Request, Response } from 'express';
22
import {
33
createSubEvent,
44
getSubEvents,
5+
getSubEventsForUser,
56
getSubEvent,
67
updateSubEvent,
78
deleteSubEvent,
89
addGuestToSubEvent,
910
removeGuestFromSubEvent,
1011
canManageSubEvent,
11-
canManageEventSubEvents
12+
canManageEventSubEvents,
13+
addGuestGroupToSubEvent,
14+
removeGuestGroupFromSubEvent,
15+
getSubEventGuestGroups
1216
} from '../services/subEventService';
1317
import { verifyIdToken } from '../middleware/verifyIdToken';
1418
import { parseMultipartForm, uploadFilesToSupabase } from '../lib/fileUpload';
@@ -33,8 +37,7 @@ router.post('/', verifyIdToken, async (req: Request, res: Response) => {
3337
address,
3438
start_date_time,
3539
end_date_time,
36-
invite_message,
37-
guests
40+
invite_message
3841
} = fields;
3942

4043
if (!title || !location || !address || !start_date_time || !end_date_time) {
@@ -62,9 +65,8 @@ router.post('/', verifyIdToken, async (req: Request, res: Response) => {
6265
start_date_time,
6366
end_date_time,
6467
invite_message,
65-
image,
66-
guests: guests ? guests.split(',') : [],
67-
});
68+
image
69+
});
6870

6971
if (!result.success) {
7072
res.status(400).json({ message: result.error });
@@ -81,7 +83,7 @@ router.post('/', verifyIdToken, async (req: Request, res: Response) => {
8183
}
8284
});
8385

84-
// Get all sub-events for an event
86+
// Get all sub-events for an event (filtered by user role)
8587
router.get('/', verifyIdToken, async (req: Request, res: Response) => {
8688
try {
8789
const { eventId } = req.params;
@@ -91,22 +93,16 @@ router.get('/', verifyIdToken, async (req: Request, res: Response) => {
9193
return;
9294
}
9395

94-
// Check if user can manage sub-events for this event
95-
// const canManage = await canManageEventSubEvents(userId, eventId);
96-
// if (!canManage) {
97-
// res.status(403).json({ message: 'Only event hosts and co-hosts can view sub-events' });
98-
// return;
99-
// }
100-
101-
const result = await getSubEvents(eventId);
96+
const result = await getSubEventsForUser(eventId, userId);
10297

10398
if (!result.success) {
10499
res.status(400).json({ message: result.error });
105100
return;
106101
}
107102

108103
res.status(200).json({
109-
subEvents: result.subEvents
104+
subEvents: result.subEvents,
105+
role: result.role
110106
});
111107
} catch (error) {
112108
console.error(error);
@@ -315,4 +311,134 @@ router.delete('/:subEventId/guests/:guestId', verifyIdToken, async (req: Request
315311
}
316312
});
317313

314+
// Get guest groups for a sub-event
315+
router.get('/:subEventId/guest-groups', verifyIdToken, async (req: Request, res: Response) => {
316+
try {
317+
const { eventId, subEventId } = req.params;
318+
const userId = req.userId;
319+
if (!userId) {
320+
res.status(401).json({ message: 'Unauthorized' });
321+
return;
322+
}
323+
324+
// Check if user can manage this sub-event
325+
const canManage = await canManageSubEvent(userId, subEventId);
326+
if (!canManage) {
327+
res.status(403).json({ message: 'Only event hosts and co-hosts can view sub-event guest groups' });
328+
return;
329+
}
330+
331+
const result = await getSubEventGuestGroups(subEventId);
332+
333+
if (!result.success) {
334+
res.status(400).json({ message: result.error });
335+
return;
336+
}
337+
338+
res.status(200).json({
339+
guestGroups: result.guestGroups
340+
});
341+
} catch (error) {
342+
console.error(error);
343+
res.status(500).json({ message: 'Internal Server Error' });
344+
}
345+
});
346+
347+
// Add guest group to sub-event
348+
router.post('/:subEventId/guest-groups', verifyIdToken, async (req: Request, res: Response) => {
349+
try {
350+
const { eventId, subEventId } = req.params;
351+
const userId = req.userId;
352+
if (!userId) {
353+
res.status(401).json({ message: 'Unauthorized' });
354+
return;
355+
}
356+
const { guestGroupId, guestGroupIds } = req.body;
357+
358+
// Support both single guestGroupId and multiple guestGroupIds
359+
let groupIds: string[] = [];
360+
if (guestGroupId) {
361+
groupIds = [guestGroupId];
362+
} else if (guestGroupIds && Array.isArray(guestGroupIds)) {
363+
groupIds = guestGroupIds;
364+
} else {
365+
res.status(400).json({ message: 'Either guestGroupId or guestGroupIds array is required' });
366+
return;
367+
}
368+
369+
if (groupIds.length === 0) {
370+
res.status(400).json({ message: 'At least one guest group ID is required' });
371+
return;
372+
}
373+
374+
// Check if user can manage this sub-event
375+
const canManage = await canManageSubEvent(userId, subEventId);
376+
if (!canManage) {
377+
res.status(403).json({ message: 'Only event hosts and co-hosts can add guest groups to sub-events' });
378+
return;
379+
}
380+
381+
// Add all guest groups
382+
const results = await Promise.all(
383+
groupIds.map(groupId => addGuestGroupToSubEvent(subEventId, groupId))
384+
);
385+
386+
// Check if any failed
387+
const failures = results.filter(r => !r.success);
388+
const successes = results.filter(r => r.success);
389+
390+
if (failures.length > 0 && successes.length === 0) {
391+
res.status(400).json({
392+
message: 'Failed to add all guest groups',
393+
errors: failures.map(f => f.error)
394+
});
395+
return;
396+
}
397+
398+
res.status(200).json({
399+
message: `Successfully added ${successes.length} guest group(s) to sub-event`,
400+
addedCount: successes.length,
401+
failedCount: failures.length,
402+
results: results
403+
});
404+
} catch (error) {
405+
console.error(error);
406+
res.status(500).json({ message: 'Internal Server Error' });
407+
}
408+
});
409+
410+
// Remove guest group from sub-event
411+
router.delete('/:subEventId/guest-groups/:guestGroupId', verifyIdToken, async (req: Request, res: Response) => {
412+
try {
413+
const { eventId, subEventId, guestGroupId } = req.params;
414+
const userId = req.userId;
415+
if (!userId) {
416+
res.status(401).json({ message: 'Unauthorized' });
417+
return;
418+
}
419+
420+
// Check if user can manage this sub-event
421+
const canManage = await canManageSubEvent(userId, subEventId);
422+
if (!canManage) {
423+
res.status(403).json({ message: 'Only event hosts and co-hosts can remove guest groups from sub-events' });
424+
return;
425+
}
426+
427+
const result = await removeGuestGroupFromSubEvent(subEventId, guestGroupId);
428+
429+
if (!result.success) {
430+
res.status(400).json({ message: result.error });
431+
return;
432+
}
433+
434+
res.status(200).json({
435+
message: result.message,
436+
subEvent: result.subEvent
437+
});
438+
} catch (error) {
439+
console.error(error);
440+
res.status(500).json({ message: 'Internal Server Error' });
441+
}
442+
});
443+
318444
export default router;

src/services/inviteService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ export const submitGroupRsvp = async (
334334
...(data.pickup_location && { pickup_location: data.pickup_location }),
335335
...(data.dropoff_date_time && { dropoff_date_time: data.dropoff_date_time }),
336336
...(data.dropoff_location && { dropoff_location: data.dropoff_location }),
337-
...(data.count && { count: data.count }),
337+
...(data.count !== undefined && { count: data.count }),
338338
},
339339
include: {
340340
user: {
@@ -442,7 +442,7 @@ export const submitGroupRsvp = async (
442442
...(data.pickup_location && { pickup_location: data.pickup_location }),
443443
...(data.dropoff_date_time && { dropoff_date_time: data.dropoff_date_time }),
444444
...(data.dropoff_location && { dropoff_location: data.dropoff_location }),
445-
...(data.count && { count: data.count }),
445+
...(data.count !== undefined && { count: data.count }),
446446
},
447447
include: {
448448
event: {

0 commit comments

Comments
 (0)