From 6020a78302e70c3e0bb4388054fa885eaafc3c95 Mon Sep 17 00:00:00 2001 From: Levente Orban Date: Mon, 1 Sep 2025 14:20:15 +0200 Subject: [PATCH 1/2] feat: add a time filter and date/time sort option to /discovery page --- src/routes/discover/+page.svelte | 184 ++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 64 deletions(-) diff --git a/src/routes/discover/+page.svelte b/src/routes/discover/+page.svelte index 66d4d2d..5b16181 100644 --- a/src/routes/discover/+page.svelte +++ b/src/routes/discover/+page.svelte @@ -9,6 +9,8 @@ let error = ''; let searchQuery = ''; let selectedEventType: EventType | 'all' = 'all'; + let selectedTimeFilter: 'any' | 'next-week' | 'next-month' = 'any'; + let selectedSortOrder: 'asc' | 'desc' = 'asc'; let fuse: Fuse; export let data: PageData; @@ -26,7 +28,29 @@ includeMatches: true }); - // Filter events based on search query and event type using Fuse.js + // Helper function to check if an event is within a time range + function isEventInTimeRange(event: Event, timeFilter: string): boolean { + if (timeFilter === 'any') return true; + + const eventDate = new Date(`${event.date}T${event.time}`); + const now = new Date(); + + if (timeFilter === 'next-week') { + const nextWeek = new Date(now); + nextWeek.setDate(now.getDate() + 7); + return eventDate >= now && eventDate <= nextWeek; + } + + if (timeFilter === 'next-month') { + const nextMonth = new Date(now); + nextMonth.setMonth(now.getMonth() + 1); + return eventDate >= now && eventDate <= nextMonth; + } + + return true; + } + + // Filter events based on search query, event type, and time filter using Fuse.js $: filteredEvents = (() => { let events = publicEvents; @@ -35,15 +59,35 @@ events = events.filter((event) => event.type === selectedEventType); } + // Then filter by time range + if (selectedTimeFilter !== 'any') { + events = events.filter((event) => isEventInTimeRange(event, selectedTimeFilter)); + } + // Then apply search query if (searchQuery.trim() !== '') { events = fuse.search(searchQuery).map((result) => result.item); - // Re-apply type filter after search + // Re-apply type and time filters after search if (selectedEventType !== 'all') { events = events.filter((event) => event.type === selectedEventType); } + if (selectedTimeFilter !== 'any') { + events = events.filter((event) => isEventInTimeRange(event, selectedTimeFilter)); + } } + // Sort events by date and time + events = events.sort((a, b) => { + const dateA = new Date(`${a.date}T${a.time}`); + const dateB = new Date(`${b.date}T${b.time}`); + + if (selectedSortOrder === 'asc') { + return dateA.getTime() - dateB.getTime(); + } else { + return dateB.getTime() - dateA.getTime(); + } + }); + return events; })(); @@ -89,77 +133,89 @@ -
-
- -
-
- +
+ +
+
+ + + +
+ + {#if searchQuery} +
- - {#if searchQuery} - - {/if} + + {/if} +
+ + +
+ +
+ + +
+ +
+ +
- -
-
From 7d1991eb9460d3456418d2b4fb7cad74fa4bbba2 Mon Sep 17 00:00:00 2001 From: Levente Orban Date: Mon, 1 Sep 2025 15:10:13 +0200 Subject: [PATCH 2/2] feat: add a filter toggle --- src/lib/dateFormatter.ts | 12 -- src/lib/dateHelpers.ts | 40 ++++++ src/routes/discover/+page.svelte | 224 ++++++++++++++++------------- src/routes/event/+page.svelte | 2 +- src/routes/event/[id]/+page.svelte | 2 +- 5 files changed, 168 insertions(+), 112 deletions(-) delete mode 100644 src/lib/dateFormatter.ts create mode 100644 src/lib/dateHelpers.ts diff --git a/src/lib/dateFormatter.ts b/src/lib/dateFormatter.ts deleted file mode 100644 index a68d3b9..0000000 --- a/src/lib/dateFormatter.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const formatDate = (dateString: string): string => { - const date = new Date(dateString); - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - return `${year}/${month}/${day}`; -}; - -export const formatTime = (timeString: string): string => { - const [hours, minutes] = timeString.split(':'); - return `${hours}:${minutes}`; -}; diff --git a/src/lib/dateHelpers.ts b/src/lib/dateHelpers.ts new file mode 100644 index 0000000..d9536c5 --- /dev/null +++ b/src/lib/dateHelpers.ts @@ -0,0 +1,40 @@ +import type { Event } from './types'; + +export const formatDate = (dateString: string): string => { + const date = new Date(dateString); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}/${month}/${day}`; +}; + +export const formatTime = (timeString: string): string => { + const [hours, minutes] = timeString.split(':'); + return `${hours}:${minutes}`; +}; + +// Helper function to check if an event is within a time range +export const isEventInTimeRange = (event: Event, timeFilter: string): boolean => { + if (timeFilter === 'any') return true; + + const eventDate = new Date(`${event.date}T${event.time}`); + const now = new Date(); + + // Handle temporal status filters + if (timeFilter === 'upcoming') { + return eventDate >= now; + } + + if (timeFilter === 'past') { + return eventDate < now; + } + + // Handle time range filters + const ranges: Record = { + 'next-week': new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000), + 'next-month': new Date(new Date(now).setMonth(now.getMonth() + 1)) + }; + + const endDate = ranges[timeFilter]; + return endDate ? eventDate >= now && eventDate <= endDate : true; +}; diff --git a/src/routes/discover/+page.svelte b/src/routes/discover/+page.svelte index 5b16181..a2b2cd1 100644 --- a/src/routes/discover/+page.svelte +++ b/src/routes/discover/+page.svelte @@ -2,7 +2,7 @@ import type { Event, EventType } from '$lib/types'; import { goto } from '$app/navigation'; import type { PageData } from '../$types'; - import { formatTime, formatDate } from '$lib/dateFormatter'; + import { formatTime, formatDate, isEventInTimeRange } from '$lib/dateHelpers'; import Fuse from 'fuse.js'; let publicEvents: Event[] = []; @@ -10,7 +10,9 @@ let searchQuery = ''; let selectedEventType: EventType | 'all' = 'all'; let selectedTimeFilter: 'any' | 'next-week' | 'next-month' = 'any'; + let selectedTemporalStatus: 'all' | 'upcoming' | 'past' = 'all'; let selectedSortOrder: 'asc' | 'desc' = 'asc'; + let showFilters = false; let fuse: Fuse; export let data: PageData; @@ -28,29 +30,7 @@ includeMatches: true }); - // Helper function to check if an event is within a time range - function isEventInTimeRange(event: Event, timeFilter: string): boolean { - if (timeFilter === 'any') return true; - - const eventDate = new Date(`${event.date}T${event.time}`); - const now = new Date(); - - if (timeFilter === 'next-week') { - const nextWeek = new Date(now); - nextWeek.setDate(now.getDate() + 7); - return eventDate >= now && eventDate <= nextWeek; - } - - if (timeFilter === 'next-month') { - const nextMonth = new Date(now); - nextMonth.setMonth(now.getMonth() + 1); - return eventDate >= now && eventDate <= nextMonth; - } - - return true; - } - - // Filter events based on search query, event type, and time filter using Fuse.js + // Filter events based on search query, event type, time filter, and temporal status $: filteredEvents = (() => { let events = publicEvents; @@ -59,6 +39,11 @@ events = events.filter((event) => event.type === selectedEventType); } + // Then filter by temporal status (past/upcoming/all) + if (selectedTemporalStatus !== 'all') { + events = events.filter((event) => isEventInTimeRange(event, selectedTemporalStatus)); + } + // Then filter by time range if (selectedTimeFilter !== 'any') { events = events.filter((event) => isEventInTimeRange(event, selectedTimeFilter)); @@ -67,10 +52,13 @@ // Then apply search query if (searchQuery.trim() !== '') { events = fuse.search(searchQuery).map((result) => result.item); - // Re-apply type and time filters after search + // Re-apply all filters after search if (selectedEventType !== 'all') { events = events.filter((event) => event.type === selectedEventType); } + if (selectedTemporalStatus !== 'all') { + events = events.filter((event) => isEventInTimeRange(event, selectedTemporalStatus)); + } if (selectedTimeFilter !== 'any') { events = events.filter((event) => isEventInTimeRange(event, selectedTimeFilter)); } @@ -134,90 +122,130 @@
- -
-
- - - -
- - {#if searchQuery} - - {/if} +
+ + {#if searchQuery} + + {/if} +
+ + +
-
- -
- - -
- -
- - -
+ {#if showFilters} +
+ +
+ + +
+ +
+ + +
+ +
+ + +
- -
- - + +
+ + +
-
+ {/if}
diff --git a/src/routes/event/+page.svelte b/src/routes/event/+page.svelte index 213f8c1..cd78948 100644 --- a/src/routes/event/+page.svelte +++ b/src/routes/event/+page.svelte @@ -1,7 +1,7 @@