matomo-tracker-for-react 1.0.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 +373 -0
  2. package/README.md +194 -0
  3. package/es/MatomoContext.d.ts +5 -0
  4. package/es/MatomoContext.d.ts.map +1 -0
  5. package/es/MatomoContext.js +4 -0
  6. package/es/MatomoContext.js.map +1 -0
  7. package/es/MatomoProvider.d.ts +5 -0
  8. package/es/MatomoProvider.d.ts.map +1 -0
  9. package/es/MatomoProvider.js +94 -0
  10. package/es/MatomoProvider.js.map +1 -0
  11. package/es/MatomoTracker.d.ts +49 -0
  12. package/es/MatomoTracker.d.ts.map +1 -0
  13. package/es/MatomoTracker.js +330 -0
  14. package/es/MatomoTracker.js.map +1 -0
  15. package/es/constants.d.ts +11 -0
  16. package/es/constants.d.ts.map +1 -0
  17. package/es/constants.js +13 -0
  18. package/es/constants.js.map +1 -0
  19. package/es/index.d.ts +15 -0
  20. package/es/index.d.ts.map +1 -0
  21. package/es/index.js +6 -0
  22. package/es/index.js.map +1 -0
  23. package/es/tracker-types.d.ts +76 -0
  24. package/es/tracker-types.d.ts.map +1 -0
  25. package/es/tracker-types.js +2 -0
  26. package/es/tracker-types.js.map +1 -0
  27. package/es/types.d.ts +19 -0
  28. package/es/types.d.ts.map +1 -0
  29. package/es/types.js +3 -0
  30. package/es/types.js.map +1 -0
  31. package/es/useMatomo.d.ts +4 -0
  32. package/es/useMatomo.d.ts.map +1 -0
  33. package/es/useMatomo.js +30 -0
  34. package/es/useMatomo.js.map +1 -0
  35. package/lib/MatomoContext.d.ts +5 -0
  36. package/lib/MatomoContext.d.ts.map +1 -0
  37. package/lib/MatomoContext.js +6 -0
  38. package/lib/MatomoContext.js.map +1 -0
  39. package/lib/MatomoProvider.d.ts +5 -0
  40. package/lib/MatomoProvider.d.ts.map +1 -0
  41. package/lib/MatomoProvider.js +122 -0
  42. package/lib/MatomoProvider.js.map +1 -0
  43. package/lib/MatomoTracker.d.ts +49 -0
  44. package/lib/MatomoTracker.d.ts.map +1 -0
  45. package/lib/MatomoTracker.js +332 -0
  46. package/lib/MatomoTracker.js.map +1 -0
  47. package/lib/constants.d.ts +11 -0
  48. package/lib/constants.d.ts.map +1 -0
  49. package/lib/constants.js +16 -0
  50. package/lib/constants.js.map +1 -0
  51. package/lib/index.d.ts +15 -0
  52. package/lib/index.d.ts.map +1 -0
  53. package/lib/index.js +29 -0
  54. package/lib/index.js.map +1 -0
  55. package/lib/tracker-types.d.ts +76 -0
  56. package/lib/tracker-types.d.ts.map +1 -0
  57. package/lib/tracker-types.js +3 -0
  58. package/lib/tracker-types.js.map +1 -0
  59. package/lib/types.d.ts +19 -0
  60. package/lib/types.d.ts.map +1 -0
  61. package/lib/types.js +19 -0
  62. package/lib/types.js.map +1 -0
  63. package/lib/useMatomo.d.ts +4 -0
  64. package/lib/useMatomo.d.ts.map +1 -0
  65. package/lib/useMatomo.js +35 -0
  66. package/lib/useMatomo.js.map +1 -0
  67. package/package.json +58 -0
  68. package/src/MatomoContext.tsx +6 -0
  69. package/src/MatomoProvider.tsx +93 -0
  70. package/src/MatomoTracker.ts +415 -0
  71. package/src/constants.ts +12 -0
  72. package/src/index.ts +20 -0
  73. package/src/tracker-types.ts +89 -0
  74. package/src/types.ts +29 -0
  75. package/src/useMatomo.ts +55 -0
@@ -0,0 +1,415 @@
1
+ import { TRACK_TYPES } from "./constants";
2
+ import {
3
+ AddEcommerceItemParams,
4
+ RemoveEcommerceItemParams,
5
+ CustomDimension,
6
+ SetEcommerceViewParams,
7
+ TrackEcommerceOrderParams,
8
+ TrackEventParams,
9
+ TrackLinkParams,
10
+ TrackPageViewParams,
11
+ TrackParams,
12
+ TrackSiteSearchParams,
13
+ UserOptions,
14
+ } from "./tracker-types";
15
+
16
+ declare global {
17
+ interface Window {
18
+ _paq?: Array<any[]>;
19
+ }
20
+ }
21
+
22
+ class MatomoTracker {
23
+ private mutationObserver?: MutationObserver;
24
+ private isInitialized = false;
25
+
26
+ constructor(userOptions: UserOptions) {
27
+ if (typeof window === "undefined") {
28
+ // Don't run in SSR or non-browser environments
29
+ return;
30
+ }
31
+ if (!userOptions.urlBase) {
32
+ throw new Error("Matomo urlBase is required.");
33
+ }
34
+ if (userOptions.siteId === undefined || userOptions.siteId === null) {
35
+ throw new Error("Matomo siteId is required.");
36
+ }
37
+
38
+ this.initialize(userOptions);
39
+ }
40
+
41
+ private initialize({
42
+ urlBase,
43
+ siteId,
44
+ userId,
45
+ trackerUrl,
46
+ srcUrl,
47
+ disabled = false,
48
+ heartBeat,
49
+ linkTracking = true,
50
+ configurations = {},
51
+ }: UserOptions) {
52
+ if (disabled) {
53
+ // If disabled, make all tracking calls no-ops by not initializing _paq or the script
54
+ this.pushInstruction = (..._args: any[]): MatomoTracker => this; // No-op
55
+ // Make other methods no-op as well
56
+ const noOp = () => {};
57
+ this.trackEvent = noOp as any;
58
+ this.trackPageView = noOp as any;
59
+ this.trackSiteSearch = noOp as any;
60
+ this.trackLink = noOp as any;
61
+ // ... and so on for all public methods
62
+ return;
63
+ }
64
+
65
+ const normalizedUrlBase = urlBase.endsWith("/") ? urlBase : `${urlBase}/`;
66
+
67
+ window._paq = window._paq || [];
68
+
69
+ // Prevent re-initialization if _paq already has Matomo commands beyond simple presence
70
+ if (
71
+ this.isInitialized ||
72
+ (window._paq.length > 0 &&
73
+ window._paq.some((cmd) => cmd[0] === "setTrackerUrl"))
74
+ ) {
75
+ // If siteId or userId needs to be updated on an existing instance:
76
+ if (siteId) this.pushInstruction("setSiteId", siteId);
77
+ if (userId) this.pushInstruction("setUserId", userId);
78
+ // Potentially re-apply other configurations if needed, or assume they are sticky
79
+ this.isInitialized = true;
80
+ return;
81
+ }
82
+
83
+ this.pushInstruction(
84
+ "setTrackerUrl",
85
+ trackerUrl ?? `${normalizedUrlBase}matomo.php`
86
+ );
87
+ this.pushInstruction("setSiteId", siteId);
88
+
89
+ if (userId) {
90
+ this.pushInstruction("setUserId", userId);
91
+ }
92
+
93
+ Object.entries(configurations).forEach(([name, instructions]) => {
94
+ if (name === "disableCookies" && typeof instructions === "boolean") {
95
+ this.pushInstruction("disableCookies"); // Matomo's disableCookies takes no arguments if called this way
96
+ } else if (instructions instanceof Array) {
97
+ this.pushInstruction(name, ...instructions);
98
+ } else {
99
+ this.pushInstruction(name, instructions);
100
+ }
101
+ });
102
+
103
+ if (!heartBeat || (heartBeat && heartBeat.active)) {
104
+ this.enableHeartBeatTimer((heartBeat && heartBeat.seconds) ?? 15);
105
+ }
106
+
107
+ this.enableLinkTracking(linkTracking);
108
+
109
+ const doc = document;
110
+ const scriptElement = doc.createElement("script");
111
+ const scripts = doc.getElementsByTagName("script")[0];
112
+
113
+ scriptElement.type = "text/javascript";
114
+ scriptElement.async = true;
115
+ scriptElement.defer = true;
116
+ scriptElement.src = srcUrl || `${normalizedUrlBase}matomo.js`;
117
+
118
+ if (scripts && scripts.parentNode) {
119
+ scripts.parentNode.insertBefore(scriptElement, scripts);
120
+ }
121
+ this.isInitialized = true;
122
+ }
123
+
124
+ enableHeartBeatTimer(seconds: number): void {
125
+ this.pushInstruction("enableHeartBeatTimer", seconds);
126
+ }
127
+
128
+ enableLinkTracking(active: boolean): void {
129
+ this.pushInstruction("enableLinkTracking", active);
130
+ }
131
+
132
+ private trackEventsForElements(elements: HTMLElement[]) {
133
+ if (elements.length) {
134
+ elements.forEach((element) => {
135
+ element.addEventListener("click", () => {
136
+ const { matomoCategory, matomoAction, matomoName, matomoValue } =
137
+ element.dataset;
138
+ if (matomoCategory && matomoAction) {
139
+ this.trackEvent({
140
+ category: matomoCategory,
141
+ action: matomoAction,
142
+ name: matomoName,
143
+ value: matomoValue ? Number(matomoValue) : undefined,
144
+ });
145
+ } else {
146
+ throw new Error(
147
+ `Error: data-matomo-category and data-matomo-action are required.`
148
+ );
149
+ }
150
+ });
151
+ });
152
+ }
153
+ }
154
+
155
+ // Tracks events based on data attributes
156
+ trackEvents(): void {
157
+ if (typeof window === "undefined" || !document) return;
158
+
159
+ const matchString = '[data-matomo-event="click"]';
160
+ let firstTime = false;
161
+ if (!this.mutationObserver) {
162
+ firstTime = true;
163
+ this.mutationObserver = new MutationObserver((mutations) => {
164
+ mutations.forEach((mutation) => {
165
+ mutation.addedNodes.forEach((node) => {
166
+ // only track HTML elements
167
+ if (!(node instanceof HTMLElement)) return;
168
+
169
+ // check the inserted element for being a code snippet
170
+ if (node.matches(matchString)) {
171
+ this.trackEventsForElements([node]);
172
+ }
173
+
174
+ const elements = Array.from(
175
+ node.querySelectorAll<HTMLElement>(matchString)
176
+ );
177
+ this.trackEventsForElements(elements);
178
+ });
179
+ });
180
+ });
181
+ }
182
+ this.mutationObserver.observe(document, { childList: true, subtree: true });
183
+
184
+ // Now track all already existing elements
185
+ if (firstTime) {
186
+ const elements = Array.from(
187
+ document.querySelectorAll<HTMLElement>(matchString)
188
+ );
189
+ this.trackEventsForElements(elements);
190
+ }
191
+ }
192
+
193
+ stopObserving(): void {
194
+ if (this.mutationObserver) {
195
+ this.mutationObserver.disconnect();
196
+ }
197
+ }
198
+
199
+ // Tracks events
200
+ // https://matomo.org/docs/event-tracking/#tracking-events
201
+ trackEvent({
202
+ category,
203
+ action,
204
+ name,
205
+ value,
206
+ ...otherParams
207
+ }: TrackEventParams): void {
208
+ if (category && action) {
209
+ this.track({
210
+ data: [TRACK_TYPES.TRACK_EVENT, category, action, name, value],
211
+ ...otherParams,
212
+ });
213
+ } else {
214
+ throw new Error(`Error: category and action are required.`);
215
+ }
216
+ }
217
+
218
+ // Tracks site search
219
+ // https://developer.matomo.org/guides/tracking-javascript-guide#internal-search-tracking
220
+ trackSiteSearch({
221
+ keyword,
222
+ category,
223
+ count,
224
+ ...otherParams
225
+ }: TrackSiteSearchParams): void {
226
+ if (keyword) {
227
+ this.track({
228
+ data: [TRACK_TYPES.TRACK_SEARCH, keyword, category, count],
229
+ ...otherParams,
230
+ });
231
+ } else {
232
+ throw new Error(`Error: keyword is required.`);
233
+ }
234
+ }
235
+
236
+ // Tracks outgoing links to other sites and downloads
237
+ // https://developer.matomo.org/guides/tracking-javascript-guide#enabling-download-outlink-tracking
238
+ trackLink({
239
+ href,
240
+ linkType = "link",
241
+ customDimensions,
242
+ }: TrackLinkParams): void {
243
+ if (
244
+ customDimensions &&
245
+ Array.isArray(customDimensions) &&
246
+ customDimensions.length
247
+ ) {
248
+ customDimensions.forEach((customDimension: CustomDimension) =>
249
+ this.pushInstruction(
250
+ "setCustomDimension",
251
+ customDimension.id,
252
+ customDimension.value
253
+ )
254
+ );
255
+ }
256
+ this.pushInstruction(TRACK_TYPES.TRACK_LINK, href, linkType);
257
+ }
258
+
259
+ // Tracks page views
260
+ // https://developer.matomo.org/guides/spa-tracking#tracking-a-new-page-view
261
+ trackPageView(params?: TrackPageViewParams): void {
262
+ this.track({ data: [TRACK_TYPES.TRACK_VIEW], ...params });
263
+ }
264
+
265
+ // Adds a product to an Ecommerce order to be tracked via trackEcommerceOrder.
266
+ // https://matomo.org/docs/ecommerce-analytics
267
+ // https://matomo.org/docs/ecommerce-analytics/#1-addecommerceitemproductsku-productname-productcategory-price-quantity
268
+ addEcommerceItem({
269
+ sku,
270
+ productName,
271
+ productCategory,
272
+ productPrice = 0.0,
273
+ productQuantity = 1,
274
+ }: AddEcommerceItemParams): void {
275
+ this.pushInstruction(
276
+ "addEcommerceItem",
277
+ sku,
278
+ productName,
279
+ productCategory,
280
+ productPrice,
281
+ productQuantity
282
+ );
283
+ }
284
+
285
+ // Removes a product from an Ecommerce order to be tracked via trackEcommerceOrder.
286
+ // https://matomo.org/docs/ecommerce-analytics
287
+ removeEcommerceItem({ sku }: RemoveEcommerceItemParams): void {
288
+ this.pushInstruction("removeEcommerceItem", sku);
289
+ }
290
+
291
+ // Removes all products from an Ecommerce order to be tracked via trackEcommerceOrder.
292
+ // https://matomo.org/docs/ecommerce-analytics
293
+ clearEcommerceCart(): void {
294
+ this.pushInstruction("clearEcommerceCart");
295
+ }
296
+
297
+ // Tracks an Ecommerce order containing items added via addEcommerceItem.
298
+ // https://matomo.org/docs/ecommerce-analytics/#2-trackecommerceorderorderid-revenue-subtotal-tax-shipping-discount
299
+ trackEcommerceOrder({
300
+ orderId,
301
+ orderRevenue,
302
+ orderSubTotal,
303
+ taxAmount,
304
+ shippingAmount,
305
+ discountOffered = false,
306
+ }: TrackEcommerceOrderParams): void {
307
+ this.track({
308
+ data: [
309
+ TRACK_TYPES.TRACK_ECOMMERCE_ORDER,
310
+ orderId,
311
+ orderRevenue,
312
+ orderSubTotal,
313
+ taxAmount,
314
+ shippingAmount,
315
+ discountOffered,
316
+ ],
317
+ });
318
+ }
319
+
320
+ // Tracks updates to an Ecommerce Cart before an actual purchase.
321
+ // This will replace currently tracked information of the cart. Always include all items of the updated cart!
322
+ // https://matomo.org/docs/ecommerce-analytics/#example-tracking-an-ecommerce-cart-update-containing-two-products
323
+ trackEcommerceCartUpdate(amount: number): void {
324
+ this.pushInstruction(TRACK_TYPES.TRACK_ECOMMERCE_CART_UPDATE, amount);
325
+ }
326
+
327
+ // Marks the next page view as an Ecommerce product page.
328
+ // https://matomo.org/docs/ecommerce-analytics/#example-tracking-a-product-page-view
329
+ setEcommerceView({
330
+ sku,
331
+ productName,
332
+ productCategory,
333
+ productPrice,
334
+ }: SetEcommerceViewParams): void {
335
+ this.pushInstruction(
336
+ "setEcommerceView",
337
+ sku,
338
+ productName,
339
+ productCategory,
340
+ productPrice
341
+ );
342
+ }
343
+
344
+ // Marks the next tracked page view as an Ecommerce category page.
345
+ // https://matomo.org/docs/ecommerce-analytics/#example-tracking-a-category-page-view
346
+ setEcommerceCategoryView(productCategory: string): void {
347
+ this.setEcommerceView({ productCategory, productName: false, sku: false });
348
+ }
349
+
350
+ // Sends the tracked page/view/search to Matomo
351
+ private track({
352
+ data = [],
353
+ documentTitle, // Changed: use passed documentTitle or fallback to window.document.title later
354
+ href,
355
+ customDimensions = false,
356
+ }: TrackParams): void {
357
+ if (typeof window === "undefined") return;
358
+
359
+ if (data.length) {
360
+ if (
361
+ customDimensions &&
362
+ Array.isArray(customDimensions) &&
363
+ customDimensions.length
364
+ ) {
365
+ customDimensions.forEach(
366
+ (
367
+ customDimension: CustomDimension // Corrected type
368
+ ) =>
369
+ this.pushInstruction(
370
+ "setCustomDimension",
371
+ customDimension.id,
372
+ customDimension.value
373
+ )
374
+ );
375
+ }
376
+
377
+ this.pushInstruction("setCustomUrl", href ?? window.location.href);
378
+ // Use provided documentTitle, fallback to actual document.title only if not provided
379
+ this.pushInstruction(
380
+ "setDocumentTitle",
381
+ documentTitle ?? window.document.title
382
+ );
383
+ this.pushInstruction(...(data as [string, ...any[]]));
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Pushes an instruction to Matomo for execution, this is equivalent to pushing entries into the `_paq` array.
389
+ *
390
+ * For example:
391
+ *
392
+ * ```ts
393
+ * pushInstruction('setDocumentTitle', document.title)
394
+ * ```
395
+ * Is the equivalent of:
396
+ *
397
+ * ```ts
398
+ * _paq.push(['setDocumentTitle', document.title]);
399
+ * ```
400
+ *
401
+ * @param name The name of the instruction to be executed.
402
+ * @param args The arguments to pass along with the instruction.
403
+ */
404
+ pushInstruction(name: string, ...args: any[]): MatomoTracker {
405
+ if (typeof window !== "undefined" && window._paq) {
406
+ window._paq.push([name, ...args]);
407
+ } else if (typeof window !== "undefined" && name === "setTrackerUrl") {
408
+ // Allow setting up _paq if it's the first instruction (like setTrackerUrl)
409
+ window._paq = [[name, ...args]];
410
+ }
411
+ return this;
412
+ }
413
+ }
414
+
415
+ export default MatomoTracker;
@@ -0,0 +1,12 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export const TRACK_TYPES = {
3
+ TRACK_EVENT: "trackEvent",
4
+ TRACK_LINK: "trackLink",
5
+ TRACK_SEARCH: "trackSiteSearch",
6
+ TRACK_VIEW: "trackPageView",
7
+ TRACK_ECOMMERCE_ORDER: "trackEcommerceOrder",
8
+ TRACK_ECOMMERCE_CART_UPDATE: "trackEcommerceCartUpdate",
9
+ // Add other Matomo instructions if needed, e.g., for goals
10
+ TRACK_GOAL: "trackGoal",
11
+ SET_USER_ID: "setUserId",
12
+ };
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ export { default as MatomoProvider } from "./MatomoProvider";
2
+ export { default as useMatomo } from "./useMatomo";
3
+ export { default as MatomoContext } from "./MatomoContext"; // Optional: if users need direct context access
4
+
5
+ // Export types for consumers
6
+ export * from "./types"; // Exports React-specific types and re-exports tracker-types
7
+ // Explicitly export core tracker types if not fully covered by ./types
8
+ export type {
9
+ CustomDimension,
10
+ UserOptions, // This is the core UserOptions, MatomoProviderProps is different
11
+ TrackPageViewParams, // Core type
12
+ TrackEventParams, // Core type
13
+ TrackLinkParams, // Core type
14
+ TrackSiteSearchParams, // Core type, though not directly used by simplified hook
15
+ TrackEcommerceOrderParams, // Core type
16
+ AddEcommerceItemParams, // Core type
17
+ RemoveEcommerceItemParams, // Core type
18
+ SetEcommerceViewParams, // Core type
19
+ TrackGoalParams, // Core type
20
+ } from "./tracker-types";
@@ -0,0 +1,89 @@
1
+ export interface CustomDimension {
2
+ id: number;
3
+ value: string;
4
+ }
5
+
6
+ export interface UserOptions {
7
+ urlBase: string;
8
+ siteId: number; // Matomo site ID is typically a number
9
+ userId?: string;
10
+ trackerUrl?: string;
11
+ srcUrl?: string;
12
+ disabled?: boolean;
13
+ heartBeat?: {
14
+ active: boolean;
15
+ seconds?: number;
16
+ };
17
+ linkTracking?: boolean;
18
+ configurations?: {
19
+ [key: string]: any;
20
+ };
21
+ }
22
+
23
+ export interface TrackPageViewParams {
24
+ documentTitle?: string;
25
+ href?: string | Location;
26
+ customDimensions?: boolean | CustomDimension[];
27
+ }
28
+
29
+ export interface TrackParams extends TrackPageViewParams {
30
+ data: any[];
31
+ }
32
+
33
+ export interface TrackEventParams {
34
+ category: string;
35
+ action: string;
36
+ name?: string;
37
+ value?: number;
38
+ // Allow other params to be passed through for flexibility with customDimensions, etc.
39
+ documentTitle?: string;
40
+ href?: string | Location;
41
+ customDimensions?: boolean | CustomDimension[];
42
+ }
43
+
44
+ export interface TrackLinkParams {
45
+ href: string;
46
+ linkType?: "download" | "link";
47
+ // Allow other params
48
+ customDimensions?: boolean | CustomDimension[];
49
+ }
50
+
51
+ export interface TrackSiteSearchParams extends TrackPageViewParams {
52
+ keyword: string;
53
+ category?: string;
54
+ count?: number;
55
+ }
56
+
57
+ export interface TrackEcommerceOrderParams {
58
+ orderId: string;
59
+ orderRevenue: number;
60
+ orderSubTotal?: number;
61
+ taxAmount?: number;
62
+ shippingAmount?: number;
63
+ discountOffered?: boolean;
64
+ }
65
+
66
+ export interface AddEcommerceItemParams {
67
+ sku: string;
68
+ productName?: string;
69
+ productCategory?: string;
70
+ productPrice?: number;
71
+ productQuantity?: number;
72
+ }
73
+
74
+ export interface RemoveEcommerceItemParams {
75
+ sku: string;
76
+ }
77
+
78
+ export interface SetEcommerceViewParams {
79
+ sku: string | boolean;
80
+ productName?: string | boolean;
81
+ productCategory?: string;
82
+ productPrice?: number;
83
+ }
84
+
85
+ // Added for useMatomo hook
86
+ export interface TrackGoalParams {
87
+ goalId: number | string;
88
+ revenue?: number;
89
+ }
package/src/types.ts ADDED
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+
3
+ // Re-export tracker types for convenience if needed by consumers of the React package
4
+ export * from "./tracker-types";
5
+
6
+ export interface MatomoProviderProps {
7
+ children: React.ReactNode;
8
+ urlBase: string;
9
+ siteId: string | number;
10
+ trackCookies?: boolean;
11
+ disabled?: boolean;
12
+ }
13
+
14
+ export interface MatomoInstance {
15
+ trackEvent: (
16
+ category: string,
17
+ action: string,
18
+ name?: string,
19
+ value?: number
20
+ ) => void;
21
+ trackPageView: (customTitle?: string) => void;
22
+ trackGoal: (goalId: number | string, revenue?: number) => void;
23
+ setUserId: (userId: string) => void;
24
+ trackLink: (url: string, linkType: "link" | "download") => void;
25
+ pushInstruction: (instruction: any[]) => void;
26
+ }
27
+
28
+ // For useMatomo hook return type
29
+ export type UseMatomo = MatomoInstance;
@@ -0,0 +1,55 @@
1
+ import { useContext, useCallback } from "react";
2
+ import MatomoContext from "./MatomoContext";
3
+ import { UseMatomo } from "./types";
4
+
5
+ function useMatomo(): UseMatomo {
6
+ const context = useContext(MatomoContext);
7
+
8
+ if (context === null) {
9
+ throw new Error("useMatomo must be used within a MatomoProvider");
10
+ }
11
+
12
+ const trackPageView = useCallback(
13
+ (customTitle?: string) => context.trackPageView(customTitle),
14
+ [context]
15
+ );
16
+
17
+ const trackEvent = useCallback(
18
+ (category: string, action: string, name?: string, value?: number) =>
19
+ context.trackEvent(category, action, name, value),
20
+ [context]
21
+ );
22
+
23
+ const trackGoal = useCallback(
24
+ (goalId: number | string, revenue?: number) =>
25
+ context.trackGoal(goalId, revenue),
26
+ [context]
27
+ );
28
+
29
+ const setUserId = useCallback(
30
+ (userId: string) => context.setUserId(userId),
31
+ [context]
32
+ );
33
+
34
+ const trackLink = useCallback(
35
+ (url: string, linkType: "link" | "download") =>
36
+ context.trackLink(url, linkType),
37
+ [context]
38
+ );
39
+
40
+ const pushInstruction = useCallback(
41
+ (instruction: any[]) => context.pushInstruction(instruction),
42
+ [context]
43
+ );
44
+
45
+ return {
46
+ trackEvent,
47
+ trackPageView,
48
+ trackGoal,
49
+ setUserId,
50
+ trackLink,
51
+ pushInstruction,
52
+ };
53
+ }
54
+
55
+ export default useMatomo;