Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/cookie-consent/youtube.ts
14422 views
1
/*
2
* This file is part of CoCalc: Copyright © 2026 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
// Stand-alone "consent for embedded YouTube" flag. Kept separate from the
7
// vanilla-cookieconsent v3 banner state on purpose: accepting a YouTube
8
// embed must not mark the main banner as "decided", otherwise the
9
// force-consent overlay on sign-up / SSO launch would stop triggering for
10
// a visitor who only clicked a video on the landing page.
11
//
12
// The preferences modal still surfaces this consent (see translations.ts +
13
// init.ts) so users can review and revoke it alongside the categories;
14
// internally that UI just reads/writes the dedicated cookie below.
15
16
import { useEffect, useState } from "react";
17
18
const YT_COOKIE = "cocalc_youtube_consent";
19
const ONE_YEAR_S = 365 * 24 * 60 * 60;
20
export const YOUTUBE_CONSENT_EVENT = "cocalc:youtube-consent";
21
22
export function hasYouTubeConsent(): boolean {
23
if (typeof document === "undefined") return false;
24
return document.cookie
25
.split(";")
26
.some((c) => c.trim() === `${YT_COOKIE}=1`);
27
}
28
29
function emitChange(): void {
30
if (typeof window !== "undefined") {
31
window.dispatchEvent(new Event(YOUTUBE_CONSENT_EVENT));
32
}
33
}
34
35
export function grantYouTubeConsent(): void {
36
if (typeof document === "undefined") return;
37
document.cookie =
38
`${YT_COOKIE}=1; path=/; max-age=${ONE_YEAR_S}; SameSite=Lax`;
39
emitChange();
40
}
41
42
export function revokeYouTubeConsent(): void {
43
if (typeof document === "undefined") return;
44
document.cookie = `${YT_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
45
emitChange();
46
}
47
48
// React hook: re-renders when YouTube consent state flips. First render
49
// returns false to avoid a Next.js hydration mismatch (the server can't
50
// read document.cookie); useEffect reconciles to the real value.
51
export function useYouTubeConsent(): boolean {
52
const [granted, setGranted] = useState(false);
53
useEffect(() => {
54
const update = () => setGranted(hasYouTubeConsent());
55
update();
56
window.addEventListener(YOUTUBE_CONSENT_EVENT, update);
57
return () =>
58
window.removeEventListener(YOUTUBE_CONSENT_EVENT, update);
59
}, []);
60
return granted;
61
}
62
63