Prevent scheduling events in the past + full events-section audit
Audited the whole events flow end-to-end (create, hosting dashboard, discovery
grid, detail, RSVP, sponsors) and confirmed the wiring is coherent:
- Create → parse → display round-trips correctly for sponsors, tour/spot/crew/
musician links, entry fee, and featured listings
- Sponsor parser safely skips shop-coordinate `sponsor` tags (no name at pos 2),
so events and tour/shop sponsorships never collide
- Batch RSVP counts feed the grid; hosting dashboard + detail keep per-item counts
Fix surfaced by the audit: CreateEventPage let a host pick a start time in the
past, silently producing a dead event in the Past tab. Added a `min={today}` on
the date pickers and a submit guard (10-min grace) with a clear message.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
fbb70983cd
commit
d577c8e455
1 changed files with 22 additions and 1 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useSeoMeta } from '@unhead/react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import ngeohash from 'ngeohash';
|
||||
|
|
@ -158,6 +158,14 @@ export default function CreateEventPage() {
|
|||
return acc;
|
||||
}, {} as Record<string, SkateSpot[]>);
|
||||
|
||||
// Today (local) as YYYY-MM-DD, used as the min for the date pickers so hosts
|
||||
// can't accidentally schedule an event in the past.
|
||||
const todayStr = useMemo(() => {
|
||||
const d = new Date();
|
||||
const off = d.getTimezoneOffset();
|
||||
return new Date(d.getTime() - off * 60_000).toISOString().split('T')[0];
|
||||
}, []);
|
||||
|
||||
const toggleType = (type: string) => {
|
||||
setSelectedTypes((prev) =>
|
||||
prev.includes(type) ? prev.filter((t) => t !== type) : [...prev, type]
|
||||
|
|
@ -272,6 +280,17 @@ export default function CreateEventPage() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Guard against scheduling in the past (a 10-min grace window covers
|
||||
// "starting right now" without rejecting it).
|
||||
if (startTimestamp < Math.floor(Date.now() / 1000) - 600) {
|
||||
toast({
|
||||
title: 'That start time is in the past',
|
||||
description: 'Pick a date and time in the future so skaters can RSVP and show up.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse end time if provided
|
||||
let endTimestamp: number | undefined;
|
||||
if (endDate && endTime) {
|
||||
|
|
@ -535,6 +554,7 @@ export default function CreateEventPage() {
|
|||
<Input
|
||||
type="date"
|
||||
value={startDate}
|
||||
min={todayStr}
|
||||
onChange={(e) => setStartDate(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
|
@ -554,6 +574,7 @@ export default function CreateEventPage() {
|
|||
<Input
|
||||
type="date"
|
||||
value={endDate}
|
||||
min={startDate || todayStr}
|
||||
onChange={(e) => setEndDate(e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
|
|
|
|||
Loading…
Reference in a new issue