@autobusal/providers 1.9.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Setup/Setup.tsx CHANGED
@@ -17,7 +17,11 @@ const Setup = ({ type, children }: Props): JSX.Element => {
17
17
 
18
18
  languages(type, data.preferences.languages.default);
19
19
 
20
- analytics(data.preferences.googleAnalyticsID);
20
+ // Edited: Ferjolt Ozuni - Date: 2026-08-01
21
+ // The brand's GTM container, from labels_settings via the admin GUI.
22
+ // obtapi sends `analytics` only when it is switched on AND configured, so
23
+ // this is a single truthy check with nothing to keep in sync.
24
+ analytics(data.analytics?.gtm_id);
21
25
 
22
26
  return (
23
27
  <Preload data={ data }>
@@ -1,18 +1,75 @@
1
- import ReactGA from 'react-ga4';
2
-
3
- // `send_page_view: false` disables gtag.js's automatic page_view on this
4
- // initial `config` call - client-side route changes in this SPA never
5
- // trigger another `config`, so relying on the automatic one meant only
6
- // the very first page of a session was ever tracked. Every pageview
7
- // (including the first) is instead sent explicitly from
8
- // @autobusal/common's Meta component, which re-fires on every route change
9
- // since it's rendered by (almost) every page - see the comment there.
10
- const analytics = (id: string | null): void => {
11
- if (id === null) {
1
+ /**
2
+ * Google Tag Manager, loaded per brand from the label's own settings.
3
+ *
4
+ * Edited: Ferjolt Ozuni - Date: 2026-08-01
5
+ *
6
+ * This replaced a direct GA4 (react-ga4) integration driven by
7
+ * `preferences.googleAnalyticsID`, which lived in each brand's static
8
+ * settings.json on disk - not in the database, with no admin screen, so
9
+ * changing it meant editing a file on the server. It was unset on every
10
+ * brand, so nothing was actually being measured.
11
+ *
12
+ * GTM instead, for the reason GTM exists: GA4, Ads and anything added later
13
+ * are configured in the container, so a new tag never needs a code change or
14
+ * a deploy. Nothing in this codebase should know which tags a brand runs.
15
+ *
16
+ * The dataLayer is created BEFORE the container script loads. GTM reads
17
+ * whatever is already queued there when it initialises, so anything pushed
18
+ * in the meantime - the first page_view, most importantly - survives the
19
+ * race with the network rather than being dropped.
20
+ */
21
+
22
+ declare global {
23
+ interface Window {
24
+ dataLayer?: Record<string, any>[]
25
+ }
26
+ }
27
+
28
+ const CONTAINER_ID = 'gtm-container';
29
+
30
+ const analytics = (container: string | null | undefined): void => {
31
+ if (!container) {
32
+ return;
33
+ }
34
+
35
+ // Guard against a second insert. Two containers on one page double-count
36
+ // every tag they fire, and Setup can re-run (a settings refetch, a
37
+ // remount) without the page ever reloading.
38
+ if (document.getElementById(CONTAINER_ID)) {
12
39
  return;
13
40
  }
14
41
 
15
- ReactGA.initialize(id, { gaOptions: { send_page_view: false } });
42
+ window.dataLayer = window.dataLayer || [];
43
+ window.dataLayer.push({ 'gtm.start': Date.now(), event: 'gtm.js' });
44
+
45
+ const script = document.createElement('script');
46
+
47
+ script.id = CONTAINER_ID;
48
+ script.async = true;
49
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${ encodeURIComponent(container) }`;
50
+
51
+ document.head.appendChild(script);
52
+ };
53
+
54
+ /**
55
+ * Announce a page view.
56
+ *
57
+ * A single-page app never reloads, so GTM's own page-load trigger fires
58
+ * exactly once per session - every client-side route change after that is
59
+ * invisible unless it is announced. The container is expected to listen for
60
+ * this `page_view` event and fire GA4 (or anything else) from it.
61
+ *
62
+ * Safe to call before GTM has finished loading: the push simply queues.
63
+ */
64
+ export const pageview = (path: string, title: string): void => {
65
+ window.dataLayer = window.dataLayer || [];
66
+
67
+ window.dataLayer.push({
68
+ event: 'page_view',
69
+ page_path: path,
70
+ page_title: title,
71
+ page_location: window.location.href
72
+ });
16
73
  };
17
74
 
18
75
  export default analytics;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/providers",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts"
package/types/settings.ts CHANGED
@@ -1,6 +1,24 @@
1
1
  export interface SettingsData {
2
2
  url: string
3
3
 
4
+ // Edited: Ferjolt Ozuni - Date: 2026-08-01
5
+ // Present ONLY while the brand is under construction - obtapi omits it
6
+ // entirely on a live site, so its presence is the switch itself and there
7
+ // is no separate boolean to disagree with.
8
+ construction?: {
9
+ title: string
10
+ message: string
11
+ } | null
12
+
13
+ // Edited: Ferjolt Ozuni - Date: 2026-08-01
14
+ // The brand's Google Tag Manager container, managed from the admin GUI.
15
+ // Present ONLY when analytics is switched on and a container is actually
16
+ // configured, so its presence is the switch. Replaces the old
17
+ // preferences.googleAnalyticsID, which lived in a static file on disk.
18
+ analytics?: {
19
+ gtm_id: string
20
+ } | null
21
+
4
22
  // Edited: Ferjolt Ozuni - Date: 2026-07-25
5
23
  // Runtime captcha config (provider + PUBLIC site key) from
6
24
  // /api/settings/get - replaces the build-time VITE_RECAPTCHA_KEY.
@@ -31,7 +49,10 @@ export interface SettingsData {
31
49
  preferences: {
32
50
  company: string
33
51
 
34
- googleAnalyticsID: string | null
52
+ /** @deprecated Replaced by the admin-managed GTM container - see
53
+ * `analytics` above. Nothing reads this any more; it remains only
54
+ * because it is still present in older brands' settings.json files. */
55
+ googleAnalyticsID?: string | null
35
56
  bookingID?: string
36
57
 
37
58
  operatorId?: number
@@ -221,6 +242,23 @@ export interface LabelSettings {
221
242
  description?: string
222
243
  keywords?: string
223
244
  }
245
+
246
+ // Edited: Ferjolt Ozuni - Date: 2026-08-01
247
+ // Admin-managed Google Tag Manager container. The PUBLIC settings payload
248
+ // exposes only the id, and only while enabled - see
249
+ // Labels\AdminController::analytics().
250
+ analytics?: {
251
+ enabled?: boolean
252
+ gtm_id?: string
253
+ }
254
+
255
+ // Edited: Ferjolt Ozuni - Date: 2026-08-01
256
+ // Admin-managed under-construction holding page.
257
+ construction?: {
258
+ enabled?: boolean
259
+ title?: string
260
+ message?: string
261
+ }
224
262
  }
225
263
 
226
264
  // Edited: Ferjolt Ozuni - Date: 2026-07-18