@g2crowd/buyer-intent-provider-sdk 0.2.0 → 0.4.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/README.md CHANGED
@@ -1,286 +1,333 @@
1
1
  # Buyer Intent JS SDK
2
2
 
3
- Buyer Intent tracking SDK for partner sites. Provides purpose-built React components for each tracked interaction type, plus low-level `ViewTracker` and `ClickTracker` primitives. Events are sent via `sendBeacon` for best-effort delivery during navigation.
4
-
5
- ## Install
3
+ Buyer intent tracking for partner sites. Drop custom HTML elements into any page no framework required. Events are sent via `sendBeacon` for reliable delivery during navigation.
6
4
 
7
5
  ```bash
8
6
  npm install @g2crowd/buyer-intent-provider-sdk
9
7
  ```
10
8
 
11
- If you plan to use the built-in Kafka connection (via `kafkaBrokers`), install the peer dependency:
9
+ ## Quick Start
12
10
 
13
- ```bash
14
- npm install kafkajs
15
- ```
11
+ Import the SDK, wrap your page in a session, and you're tracking:
16
12
 
17
- ## Quick Start (Next.js)
13
+ ```html
14
+ <script type="module">
15
+ import '@g2crowd/buyer-intent-provider-sdk';
16
+ </script>
18
17
 
19
- ```tsx
20
- import { BuyerIntent } from '@g2crowd/buyer-intent-provider-sdk';
18
+ <buyer-intent-session
19
+ origin="yoursite.com"
20
+ activity-endpoint="/api/activity/events"
21
+ >
21
22
 
22
- // Product profile page — fires a $view with tag "products.show"
23
- export default function ProductPage() {
24
- return (
25
- <BuyerIntent.ProfileView
26
- productId={123}
27
- origin="g2.com"
28
- activityEndpoint="/api/activity/events"
29
- >
30
- <h1>Acme CRM</h1>
31
- <p>Product details here.</p>
32
-
33
- <BuyerIntent.LeadCreateClick productId={123}>
34
- <button>Get a Demo</button>
35
- </BuyerIntent.LeadCreateClick>
36
- </BuyerIntent.ProfileView>
37
- );
38
- }
23
+ <buyer-intent-view tag="products.show">
24
+ <buyer-intent-subject product-id="123"></buyer-intent-subject>
25
+
26
+ <h1>Acme CRM</h1>
27
+ <p>Product details here.</p>
28
+
29
+ <buyer-intent-click event-name="/leads/create">
30
+ <button>Get a Demo</button>
31
+ </buyer-intent-click>
32
+ </buyer-intent-view>
33
+
34
+ </buyer-intent-session>
39
35
  ```
40
36
 
41
- ## Backend (Next.js Route)
37
+ That's it. When the page loads, a `$view` event fires with `product_ids: [123]` and `tag: "products.show"`. When the user clicks "Get a Demo", a `/leads/create` event fires. Both events inherit the session's `origin` and `activity-endpoint` automatically.
42
38
 
43
- ```ts
44
- // app/api/activity/events/route.ts
45
- import { createNextRouteHandler } from '@g2crowd/buyer-intent-provider-sdk/server';
39
+ ## Elements
46
40
 
47
- const POST = createNextRouteHandler({
48
- kafkaBrokers: [process.env.KAFKA_BROKER || 'localhost:9092'],
49
- partnerId: process.env.PARTNER_ID,
50
- });
41
+ ### `<buyer-intent-session>`
51
42
 
52
- export { POST };
43
+ Wraps a page (or your entire app) and provides config to all elements inside it. Does not fire any events itself.
44
+
45
+ | Attribute | Description |
46
+ | -------------------- | -------------------------------------------- |
47
+ | `origin` | Partner hostname |
48
+ | `activity-endpoint` | URL to POST events to |
49
+ | `user-type` | Visitor role (default: `"standard"`) |
50
+ | `distinct-id` | Override the auto-generated visitor ID |
51
+
52
+ | User Type | Meaning |
53
+ | ---------------- | ------------------------------------------------- |
54
+ | `guest` | Logged-out visitor |
55
+ | `standard` | Logged-in user (default) |
56
+ | `vendor-admin` | Vendor role viewing their own content |
57
+ | `observer` | Internal employee / superuser |
58
+
59
+ ```html
60
+ <buyer-intent-session origin="yoursite.com" activity-endpoint="/api/activity/events">
61
+ <!-- everything inside inherits origin and endpoint -->
62
+ </buyer-intent-session>
53
63
  ```
54
64
 
55
- ## Barebones Server
65
+ ### `<buyer-intent-view>`
56
66
 
57
- This package ships a tiny server that hosts `POST /activity/events`.
67
+ Fires a `$view` event when the element connects to the DOM. One event per page navigation.
58
68
 
59
- ```bash
60
- PARTNER_ID=partner-a KAFKA_BROKERS=broker1:9092,broker2:9092 \
61
- buyer-intent-server
69
+ | Attribute | Description |
70
+ | ----------------- | ------------------------------------------- |
71
+ | `tag` | View type identifier (optional) |
72
+ | `source-location` | Controller/action string (optional) |
73
+ | `product-id` | Single product ID (simple pages) |
74
+ | `category-id` | Single category ID (simple pages) |
75
+
76
+ For pages with one product, you can put the ID directly on the view:
77
+
78
+ ```html
79
+ <buyer-intent-view tag="products.show" product-id="123">
80
+ <h1>Acme CRM</h1>
81
+ </buyer-intent-view>
62
82
  ```
63
83
 
64
- Environment variables:
84
+ For pages with multiple products, use `<buyer-intent-subject>` children instead (see below).
65
85
 
66
- - `PORT` (default: 3000)
67
- - `PARTNER_ID`
68
- - `TOPIC_PREFIX` (optional)
69
- - `KAFKA_BROKERS` (comma-separated)
70
- - `KAFKA_TOPIC` (optional override)
71
- - `KAFKA_CLIENT_ID` (optional)
72
- - `USE_DEV_LOGGER=true` (logs instead of Kafka)
86
+ ### `<buyer-intent-subject>`
73
87
 
74
- ## Kafka Setup (Partner Checklist)
88
+ Declares that a product or category is a **subject** of the current view. Nest any number of these inside a `<buyer-intent-view>` — their IDs accumulate into the view's event automatically. Does not render anything visible.
75
89
 
76
- Provide these values to your partners so they can publish to their scoped topic:
90
+ | Attribute | Description |
91
+ | -------------- | ---------------------------------------------------- |
92
+ | `product-id` | Single product ID |
93
+ | `product-ids` | Multiple product IDs (JSON array or comma-separated) |
94
+ | `category-id` | Single category ID |
95
+ | `category-ids` | Multiple category IDs (JSON array or comma-separated)|
77
96
 
78
- - Kafka broker list (host:port)
79
- - Topic name (scoped to their tenant)
80
- - Auth mechanism (SASL user/pass or mTLS)
81
- - TLS requirements (on/off, CA certs if needed)
97
+ A comparison page that references two products:
82
98
 
83
- By default, the SDK derives the topic from `partnerId` using `intent_events_<partnerId>`.
99
+ ```html
100
+ <buyer-intent-view tag="comparisons.show">
101
+ <buyer-intent-subject product-id="101"></buyer-intent-subject>
102
+ <buyer-intent-subject product-id="201"></buyer-intent-subject>
84
103
 
85
- Example using a prebuilt producer:
104
+ <h1>Acme CRM vs. Rival CRM</h1>
105
+ </buyer-intent-view>
106
+ ```
86
107
 
87
- ```ts
88
- // app/api/activity/events/route.ts
89
- import { Kafka } from 'kafkajs';
90
- import { createNextRouteHandler } from '@g2crowd/buyer-intent-provider-sdk/server';
108
+ The resulting event has `product_ids: [101, 201]`. If the view also has an inline `product-id`, they merge together without duplicates.
91
109
 
92
- const kafka = new Kafka({
93
- clientId: 'partner-app',
94
- brokers: (process.env.KAFKA_BROKERS || '').split(','),
95
- });
110
+ Subjects can live anywhere inside the view — they don't need to be direct children. This makes them easy to place next to the content they describe:
96
111
 
97
- const producer = kafka.producer({
98
- allowAutoTopicCreation: false,
99
- });
112
+ ```html
113
+ <buyer-intent-view tag="categories.show">
114
+ <buyer-intent-subject category-id="45"></buyer-intent-subject>
115
+ <h1>CRM Software</h1>
100
116
 
101
- const POST = createNextRouteHandler({
102
- producer,
103
- partnerId: process.env.PARTNER_ID,
104
- topicPrefix: process.env.TOPIC_PREFIX,
105
- });
117
+ <div class="product-grid">
118
+ <div class="product-card">
119
+ <buyer-intent-subject product-id="101"></buyer-intent-subject>
120
+ <h2>Acme CRM</h2>
121
+ </div>
106
122
 
107
- export { POST };
123
+ <div class="product-card">
124
+ <buyer-intent-subject product-id="201"></buyer-intent-subject>
125
+ <h2>Rival CRM</h2>
126
+ </div>
127
+ </div>
128
+ </buyer-intent-view>
108
129
  ```
109
130
 
110
- ## Dev Adapter (No Kafka)
131
+ This fires one event: `category_ids: [45]`, `product_ids: [101, 201]`, `tag: "categories.show"`.
111
132
 
112
- If you want to test locally without Kafka, use the dev logger producer.
133
+ ### `<buyer-intent-click>`
113
134
 
114
- ```ts
115
- // app/api/activity/events/route.ts
116
- import {
117
- createNextRouteHandler,
118
- createDevLoggerProducer,
119
- } from '@g2crowd/buyer-intent-provider-sdk/server';
135
+ Fires an event when the user clicks anything inside it.
120
136
 
121
- const POST = createNextRouteHandler({
122
- producer: createDevLoggerProducer(),
123
- partnerId: 'dev',
124
- });
137
+ | Attribute | Description |
138
+ | ------------ | ------------------------ |
139
+ | `event-name` | Click event type |
125
140
 
126
- export { POST };
141
+ ```html
142
+ <buyer-intent-click event-name="/leads/create">
143
+ <button>Get a Demo</button>
144
+ </buyer-intent-click>
127
145
  ```
128
146
 
129
- ## Interaction Components
147
+ A click element inside a view automatically inherits the view's tag, product IDs, and category IDs. A click inside a session inherits the session's config. You don't need to repeat anything.
130
148
 
131
- Purpose-built components for each tracked interaction type. Each sets the correct event name and tag automatically — you just provide the required ID.
149
+ ## Full Example
132
150
 
133
- ### Page Views
151
+ Putting it all together — a product page with a session, view, subjects, and two click actions:
134
152
 
135
- These fire a `$view` event when the component appears in the DOM. One event per page navigation.
153
+ ```html
154
+ <script type="module">
155
+ import '@g2crowd/buyer-intent-provider-sdk';
156
+ </script>
136
157
 
137
- | Component | Required Prop | Tag |
138
- | ----------------- | ----------------- | ----------------------- |
139
- | `ProfileView` | `productId` | `products.show` |
140
- | `PricingView` | `productId` | `products.pricing` |
141
- | `CompetitorsView` | `productId` | `products.competitors` |
142
- | `CategoryView` | `categoryId` | `categories.show` |
143
- | `CompareView` | `productIds` (2+) | `comparisons.show` |
144
- | `WriteReviewView` | `productId` | `reviewers.take_survey` |
158
+ <buyer-intent-session
159
+ origin="yoursite.com"
160
+ activity-endpoint="/api/activity/events"
161
+ user-type="standard"
162
+ >
145
163
 
146
- ```tsx
147
- import { BuyerIntent } from '@g2crowd/buyer-intent-provider-sdk';
164
+ <buyer-intent-view
165
+ tag="products.show"
166
+ source-location="ProductsController#show"
167
+ >
168
+ <buyer-intent-subject product-id="123"></buyer-intent-subject>
169
+ <buyer-intent-subject category-id="45"></buyer-intent-subject>
148
170
 
149
- <BuyerIntent.ProfileView productId={123} origin="g2.com" activityEndpoint="/api/activity/events">
150
- <ProductPage />
151
- </BuyerIntent.ProfileView>
171
+ <h1>Acme CRM</h1>
172
+ <p>The best CRM for small teams.</p>
152
173
 
153
- <BuyerIntent.CategoryView categoryId={45} origin="g2.com" activityEndpoint="/api/activity/events">
154
- <CategoryPage />
155
- </BuyerIntent.CategoryView>
174
+ <buyer-intent-click event-name="/leads/create">
175
+ <button>Get a Demo</button>
176
+ </buyer-intent-click>
156
177
 
157
- <BuyerIntent.CompareView productIds={[123, 456]} origin="g2.com" activityEndpoint="/api/activity/events">
158
- <ComparisonPage />
159
- </BuyerIntent.CompareView>
160
- ```
178
+ <buyer-intent-click event-name="/ad/clicked">
179
+ <a href="https://acme.example.com">Visit Acme</a>
180
+ </buyer-intent-click>
181
+ </buyer-intent-view>
161
182
 
162
- ### Click Events
183
+ </buyer-intent-session>
184
+ ```
163
185
 
164
- These fire an event each time the user clicks anything inside the component.
186
+ ## React Support
165
187
 
166
- | Component | Required Prop | Event Name |
167
- | ----------------- | ------------- | --------------- |
168
- | `AdClick` | `productId` | `/ad/clicked` |
169
- | `LeadCreateClick` | `productId` | `/leads/create` |
188
+ Import from `/react` and use the same element hierarchy with camelCase props:
170
189
 
171
190
  ```tsx
172
- <BuyerIntent.LeadCreateClick productId={123}>
173
- <button>Get a Demo</button>
174
- </BuyerIntent.LeadCreateClick>
191
+ import { BuyerIntent } from '@g2crowd/buyer-intent-provider-sdk/react';
175
192
 
176
- <BuyerIntent.AdClick productId={123}>
177
- <button>Sponsored Link</button>
178
- </BuyerIntent.AdClick>
193
+ export default function ProductPage() {
194
+ return (
195
+ <BuyerIntent.Session origin="yoursite.com" activityEndpoint="/api/activity/events">
196
+ <BuyerIntent.View tag="products.show" sourceLocation="ProductsController#show">
197
+ <BuyerIntent.Subject productId={123} />
198
+ <BuyerIntent.Subject categoryId={45} />
199
+
200
+ <h1>Acme CRM</h1>
201
+
202
+ <BuyerIntent.Click eventName="/leads/create">
203
+ <button>Get a Demo</button>
204
+ </BuyerIntent.Click>
205
+ </BuyerIntent.View>
206
+ </BuyerIntent.Session>
207
+ );
208
+ }
179
209
  ```
180
210
 
181
- ### Common Props
211
+ `BuyerIntent.Session`, `BuyerIntent.View`, `BuyerIntent.Subject`, and `BuyerIntent.Click` map 1:1 to the HTML elements described above. The session is a good fit for a layout component or `_app` wrapper so it's set once for every page.
212
+
213
+ ## Syntactic Sugar
182
214
 
183
- All interaction components accept these optional props:
215
+ For common page types, pre-built components hardcode the `tag` or `event-name` so you don't have to:
184
216
 
185
- | Prop | Description |
186
- | ------------------ | ---------------------------------------- |
187
- | `origin` | Partner hostname |
188
- | `activityEndpoint` | URL to POST events to |
189
- | `userType` | User type string (default: `"standard"`) |
190
- | `distinctId` | Override the auto-generated visitor ID |
191
- | `sourceLocation` | Controller/action identifier |
192
- | `context` | Arbitrary metadata object |
193
- | `eventName` | Override the default event name |
217
+ ### Views
194
218
 
195
- ### Low-Level Primitives
219
+ | Component | Tag | Required Prop |
220
+ | ----------------- | ----------------------- | ------------- |
221
+ | `ProfileView` | `products.show` | `productId` |
222
+ | `PricingView` | `products.pricing` | `productId` |
223
+ | `CompetitorsView` | `products.competitors` | `productId` |
224
+ | `CategoryView` | `categories.show` | `categoryId` |
225
+ | `CompareView` | `comparisons.show` | `productIds` |
226
+ | `WriteReviewView` | `reviewers.take_survey` | `productId` |
196
227
 
197
- For interaction types not covered above, use `ViewTracker` and `ClickTracker` directly with a custom `tag` or `eventName`:
228
+ ### Clicks
229
+
230
+ | Component | Event Name | Required Prop |
231
+ | ----------------- | --------------- | ------------- |
232
+ | `AdClick` | `/ad/clicked` | `productId` |
233
+ | `LeadCreateClick` | `/leads/create` | `productId` |
198
234
 
199
235
  ```tsx
200
- <BuyerIntent.ViewTracker
201
- tag="custom.page_type"
202
- productIds={[123]}
203
- origin="g2.com"
204
- activityEndpoint="/api/activity/events"
205
- >
206
- <CustomPage />
207
- </BuyerIntent.ViewTracker>
236
+ import { BuyerIntent } from '@g2crowd/buyer-intent-provider-sdk/react';
208
237
 
209
- <BuyerIntent.ClickTracker
210
- eventName="$custom_action"
211
- productIds={[123]}
212
- >
213
- <button>Custom Action</button>
214
- </BuyerIntent.ClickTracker>
238
+ <BuyerIntent.Session origin="yoursite.com" activityEndpoint="/api/activity/events">
239
+ <BuyerIntent.ProfileView productId={123}>
240
+ <h1>Acme CRM</h1>
241
+
242
+ <BuyerIntent.LeadCreateClick productId={123}>
243
+ <button>Get a Demo</button>
244
+ </BuyerIntent.LeadCreateClick>
245
+ </BuyerIntent.ProfileView>
246
+ </BuyerIntent.Session>
215
247
  ```
216
248
 
217
- ### Visit Properties
249
+ These components still accept `origin`, `activityEndpoint`, `sourceLocation`, and `context` props for cases where you aren't using a session wrapper.
218
250
 
219
- ```tsx
220
- import { buyerIntent } from '@g2crowd/buyer-intent-provider-sdk';
221
-
222
- buyerIntent.setVisitProperties({
223
- ip: '203.0.113.10',
224
- referrer: 'https://example.com/',
225
- landing_page: 'https://example.com/products/abc',
226
- user_agent: 'Mozilla/5.0',
227
- utm_source: 'newsletter',
228
- utm_medium: 'email',
229
- utm_campaign: 'spring_launch',
230
- utm_term: 'buyer-intent',
231
- utm_content: 'cta-button',
251
+ ## Backend
252
+
253
+ ### Next.js Route Handler
254
+
255
+ ```ts
256
+ import { createNextRouteHandler } from '@g2crowd/buyer-intent-provider-sdk/server';
257
+
258
+ const POST = createNextRouteHandler({
259
+ kafkaBrokers: [process.env.KAFKA_BROKER || 'localhost:9092'],
260
+ partnerId: process.env.PARTNER_ID,
232
261
  });
262
+
263
+ export { POST };
264
+ ```
265
+
266
+ ### Standalone Server
267
+
268
+ ```bash
269
+ PARTNER_ID=partner-a KAFKA_BROKERS=broker1:9092,broker2:9092 \
270
+ buyer-intent-server
233
271
  ```
234
272
 
235
- ## Server API
273
+ Environment variables: `PORT` (default 3000), `PARTNER_ID`, `KAFKA_BROKERS` (comma-separated), `TOPIC_PREFIX`, `KAFKA_TOPIC`, `KAFKA_CLIENT_ID`, `USE_DEV_LOGGER=true`.
236
274
 
237
- ### createActivityHandler(options)
275
+ ### Custom Kafka Producer
238
276
 
239
- Returns a framework-agnostic handler that validates, enriches, and publishes events to Kafka.
277
+ ```ts
278
+ import { Kafka } from 'kafkajs';
279
+ import { createNextRouteHandler } from '@g2crowd/buyer-intent-provider-sdk/server';
240
280
 
241
- ### createNextRouteHandler(options)
281
+ const kafka = new Kafka({
282
+ clientId: 'partner-app',
283
+ brokers: (process.env.KAFKA_BROKERS || '').split(','),
284
+ });
242
285
 
243
- Next.js Route Handler wrapper around `createActivityHandler`.
286
+ const POST = createNextRouteHandler({
287
+ producer: kafka.producer({ allowAutoTopicCreation: false }),
288
+ partnerId: process.env.PARTNER_ID,
289
+ });
244
290
 
245
- ### createDevLoggerProducer(options)
291
+ export { POST };
292
+ ```
246
293
 
247
- Dev-only producer that logs messages instead of sending to Kafka.
294
+ ### Dev Adapter (No Kafka)
248
295
 
249
- ### topicName(options)
296
+ ```ts
297
+ import {
298
+ createNextRouteHandler,
299
+ createDevLoggerProducer,
300
+ } from '@g2crowd/buyer-intent-provider-sdk/server';
250
301
 
251
- Builds a topic name from a `partnerId` and optional `prefix`.
302
+ const POST = createNextRouteHandler({
303
+ producer: createDevLoggerProducer(),
304
+ partnerId: 'dev',
305
+ });
252
306
 
253
- ## Event Payload
307
+ export { POST };
308
+ ```
254
309
 
255
- The SDK sends the following JSON body to `activityEndpoint`:
310
+ ## Event Payload
256
311
 
257
312
  ```json
258
313
  {
259
314
  "name": "$view",
260
315
  "properties": {
261
316
  "product_ids": [123],
262
- "category_ids": [78],
317
+ "category_ids": [45],
263
318
  "tag": "products.show",
264
- "url": "https://example.com/products/abc",
319
+ "url": "https://yoursite.com/products/acme-crm",
265
320
  "user_type": "standard",
266
321
  "distinct_id": "visitor-uuid",
267
- "origin": "g2.com",
268
- "source_location": "ProductsController#show",
269
- "context": {
270
- "page": "product"
271
- }
322
+ "origin": "yoursite.com",
323
+ "source_location": "ProductsController#show"
272
324
  },
273
325
  "visit": {
274
326
  "properties": {
275
- "landing_page": "https://example.com/products/abc",
276
- "referrer": "https://example.com/",
327
+ "landing_page": "https://yoursite.com/products/acme-crm",
328
+ "referrer": "https://google.com/",
277
329
  "user_agent": "Mozilla/5.0",
278
- "ip": "203.0.113.10",
279
- "utm_source": "newsletter",
280
- "utm_medium": "email",
281
- "utm_campaign": "spring_launch",
282
- "utm_term": "buyer-intent",
283
- "utm_content": "cta-button"
330
+ "utm_source": "newsletter"
284
331
  }
285
332
  }
286
333
  }
package/package.json CHANGED
@@ -1,27 +1,24 @@
1
1
  {
2
2
  "name": "@g2crowd/buyer-intent-provider-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Buyer intent tracking SDK with pageview defaults",
5
5
  "type": "module",
6
- "main": "index.js",
6
+ "main": "src/index.js",
7
7
  "exports": {
8
- ".": "./index.js",
9
- "./server": "./server/index.js"
8
+ ".": "./src/index.js",
9
+ "./react": "./src/react/index.js",
10
+ "./server": "./src/server/index.js"
10
11
  },
11
- "types": "index.d.ts",
12
+ "types": "src/index.d.ts",
12
13
  "files": [
13
- "index.js",
14
- "index.d.ts",
15
- "browser",
16
- "server.js",
17
- "server",
14
+ "src",
18
15
  "README.md"
19
16
  ],
20
17
  "scripts": {
21
18
  "test": "node --experimental-vm-modules ./node_modules/.bin/jest --config ./jest.config.cjs"
22
19
  },
23
20
  "bin": {
24
- "buyer-intent-server": "server.js"
21
+ "buyer-intent-server": "src/server.js"
25
22
  },
26
23
  "license": "MIT",
27
24
  "repository": {
@@ -35,7 +32,17 @@
35
32
  "kafkajs": "^2.2.4",
36
33
  "react": ">=17"
37
34
  },
38
- "sideEffects": false,
35
+ "peerDependenciesMeta": {
36
+ "react": {
37
+ "optional": true
38
+ },
39
+ "kafkajs": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "sideEffects": [
44
+ "./src/browser/elements/*.js"
45
+ ],
39
46
  "devDependencies": {
40
47
  "@testing-library/dom": "^9.3.4",
41
48
  "@testing-library/react": "^14.3.1",
@@ -0,0 +1,29 @@
1
+ export {
2
+ SessionProvider,
3
+ SubjectTracker,
4
+ ViewTracker,
5
+ ClickTracker,
6
+ } from './tracker.js';
7
+ import { SessionProvider, SubjectTracker, ViewTracker, ClickTracker } from './tracker.js';
8
+ import React from 'react';
9
+
10
+ function view(tag) {
11
+ return function ViewComponent({ children, ...rest }) {
12
+ return React.createElement(ViewTracker, { ...rest, tag }, children);
13
+ };
14
+ }
15
+
16
+ function click(eventName) {
17
+ return function ClickComponent({ children, ...rest }) {
18
+ return React.createElement(ClickTracker, { ...rest, eventName }, children);
19
+ };
20
+ }
21
+
22
+ export const ProfileView = view('products.show');
23
+ export const PricingView = view('products.pricing');
24
+ export const CompetitorsView = view('products.competitors');
25
+ export const CategoryView = view('categories.show');
26
+ export const CompareView = view('comparisons.show');
27
+ export const WriteReviewView = view('reviewers.take_survey');
28
+ export const AdClick = click('/ad/clicked');
29
+ export const LeadCreateClick = click('/leads/create');