diff --git a/backend/src/routes/matches.js b/backend/src/routes/matches.js index 1a0cfcf..a035ff6 100644 --- a/backend/src/routes/matches.js +++ b/backend/src/routes/matches.js @@ -177,15 +177,7 @@ router.get('/', authenticate, async (req, res, next) => { const userId = req.user.id; const { eventSlug, status } = req.query; - // Build where clause - const where = { - OR: [ - { user1Id: userId }, - { user2Id: userId }, - ], - }; - - // Filter by event if provided + let eventId = null; if (eventSlug) { const event = await prisma.event.findUnique({ where: { slug: eventSlug }, @@ -199,17 +191,28 @@ router.get('/', authenticate, async (req, res, next) => { }); } - where.eventId = event.id; + eventId = event.id; + } + + // Build where clause for matches + const matchWhere = { + OR: [ + { user1Id: userId }, + { user2Id: userId }, + ], + }; + + if (eventId) { + matchWhere.eventId = eventId; } - // Filter by status if provided if (status) { - where.status = status; + matchWhere.status = status; } - // Fetch matches + // Fetch matches (manual match requests) const matches = await prisma.match.findMany({ - where, + where: matchWhere, include: { user1: { select: { @@ -250,7 +253,85 @@ router.get('/', authenticate, async (req, res, next) => { }, }); - // Transform matches to include partner info + // Fetch recording suggestions (auto matches from matching algorithm) + // Get user's heats first + const userHeats = await prisma.eventUserHeat.findMany({ + where: { + userId: userId, + ...(eventId ? { eventId } : {}), + }, + select: { + id: true, + eventId: true, + }, + }); + + const heatIds = userHeats.map(h => h.id); + + // Fetch suggestions where user is dancer (to be recorded) + const suggestionsAsDancer = await prisma.recordingSuggestion.findMany({ + where: { + heatId: { in: heatIds }, + ...(status ? { status } : {}), + }, + include: { + recorder: { + select: { + id: true, + username: true, + avatar: true, + firstName: true, + lastName: true, + }, + }, + event: { + select: { + id: true, + slug: true, + name: true, + location: true, + startDate: true, + endDate: true, + }, + }, + }, + }); + + // Fetch suggestions where user is recorder (recording others) + const suggestionsAsRecorder = await prisma.recordingSuggestion.findMany({ + where: { + recorderId: userId, + ...(eventId ? { eventId } : {}), + ...(status ? { status } : {}), + }, + include: { + heat: { + include: { + user: { + select: { + id: true, + username: true, + avatar: true, + firstName: true, + lastName: true, + }, + }, + }, + }, + event: { + select: { + id: true, + slug: true, + name: true, + location: true, + startDate: true, + endDate: true, + }, + }, + }, + }); + + // Transform matches to include partner info and type const transformedMatches = matches.map(match => { const isUser1 = match.user1Id === userId; const partner = isUser1 ? match.user2 : match.user1; @@ -259,6 +340,7 @@ router.get('/', authenticate, async (req, res, next) => { return { id: match.id, slug: match.slug, + type: 'manual', partner: { id: partner.id, username: partner.username, @@ -274,10 +356,60 @@ router.get('/', authenticate, async (req, res, next) => { }; }); + // Transform recording suggestions to match format + const transformedSuggestionsAsDancer = suggestionsAsDancer + .filter(s => s.recorder) // Only include if recorder exists + .map(suggestion => ({ + id: `suggestion-${suggestion.id}`, + slug: null, + type: 'auto', + partner: { + id: suggestion.recorder.id, + username: suggestion.recorder.username, + avatar: suggestion.recorder.avatar, + firstName: suggestion.recorder.firstName, + lastName: suggestion.recorder.lastName, + }, + event: suggestion.event, + status: suggestion.status, + roomId: null, + isInitiator: false, + createdAt: suggestion.createdAt, + suggestionId: suggestion.id, + })); + + const transformedSuggestionsAsRecorder = suggestionsAsRecorder + .filter(s => s.heat?.user) // Only include if dancer exists + .map(suggestion => ({ + id: `suggestion-${suggestion.id}`, + slug: null, + type: 'auto', + partner: { + id: suggestion.heat.user.id, + username: suggestion.heat.user.username, + avatar: suggestion.heat.user.avatar, + firstName: suggestion.heat.user.firstName, + lastName: suggestion.heat.user.lastName, + }, + event: suggestion.event, + status: suggestion.status, + roomId: null, + isInitiator: true, + createdAt: suggestion.createdAt, + suggestionId: suggestion.id, + })); + + // Combine all and sort by createdAt + const allItems = [ + ...transformedMatches, + ...transformedSuggestionsAsDancer, + ...transformedSuggestionsAsRecorder, + ].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + res.json({ success: true, - count: transformedMatches.length, - data: transformedMatches, + count: allItems.length, + data: allItems, }); } catch (error) { next(error); diff --git a/frontend/src/components/matches/MatchCard.jsx b/frontend/src/components/matches/MatchCard.jsx index ca18f7e..a5b4c53 100644 --- a/frontend/src/components/matches/MatchCard.jsx +++ b/frontend/src/components/matches/MatchCard.jsx @@ -47,6 +47,15 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {