diff --git a/frontend/src/styles/popups.scss b/frontend/src/styles/popups.scss index eac6a1cdb..a6c8c2a38 100644 --- a/frontend/src/styles/popups.scss +++ b/frontend/src/styles/popups.scss @@ -419,6 +419,62 @@ } } +#cookiePopup { + position: fixed; + right: 2rem; + bottom: 2rem; + background: var(--sub-alt-color); + border-radius: var(--roundness); + padding: 2rem; + display: grid; + gap: 1rem; + width: 465px; + z-index: 10000; + // outline: 0.5rem solid var(--bg-color) + user-select: none; + .main { + display: grid; + gap: 1rem; + } + .title { + font-size: 1.5rem; + color: var(--sub-color); + } + .buttons { + margin-top: 0.25rem; + display: grid; + grid-auto-flow: column; + gap: 1rem; + grid-template-columns: 1fr 2.25rem; + } + .settings { + display: grid; + gap: 1rem; + .customTextCheckbox { + background: var(--sub-color); + } + .cookie label { + display: grid; + gap: 0 1rem; + grid-template-columns: 1fr min-content; + grid-template-areas: + "title check" + "description check"; + .title { + grid-area: title; + font-size: 1.25rem; + } + .description { + grid-area: description; + } + .customTextCheckbox { + place-self: center; + grid-area: check; + } + } + } +} + #pbTablesPopupWrapper #pbTablesPopup { .title { color: var(--text-color); diff --git a/frontend/src/styles/z_media-queries.scss b/frontend/src/styles/z_media-queries.scss index 86552c0c8..8423f9bbb 100644 --- a/frontend/src/styles/z_media-queries.scss +++ b/frontend/src/styles/z_media-queries.scss @@ -390,6 +390,11 @@ } @media only screen and (max-width: 550px) { + #cookiePopup { + right: 1rem; + bottom: 1rem; + width: calc(100vw - 2rem); + } #keymap { .row { height: 1.25rem; diff --git a/frontend/src/ts/controllers/analytics-controller.ts b/frontend/src/ts/controllers/analytics-controller.ts index aaa30c930..e5cc67fc3 100644 --- a/frontend/src/ts/controllers/analytics-controller.ts +++ b/frontend/src/ts/controllers/analytics-controller.ts @@ -1,5 +1,8 @@ -import { Analytics } from "../firebase"; -import { logEvent } from "firebase/analytics"; +import { Analytics as AnalyticsType, getAnalytics } from "firebase/analytics"; +import { logEvent, setAnalyticsCollectionEnabled } from "firebase/analytics"; +import { app as firebaseApp } from "../firebase"; + +export let Analytics: AnalyticsType; export async function log( eventName: string, @@ -11,3 +14,39 @@ export async function log( console.log("Analytics unavailable"); } } + +const lsString = localStorage.getItem("acceptedCookies"); +let acceptedCookies: { + security: boolean; + analytics: boolean; +} | null; +if (lsString) { + acceptedCookies = JSON.parse(lsString); +} else { + acceptedCookies = null; +} + +if (acceptedCookies !== null) { + if (acceptedCookies["analytics"] === true) { + activateAnalytics(); + } +} + +export function activateAnalytics(): void { + Analytics = getAnalytics(firebaseApp); + setAnalyticsCollectionEnabled(Analytics, true); + $("body").append(` + + `); +} diff --git a/frontend/src/ts/firebase.ts b/frontend/src/ts/firebase.ts index 86f84bed1..f3fcfec57 100644 --- a/frontend/src/ts/firebase.ts +++ b/frontend/src/ts/firebase.ts @@ -2,18 +2,14 @@ import { FirebaseApp, initializeApp } from "firebase/app"; import { getAuth, Auth as AuthType } from "firebase/auth"; import { firebaseConfig } from "./constants/firebase-config"; // eslint-disable-line require-path-exists/exists -import { Analytics as AnalyticsType, getAnalytics } from "firebase/analytics"; // Initialize Firebase -let app: FirebaseApp; - +export let app: FirebaseApp; export let Auth: AuthType; -export let Analytics: AnalyticsType; try { app = initializeApp(firebaseConfig); Auth = getAuth(app); - Analytics = getAnalytics(app); } catch (e) { console.error(e); $("body").text( diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts index 60a1e8639..1721cdc9f 100644 --- a/frontend/src/ts/pages/settings.ts +++ b/frontend/src/ts/pages/settings.ts @@ -12,6 +12,7 @@ import * as ImportExportSettingsPopup from "../popups/import-export-settings-pop import * as ConfigEvent from "../observables/config-event"; import * as ActivePage from "../states/active-page"; import * as ApeKeysPopup from "../popups/ape-keys-popup"; +import * as CookiePopup from "../popups/cookie-popup"; import Page from "./page"; import { Auth } from "../firebase"; @@ -1008,6 +1009,11 @@ $(".quickNav .links a").on("click", (e) => { isOpen && toggleSettingsGroup(settingsGroup); }); +$(".pageSettings .section.updateCookiePreferences .button").on("click", () => { + CookiePopup.show(); + CookiePopup.showSettings(); +}); + $(document).on( "change", `.pageSettings .section.autoSwitchThemeInputs select.light`, diff --git a/frontend/src/ts/popups/cookie-popup.ts b/frontend/src/ts/popups/cookie-popup.ts new file mode 100644 index 000000000..7ad53a929 --- /dev/null +++ b/frontend/src/ts/popups/cookie-popup.ts @@ -0,0 +1,87 @@ +import { activateAnalytics } from "../controllers/analytics-controller"; + +type Accepted = { + security: boolean; + analytics: boolean; +}; + +function getAcceptedObject(): Accepted | null { + const acceptedCookies = localStorage.getItem("acceptedCookies"); + if (acceptedCookies) { + return JSON.parse(acceptedCookies); + } else { + return null; + } +} + +function setAcceptedObject(obj: Accepted): void { + localStorage.setItem("acceptedCookies", JSON.stringify(obj)); +} + +export function check(): void { + const accepted = getAcceptedObject(); + if (accepted === null) { + show(); + } +} + +export function show(): void { + if ($("#cookiePopupWrapper").hasClass("hidden")) { + $("#wordsInput").blur(); + $("#cookiePopupWrapper") + .stop(true, true) + .css("opacity", 0) + .removeClass("hidden") + .animate({ opacity: 1 }, 100); + } +} + +export async function hide(): Promise { + if (!$("#cookiePopupWrapper").hasClass("hidden")) { + $("#cookiePopupWrapper") + .stop(true, true) + .css("opacity", 1) + .animate( + { + opacity: 0, + }, + 100, + () => { + $("#cookiePopupWrapper").addClass("hidden"); + } + ); + } +} + +export function showSettings(): void { + $("#cookiePopup .main").addClass("hidden"); + $("#cookiePopup .settings").removeClass("hidden"); +} + +$("#cookiePopup .acceptAll").on("click", () => { + const accepted = { + security: true, + analytics: true, + }; + setAcceptedObject(accepted); + activateAnalytics(); + hide(); +}); + +$("#cookiePopup .acceptSelected").on("click", () => { + const analytics = $("#cookiePopup .cookie.analytics input").prop("checked"); + const accepted = { + security: true, + analytics, + }; + setAcceptedObject(accepted); + hide(); + + if (analytics === true) { + activateAnalytics(); + } +}); + +$("#cookiePopup .openSettings").on("click", () => { + showSettings(); +}); diff --git a/frontend/src/ts/ready.ts b/frontend/src/ts/ready.ts index 28ede4acb..2a9c7b2c2 100644 --- a/frontend/src/ts/ready.ts +++ b/frontend/src/ts/ready.ts @@ -8,6 +8,7 @@ import * as MonkeyPower from "./elements/monkey-power"; import * as NewVersionNotification from "./elements/version-check"; import * as Notifications from "./elements/notifications"; import * as Focus from "./test/focus"; +import * as CookiePopup from "./popups/cookie-popup"; ManualRestart.set(); UpdateConfig.loadFromLocalStorage(); @@ -27,6 +28,7 @@ $(document).ready(() => { if (window.location.pathname === "/") { // $("#top .config").removeClass("hidden"); } + CookiePopup.check(); $("body").css("transition", "all .25s, transform .05s"); if (Config.quickTab) { $("#restartTestButton").addClass("hidden"); diff --git a/frontend/static/html/pages/settings.html b/frontend/static/html/pages/settings.html index 78b60e50a..4bccbcf6d 100644 --- a/frontend/static/html/pages/settings.html +++ b/frontend/static/html/pages/settings.html @@ -2345,6 +2345,18 @@ + + update cookie preferences + + If you changed your mind about which cookies you conset to, you can + change your preferences here. + + + + open + + + reset settings diff --git a/frontend/static/html/popups.html b/frontend/static/html/popups.html index f12081ac5..6a516dd6b 100644 --- a/frontend/static/html/popups.html +++ b/frontend/static/html/popups.html @@ -2,6 +2,64 @@ + + + + + We use cookies by the way + + + + Cookies enhance your experience and help us improve our website. + + + Accept all + + + + + + + + + Security + + We use Cloudflare cookies to improve security and performance of our + site. + + + They + do not + store any personal information and are required. + + + + + + + + + + + + Analytics + + We use Google Analytics cookies to check how users interact with our + website and use this data to improve our site design. + + + + + + + + + + Accept selected + + + + Share test settings diff --git a/frontend/static/index.html b/frontend/static/index.html index 245550b17..acd695e3f 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -59,20 +59,6 @@