Fix event capacity: no negative availability, sold-out enforcement, admin override
- Backend: use calculateAvailableSeats so availableSeats is never negative - Backend: reject public booking when confirmed >= capacity; admin create/manual bypass capacity - Frontend: spotsLeft = max(0, capacity - bookedCount), isSoldOut when bookedCount >= capacity - Frontend: sold-out redirect on booking page, cap quantity by spotsLeft, never show negative Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -619,7 +619,7 @@ export default function AdminEventDetailPage() {
|
||||
<div>
|
||||
<p className="font-medium">Capacity</p>
|
||||
<p className="text-gray-600">{confirmedCount + checkedInCount} / {event.capacity} spots filled</p>
|
||||
<p className="text-sm text-gray-500">{event.capacity - confirmedCount - checkedInCount} spots remaining</p>
|
||||
<p className="text-sm text-gray-500">{Math.max(0, event.capacity - confirmedCount - checkedInCount)} spots remaining</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -113,12 +113,12 @@ export default function AdminDashboardPage() {
|
||||
{/* Low capacity warnings */}
|
||||
{data?.upcomingEvents
|
||||
.filter(event => {
|
||||
const availableSeats = event.availableSeats ?? (event.capacity - (event.bookedCount || 0));
|
||||
const spotsLeft = Math.max(0, event.capacity - (event.bookedCount || 0));
|
||||
const percentFull = ((event.bookedCount || 0) / event.capacity) * 100;
|
||||
return percentFull >= 80 && availableSeats > 0;
|
||||
return percentFull >= 80 && spotsLeft > 0;
|
||||
})
|
||||
.map(event => {
|
||||
const availableSeats = event.availableSeats ?? (event.capacity - (event.bookedCount || 0));
|
||||
const spotsLeft = Math.max(0, event.capacity - (event.bookedCount || 0));
|
||||
const percentFull = Math.round(((event.bookedCount || 0) / event.capacity) * 100);
|
||||
return (
|
||||
<Link
|
||||
@@ -130,7 +130,7 @@ export default function AdminDashboardPage() {
|
||||
<ExclamationTriangleIcon className="w-5 h-5 text-orange-600" />
|
||||
<div>
|
||||
<span className="text-sm font-medium">{event.title}</span>
|
||||
<p className="text-xs text-gray-500">Only {availableSeats} spots left ({percentFull}% full)</p>
|
||||
<p className="text-xs text-gray-500">Only {spotsLeft} spots left ({percentFull}% full)</p>
|
||||
</div>
|
||||
</div>
|
||||
<span className="badge badge-warning">Low capacity</span>
|
||||
@@ -140,7 +140,7 @@ export default function AdminDashboardPage() {
|
||||
|
||||
{/* Sold out events */}
|
||||
{data?.upcomingEvents
|
||||
.filter(event => (event.availableSeats ?? (event.capacity - (event.bookedCount || 0))) === 0)
|
||||
.filter(event => Math.max(0, event.capacity - (event.bookedCount || 0)) === 0)
|
||||
.map(event => (
|
||||
<Link
|
||||
key={event.id}
|
||||
|
||||
Reference in New Issue
Block a user