diff --git a/backend/src/socket/index.js b/backend/src/socket/index.js index cef1966..9713dbc 100644 --- a/backend/src/socket/index.js +++ b/backend/src/socket/index.js @@ -69,26 +69,27 @@ function initializeSocket(httpServer) { const eventId = event.id; const roomName = `event_${eventId}`; - socket.join(roomName); - socket.currentEventRoom = roomName; - socket.currentEventId = eventId; - socket.currentEventSlug = slug; - // Record event participation in database - await prisma.eventParticipant.upsert({ + // Verify that user has checked in to this event + const participant = await prisma.eventParticipant.findUnique({ where: { userId_eventId: { userId: socket.user.id, eventId: eventId, }, }, - update: {}, // Don't update anything if already exists - create: { - userId: socket.user.id, - eventId: eventId, - }, }); + if (!participant) { + socket.emit('error', { message: 'You must check in to this event first' }); + return; + } + + socket.join(roomName); + socket.currentEventRoom = roomName; + socket.currentEventId = eventId; + socket.currentEventSlug = slug; + // Add user to active users if (!activeUsers.has(eventId)) { activeUsers.set(eventId, new Set()); diff --git a/frontend/src/pages/EventChatPage.jsx b/frontend/src/pages/EventChatPage.jsx index 3cba8da..49d09ae 100644 --- a/frontend/src/pages/EventChatPage.jsx +++ b/frontend/src/pages/EventChatPage.jsx @@ -1,8 +1,8 @@ import { useState, useRef, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; +import { useParams, useNavigate, Link } from 'react-router-dom'; import Layout from '../components/layout/Layout'; import { useAuth } from '../contexts/AuthContext'; -import { Send, UserPlus, Loader2, LogOut, AlertTriangle } from 'lucide-react'; +import { Send, UserPlus, Loader2, LogOut, AlertTriangle, QrCode } from 'lucide-react'; import { connectSocket, disconnectSocket, getSocket } from '../services/socket'; import { eventsAPI } from '../services/api'; @@ -11,6 +11,7 @@ const EventChatPage = () => { const { user } = useAuth(); const navigate = useNavigate(); const [event, setEvent] = useState(null); + const [isParticipant, setIsParticipant] = useState(false); const [loading, setLoading] = useState(true); const [messages, setMessages] = useState([]); const [newMessage, setNewMessage] = useState(''); @@ -27,16 +28,27 @@ const EventChatPage = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; - // Fetch event data + // Fetch event data and check participation useEffect(() => { const fetchEvent = async () => { try { setLoading(true); - const data = await eventsAPI.getBySlug(slug); - setEvent(data); + + // Get all events with participation info + const allEvents = await eventsAPI.getAll(); + const eventData = allEvents.find(e => e.slug === slug); + + if (eventData) { + setEvent(eventData); + setIsParticipant(eventData.isJoined); + } else { + setEvent(null); + setIsParticipant(false); + } } catch (err) { console.error('Error loading event:', err); setEvent(null); + setIsParticipant(false); } finally { setLoading(false); } @@ -237,6 +249,55 @@ const EventChatPage = () => { ); } + // Check if user is participant + if (!isParticipant) { + return ( + + + + + + + + + Check-in Required + + + You need to check in at the event venue by scanning the QR code to access this chat. + + + + + {event.name} + + + {event.location} + + + + + + Back to Events + + {import.meta.env.DEV && ( + + View QR Code (dev) + + )} + + + + + + ); + } + return (
+ You need to check in at the event venue by scanning the QR code to access this chat. +
+ {event.name} +
+ {event.location} +