Skip to content

Commit 78f44ab

Browse files
authored
Fix Google Calendar subscription flow (#256)
1 parent 410c7e5 commit 78f44ab

1 file changed

Lines changed: 47 additions & 9 deletions

File tree

frontend/src/pages/lectures/Lectures.tsx

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,28 @@ import Loading from "../../components/common/loading";
77

88
const LECTURE_CALENDAR_FEED_URL =
99
"https://www.gpumode.com/api/events/calendar.ics";
10-
const GOOGLE_CALENDAR_SUBSCRIBE_URL = `https://calendar.google.com/calendar/r?cid=${encodeURIComponent(
11-
LECTURE_CALENDAR_FEED_URL,
12-
)}`;
10+
const GOOGLE_CALENDAR_ADD_BY_URL =
11+
"https://calendar.google.com/calendar/r/settings/addbyurl";
12+
13+
async function copyCalendarFeedUrl(): Promise<void> {
14+
if (navigator.clipboard?.writeText) {
15+
await navigator.clipboard.writeText(LECTURE_CALENDAR_FEED_URL);
16+
return;
17+
}
18+
19+
const textarea = document.createElement("textarea");
20+
textarea.value = LECTURE_CALENDAR_FEED_URL;
21+
textarea.style.position = "fixed";
22+
textarea.style.opacity = "0";
23+
document.body.appendChild(textarea);
24+
textarea.select();
25+
const copied = document.execCommand("copy");
26+
document.body.removeChild(textarea);
27+
28+
if (!copied) {
29+
throw new Error("Unable to copy calendar feed URL");
30+
}
31+
}
1332

1433
const styles = {
1534
container: {
@@ -326,6 +345,16 @@ export default function Lectures() {
326345
const [events, setEvents] = useState<DiscordEvent[]>([]);
327346
const [loading, setLoading] = useState(true);
328347
const [error, setError] = useState<string | null>(null);
348+
const [calendarCopyError, setCalendarCopyError] = useState(false);
349+
350+
const openGoogleCalendarSubscription = async () => {
351+
try {
352+
await copyCalendarFeedUrl();
353+
window.location.assign(GOOGLE_CALENDAR_ADD_BY_URL);
354+
} catch {
355+
setCalendarCopyError(true);
356+
}
357+
};
329358

330359
useEffect(() => {
331360
fetchEvents()
@@ -412,16 +441,25 @@ export default function Lectures() {
412441
.
413442
</Typography>
414443
<Button
415-
component="a"
416-
href={GOOGLE_CALENDAR_SUBSCRIBE_URL}
417-
target="_blank"
418-
rel="noopener noreferrer"
444+
onClick={openGoogleCalendarSubscription}
419445
variant="outlined"
420446
size="small"
421-
sx={{ marginBottom: "16px", textTransform: "none" }}
447+
sx={{ textTransform: "none" }}
422448
>
423-
Subscribe in Google Calendar
449+
Copy URL and open Google Calendar
424450
</Button>
451+
<Typography
452+
sx={{
453+
color: calendarCopyError ? "error.main" : "text.secondary",
454+
fontSize: "0.8rem",
455+
marginTop: "8px",
456+
marginBottom: "16px",
457+
}}
458+
>
459+
{calendarCopyError
460+
? `Copy ${LECTURE_CALENDAR_FEED_URL}, then open Google Calendar → Other calendars → From URL.`
461+
: "Paste the copied URL into “URL of calendar,” then click Add calendar. You only need to do this once."}
462+
</Typography>
425463
{loading ? (
426464
<Loading />
427465
) : error ? (

0 commit comments

Comments
 (0)