-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUpcomingEvents.page.tsx
More file actions
98 lines (90 loc) · 3.76 KB
/
Copy pathUpcomingEvents.page.tsx
File metadata and controls
98 lines (90 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { useCallback, useEffect, useMemo } from 'react';
import { MainLayout } from '../../components/Layout';
import { Event } from '../../common/types/event';
import { config } from '../../config';
import { useAuth } from '../../components/AuthContext';
import { useEvents } from '../../components/EventsContext';
import { useRsvps } from '../../components/RsvpsContext';
import { UpcomingEventsView } from './UpcomingEvents.view';
import { ApiRequestError, parseBodyText } from '../../common/utils/apiError';
import { showApiErrorNotification } from '../../common/utils/notifyError';
import { Configuration, RSVPApi, ResponseError } from '@acm-uiuc/core-client';
export function UpcomingEventsPage() {
const { getToken } = useAuth();
const { events, loading, error: eventsError, refetch: refetchEvents } = useEvents();
const { rsvps, refetch: refetchRsvps } = useRsvps();
useEffect(() => {
if (eventsError) showApiErrorNotification(eventsError);
}, [eventsError]);
const rsvpedEventIds = useMemo(() => new Set(rsvps.map(r => r.eventId)), [rsvps]);
const rsvpEvents = useMemo(() =>
[...events].sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime()),
[events]
);
const handleRsvp = useCallback(async (event: Event, turnstileToken: string) => {
const xUiucToken = await getToken();
const api = new RSVPApi(new Configuration({ basePath: config.apiBaseUrl }));
try {
const raw = await api.apiV1RsvpEventEventIdPostRaw({
eventId: event.id,
xUiucToken: xUiucToken || '',
xTurnstileResponse: turnstileToken,
});
// 201 response body may be empty; don't parse it
if (!raw.raw.ok) throw new Error('Unexpected response');
await refetchRsvps();
} catch (err) {
if (err instanceof ResponseError) {
const { status, headers } = err.response;
const requestId = headers.get('x-request-id') ?? undefined;
let text = '';
try { text = await err.response.text(); } catch { /* ignore */ }
const message = parseBodyText(text);
if (text.includes('is not a valid URL')) {
throw new ApiRequestError('RSVP registration has not been enabled yet.', 'Registration Unavailable', requestId);
}
if (status === 400) {
if (
text.toLowerCase().includes('profile') ||
text.toLowerCase().includes('complete') ||
text.toLowerCase().includes('required')
) {
throw new ApiRequestError(
'Profile setup is required before RSVPing.',
'Profile Required',
requestId,
true,
);
}
throw new ApiRequestError(message || 'Bad request', 'Bad Request', requestId);
}
if (status === 409) {
// The API returns 409 both for duplicate RSVPs and for a full event,
// so distinguish them by the server's message.
if (message.toLowerCase().includes('limit')) {
throw new ApiRequestError(
'This event has reached its RSVP limit. No more spots are available.',
'Event Full',
requestId,
);
}
throw new ApiRequestError("You've already RSVP'd to this event.", 'Already Registered', requestId);
}
if (status === 403) throw new ApiRequestError('This event is at full capacity.', 'Event Full', requestId);
throw new ApiRequestError(message || 'Failed to RSVP', 'Request Failed', requestId);
}
throw err;
}
}, [getToken, refetchRsvps]);
return (
<MainLayout>
<UpcomingEventsView
events={rsvpEvents}
rsvpedEventIds={rsvpedEventIds}
loading={loading}
onRsvp={handleRsvp}
onRefresh={refetchEvents}
/>
</MainLayout>
);
}