Skip to content

Commit 2fbbe9e

Browse files
Tony QiuTony Qiu
authored andcommitted
fix bug where events with multiple occurences show up as past event
1 parent 422bbe2 commit 2fbbe9e

File tree

12 files changed

+63
-48
lines changed

12 files changed

+63
-48
lines changed

backend/apps/events/views.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,30 @@ def get_events(request):
132132
Prefetch('event_dates', queryset=EventDates.objects.order_by('dtstart_utc'))
133133
)[:limit + 1])
134134

135-
# Build results with earliest occurrence dates
135+
# Build results with most recent upcoming occurrence dates
136136
results = []
137+
now = timezone.now()
138+
ninety_minutes_ago = now - timedelta(minutes=90)
139+
137140
for event in events_list:
138-
event_dates = list(event.event_dates.all())
139-
earliest_date = event_dates[0] if event_dates else None
141+
# Get all event dates and filter for upcoming ones
142+
all_dates = list(event.event_dates.all())
143+
# Filter to only upcoming dates (>= ninety_minutes_ago to match the filter logic)
144+
upcoming_dates = [
145+
date for date in all_dates
146+
if date.dtstart_utc >= ninety_minutes_ago
147+
]
148+
# Select the most recent upcoming date (first one since they're ordered by dtstart_utc)
149+
# If no upcoming dates, fall back to the earliest date overall
150+
selected_date = upcoming_dates[0] if upcoming_dates else (all_dates[0] if all_dates else None)
140151

141152
event_data = {
142153
"id": event.id,
143154
"title": event.title,
144155
"description": event.description,
145156
"location": event.location,
146-
"dtstart_utc": earliest_date.dtstart_utc if earliest_date else None,
147-
"dtend_utc": earliest_date.dtend_utc if earliest_date else None,
157+
"dtstart_utc": selected_date.dtstart_utc if selected_date else None,
158+
"dtend_utc": selected_date.dtend_utc if selected_date else None,
148159
"price": event.price,
149160
"food": event.food,
150161
"registration": event.registration,

frontend/src/features/admin/pages/SubmissionsReviewPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ArrowLeft } from "lucide-react";
55
import { useSubmissionsReview } from "@/features/admin/hooks/useSubmissionsReview";
66
import { Badge } from "@/shared/components/ui/badge";
77
import { Loading } from "@/shared/components/ui/loading";
8-
import { getSubmissionStatusVariant } from "@/shared/components/badges/EventBadges";
8+
import { getSubmissionStatusVariant } from "@/shared/lib/eventUtils";
99

1010
export function SubmissionsReviewPage() {
1111
const { signOut } = useClerk();

frontend/src/features/clubs/hooks/useClubs.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo } from "react";
2-
import { useInfiniteQuery } from "@tanstack/react-query";
2+
import { useInfiniteQuery, type InfiniteData } from "@tanstack/react-query";
33
import { useSearchParams } from "react-router-dom";
44
import { useApi } from "@/shared/hooks/useApi";
55
import type { ClubsResponse } from "@/shared/api";
@@ -17,10 +17,10 @@ export function useClubs() {
1717
fetchNextPage,
1818
hasNextPage,
1919
isFetchingNextPage,
20-
} = useInfiniteQuery<ClubsResponse, Error, any, string[], string | undefined>({
20+
} = useInfiniteQuery<ClubsResponse, Error, ClubsResponse, string[], string | undefined>({
2121
queryKey: ["clubs", searchTerm, categoryFilter],
2222
queryFn: async ({ pageParam }: { pageParam: string | undefined }) => {
23-
const queryParams: Record<string, any> = {};
23+
const queryParams: Record<string, string | undefined> = {};
2424

2525
if (pageParam) {
2626
queryParams.cursor = pageParam;
@@ -44,12 +44,13 @@ export function useClubs() {
4444

4545
// Flatten all pages into a single array of clubs
4646
const clubs = useMemo(() => {
47-
if (!data?.pages) return [];
48-
return data.pages.flatMap((page: ClubsResponse) => page.results);
47+
const infiniteData = data as unknown as InfiniteData<ClubsResponse> | undefined;
48+
if (!infiniteData?.pages) return [];
49+
return infiniteData.pages.flatMap((page: ClubsResponse) => page.results);
4950
}, [data]);
5051

5152
// Get total count from first page
52-
const totalCount = (data?.pages?.[0] as ClubsResponse | undefined)?.totalCount ?? 0;
53+
const totalCount = ((data as unknown as InfiniteData<ClubsResponse>)?.pages?.[0] as ClubsResponse | undefined)?.totalCount ?? 0;
5354

5455
const uniqueCategories = useMemo(() => {
5556
return [

frontend/src/features/events/components/EventEditForm.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export function EventEditForm({ event }: EventEditFormProps) {
4242
});
4343

4444
const updateEventMutation = useMutation({
45-
mutationFn: (eventData: any) =>
46-
eventsAPIClient.updateEvent(Number(event.id), eventData),
45+
mutationFn: (eventData: EventFormData) =>
46+
eventsAPIClient.updateEvent(Number(event.id), eventData as unknown as Record<string, unknown>),
4747
onSuccess: () => {
4848
queryClient.invalidateQueries({ queryKey: ["event", event.id] });
4949
toast.success("Event updated successfully");
@@ -79,7 +79,7 @@ export function EventEditForm({ event }: EventEditFormProps) {
7979
dtend_utc: d.dtend_local ? localToUtc(d.dtend_local) : null,
8080
})),
8181
};
82-
updateEventMutation.mutate(submitData);
82+
updateEventMutation.mutate(submitData as unknown as EventFormData);
8383
};
8484

8585
const handleApprove = () => {

frontend/src/features/events/components/EventFormFields.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useState } from "react";
2-
import { useFieldArray } from "react-hook-form";
2+
import { useFieldArray, type UseFormReturn } from "react-hook-form";
33
import { Plus, Trash2, Undo2 } from "lucide-react";
44
import { Button } from "@/shared/components/ui/button";
55
import { Input } from "@/shared/components/ui/input";
@@ -36,7 +36,7 @@ interface DeletedDate {
3636
}
3737

3838
interface EventFormFieldsProps {
39-
form: any; // UseFormReturn from react-hook-form
39+
form: UseFormReturn<EventFormData>;
4040
isDisabled?: boolean;
4141
showUndoHistory?: boolean;
4242
}

frontend/src/features/events/hooks/useEventInterest.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { useMutation, useQuery, useQueryClient, InfiniteData } from "@tanstack/react-query";
22
import { useAuth } from "@clerk/clerk-react";
33
import { useApi } from "@/shared/hooks/useApi";
4+
import type { EventsResponse } from "@/shared/api/EventsAPIClient";
5+
import type { Event } from "@/features/events/types/events";
46

57
/**
68
* Hook to get all event IDs the current user is interested in
@@ -59,14 +61,14 @@ export function useToggleEventInterest(eventId: number) {
5961
});
6062

6163
// Optimistically update event interest counts in events list (infinite query structure)
62-
queryClient.setQueriesData<InfiniteData<any>>({ queryKey: ["events"] }, (oldData) => {
64+
queryClient.setQueriesData<InfiniteData<EventsResponse>>({ queryKey: ["events"] }, (oldData) => {
6365
if (!oldData?.pages) return oldData;
6466

6567
return {
6668
...oldData,
67-
pages: oldData.pages.map((page: any) => ({
69+
pages: oldData.pages.map((page: EventsResponse) => ({
6870
...page,
69-
results: page.results.map((event: any) => {
71+
results: page.results.map((event: Event) => {
7072
if (event.id === eventId) {
7173
const delta = nextInterested ? 1 : -1;
7274
return {
@@ -84,14 +86,14 @@ export function useToggleEventInterest(eventId: number) {
8486
},
8587
onSuccess: (response) => {
8688
// Update the event's interest count with the actual server value (infinite query structure)
87-
queryClient.setQueriesData<InfiniteData<any>>({ queryKey: ["events"] }, (oldData) => {
89+
queryClient.setQueriesData<InfiniteData<EventsResponse>>({ queryKey: ["events"] }, (oldData) => {
8890
if (!oldData?.pages) return oldData;
8991

9092
return {
9193
...oldData,
92-
pages: oldData.pages.map((page: any) => ({
94+
pages: oldData.pages.map((page: EventsResponse) => ({
9395
...page,
94-
results: page.results.map((event: any) => {
96+
results: page.results.map((event: Event) => {
9597
if (event.id === eventId) {
9698
return {
9799
...event,
@@ -111,14 +113,14 @@ export function useToggleEventInterest(eventId: number) {
111113
}
112114

113115
// Rollback event interest count (infinite query structure)
114-
queryClient.setQueriesData<InfiniteData<any>>({ queryKey: ["events"] }, (oldData) => {
116+
queryClient.setQueriesData<InfiniteData<EventsResponse>>({ queryKey: ["events"] }, (oldData) => {
115117
if (!oldData?.pages) return oldData;
116118

117119
return {
118120
...oldData,
119-
pages: oldData.pages.map((page: any) => ({
121+
pages: oldData.pages.map((page: EventsResponse) => ({
120122
...page,
121-
results: page.results.map((event: any) => {
123+
results: page.results.map((event: Event) => {
122124
if (event.id === eventId) {
123125
const delta = nextInterested ? -1 : 1; // Reverse the optimistic update
124126
return {

frontend/src/features/events/hooks/useEvents.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { useMemo, useRef } from "react";
2-
import { useInfiniteQuery } from "@tanstack/react-query";
2+
import { useInfiniteQuery, type InfiniteData } from "@tanstack/react-query";
33
import { useSearchParams, useNavigate } from "react-router-dom";
44
import { useAuth } from "@clerk/clerk-react";
55
import { useDocumentTitle } from "@/shared/hooks/useDocumentTitle";
66
import { useApi } from "@/shared/hooks/useApi";
77
import { getTodayString } from "@/shared/lib/dateUtils";
88
import { useMyInterestedEvents } from "./useEventInterest";
9-
import { EventsResponse } from "@/shared/api/EventsAPIClient";
9+
import { EventsResponse, type EventsQueryParams } from "@/shared/api/EventsAPIClient";
1010
import { Event } from "@/features/events";
1111

1212
export function useEvents() {
@@ -33,7 +33,7 @@ export function useEvents() {
3333
} = useInfiniteQuery<
3434
EventsResponse,
3535
Error,
36-
any,
36+
EventsResponse,
3737
string[],
3838
string | undefined
3939
>({
@@ -47,7 +47,7 @@ export function useEvents() {
4747
showInterested ? "interested" : "",
4848
],
4949
queryFn: async ({ pageParam }: { pageParam: string | undefined }) => {
50-
const queryParams: Record<string, any> = {};
50+
const queryParams: EventsQueryParams = {};
5151

5252
if (pageParam) {
5353
queryParams.cursor = pageParam;
@@ -90,13 +90,14 @@ export function useEvents() {
9090

9191
// Flatten all pages into a single array of events
9292
const events = useMemo(() => {
93-
if (!data?.pages) return [];
94-
return data.pages.flatMap((page: EventsResponse) => page.results);
93+
const infiniteData = data as unknown as InfiniteData<EventsResponse> | undefined;
94+
if (!infiniteData?.pages) return [];
95+
return infiniteData.pages.flatMap((page: EventsResponse) => page.results);
9596
}, [data]);
9697

9798
// Get total count from first page
9899
const totalCount =
99-
(data?.pages?.[0] as EventsResponse | undefined)?.totalCount ?? 0;
100+
((data as unknown as InfiniteData<EventsResponse>)?.pages?.[0] as EventsResponse | undefined)?.totalCount ?? 0;
100101

101102
// Filter events by interested if the filter is active
102103
const filteredEvents = useMemo(() => {

frontend/src/features/events/pages/MySubmissionsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
import { formatEventDate } from "@/shared/lib/dateUtils";
1717
import type { EventSubmission } from "@/features/events/types/submission";
1818
import { useNavigate } from "react-router-dom";
19-
import { getSubmissionStatusVariant } from "@/shared/components/badges/EventBadges";
19+
import { getSubmissionStatusVariant } from "@/shared/lib/eventUtils";
2020

2121
export function MySubmissionsPage() {
2222
const {

frontend/src/features/events/pages/SubmitEventPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function SubmitEventPage() {
6363

6464
// Convert UTC occurrences to local dates format
6565
const occurrences = result.occurrences && result.occurrences.length > 0
66-
? result.occurrences.map((occ: any) => ({
66+
? result.occurrences.map((occ: { dtstart_utc?: string; dtend_utc?: string }) => ({
6767
dtstart_local: occ.dtstart_utc ? utcToLocal(occ.dtstart_utc) : "",
6868
dtend_local: occ.dtend_utc ? utcToLocal(occ.dtend_utc) : "",
6969
}))

frontend/src/shared/api/EventsAPIClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class EventsAPIClient {
105105
food?: string;
106106
registration: boolean;
107107
occurrences: Array<{ dtstart_utc: string; dtend_utc?: string; tz?: string }>;
108-
all_extracted: any[];
108+
all_extracted: unknown[];
109109
}> {
110110
const dataForm = new FormData();
111111
dataForm.append('screenshot', screenshot);
@@ -175,7 +175,7 @@ class EventsAPIClient {
175175
eventData?: Record<string, unknown>
176176
): Promise<{ message: string }> {
177177
// Event data is now passed flat at top level (not nested)
178-
const payload: any = { action };
178+
const payload: Record<string, unknown> = { action };
179179
if (eventData) {
180180
Object.assign(payload, eventData);
181181
}

0 commit comments

Comments
 (0)