@endora-commerce/mod-google-analytics 0.100.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/admin/api/google-analytics-client.d.ts +17 -0
  4. package/dist/admin/api/google-analytics-client.d.ts.map +1 -0
  5. package/dist/admin/api/google-analytics-client.js +21 -0
  6. package/dist/admin/api/google-analytics-client.js.map +1 -0
  7. package/dist/admin/index.d.ts +29 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +63 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/CustomEventEditPage.d.ts +3 -0
  12. package/dist/admin/pages/CustomEventEditPage.d.ts.map +1 -0
  13. package/dist/admin/pages/CustomEventEditPage.js +179 -0
  14. package/dist/admin/pages/CustomEventEditPage.js.map +1 -0
  15. package/dist/admin/pages/CustomEventsListPage.d.ts +8 -0
  16. package/dist/admin/pages/CustomEventsListPage.d.ts.map +1 -0
  17. package/dist/admin/pages/CustomEventsListPage.js +36 -0
  18. package/dist/admin/pages/CustomEventsListPage.js.map +1 -0
  19. package/dist/backend/entities/ga-custom-event.entity.d.ts +26 -0
  20. package/dist/backend/entities/ga-custom-event.entity.d.ts.map +1 -0
  21. package/dist/backend/entities/ga-custom-event.entity.js +82 -0
  22. package/dist/backend/entities/ga-custom-event.entity.js.map +1 -0
  23. package/dist/backend/index.d.ts +85 -0
  24. package/dist/backend/index.d.ts.map +1 -0
  25. package/dist/backend/index.js +102 -0
  26. package/dist/backend/index.js.map +1 -0
  27. package/dist/backend/routes.admin.d.ts +15 -0
  28. package/dist/backend/routes.admin.d.ts.map +1 -0
  29. package/dist/backend/routes.admin.js +35 -0
  30. package/dist/backend/routes.admin.js.map +1 -0
  31. package/dist/backend/routes.storefront.d.ts +17 -0
  32. package/dist/backend/routes.storefront.d.ts.map +1 -0
  33. package/dist/backend/routes.storefront.js +30 -0
  34. package/dist/backend/routes.storefront.js.map +1 -0
  35. package/dist/backend/services/cookie-consent-block-seeder.d.ts +29 -0
  36. package/dist/backend/services/cookie-consent-block-seeder.d.ts.map +1 -0
  37. package/dist/backend/services/cookie-consent-block-seeder.js +51 -0
  38. package/dist/backend/services/cookie-consent-block-seeder.js.map +1 -0
  39. package/dist/backend/services/custom-events.service.d.ts +54 -0
  40. package/dist/backend/services/custom-events.service.d.ts.map +1 -0
  41. package/dist/backend/services/custom-events.service.js +158 -0
  42. package/dist/backend/services/custom-events.service.js.map +1 -0
  43. package/dist/backend/services/ga-config.service.d.ts +27 -0
  44. package/dist/backend/services/ga-config.service.d.ts.map +1 -0
  45. package/dist/backend/services/ga-config.service.js +66 -0
  46. package/dist/backend/services/ga-config.service.js.map +1 -0
  47. package/dist/backend/services/ga4-mp-client.d.ts +32 -0
  48. package/dist/backend/services/ga4-mp-client.d.ts.map +1 -0
  49. package/dist/backend/services/ga4-mp-client.js +46 -0
  50. package/dist/backend/services/ga4-mp-client.js.map +1 -0
  51. package/dist/backend/services/ss-delivery-queue.d.ts +32 -0
  52. package/dist/backend/services/ss-delivery-queue.d.ts.map +1 -0
  53. package/dist/backend/services/ss-delivery-queue.js +29 -0
  54. package/dist/backend/services/ss-delivery-queue.js.map +1 -0
  55. package/dist/backend/services/ss-delivery.service.d.ts +24 -0
  56. package/dist/backend/services/ss-delivery.service.d.ts.map +1 -0
  57. package/dist/backend/services/ss-delivery.service.js +52 -0
  58. package/dist/backend/services/ss-delivery.service.js.map +1 -0
  59. package/dist/manifest.d.ts +194 -0
  60. package/dist/manifest.d.ts.map +1 -0
  61. package/dist/manifest.js +134 -0
  62. package/dist/manifest.js.map +1 -0
  63. package/dist/migrations/20260715T171116_google_analytics_init.d.ts +14 -0
  64. package/dist/migrations/20260715T171116_google_analytics_init.d.ts.map +1 -0
  65. package/dist/migrations/20260715T171116_google_analytics_init.js +35 -0
  66. package/dist/migrations/20260715T171116_google_analytics_init.js.map +1 -0
  67. package/dist/migrations/index.d.ts +28 -0
  68. package/dist/migrations/index.d.ts.map +1 -0
  69. package/dist/migrations/index.js +28 -0
  70. package/dist/migrations/index.js.map +1 -0
  71. package/docs/google-analytics.md +106 -0
  72. package/i18n/en.json +33 -0
  73. package/i18n/pl.json +33 -0
  74. package/package.json +98 -0
  75. package/tailwind.css +14 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ <!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
2
+
3
+ # @endora-commerce/mod-google-analytics
4
+
5
+ Google Analytics 4 integration: per-sales-channel activation and Measurement ID, Enhanced Ecommerce, configurable custom events, and optional server-side tagging.
6
+
7
+ ## What this is
8
+
9
+ An **Endora Commerce module package**. Its module id is `google_analytics` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
10
+
11
+ A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
12
+
13
+ ## Entry points
14
+
15
+ | Import | Contents |
16
+ | --- | --- |
17
+ | `@endora-commerce/mod-google-analytics` | the module manifest — its id, version, dependencies, settings and activation |
18
+ | `@endora-commerce/mod-google-analytics/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
19
+ | `@endora-commerce/mod-google-analytics/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
20
+ | `@endora-commerce/mod-google-analytics/migrations` | the module’s own schema migrations, in the order the platform runs them |
21
+ | `@endora-commerce/mod-google-analytics/tailwind.css` | the Tailwind source declaration for the admin code above |
22
+
23
+ ## Depends on
24
+
25
+ Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
26
+
27
+ **Endora packages**
28
+
29
+ - `@endora-commerce/admin-kit` — *optional*
30
+ - `@endora-commerce/contracts`
31
+ - `@endora-commerce/platform`
32
+
33
+ **Third-party**
34
+
35
+ - `@mikro-orm/core` ^6
36
+ - `@mikro-orm/migrations` ^6
37
+ - `@mikro-orm/postgresql` ^6
38
+ - `bullmq` ^5
39
+ - `fastify` ^5
40
+ - `ioredis` ^5
41
+ - `react` ^19 — *optional*
42
+ - `react-router-dom` ^7 — *optional*
43
+ - `zod` ^4
44
+
45
+ ## What the tarball carries
46
+
47
+ - `dist/` — the compiled JavaScript and its type declarations
48
+ - `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
49
+ - `docs/` — the package’s own pages in the Endora Commerce documentation site
50
+ - `tailwind.css` — the Tailwind source declaration
51
+
52
+ ## Install
53
+
54
+ ```bash
55
+ pnpm add @endora-commerce/mod-google-analytics
56
+ ```
57
+
58
+ ## Licence
59
+
60
+ MIT — the text is in `LICENSE`, beside this file.
@@ -0,0 +1,17 @@
1
+ import type { GaCustomEventCreate, GaCustomEventResponse, GaCustomEventUpdate, GaTriggerAction } from '@endora-commerce/contracts';
2
+ export type GaActionCatalogue = Record<GaTriggerAction, {
3
+ static: string[] | null;
4
+ }>;
5
+ /** Typed admin client for the Google Analytics module (feature 049). */
6
+ export declare const googleAnalyticsClient: {
7
+ actionCatalogue: () => Promise<GaActionCatalogue>;
8
+ list: (query?: {
9
+ salesChannelCode?: string;
10
+ triggerAction?: GaTriggerAction;
11
+ }) => Promise<GaCustomEventResponse[]>;
12
+ get: (id: string) => Promise<GaCustomEventResponse>;
13
+ create: (body: GaCustomEventCreate) => Promise<GaCustomEventResponse>;
14
+ update: (id: string, body: GaCustomEventUpdate) => Promise<GaCustomEventResponse>;
15
+ remove: (id: string) => Promise<void>;
16
+ };
17
+ //# sourceMappingURL=google-analytics-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-analytics-client.d.ts","sourceRoot":"","sources":["../../../src/admin/api/google-analytics-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAMpC,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,eAAe,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC;AAErF,wEAAwE;AACxE,eAAO,MAAM,qBAAqB;2BACX,OAAO,CAAC,iBAAiB,CAAC;mBAGjC;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,eAAe,CAAA;KAAE,KAAQ,OAAO,CACzF,qBAAqB,EAAE,CACxB;cAUS,MAAM,KAAG,OAAO,CAAC,qBAAqB,CAAC;mBAGlC,mBAAmB,KAAG,OAAO,CAAC,qBAAqB,CAAC;iBAGtD,MAAM,QAAQ,mBAAmB,KAAG,OAAO,CAAC,qBAAqB,CAAC;iBAGlE,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAEpC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { apiClient } from '@endora-commerce/admin-kit/lib';
2
+ const unwrap = (p) => p.then((r) => r.data);
3
+ const BASE = '/api/v1/admin/google-analytics';
4
+ /** Typed admin client for the Google Analytics module (feature 049). */
5
+ export const googleAnalyticsClient = {
6
+ actionCatalogue: () => unwrap(apiClient.get(`${BASE}/action-catalogue`)),
7
+ list: (query = {}) => {
8
+ const sp = new URLSearchParams();
9
+ if (query.salesChannelCode)
10
+ sp.set('salesChannelCode', query.salesChannelCode);
11
+ if (query.triggerAction)
12
+ sp.set('triggerAction', query.triggerAction);
13
+ const tail = sp.toString();
14
+ return unwrap(apiClient.get(`${BASE}/custom-events${tail ? `?${tail}` : ''}`));
15
+ },
16
+ get: (id) => unwrap(apiClient.get(`${BASE}/custom-events/${id}`)),
17
+ create: (body) => unwrap(apiClient.post(`${BASE}/custom-events`, body)),
18
+ update: (id, body) => unwrap(apiClient.patch(`${BASE}/custom-events/${id}`, body)),
19
+ remove: (id) => apiClient.delete(`${BASE}/custom-events/${id}`).then(() => undefined),
20
+ };
21
+ //# sourceMappingURL=google-analytics-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-analytics-client.js","sourceRoot":"","sources":["../../../src/admin/api/google-analytics-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAS3D,MAAM,MAAM,GAAG,CAAI,CAAmB,EAAc,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7E,MAAM,IAAI,GAAG,gCAAgC,CAAC;AAI9C,wEAAwE;AACxE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,eAAe,EAAE,GAA+B,EAAE,CAChD,MAAM,CAAC,SAAS,CAAC,GAAG,CAA0B,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAE5E,IAAI,EAAE,CAAC,QAAwE,EAAE,EAE/E,EAAE;QACF,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,gBAAgB;YAAE,EAAE,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC/E,IAAI,KAAK,CAAC,aAAa;YAAE,EAAE,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,MAAM,CACX,SAAS,CAAC,GAAG,CAAgC,GAAG,IAAI,iBAAiB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAC/F,CAAC;IACJ,CAAC;IAED,GAAG,EAAE,CAAC,EAAU,EAAkC,EAAE,CAClD,MAAM,CAAC,SAAS,CAAC,GAAG,CAA8B,GAAG,IAAI,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAEnF,MAAM,EAAE,CAAC,IAAyB,EAAkC,EAAE,CACpE,MAAM,CAAC,SAAS,CAAC,IAAI,CAA8B,GAAG,IAAI,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAEpF,MAAM,EAAE,CAAC,EAAU,EAAE,IAAyB,EAAkC,EAAE,CAChF,MAAM,CAAC,SAAS,CAAC,KAAK,CAA8B,GAAG,IAAI,kBAAkB,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAE3F,MAAM,EAAE,CAAC,EAAU,EAAiB,EAAE,CACpC,SAAS,CAAC,MAAM,CAAO,GAAG,IAAI,kBAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;CAC9E,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `google_analytics`' admin surface — three routes and one sidebar entry,
3
+ * declared by the module that owns them (feature 091, Phase 4;
4
+ * `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
5
+ *
6
+ * This is the first batch of the drain. It was selected by the rule
7
+ * `research.md` §6 sets — ascending incoming cross-module reach — and this
8
+ * module has **none in either direction**: no admin file outside its own
9
+ * directory reached into it, and its three files reached nothing but the host
10
+ * design system, every symbol of which `@endora-commerce/admin-kit` publishes.
11
+ * The reason that matters is not tidiness: a directory something reaches into
12
+ * cannot move until the reach has an answer, and a directory that reaches out
13
+ * cannot move until what it reaches is published — so the batches are ordered
14
+ * by the reach and not by the size of the screen.
15
+ *
16
+ * **This entry exports data and nothing else** (R2), like every `./admin`
17
+ * layer: `check:module-boundary`'s D-171 rule designates a subpath as contract
18
+ * surface when it emits no runtime binding, and `./admin` deliberately does not
19
+ * qualify, so a consumer reaching into another module's `./admin` stays a
20
+ * counted boundary reach.
21
+ *
22
+ * **Every component is a dynamic-import factory** (R6). The editor is named
23
+ * twice below — once for `/new` and once for `/:id` — and both are the same
24
+ * factory value, so Vite emits one chunk for the screen rather than one per
25
+ * route.
26
+ */
27
+ import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
28
+ export declare const contributions: AdminContributions;
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAgBnF,eAAO,MAAM,aAAa,EAAE,kBAkD3B,CAAC"}
@@ -0,0 +1,63 @@
1
+ /** The module's landing route: the custom-event list. */
2
+ const ROUTE_PATH = '/google-analytics';
3
+ /**
4
+ * The create and edit screens are one component behind one factory.
5
+ *
6
+ * `react-router` matches `/google-analytics/new` against the parametric route
7
+ * too, so the two declarations are deliberately separate — the editor reads
8
+ * `id === 'new'` as its create mode, which is the behaviour the host route
9
+ * table had when it declared both paths against one imported component.
10
+ */
11
+ const editor = () => import('./pages/CustomEventEditPage.js');
12
+ export const contributions = {
13
+ routes: [
14
+ {
15
+ path: ROUTE_PATH,
16
+ component: () => import('./pages/CustomEventsListPage.js'),
17
+ // Read from the route this screen calls
18
+ // (`requireAdmin('google_analytics:read')` on
19
+ // `GET /admin/google-analytics/custom-events`), not copied from a
20
+ // neighbour — the rule `check:action-route-permissions` already holds
21
+ // this module's `open-google-analytics` palette action to.
22
+ requiredPermission: 'google_analytics:read',
23
+ index: true,
24
+ },
25
+ {
26
+ path: `${ROUTE_PATH}/new`,
27
+ component: editor,
28
+ // The create form posts to `POST /admin/google-analytics/custom-events`,
29
+ // which enforces the write code — the same code the
30
+ // `new-google-analytics-event` palette action declares for this path.
31
+ requiredPermission: 'google_analytics:write',
32
+ },
33
+ {
34
+ path: `${ROUTE_PATH}/:id`,
35
+ component: editor,
36
+ requiredPermission: 'google_analytics:write',
37
+ },
38
+ ],
39
+ nav: [
40
+ {
41
+ to: ROUTE_PATH,
42
+ // Module-relative (R8), resolved in this module's own namespace out of
43
+ // `packages/modules/google_analytics/i18n/`. It was
44
+ // `appShell.nav.googleAnalytics` in the shared `_i18n` bundle, one of the
45
+ // four shared files a module author had to edit.
46
+ labelKey: 'nav.googleAnalytics.label',
47
+ // The icon the hand-written NAV entry carried.
48
+ icon: 'Sparkles',
49
+ section: 'analyticsAds',
50
+ // The weight the hand-written NAV gave it by position: second of the four
51
+ // entries in the Analytics & Ads group. It does not restore that position
52
+ // yet — a module's entries append to their section until the host's own
53
+ // entries carry weights, which is Story 3's to deliver as it drains them
54
+ // — so the number records the intent rather than the current render.
55
+ weight: 200,
56
+ // The code that opens the screen. The sidebar advertises a destination,
57
+ // so it gates on the read code the landing route enforces and not on the
58
+ // write code its editor does.
59
+ requiredPermission: 'google_analytics:read',
60
+ },
61
+ ],
62
+ };
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AA4BA,yDAAyD;AACzD,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,MAAM,GAAG,GAA2C,EAAE,CAC1D,MAAM,CAAC,gCAAgC,CAAC,CAAC;AAE3C,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iCAAiC,CAAC;YAC1D,wCAAwC;YACxC,8CAA8C;YAC9C,kEAAkE;YAClE,sEAAsE;YACtE,2DAA2D;YAC3D,kBAAkB,EAAE,uBAAuB;YAC3C,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,GAAG,UAAU,MAAM;YACzB,SAAS,EAAE,MAAM;YACjB,yEAAyE;YACzE,oDAAoD;YACpD,sEAAsE;YACtE,kBAAkB,EAAE,wBAAwB;SAC7C;QACD;YACE,IAAI,EAAE,GAAG,UAAU,MAAM;YACzB,SAAS,EAAE,MAAM;YACjB,kBAAkB,EAAE,wBAAwB;SAC7C;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,oDAAoD;YACpD,0EAA0E;YAC1E,iDAAiD;YACjD,QAAQ,EAAE,2BAA2B;YACrC,+CAA+C;YAC/C,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,cAAc;YACvB,0EAA0E;YAC1E,0EAA0E;YAC1E,wEAAwE;YACxE,yEAAyE;YACzE,qEAAqE;YACrE,MAAM,EAAE,GAAG;YACX,wEAAwE;YACxE,yEAAyE;YACzE,8BAA8B;YAC9B,kBAAkB,EAAE,uBAAuB;SAC5C;KACF;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ReactNode } from 'react';
2
+ export default function CustomEventEditPage(): ReactNode;
3
+ //# sourceMappingURL=CustomEventEditPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomEventEditPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/CustomEventEditPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAuClF,MAAM,CAAC,OAAO,UAAU,mBAAmB,IAAI,SAAS,CA0RvD"}
@@ -0,0 +1,179 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useState } from 'react';
3
+ import { useNavigate, useParams } from 'react-router-dom';
4
+ import { ApiError } from '@endora-commerce/admin-kit/lib';
5
+ import { Alert, AlertDescription, Button, Card, CardContent, Checkbox, Input, Label, PageHeader, Select, } from '@endora-commerce/admin-kit/ui';
6
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
7
+ import { googleAnalyticsClient } from '../api/google-analytics-client.js';
8
+ const ACTIONS = [
9
+ 'contact_form_submitted',
10
+ 'place_order_clicked',
11
+ 'add_to_cart',
12
+ 'add_to_quote_request',
13
+ 'add_to_shopping_list',
14
+ 'button_click_by_id',
15
+ ];
16
+ export default function CustomEventEditPage() {
17
+ const t = useTranslation('google_analytics');
18
+ const { id } = useParams();
19
+ const navigate = useNavigate();
20
+ const isCreate = id === 'new' || id === undefined;
21
+ const [catalogue, setCatalogue] = useState(null);
22
+ const [loading, setLoading] = useState(!isCreate);
23
+ const [saving, setSaving] = useState(false);
24
+ const [error, setError] = useState(null);
25
+ const [version, setVersion] = useState(null);
26
+ const [eventName, setEventName] = useState('');
27
+ const [triggerAction, setTriggerAction] = useState('add_to_cart');
28
+ const [buttonId, setButtonId] = useState('');
29
+ const [channelCode, setChannelCode] = useState('');
30
+ const [enabled, setEnabled] = useState(true);
31
+ const [staticSelected, setStaticSelected] = useState(new Set());
32
+ const [dynamicRows, setDynamicRows] = useState([]);
33
+ const staticFields = useMemo(() => catalogue?.[triggerAction]?.static ?? null, [catalogue, triggerAction]);
34
+ useEffect(() => {
35
+ let cancelled = false;
36
+ (async () => {
37
+ try {
38
+ const cat = await googleAnalyticsClient.actionCatalogue();
39
+ if (cancelled)
40
+ return;
41
+ setCatalogue(cat);
42
+ if (!isCreate) {
43
+ const ev = await googleAnalyticsClient.get(id);
44
+ if (cancelled)
45
+ return;
46
+ hydrate(ev, cat);
47
+ }
48
+ }
49
+ catch (err) {
50
+ if (!cancelled)
51
+ setError(err instanceof ApiError ? err.envelope.error.message : String(err));
52
+ }
53
+ finally {
54
+ if (!cancelled)
55
+ setLoading(false);
56
+ }
57
+ })();
58
+ return () => {
59
+ cancelled = true;
60
+ };
61
+ // eslint-disable-next-line react-hooks/exhaustive-deps
62
+ }, [id]);
63
+ function hydrate(ev, cat) {
64
+ setEventName(ev.eventName);
65
+ setTriggerAction(ev.triggerAction);
66
+ setButtonId(ev.buttonId ?? '');
67
+ setChannelCode(ev.salesChannelCode ?? '');
68
+ setEnabled(ev.enabled);
69
+ setVersion(ev.version);
70
+ const isStatic = cat[ev.triggerAction]?.static !== null;
71
+ if (isStatic) {
72
+ setStaticSelected(new Set(ev.fields.map((f) => f.fieldKey)));
73
+ }
74
+ else {
75
+ setDynamicRows(ev.fields.map((f) => ({ fieldKey: f.fieldKey, payloadKey: f.payloadKey ?? '' })));
76
+ }
77
+ }
78
+ function buildFields() {
79
+ if (staticFields !== null) {
80
+ return staticFields
81
+ .filter((k) => staticSelected.has(k))
82
+ .map((fieldKey, position) => ({ fieldKey, position }));
83
+ }
84
+ return dynamicRows
85
+ .filter((r) => r.fieldKey.trim())
86
+ .map((r, position) => ({
87
+ fieldKey: r.fieldKey.trim(),
88
+ position,
89
+ ...(r.payloadKey.trim() ? { payloadKey: r.payloadKey.trim() } : {}),
90
+ }));
91
+ }
92
+ const save = useCallback(async () => {
93
+ setSaving(true);
94
+ setError(null);
95
+ try {
96
+ const fields = buildFields();
97
+ const isButton = triggerAction === 'button_click_by_id';
98
+ if (isCreate) {
99
+ const body = {
100
+ eventName,
101
+ triggerAction,
102
+ enabled,
103
+ fields,
104
+ ...(channelCode.trim() ? { salesChannelCode: channelCode.trim() } : {}),
105
+ ...(isButton ? { buttonId: buttonId.trim() } : {}),
106
+ };
107
+ await googleAnalyticsClient.create(body);
108
+ }
109
+ else {
110
+ const body = {
111
+ eventName,
112
+ triggerAction,
113
+ enabled,
114
+ fields,
115
+ version: version ?? 1,
116
+ salesChannelCode: channelCode.trim() ? channelCode.trim() : null,
117
+ buttonId: isButton ? buttonId.trim() : null,
118
+ };
119
+ await googleAnalyticsClient.update(id, body);
120
+ }
121
+ navigate('/google-analytics');
122
+ }
123
+ catch (err) {
124
+ setError(err instanceof ApiError ? err.envelope.error.message : String(err));
125
+ }
126
+ finally {
127
+ setSaving(false);
128
+ }
129
+ // eslint-disable-next-line react-hooks/exhaustive-deps
130
+ }, [
131
+ eventName,
132
+ triggerAction,
133
+ enabled,
134
+ channelCode,
135
+ buttonId,
136
+ version,
137
+ id,
138
+ isCreate,
139
+ staticSelected,
140
+ dynamicRows,
141
+ staticFields,
142
+ ]);
143
+ const remove = useCallback(async () => {
144
+ if (isCreate)
145
+ return;
146
+ setSaving(true);
147
+ try {
148
+ await googleAnalyticsClient.remove(id);
149
+ navigate('/google-analytics');
150
+ }
151
+ catch (err) {
152
+ setError(err instanceof ApiError ? err.envelope.error.message : String(err));
153
+ setSaving(false);
154
+ }
155
+ }, [id, isCreate, navigate]);
156
+ if (loading)
157
+ return _jsx("p", { className: "p-6 text-muted-foreground", children: "\u2026" });
158
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: isCreate ? t('customEvents.new') : t('customEvents.edit') }), error && (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })), _jsx(Card, { children: _jsxs(CardContent, { className: "flex flex-col gap-4 pt-6", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ga-name", children: t('customEvents.eventName') }), _jsx(Input, { id: "ga-name", value: eventName, onChange: (e) => setEventName(e.target.value) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ga-action", children: t('customEvents.triggerAction') }), _jsx(Select, { id: "ga-action", value: triggerAction, onChange: (e) => {
159
+ setTriggerAction(e.target.value);
160
+ setStaticSelected(new Set());
161
+ setDynamicRows([]);
162
+ }, children: ACTIONS.map((a) => (_jsx("option", { value: a, children: t(`customEvents.actions.${a}`) }, a))) })] }), triggerAction === 'button_click_by_id' && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ga-button", children: t('customEvents.buttonId') }), _jsx(Input, { id: "ga-button", value: buttonId, onChange: (e) => setButtonId(e.target.value) })] })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ga-channel", children: t('customEvents.salesChannel') }), _jsx(Input, { id: "ga-channel", value: channelCode, placeholder: t('customEvents.allChannels'), onChange: (e) => setChannelCode(e.target.value) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: "ga-enabled", checked: enabled, onChange: (e) => setEnabled(e.target.checked) }), _jsx(Label, { htmlFor: "ga-enabled", className: "cursor-pointer", children: t('customEvents.enabled') })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t('customEvents.fields') }), staticFields !== null ? (_jsx("div", { className: "flex flex-col gap-2", children: staticFields.map((key) => (_jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx(Checkbox, { id: `ga-field-${key}`, checked: staticSelected.has(key), onChange: (e) => {
163
+ const next = new Set(staticSelected);
164
+ if (e.target.checked)
165
+ next.add(key);
166
+ else
167
+ next.delete(key);
168
+ setStaticSelected(next);
169
+ } }), _jsx("span", { children: key })] }, key))) })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: t('customEvents.fieldsHint') }), dynamicRows.map((row, i) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { placeholder: t('customEvents.fieldKey'), value: row.fieldKey, onChange: (e) => {
170
+ const next = [...dynamicRows];
171
+ next[i] = { ...row, fieldKey: e.target.value };
172
+ setDynamicRows(next);
173
+ } }), _jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: t('customEvents.sentAs') }), _jsx(Input, { placeholder: t('customEvents.payloadKeyHint'), value: row.payloadKey, onChange: (e) => {
174
+ const next = [...dynamicRows];
175
+ next[i] = { ...row, payloadKey: e.target.value };
176
+ setDynamicRows(next);
177
+ } }), _jsx(Button, { variant: "ghost", onClick: () => setDynamicRows(dynamicRows.filter((_, j) => j !== i)), children: "\u00D7" })] }, i))), _jsx(Button, { variant: "outline", onClick: () => setDynamicRows([...dynamicRows, { fieldKey: '', payloadKey: '' }]), children: t('customEvents.addField') })] }))] }), _jsxs("div", { className: "flex items-center gap-2 pt-2", children: [_jsx(Button, { onClick: () => void save(), disabled: saving, children: t('customEvents.save') }), !isCreate && (_jsx(Button, { variant: "destructive", onClick: () => void remove(), disabled: saving, children: t('customEvents.delete') }))] })] }) })] }));
178
+ }
179
+ //# sourceMappingURL=CustomEventEditPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomEventEditPage.js","sourceRoot":"","sources":["../../../src/admin/pages/CustomEventEditPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * CustomEventsListPage (feature 049, US3). Lists the module's custom events and
4
+ * links to the create/edit form. Per-channel Measurement ID / Enhanced
5
+ * Ecommerce / server-side settings are managed on the generic Settings screen.
6
+ */
7
+ export default function CustomEventsListPage(): ReactNode;
8
+ //# sourceMappingURL=CustomEventsListPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomEventsListPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/CustomEventsListPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAqBzE;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,IAAI,SAAS,CA6ExD"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { Link } from 'react-router-dom';
4
+ import { ApiError } from '@endora-commerce/admin-kit/lib';
5
+ import { Alert, AlertDescription, Badge, Button, Card, PageHeader, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@endora-commerce/admin-kit/ui';
6
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
7
+ import { googleAnalyticsClient } from '../api/google-analytics-client.js';
8
+ /**
9
+ * CustomEventsListPage (feature 049, US3). Lists the module's custom events and
10
+ * links to the create/edit form. Per-channel Measurement ID / Enhanced
11
+ * Ecommerce / server-side settings are managed on the generic Settings screen.
12
+ */
13
+ export default function CustomEventsListPage() {
14
+ const t = useTranslation('google_analytics');
15
+ const [rows, setRows] = useState([]);
16
+ const [loading, setLoading] = useState(true);
17
+ const [error, setError] = useState(null);
18
+ const refresh = useCallback(async () => {
19
+ setLoading(true);
20
+ setError(null);
21
+ try {
22
+ setRows(await googleAnalyticsClient.list());
23
+ }
24
+ catch (err) {
25
+ setError(err instanceof ApiError ? err.envelope.error.message : String(err));
26
+ }
27
+ finally {
28
+ setLoading(false);
29
+ }
30
+ }, []);
31
+ useEffect(() => {
32
+ void refresh();
33
+ }, [refresh]);
34
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('customEvents.title'), description: t('customEvents.subtitle'), actions: _jsx(Button, { asChild: true, children: _jsx(Link, { to: "/google-analytics/new", children: t('customEvents.new') }) }) }), error && (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })), _jsx(Card, { children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t('customEvents.eventName') }), _jsx(TableHead, { children: t('customEvents.triggerAction') }), _jsx(TableHead, { children: t('customEvents.salesChannel') }), _jsx(TableHead, { children: t('customEvents.enabled') })] }) }), _jsxs(TableBody, { children: [rows.map((row) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Link, { to: `/google-analytics/${row.id}`, className: "font-medium hover:underline", children: row.eventName }) }), _jsx(TableCell, { children: t(`customEvents.actions.${row.triggerAction}`) }), _jsx(TableCell, { children: row.salesChannelCode ?? t('customEvents.allChannels') }), _jsx(TableCell, { children: _jsx(Badge, { variant: row.enabled ? 'default' : 'secondary', children: row.enabled ? '✓' : '—' }) })] }, row.id))), !loading && rows.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "text-center text-muted-foreground", children: t('customEvents.empty') }) }))] })] }) })] }));
35
+ }
36
+ //# sourceMappingURL=CustomEventsListPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomEventsListPage.js","sourceRoot":"","sources":["../../../src/admin/pages/CustomEventsListPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EACL,KAAK,EACL,gBAAgB,EAChB,KAAK,EACL,MAAM,EACN,IAAI,EACJ,UAAU,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,GACT,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB;IAC1C,MAAM,CAAC,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAA0B,EAAE,CAAC,CAAC;IAC9D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACpD,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/E,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,OAAO,EAAE,CAAC;IACjB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,CACL,8BACE,KAAC,UAAU,IACT,KAAK,EAAE,CAAC,CAAC,oBAAoB,CAAC,EAC9B,WAAW,EAAE,CAAC,CAAC,uBAAuB,CAAC,EACvC,OAAO,EACL,KAAC,MAAM,IAAC,OAAO,kBACb,KAAC,IAAI,IAAC,EAAE,EAAC,uBAAuB,YAAE,CAAC,CAAC,kBAAkB,CAAC,GAAQ,GACxD,GAEX,EACD,KAAK,IAAI,CACR,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,EAAC,SAAS,EAAC,MAAM,YAC3C,KAAC,gBAAgB,cAAE,KAAK,GAAoB,GACtC,CACT,EACD,KAAC,IAAI,cACH,MAAC,KAAK,eACJ,KAAC,WAAW,cACV,MAAC,QAAQ,eACP,KAAC,SAAS,cAAE,CAAC,CAAC,wBAAwB,CAAC,GAAa,EACpD,KAAC,SAAS,cAAE,CAAC,CAAC,4BAA4B,CAAC,GAAa,EACxD,KAAC,SAAS,cAAE,CAAC,CAAC,2BAA2B,CAAC,GAAa,EACvD,KAAC,SAAS,cAAE,CAAC,CAAC,sBAAsB,CAAC,GAAa,IACzC,GACC,EACd,MAAC,SAAS,eACP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,MAAC,QAAQ,eACP,KAAC,SAAS,cACR,KAAC,IAAI,IAAC,EAAE,EAAE,qBAAqB,GAAG,CAAC,EAAE,EAAE,EAAE,SAAS,EAAC,6BAA6B,YAC7E,GAAG,CAAC,SAAS,GACT,GACG,EACZ,KAAC,SAAS,cAAE,CAAC,CAAC,wBAAwB,GAAG,CAAC,aAAa,EAAE,CAAC,GAAa,EACvE,KAAC,SAAS,cAAE,GAAG,CAAC,gBAAgB,IAAI,CAAC,CAAC,0BAA0B,CAAC,GAAa,EAC9E,KAAC,SAAS,cACR,KAAC,KAAK,IAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,YAClD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAClB,GACE,KAZC,GAAG,CAAC,EAAE,CAaV,CACZ,CAAC,EACD,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAChC,KAAC,QAAQ,cACP,KAAC,SAAS,IAAC,OAAO,EAAE,CAAC,EAAE,SAAS,EAAC,mCAAmC,YACjE,CAAC,CAAC,oBAAoB,CAAC,GACd,GACH,CACZ,IACS,IACN,GACH,IACN,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { OptionalProps } from '@mikro-orm/core';
2
+ import type { GaCustomEventField, GaTriggerAction } from '@endora-commerce/contracts';
3
+ /**
4
+ * GaCustomEvent (feature 049, US3). Maps a storefront trigger action to a named
5
+ * GA4 event with a selected list of payload fields.
6
+ *
7
+ * The selected fields are a small, ordered, always-loaded-with-the-event list
8
+ * that is never queried independently, so they are stored inline as a JSONB
9
+ * column rather than a second table (Principle IV — the boundary Zod schema
10
+ * already enforces the static-field-set and uniqueness rules). `sales_channel_id`
11
+ * null means the event applies to all channels.
12
+ */
13
+ export declare class GaCustomEvent {
14
+ [OptionalProps]?: 'salesChannelId' | 'buttonId' | 'enabled' | 'fields' | 'version' | 'createdAt' | 'updatedAt';
15
+ id: string;
16
+ salesChannelId: string | null;
17
+ eventName: string;
18
+ triggerAction: GaTriggerAction;
19
+ buttonId: string | null;
20
+ enabled: boolean;
21
+ fields: GaCustomEventField[];
22
+ version: number;
23
+ createdAt: Date;
24
+ updatedAt: Date;
25
+ }
26
+ //# sourceMappingURL=ga-custom-event.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ga-custom-event.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/ga-custom-event.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAGrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAEtF;;;;;;;;;GASG;AACH,qBAGa,aAAa;IACxB,CAAC,aAAa,CAAC,CAAC,EACZ,gBAAgB,GAChB,UAAU,GACV,SAAS,GACT,QAAQ,GACR,SAAS,GACT,WAAW,GACX,WAAW,CAAC;IAGhB,EAAE,EAAE,MAAM,CAAgB;IAG1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGrC,SAAS,EAAG,MAAM,CAAC;IAGnB,aAAa,EAAG,eAAe,CAAC;IAGhC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG/B,OAAO,EAAE,OAAO,CAAQ;IAGxB,MAAM,EAAE,kBAAkB,EAAE,CAAM;IAGlC,OAAO,EAAE,MAAM,CAAK;IAGpB,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B"}
@@ -0,0 +1,82 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, Index, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core';
11
+ import { GlobalEntity } from '@endora-commerce/platform/tenancy';
12
+ import { randomUUID } from 'crypto';
13
+ /**
14
+ * GaCustomEvent (feature 049, US3). Maps a storefront trigger action to a named
15
+ * GA4 event with a selected list of payload fields.
16
+ *
17
+ * The selected fields are a small, ordered, always-loaded-with-the-event list
18
+ * that is never queried independently, so they are stored inline as a JSONB
19
+ * column rather than a second table (Principle IV — the boundary Zod schema
20
+ * already enforces the static-field-set and uniqueness rules). `sales_channel_id`
21
+ * null means the event applies to all channels.
22
+ */
23
+ let GaCustomEvent = class GaCustomEvent {
24
+ [OptionalProps];
25
+ id = randomUUID();
26
+ salesChannelId = null;
27
+ eventName;
28
+ triggerAction;
29
+ buttonId = null;
30
+ enabled = true;
31
+ fields = [];
32
+ version = 1;
33
+ createdAt = new Date();
34
+ updatedAt = new Date();
35
+ };
36
+ __decorate([
37
+ PrimaryKey({ type: 'uuid' }),
38
+ __metadata("design:type", String)
39
+ ], GaCustomEvent.prototype, "id", void 0);
40
+ __decorate([
41
+ Property({ type: 'uuid', fieldName: 'sales_channel_id', nullable: true }),
42
+ __metadata("design:type", Object)
43
+ ], GaCustomEvent.prototype, "salesChannelId", void 0);
44
+ __decorate([
45
+ Property({ type: 'string', length: 40, fieldName: 'event_name' }),
46
+ __metadata("design:type", String)
47
+ ], GaCustomEvent.prototype, "eventName", void 0);
48
+ __decorate([
49
+ Property({ type: 'string', length: 32, fieldName: 'trigger_action' }),
50
+ __metadata("design:type", String)
51
+ ], GaCustomEvent.prototype, "triggerAction", void 0);
52
+ __decorate([
53
+ Property({ type: 'string', length: 128, fieldName: 'button_id', nullable: true }),
54
+ __metadata("design:type", Object)
55
+ ], GaCustomEvent.prototype, "buttonId", void 0);
56
+ __decorate([
57
+ Property({ type: 'boolean' }),
58
+ __metadata("design:type", Boolean)
59
+ ], GaCustomEvent.prototype, "enabled", void 0);
60
+ __decorate([
61
+ Property({ type: 'json' }),
62
+ __metadata("design:type", Array)
63
+ ], GaCustomEvent.prototype, "fields", void 0);
64
+ __decorate([
65
+ Property({ type: 'integer' }),
66
+ __metadata("design:type", Number)
67
+ ], GaCustomEvent.prototype, "version", void 0);
68
+ __decorate([
69
+ Property({ type: 'datetime', fieldName: 'created_at', onCreate: () => new Date() }),
70
+ __metadata("design:type", Date)
71
+ ], GaCustomEvent.prototype, "createdAt", void 0);
72
+ __decorate([
73
+ Property({ type: 'datetime', fieldName: 'updated_at', onUpdate: () => new Date() }),
74
+ __metadata("design:type", Date)
75
+ ], GaCustomEvent.prototype, "updatedAt", void 0);
76
+ GaCustomEvent = __decorate([
77
+ GlobalEntity(),
78
+ Entity({ tableName: 'ga_custom_events' }),
79
+ Index({ name: 'ga_custom_events_channel_action_idx', properties: ['salesChannelId', 'triggerAction'] })
80
+ ], GaCustomEvent);
81
+ export { GaCustomEvent };
82
+ //# sourceMappingURL=ga-custom-event.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ga-custom-event.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/ga-custom-event.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC;;;;;;;;;GASG;AAII,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,CAAC,aAAa,CAAC,CAOC;IAGhB,EAAE,GAAW,UAAU,EAAE,CAAC;IAG1B,cAAc,GAAkB,IAAI,CAAC;IAGrC,SAAS,CAAU;IAGnB,aAAa,CAAmB;IAGhC,QAAQ,GAAkB,IAAI,CAAC;IAG/B,OAAO,GAAY,IAAI,CAAC;IAGxB,MAAM,GAAyB,EAAE,CAAC;IAGlC,OAAO,GAAW,CAAC,CAAC;IAGpB,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AA5BC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;yCACH;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDACrC;AAGrC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;;gDAC/C;AAGnB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;;oDACtC;AAGhC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CACnD;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;8CACN;AAGxB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;6CACO;AAGlC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;8CACV;AAGpB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BACzE,IAAI;gDAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BACzE,IAAI;gDAAc;AAtClB,aAAa;IAHzB,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;IACzC,KAAK,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,UAAU,EAAE,CAAC,gBAAgB,EAAE,eAAe,CAAC,EAAE,CAAC;GAC3F,aAAa,CAuCzB"}