Skip to content

Commit 42d348e

Browse files
Integrate ReoDev (#951)
1 parent 597dc11 commit 42d348e

File tree

9 files changed

+169
-22
lines changed

9 files changed

+169
-22
lines changed

docs/.vuepress/client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import KapaWidget from './components/KapaWidget.vue';
88
import UserFeedback from './components/TocWithFeedback';
99
import SidebarLayout from "./layouts/SidebarLayout.vue";
1010
import {usePostHog} from "./lib/usePosthog";
11+
import { useReoDev } from "./lib/useReoDev";
1112

1213
declare const __VERSIONS__: {
1314
latest: string,
@@ -57,8 +58,9 @@ export default defineClientConfig({
5758
layouts: {
5859
Layout: SidebarLayout
5960
},
60-
enhance({app, router, _}) {
61+
enhance({app, router}) {
6162
const { hasConsent, posthog } = usePostHog();
63+
useReoDev();
6264

6365
const captureEvent = (event: string, properties?: Record<string, any>) => {
6466
if (!hasConsent()) return;

docs/.vuepress/lib/consent.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Type declarations for Cookiebot
2+
declare global {
3+
interface Window {
4+
Cookiebot?: {
5+
consent?: {
6+
necessary?: boolean;
7+
preferences?: boolean;
8+
statistics?: boolean;
9+
marketing?: boolean;
10+
};
11+
renew?: () => void;
12+
withdraw?: () => void;
13+
};
14+
}
15+
}
16+
17+
/**
18+
* Checks if the user has given consent for statistics cookies.
19+
* This is used for analytics tools like PostHog and Reo.dev.
20+
*/
21+
export function hasStatisticsConsent(): boolean {
22+
if (typeof window === "undefined") return false;
23+
return window.Cookiebot?.consent?.statistics === true;
24+
}

docs/.vuepress/lib/usePosthog.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import posthog from "posthog-js";
2+
import { hasStatisticsConsent } from "./consent";
23

34
const POSTHOG_CONFIG = {
45
apiKey: "phc_DeHBgHGersY4LmDlADnPrsCPOAmMO7QFOH8f4DVEVmD",
@@ -8,11 +9,6 @@ const POSTHOG_CONFIG = {
89
let isInitialized = false;
910
let listenersRegistered = false;
1011

11-
function hasStatisticsConsent(): boolean {
12-
if (typeof window === "undefined") return false;
13-
return window.Cookiebot?.consent?.statistics === true;
14-
}
15-
1612
function initializePostHog(): void {
1713
if (isInitialized) return;
1814
try {
@@ -86,19 +82,3 @@ export function usePostHog() {
8682
hasConsent: hasStatisticsConsent,
8783
};
8884
}
89-
90-
// Type declarations for Cookiebot
91-
declare global {
92-
interface Window {
93-
Cookiebot?: {
94-
consent?: {
95-
necessary?: boolean;
96-
preferences?: boolean;
97-
statistics?: boolean;
98-
marketing?: boolean;
99-
};
100-
renew?: () => void;
101-
withdraw?: () => void;
102-
};
103-
}
104-
}

docs/.vuepress/lib/useReoDev.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { loadReoScript } from "reodotdev";
2+
import { hasStatisticsConsent } from "./consent";
3+
4+
let listenersRegistered = false;
5+
let isInitialized = false;
6+
let reoInstance: any | null = null;
7+
let reoPromise: Promise<any> | null = null;
8+
9+
declare global {
10+
interface Window {
11+
Reo?: unknown;
12+
}
13+
}
14+
15+
const CLIENT_ID = "f1c2b9fbebbf202";
16+
17+
function stopReoDev(): void {
18+
if (typeof window === "undefined" || typeof document === "undefined") return;
19+
20+
try {
21+
const reoPrefix = "__sec__";
22+
Object.keys(localStorage).forEach((key) => {
23+
if (key.startsWith(reoPrefix)) {
24+
localStorage.removeItem(key);
25+
}
26+
});
27+
} catch (_error) {
28+
console.error("Error clearing Reo LocalStorage");
29+
}
30+
31+
try {
32+
const cookies = document.cookie.split(";");
33+
const expiry = "expires=Thu, 01 Jan 1970 00:00:00 GMT";
34+
35+
const domainParts = window.location.hostname.split('.');
36+
const mainDomain = domainParts.length > 2 ? `.${domainParts.slice(-2).join('.')}` : '';
37+
38+
for (let i = 0; i < cookies.length; i++) {
39+
const name = cookies[i].split("=")[0].trim();
40+
41+
if (name.startsWith("__sec__")) {
42+
document.cookie = `${name}=;${expiry};path=/;`;
43+
if (mainDomain) {
44+
document.cookie = `${name}=;${expiry};path=/;domain=${mainDomain};`;
45+
}
46+
}
47+
}
48+
} catch (_error) {
49+
console.error("Error resetting Reo cookies");
50+
}
51+
52+
const Reo: any = (window.Reo ?? reoInstance) as any;
53+
try {
54+
Reo?.unload?.();
55+
Reo?.reset?.();
56+
} catch (error) {
57+
console.error("Error stopping Reo instance");
58+
}
59+
60+
document.querySelectorAll('script[src*="reo.dev"]').forEach(el => el.remove());
61+
62+
isInitialized = false;
63+
reoInstance = null;
64+
reoPromise = null;
65+
window.Reo = undefined;
66+
}
67+
68+
async function initializeReoDev(): Promise<void> {
69+
if (typeof window === "undefined") return;
70+
if (!hasStatisticsConsent()) return;
71+
if (isInitialized || reoInstance || reoPromise || typeof window.Reo !== 'undefined') return;
72+
73+
try {
74+
reoPromise = loadReoScript({ clientID: CLIENT_ID });
75+
reoInstance = await reoPromise;
76+
reoInstance.init({ clientID: CLIENT_ID });
77+
isInitialized = true;
78+
} catch (error) {
79+
console.error("Error loading Reo");
80+
reoInstance = null;
81+
} finally {
82+
reoPromise = null;
83+
}
84+
}
85+
86+
function applyConsentState(): void {
87+
if (hasStatisticsConsent()) void initializeReoDev();
88+
else stopReoDev();
89+
}
90+
91+
function setupConsentListeners(): void {
92+
if (typeof window === "undefined") return;
93+
if (listenersRegistered) return;
94+
listenersRegistered = true;
95+
96+
window.addEventListener("CookiebotOnAccept", applyConsentState);
97+
window.addEventListener("CookiebotOnDecline", applyConsentState);
98+
window.addEventListener("CookiebotOnConsentReady", applyConsentState);
99+
}
100+
101+
export function useReoDev() {
102+
if (typeof window !== "undefined") {
103+
setupConsentListeners();
104+
applyConsentState();
105+
}
106+
107+
return {
108+
hasConsent: hasStatisticsConsent,
109+
init: initializeReoDev,
110+
};
111+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
declare module "reodotdev" {
2+
export type ReoClient = {
3+
init: (options: { clientID: string }) => void;
4+
[key: string]: unknown;
5+
};
6+
7+
export function loadReoScript(options: {
8+
clientID: string;
9+
scriptUrlPattern?: string | string[];
10+
version?: string;
11+
}): Promise<ReoClient>;
12+
}
13+

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"iconify-icon": "^2.1.0",
5050
"mermaid": "^11.4.0",
5151
"posthog-js": "^1.235.0",
52+
"reodotdev": "^1.0.0",
5253
"sass-loader": "^16.0.5",
5354
"uglify-js": "^3.19.3",
5455
"vue": "^3.5.17",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"declaration": false,
99
"allowJs": true
1010
},
11+
"files": ["docs/.vuepress/types/reodotdev.d.ts"],
1112
"include": ["**/.vuepress/**/*"],
1213
"exclude": ["node_modules", ".cache", ".temp", "dist"]
1314
}

0 commit comments

Comments
 (0)