diff options
| -rw-r--r-- | app/components/FilterBar.tsx | 8 | ||||
| -rw-r--r-- | app/lib/scraper-runner.server.ts | 28 | ||||
| -rw-r--r-- | app/routes/events._index.tsx | 22 |
3 files changed, 48 insertions, 10 deletions
diff --git a/app/components/FilterBar.tsx b/app/components/FilterBar.tsx index 97a3c02..266865d 100644 --- a/app/components/FilterBar.tsx +++ b/app/components/FilterBar.tsx @@ -3,9 +3,11 @@ import type { Venue } from "~/lib/db.server"; interface Props { venues: Venue[]; + defaultDateFrom?: string; + defaultDateTo?: string; } -export default function FilterBar({ venues }: Props) { +export default function FilterBar({ venues, defaultDateFrom, defaultDateTo }: Props) { const [searchParams] = useSearchParams(); return ( @@ -45,7 +47,7 @@ export default function FilterBar({ venues }: Props) { <input name="date_from" type="date" - defaultValue={searchParams.get("date_from") ?? ""} + defaultValue={searchParams.get("date_from") ?? defaultDateFrom ?? ""} className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500" /> </div> @@ -56,7 +58,7 @@ export default function FilterBar({ venues }: Props) { <input name="date_to" type="date" - defaultValue={searchParams.get("date_to") ?? ""} + defaultValue={searchParams.get("date_to") ?? defaultDateTo ?? ""} className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500" /> </div> diff --git a/app/lib/scraper-runner.server.ts b/app/lib/scraper-runner.server.ts index 070a568..191dd00 100644 --- a/app/lib/scraper-runner.server.ts +++ b/app/lib/scraper-runner.server.ts @@ -1,6 +1,24 @@ import { upsertVenue, upsertEvent } from "./db.server"; import { generateVenueMarkdown, generateAllVenueMarkdown } from "./markdown-writer.server"; import { ALL_SCRAPERS } from "~/scrapers/index"; +import type { EventInput } from "./db.server"; + +const SCRAPE_WINDOW_DAYS = 35; // ~1 month + +function scrapeWindow(): { from: string; to: string } { + const from = new Date(); + from.setHours(0, 0, 0, 0); + const to = new Date(from); + to.setDate(to.getDate() + SCRAPE_WINDOW_DAYS); + return { + from: from.toISOString().slice(0, 10), + to: to.toISOString().slice(0, 10), + }; +} + +function withinWindow(event: EventInput, from: string, to: string): boolean { + return event.date >= from && event.date <= to; +} export interface ScrapeResult { venue_id: string; @@ -19,7 +37,10 @@ export async function runAllScrapers(): Promise<ScrapeResult[]> { upsertVenue(venue.id, venue.name, venue.url, venue.area); try { - const events = await scraper.scrape(); + const { from, to } = scrapeWindow(); + const events = (await scraper.scrape()).filter((e) => + withinWindow(e, from, to) + ); for (const event of events) { upsertEvent(event); } @@ -55,7 +76,10 @@ export async function runScraper(venueId: string): Promise<ScrapeResult> { upsertVenue(venue.id, venue.name, venue.url, venue.area); try { - const events = await scraper.scrape(); + const { from, to } = scrapeWindow(); + const events = (await scraper.scrape()).filter((e) => + withinWindow(e, from, to) + ); for (const event of events) { upsertEvent(event); } diff --git a/app/routes/events._index.tsx b/app/routes/events._index.tsx index 3883d37..3ff441a 100644 --- a/app/routes/events._index.tsx +++ b/app/routes/events._index.tsx @@ -4,10 +4,22 @@ import { queryEvents, getVenues } from "~/lib/db.server"; import EventCard from "~/components/EventCard"; import FilterBar from "~/components/FilterBar"; +function defaultWindow() { + const today = new Date(); + today.setHours(0, 0, 0, 0); + const end = new Date(today); + end.setDate(end.getDate() + 35); + return { + from: today.toISOString().slice(0, 10), + to: end.toISOString().slice(0, 10), + }; +} + export async function loader({ request }: Route.LoaderArgs) { const url = new URL(request.url); - const date_from = url.searchParams.get("date_from") ?? undefined; - const date_to = url.searchParams.get("date_to") ?? undefined; + const { from: defaultFrom, to: defaultTo } = defaultWindow(); + const date_from = url.searchParams.get("date_from") ?? defaultFrom; + const date_to = url.searchParams.get("date_to") ?? defaultTo; const venue_id = url.searchParams.get("venue_id") ?? undefined; const keyword = url.searchParams.get("keyword") ?? undefined; const page = Math.max(1, parseInt(url.searchParams.get("page") ?? "1", 10)); @@ -17,11 +29,11 @@ export async function loader({ request }: Route.LoaderArgs) { const events = queryEvents({ date_from, date_to, venue_id, keyword, limit, offset }); const venues = getVenues(); - return { events, venues, page, hasMore: events.length === limit }; + return { events, venues, page, hasMore: events.length === limit, date_from, date_to }; } export default function EventsIndex() { - const { events, venues, page, hasMore } = useLoaderData<typeof loader>(); + const { events, venues, page, hasMore, date_from, date_to } = useLoaderData<typeof loader>(); const [searchParams] = useSearchParams(); return ( @@ -49,7 +61,7 @@ export default function EventsIndex() { </Form> </div> - <FilterBar venues={venues} /> + <FilterBar venues={venues} defaultDateFrom={date_from} defaultDateTo={date_to} /> {events.length === 0 ? ( <div className="mt-16 text-center text-gray-500"> |
