feat: gtm

This commit is contained in:
Nevo David 2026-05-14 16:50:01 +07:00
parent 5f2f5581b2
commit 630602858e
6 changed files with 89 additions and 0 deletions

3
.gitignore vendored
View file

@ -58,3 +58,6 @@ Thumbs.db
.secrets/
libraries/plugins/src/plugins.ts
i18n.cache
# Generated by apps/frontend/scripts/fetch-gtm.mjs on install
apps/frontend/public/g.js

View file

@ -5,6 +5,8 @@
"type": "module",
"scripts": {
"dev": "dotenv -e ../../.env -- next dev -p 4200",
"fetch-gtm": "node scripts/fetch-gtm.mjs",
"postinstall": "node scripts/fetch-gtm.mjs",
"build": "next build",
"build:sentry": "dotenv -e ../../.env -- next build",
"start": "dotenv -e ../../.env -- next start -p 4200",

View file

@ -0,0 +1,50 @@
import { writeFile, mkdir, readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const envPath = resolve(__dirname, '..', '..', '..', '.env');
const outPath = resolve(__dirname, '..', 'public', 'g.js');
if (!process.env.NEXT_PUBLIC_GTM_ID && existsSync(envPath)) {
const content = await readFile(envPath, 'utf8');
for (const raw of content.split('\n')) {
const line = raw.trim();
if (!line || line.startsWith('#')) continue;
const eq = line.indexOf('=');
if (eq === -1) continue;
const key = line.slice(0, eq).trim();
let value = line.slice(eq + 1).trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
if (!process.env[key]) process.env[key] = value;
}
}
const id = process.env.NEXT_PUBLIC_GTM_ID;
if (!id) {
console.log('[fetch-gtm] NEXT_PUBLIC_GTM_ID not set, skipping');
process.exit(0);
}
const url = `https://www.googletagmanager.com/gtm.js?id=${encodeURIComponent(id)}`;
try {
console.log(`[fetch-gtm] fetching ${url}`);
const res = await fetch(url);
if (!res.ok) {
console.warn(`[fetch-gtm] non-OK response ${res.status}, skipping`);
process.exit(0);
}
const body = await res.text();
await mkdir(dirname(outPath), { recursive: true });
await writeFile(outPath, body, 'utf8');
console.log(`[fetch-gtm] wrote ${outPath} (${body.length} bytes)`);
} catch (err) {
console.warn(`[fetch-gtm] failed: ${err?.message || err}, skipping`);
process.exit(0);
}

View file

@ -15,6 +15,7 @@ import { PHProvider } from '@gitroom/react/helpers/posthog';
import UtmSaver from '@gitroom/helpers/utils/utm.saver';
import { DubAnalytics } from '@gitroom/frontend/components/layout/dubAnalytics';
import { FacebookComponent } from '@gitroom/frontend/components/layout/facebook.component';
import { GoogleTagManagerComponent } from '@gitroom/frontend/components/layout/gtm.component';
import { cookies } from 'next/headers';
import {
cookieName,
@ -96,6 +97,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
<HtmlComponent />
<DubAnalytics />
<FacebookComponent />
<GoogleTagManagerComponent gtmId={process.env.NEXT_PUBLIC_GTM_ID} />
<Plausible
domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'}
>

View file

@ -0,0 +1,21 @@
'use client';
import Script from 'next/script';
import { FC } from 'react';
export const GoogleTagManagerComponent: FC<{ gtmId?: string }> = ({
gtmId,
}) => {
if (!gtmId) {
return null;
}
return (
<Script strategy="afterInteractive" id="gtm">
{`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'/g.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}');`}
</Script>
);
};

View file

@ -27,6 +27,17 @@ export const Onboarding: FC = () => {
}
return;
}
if (typeof window !== 'undefined') {
const check = query.get('check') || 'unknown';
const key = `gtm_start_trial_${check}`;
if (!sessionStorage.getItem(key)) {
sessionStorage.setItem(key, '1');
// @ts-ignore
window.dataLayer = window.dataLayer || [];
// @ts-ignore
window.dataLayer.push({ event: 'start_trial', check });
}
}
if (modalOpen.current) {
return;
}