fix: improve event check-in UX and participant counting

Backend:
- Use _count.participants for accurate real-time participant count
- Remove reliance on stale participantsCount column

Frontend:
- Show check-in requirement message for non-joined events
- Display "Open chat" button only for joined events
- Add dev-only "View details" button for QR code access during testing
- Improve visual feedback with amber-colored check-in notice

This ensures the participant count reflects actual checked-in users
and prevents unauthorized access to QR codes in production while
maintaining developer convenience in development mode.
This commit is contained in:
Radosław Gierwiało
2025-11-14 14:20:20 +01:00
parent 71cba01db3
commit 6823851b63
2 changed files with 37 additions and 9 deletions

View File

@@ -19,7 +19,6 @@ router.get('/', authenticate, async (req, res, next) => {
startDate: true, startDate: true,
endDate: true, endDate: true,
worldsdcId: true, worldsdcId: true,
participantsCount: true,
description: true, description: true,
createdAt: true, createdAt: true,
participants: { participants: {
@@ -30,6 +29,11 @@ router.get('/', authenticate, async (req, res, next) => {
joinedAt: true, joinedAt: true,
}, },
}, },
_count: {
select: {
participants: true,
},
},
}, },
}); });
@@ -42,7 +46,7 @@ router.get('/', authenticate, async (req, res, next) => {
startDate: event.startDate, startDate: event.startDate,
endDate: event.endDate, endDate: event.endDate,
worldsdcId: event.worldsdcId, worldsdcId: event.worldsdcId,
participantsCount: event.participantsCount, participantsCount: event._count.participants,
description: event.description, description: event.description,
createdAt: event.createdAt, createdAt: event.createdAt,
isJoined: event.participants.length > 0, isJoined: event.participants.length > 0,

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import Layout from '../components/layout/Layout'; import Layout from '../components/layout/Layout';
import { eventsAPI } from '../services/api'; import { eventsAPI } from '../services/api';
import { Calendar, MapPin, Users, Loader2, CheckCircle } from 'lucide-react'; import { Calendar, MapPin, Users, Loader2, CheckCircle, QrCode } from 'lucide-react';
const EventsPage = () => { const EventsPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -101,12 +101,36 @@ const EventsPage = () => {
<p className="text-gray-600 text-sm mb-4">{event.description}</p> <p className="text-gray-600 text-sm mb-4">{event.description}</p>
)} )}
<button <div className="space-y-2">
onClick={() => handleJoinEvent(event.slug)} {event.isJoined ? (
className="w-full px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 transition-colors" <button
> onClick={() => handleJoinEvent(event.slug)}
{event.isJoined ? 'Open chat' : 'Join chat'} className="w-full px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 transition-colors"
</button> >
Open chat
</button>
) : (
<div className="bg-amber-50 border border-amber-200 rounded-md p-4 text-sm text-amber-800">
<div className="flex items-center gap-2 font-medium mb-2">
<QrCode className="w-5 h-5" />
Check-in required
</div>
<p className="text-amber-700">
Scan the QR code at the event venue to join the chat
</p>
</div>
)}
{/* Development mode: Show details link */}
{import.meta.env.DEV && (
<button
onClick={() => navigate(`/events/${event.slug}/details`)}
className="w-full px-4 py-2 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 transition-colors text-sm"
>
View details (dev)
</button>
)}
</div>
</div> </div>
))} ))}
</div> </div>