aesirx-analytics 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +18 -9
- package/dist/index.js +5 -0
- package/package.json +12 -34
- package/src/AnalyticsNext/{handle.js → handle.tsx} +42 -10
- package/src/AnalyticsNext/index.tsx +26 -0
- package/src/AnalyticsReact/handle.tsx +72 -0
- package/src/AnalyticsReact/index.tsx +21 -0
- package/src/{analytics.js → analytics.ts} +15 -20
- package/src/{index.js → index.ts} +1 -1
- package/src/utils/AnalyticsContextProvider.tsx +57 -0
- package/src/utils/{index.js → index.ts} +32 -10
- package/src/utils/{services.js → services.ts} +3 -3
- package/build/analytics.js +0 -1
- package/build/lib/bundles/bundle.esm.min.js +0 -2
- package/build/lib/bundles/bundle.esm.min.js.map +0 -1
- package/build/lib/cjs/AnalyticsNext/handle.js +0 -119
- package/build/lib/cjs/AnalyticsNext/handle.js.map +0 -1
- package/build/lib/cjs/AnalyticsNext/index.js +0 -51
- package/build/lib/cjs/AnalyticsNext/index.js.map +0 -1
- package/build/lib/cjs/AnalyticsReact/handle.js +0 -77
- package/build/lib/cjs/AnalyticsReact/handle.js.map +0 -1
- package/build/lib/cjs/AnalyticsReact/index.js +0 -51
- package/build/lib/cjs/AnalyticsReact/index.js.map +0 -1
- package/build/lib/cjs/analytics.js +0 -197
- package/build/lib/cjs/analytics.js.map +0 -1
- package/build/lib/cjs/index.js +0 -35
- package/build/lib/cjs/index.js.map +0 -1
- package/build/lib/cjs/utils/AnalyticsContextProvider.js +0 -39
- package/build/lib/cjs/utils/AnalyticsContextProvider.js.map +0 -1
- package/build/lib/cjs/utils/index.js +0 -202
- package/build/lib/cjs/utils/index.js.map +0 -1
- package/build/lib/cjs/utils/services.js +0 -51
- package/build/lib/cjs/utils/services.js.map +0 -1
- package/build/lib/esm/AnalyticsNext/handle.js +0 -124
- package/build/lib/esm/AnalyticsNext/handle.js.map +0 -1
- package/build/lib/esm/AnalyticsNext/index.js +0 -56
- package/build/lib/esm/AnalyticsNext/index.js.map +0 -1
- package/build/lib/esm/AnalyticsReact/handle.js +0 -82
- package/build/lib/esm/AnalyticsReact/handle.js.map +0 -1
- package/build/lib/esm/AnalyticsReact/index.js +0 -56
- package/build/lib/esm/AnalyticsReact/index.js.map +0 -1
- package/build/lib/esm/analytics.js +0 -198
- package/build/lib/esm/analytics.js.map +0 -1
- package/build/lib/esm/index.js +0 -35
- package/build/lib/esm/index.js.map +0 -1
- package/build/lib/esm/utils/AnalyticsContextProvider.js +0 -45
- package/build/lib/esm/utils/AnalyticsContextProvider.js.map +0 -1
- package/build/lib/esm/utils/index.js +0 -206
- package/build/lib/esm/utils/index.js.map +0 -1
- package/build/lib/esm/utils/services.js +0 -54
- package/build/lib/esm/utils/services.js.map +0 -1
- package/build/lib/types/AnalyticsNext/handle.d.ts +0 -3
- package/build/lib/types/AnalyticsNext/handle.d.ts.map +0 -1
- package/build/lib/types/AnalyticsNext/index.d.ts +0 -3
- package/build/lib/types/AnalyticsNext/index.d.ts.map +0 -1
- package/build/lib/types/AnalyticsReact/handle.d.ts +0 -3
- package/build/lib/types/AnalyticsReact/handle.d.ts.map +0 -1
- package/build/lib/types/AnalyticsReact/index.d.ts +0 -3
- package/build/lib/types/AnalyticsReact/index.d.ts.map +0 -1
- package/build/lib/types/index.d.ts +0 -5
- package/build/lib/types/index.d.ts.map +0 -1
- package/build/lib/types/index.min.js +0 -1
- package/build/lib/types/utils/AnalyticsContextProvider.d.ts +0 -3
- package/build/lib/types/utils/AnalyticsContextProvider.d.ts.map +0 -1
- package/build/lib/types/utils/index.d.ts +0 -5
- package/build/lib/types/utils/index.d.ts.map +0 -1
- package/build/lib/types/utils/services.d.ts +0 -2
- package/build/lib/types/utils/services.d.ts.map +0 -1
- package/src/AnalyticsNext/index.js +0 -30
- package/src/AnalyticsReact/handle.js +0 -39
- package/src/AnalyticsReact/index.js +0 -29
- package/src/utils/AnalyticsContextProvider.js +0 -17
package/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# AesirX Analytics JS Collector
|
2
2
|
|
3
|
-
A powerful and compliant web Analytics platform (1st-party alternative to Google Analytics) that only collects 1st-party data to deliver meaningful customer insights for your organization.
|
3
|
+
A powerful and compliant web Analytics platform (1st-party alternative to Google Analytics) that only collects 1st-party data to deliver meaningful customer insights for your organization.
|
4
4
|
|
5
5
|
AesirX Analytics comes with a locally hosted JavaScript solution that gathers and stores data legally and compliantly in accordance with GDPR and other regional legislation including storage of citizens’ data in-country and 1st-party.
|
6
6
|
|
@@ -25,7 +25,6 @@ Follow the instructions in: [https://github.com/aesirxio/analytics-1stparty](htt
|
|
25
25
|
|
26
26
|
(`https://example.com` is the link to your 1st party server which must be installed)
|
27
27
|
|
28
|
-
|
29
28
|
#### Usage in ReactJS
|
30
29
|
|
31
30
|
`npm i aesirx-analytics`
|
@@ -44,18 +43,20 @@ Create AnalyticsContainer component:
|
|
44
43
|
|
45
44
|
```
|
46
45
|
import React from 'react';
|
47
|
-
import { useLocation } from 'react-router-dom';
|
46
|
+
import { useLocation, useHistory } from 'react-router-dom';
|
48
47
|
import { AnalyticsReact } from 'aesirx-analytics';
|
49
48
|
const AnalyticsContainer = ({children}) => {
|
50
49
|
const location = useLocation();
|
51
|
-
|
50
|
+
let history = useHistory();
|
51
|
+
return <AnalyticsReact location={location} history={history}>{children}</AnalyticsReact>;
|
52
52
|
};
|
53
53
|
|
54
54
|
export default AnalyticsContainer;
|
55
55
|
```
|
56
56
|
|
57
57
|
###### Wrap your component in `<AnalyticsContainer><[YOUR-COMPONENT]/></AnalyticsContainer>`
|
58
|
-
|
58
|
+
|
59
|
+
###### `<AnalyticsContainer>` need to using inside `<Router>` component
|
59
60
|
|
60
61
|
#### Usage in NextJS
|
61
62
|
|
@@ -85,10 +86,12 @@ import { AnalyticsNext } from "aesirx-analytics";
|
|
85
86
|
## Track events:
|
86
87
|
|
87
88
|
#### In SSR Site:
|
89
|
+
|
88
90
|
To track events, simply add special data-attribute to the element you want to track.
|
89
91
|
For example, you might have a button with the following code:
|
92
|
+
|
90
93
|
```
|
91
|
-
<button class="button"
|
94
|
+
<button class="button"
|
92
95
|
data-aesirx-event-name="sign up"
|
93
96
|
data-aesirx-event-type="login"
|
94
97
|
data-aesirx-event-attribute-a="value-a"
|
@@ -97,17 +100,22 @@ For example, you might have a button with the following code:
|
|
97
100
|
Sign Up
|
98
101
|
</button>
|
99
102
|
```
|
103
|
+
|
100
104
|
Add data-attribute with the following format:
|
105
|
+
|
101
106
|
```
|
102
107
|
data-aesirx-event-name="<event-name>"
|
103
108
|
data-aesirx-event-type="<event-type>"
|
104
109
|
data-aesirx-event-attribute-<attribute-name-1>="<attribute-value-1>"
|
105
110
|
data-aesirx-event-attribute-<attribute-name-2>="<attribute-value-1>"
|
106
111
|
```
|
112
|
+
|
107
113
|
##### Or you can use your own Javascript to Track events:
|
114
|
+
|
108
115
|
```
|
109
116
|
window.trackEvent(endpoint, event_uuid, visitor_uuid, referrer, data)
|
110
117
|
```
|
118
|
+
|
111
119
|
(`endpoint` is the link to your 1st party server which must be installed)
|
112
120
|
|
113
121
|
(`event_uuid` is the params get from url - it will auto generated)
|
@@ -118,12 +126,13 @@ window.trackEvent(endpoint, event_uuid, visitor_uuid, referrer, data)
|
|
118
126
|
|
119
127
|
(`data` is the data you want to track)
|
120
128
|
|
121
|
-
For example:
|
129
|
+
For example:
|
130
|
+
|
122
131
|
```
|
123
132
|
trackEvent(
|
124
133
|
"https://example.com",
|
125
|
-
event_uuid,
|
126
|
-
visitor_uuid,
|
134
|
+
event_uuid,
|
135
|
+
visitor_uuid,
|
127
136
|
"https://aesirx.io",
|
128
137
|
{
|
129
138
|
event_name: "<event_name>",
|
package/dist/index.js
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
var O=Object.create;var A=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var J=(t,i)=>{for(var e in i)A(t,e,{get:i[e],enumerable:!0})},T=(t,i,e,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of Q(i))!F.call(t,s)&&s!==e&&A(t,s,{get:()=>i[s],enumerable:!(n=B(i,s))||n.enumerable});return t};var g=(t,i,e)=>(e=t!=null?O(Y(t)):{},T(i||!t||!t.__esModule?A(e,"default",{value:t,enumerable:!0}):e,t)),W=t=>T(A({},"__esModule",{value:!0}),t);var Z={};J(Z,{AnalyticsContext:()=>m,AnalyticsNext:()=>L,AnalyticsReact:()=>j,trackEvent:()=>q});module.exports=W(Z);var w=g(require("react"));var l=g(require("react"));var m=l.default.createContext({event_uuid:void 0,visitor_uuid:void 0,event_uuid_start:void 0,visitor_uuid_start:void 0,setEventID:void 0,setUUID:void 0,setEventIDStart:void 0,setUUIDStart:void 0}),P=({children:t})=>{let[i,e]=(0,l.useState)(),[n,s]=(0,l.useState)(),[a,d]=(0,l.useState)(),[u,r]=(0,l.useState)();return l.default.createElement(m.Provider,{value:{event_uuid:i,visitor_uuid:n,event_uuid_start:a,visitor_uuid_start:u,setEventID:e,setUUID:s,setEventIDStart:d,setUUIDStart:r}},t)};var v=g(require("react"));var X,z=(t,i)=>(Object.keys(i).forEach(e=>{i[e]!==void 0&&(t[e]=i[e])}),t),y=async(t,i)=>await(await fetch(t,{method:"POST",body:JSON.stringify(i),headers:z({"Content-Type":"application/json"},{["x-tracker-cache"]:X})})).json();var k=g(require("bowser")),U=(t,i)=>`${t}/visitor/v1/${i}`,D=async(t,i,e,n)=>{let{document:s}=window,{pathname:a,search:d,origin:u}=location;i=`${u}${a}${d}`,e=s.referrer,n=window.navigator.userAgent;let r=k.default.parse(window.navigator.userAgent),o=r?.browser?.name,_=r?.browser?.version,c=window.navigator.userLanguage||window.navigator.language,E=r?.platform?.model??r?.platform?.type,C=`${u}`,$=window.location.search,f=new URLSearchParams($),N=[];for(let h of f.keys())h.startsWith("utm_")&&f.get(h)&&N.push({name:h,value:f.get(h)});if(!f.get("event_uuid")&&!f.get("visitor_uuid")){let h="";return await y(U(t,"init"),{url:i,referrer:e,user_agent:n,ip:h,domain:C,browser_name:o,browser_version:_,lang:c,device:E,event_name:"visit",event_type:"action",attributes:N})}},I=async(t,i,e,n)=>{let{location:s,document:a}=window;n=n?s.protocol+"//"+s.host+n:a.referrer.split("?")[0];let d=s.protocol+"//"+s.host+s.pathname,u=window.location.search,r=new URLSearchParams(u);return await y(U(t,"start"),{...r.get("event_uuid")&&{event_uuid:r.get("event_uuid")},...r.get("visitor_uuid")&&{visitor_uuid:r.get("visitor_uuid")},...i&&{event_uuid:i},...e&&{visitor_uuid:e},referrer:n==="/"?"":n,url:d})},x=async(t,i,e)=>{let n=window.location.search,s=new URLSearchParams(n);return await y(U(t,"end"),{...s.get("event_uuid_start")&&{event_uuid:s.get("event_uuid_start")},...s.get("visitor_uuid_start")&&{visitor_uuid:s.get("visitor_uuid_start")},...i&&{event_uuid:i},...e&&{visitor_uuid:e}})},q=async(t,i,e,n,s)=>{let{location:a,document:d}=window;n=n?a.protocol+"//"+a.host+n:d.referrer.split("?")[0];let u=a.protocol+"//"+a.host+a.pathname,r=window.location.search,o=new URLSearchParams(r);return await y(U(t,"start"),{...o.get("event_uuid")&&{event_uuid:o.get("event_uuid")},...o.get("visitor_uuid")&&{visitor_uuid:o.get("visitor_uuid")},...i&&{event_uuid:i},...e&&{visitor_uuid:e},referrer:n==="/"?"":n,url:u,...s})};var G=({router:t,children:i})=>{let e=v.default.useContext(m),n=process.env.NEXT_PUBLIC_ENDPOINT_ANALYTICS_URL,[s,a]=(0,v.useState)(t.asPath),d=(0,v.useCallback)(async u=>{let r=u||"",o=await I(n,e.event_uuid,e.visitor_uuid,r);o.event_uuid&&e.setEventIDStart(o.event_uuid),o.visitor_uuid&&e.setUUIDStart(o.visitor_uuid)},[e,n]);return(0,v.useEffect)(()=>{(async()=>{let r=new URLSearchParams(window.location.search),o=r.get("event_uuid"),_=r.get("visitor_uuid");if(!e.event_uuid&&!e.visitor_uuid)if(o&&_)e.setEventID(o),e.setUUID(_);else{let c=await D(n);c?.event_uuid&&e.setEventID(c?.event_uuid),e.setUUID(c?.visitor_uuid)}else await d(s)})()},[e.visitor_uuid]),(0,v.useEffect)(()=>{let u=async()=>{let{event_uuid:r,visitor_uuid:o}=t.query;e.visitor_uuid_start&&!r&&!o&&(await x(n,e.event_uuid_start,e.visitor_uuid_start),await d(s)),a(t.asPath)};return t.events.on("routeChangeComplete",u),t.replace({query:{...t.query,event_uuid:e.event_uuid,visitor_uuid:e.visitor_uuid}},void 0,{shallow:!0}),()=>{t.events.off("routeChangeComplete",u)}},[t.events,e.visitor_uuid_start,t.asPath]),v.default.createElement(v.default.Fragment,null,i)},b=G;var K=({router:t,children:i})=>w.default.createElement(w.default.Fragment,null,w.default.createElement(P,null,w.default.createElement(b,{router:t},i))),L=K;var R=g(require("react"));var p=g(require("react")),S=g(require("query-string"));var M=({location:t,history:i,children:e})=>{let n=p.default.useContext(m),s=process.env.REACT_APP_ENDPOINT_ANALYTICS_URL,[a,d]=(0,p.useState)(null);return(0,p.useEffect)(()=>{(async()=>{if(n.visitor_uuid_start&&await x(s,n.event_uuid_start,n.visitor_uuid_start),!n.event_uuid&&!n.visitor_uuid){let r=new URLSearchParams(window.location.search),o=r.get("event_uuid"),_=r.get("visitor_uuid");if(o&&_)n.setEventID(o),n.setUUID(_);else{let c=await D(s);c.event_uuid&&n.setEventID(c.event_uuid),n.setUUID(c.visitor_uuid);let C={...S.default.parse(t.search),event_uuid:c.event_uuid,visitor_uuid:c.visitor_uuid};i.push({search:S.default.stringify(C)})}}else{let o={...S.default.parse(t.search),event_uuid:n.event_uuid,visitor_uuid:n.visitor_uuid};i.push({search:S.default.stringify(o)});let _=a||"",c=await I(s,n.event_uuid,n.visitor_uuid,_);c.event_uuid&&n.setEventIDStart(c.event_uuid),c.visitor_uuid&&n.setUUIDStart(c.visitor_uuid),d(t.pathname)}})()},[t.pathname,n.visitor_uuid,i]),p.default.createElement(p.default.Fragment,null,e)},H=M;var V=({location:t,history:i,children:e})=>R.default.createElement(P,null,R.default.createElement(H,{location:t,history:i},e)),j=V;0&&(module.exports={AnalyticsContext,AnalyticsNext,AnalyticsReact,trackEvent});
|
2
|
+
/*
|
3
|
+
* @copyright Copyright (C) 2022 AesirX. All rights reserved.
|
4
|
+
* @license GNU General Public License version 3, see LICENSE.
|
5
|
+
*/
|
package/package.json
CHANGED
@@ -1,31 +1,17 @@
|
|
1
1
|
{
|
2
2
|
"name": "aesirx-analytics",
|
3
|
-
"version": "1.0
|
3
|
+
"version": "1.1.0",
|
4
4
|
"license": "GPL-3.0-only",
|
5
5
|
"author": "AesirX",
|
6
6
|
"repository": "https://gitlab.redweb.dk/aesirx/analytics",
|
7
|
-
"main": "
|
8
|
-
"module": "build/lib/esm/index.js",
|
9
|
-
"exports": {
|
10
|
-
"require": "./build/lib/cjs/index.js",
|
11
|
-
"import": "./build/lib/esm/index.js"
|
12
|
-
},
|
13
|
-
"types": "build/lib/types/index.d.ts",
|
14
|
-
"source": "src/index.js",
|
7
|
+
"main": "dist/index.js",
|
15
8
|
"dependencies": {
|
16
9
|
"bowser": "^2.11.0",
|
17
|
-
"
|
18
|
-
"dotenv": "^16.0.3",
|
19
|
-
"npm-run-all": "^4.1.5",
|
20
|
-
"public-ip": "^6.0.1",
|
21
|
-
"rimraf": "^3.0.2"
|
10
|
+
"query-string": "^7.1.1"
|
22
11
|
},
|
23
12
|
"scripts": {
|
24
13
|
"clean": "rimraf lib",
|
25
|
-
"build
|
26
|
-
"build:cjs": "cross-env BABEL_ENV=cjs babel src --extensions '.js' --out-dir 'build/lib/cjs' --source-maps",
|
27
|
-
"build:bundles": "cross-env BABEL_ENV=esmBundled rollup -c",
|
28
|
-
"build": "npm-run-all -l clean -p build:esm build:cjs build:bundles",
|
14
|
+
"build": "tsup",
|
29
15
|
"lint": "eslint --fix \"src/**/\"",
|
30
16
|
"lint:check": "eslint \"src/**/\"",
|
31
17
|
"lint:nowarns": "eslint --quiet \"src/**/\"",
|
@@ -56,24 +42,16 @@
|
|
56
42
|
"react-dom": "^17.0.1"
|
57
43
|
},
|
58
44
|
"devDependencies": {
|
59
|
-
"@
|
60
|
-
"@
|
61
|
-
"@
|
62
|
-
"@
|
63
|
-
"@
|
64
|
-
"
|
65
|
-
"@rollup/plugin-babel": "^6.0.2",
|
66
|
-
"@rollup/plugin-json": "^6.0.0",
|
67
|
-
"@rollup/plugin-commonjs": "^24.0.1",
|
68
|
-
"@rollup/plugin-node-resolve": "^15.0.1",
|
69
|
-
"@rollup/plugin-replace": "^4.0.0",
|
70
|
-
"babel-plugin-module-resolver": "^5.0.0",
|
71
|
-
"eslint": "^8.34",
|
45
|
+
"@types/node": "^18.15.11",
|
46
|
+
"@types/react": "^18.0.30",
|
47
|
+
"@types/react-dom": "^18.0.11",
|
48
|
+
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
49
|
+
"@typescript-eslint/parser": "^5.57.0",
|
50
|
+
"eslint": "^8.36",
|
72
51
|
"eslint-plugin-react": "^7.31.10",
|
73
52
|
"prettier": "^2.8.4",
|
74
|
-
"
|
75
|
-
"
|
76
|
-
"rollup-plugin-typescript2": "^0.34.1",
|
53
|
+
"rimraf": "^4.4.1",
|
54
|
+
"tsup": "^6.7.0",
|
77
55
|
"typescript": "^4.9.3"
|
78
56
|
},
|
79
57
|
"overrides": {
|
@@ -1,13 +1,24 @@
|
|
1
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
1
|
+
import React, { ReactNode, useCallback, useEffect, useState } from 'react';
|
2
2
|
import { AnalyticsContext } from '../utils/AnalyticsContextProvider';
|
3
3
|
import { initTracker, startTracker, endTracker } from '../utils/index';
|
4
4
|
|
5
|
-
|
5
|
+
interface AnalyticsHandle {
|
6
|
+
router: {
|
7
|
+
asPath: string;
|
8
|
+
events: { on: (_: string, __: () => void) => void; off: (_: string, __: () => void) => void };
|
9
|
+
replace: any;
|
10
|
+
query: any;
|
11
|
+
push: any;
|
12
|
+
};
|
13
|
+
children?: ReactNode;
|
14
|
+
}
|
15
|
+
|
16
|
+
const AnalyticsHandle = ({ router, children }: AnalyticsHandle) => {
|
6
17
|
const AnalyticsStore = React.useContext(AnalyticsContext);
|
7
18
|
const endPoint = process.env.NEXT_PUBLIC_ENDPOINT_ANALYTICS_URL;
|
8
|
-
const [prevRoute, setPrevRoute] = useState(router.asPath);
|
19
|
+
const [prevRoute, setPrevRoute] = useState<string>(router.asPath);
|
9
20
|
const handleStartTracker = useCallback(
|
10
|
-
async (prevRoute) => {
|
21
|
+
async (prevRoute: string) => {
|
11
22
|
const referrer = prevRoute ? prevRoute : '';
|
12
23
|
const responseStart = await startTracker(
|
13
24
|
endPoint,
|
@@ -23,12 +34,20 @@ const AnalyticsHandle = ({ router, children }) => {
|
|
23
34
|
|
24
35
|
useEffect(() => {
|
25
36
|
const init = async () => {
|
37
|
+
const urlParams = new URLSearchParams(window.location.search);
|
38
|
+
const event_uuid = urlParams.get('event_uuid');
|
39
|
+
const visitor_uuid = urlParams.get('visitor_uuid');
|
26
40
|
if (!AnalyticsStore.event_uuid && !AnalyticsStore.visitor_uuid) {
|
27
|
-
|
28
|
-
|
29
|
-
|
41
|
+
if (event_uuid && visitor_uuid) {
|
42
|
+
AnalyticsStore.setEventID(event_uuid);
|
43
|
+
AnalyticsStore.setUUID(visitor_uuid);
|
44
|
+
} else {
|
45
|
+
const responseInit = await initTracker(endPoint);
|
46
|
+
responseInit?.event_uuid && AnalyticsStore.setEventID(responseInit?.event_uuid);
|
47
|
+
AnalyticsStore.setUUID(responseInit?.visitor_uuid);
|
48
|
+
}
|
30
49
|
} else {
|
31
|
-
await handleStartTracker();
|
50
|
+
await handleStartTracker(prevRoute);
|
32
51
|
}
|
33
52
|
};
|
34
53
|
init();
|
@@ -36,7 +55,8 @@ const AnalyticsHandle = ({ router, children }) => {
|
|
36
55
|
|
37
56
|
useEffect(() => {
|
38
57
|
const handleRouteChange = async () => {
|
39
|
-
|
58
|
+
const { event_uuid, visitor_uuid } = router.query;
|
59
|
+
if (AnalyticsStore.visitor_uuid_start && !event_uuid && !visitor_uuid) {
|
40
60
|
await endTracker(
|
41
61
|
endPoint,
|
42
62
|
AnalyticsStore.event_uuid_start,
|
@@ -47,7 +67,19 @@ const AnalyticsHandle = ({ router, children }) => {
|
|
47
67
|
setPrevRoute(router.asPath);
|
48
68
|
};
|
49
69
|
router.events.on('routeChangeComplete', handleRouteChange);
|
50
|
-
|
70
|
+
router.replace(
|
71
|
+
{
|
72
|
+
query: {
|
73
|
+
...router.query,
|
74
|
+
event_uuid: AnalyticsStore.event_uuid,
|
75
|
+
visitor_uuid: AnalyticsStore.visitor_uuid,
|
76
|
+
},
|
77
|
+
},
|
78
|
+
undefined,
|
79
|
+
{
|
80
|
+
shallow: true,
|
81
|
+
}
|
82
|
+
);
|
51
83
|
return () => {
|
52
84
|
router.events.off('routeChangeComplete', handleRouteChange);
|
53
85
|
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React, { ReactNode } from 'react';
|
2
|
+
|
3
|
+
import { AnalyticsContextProvider } from '../utils/AnalyticsContextProvider';
|
4
|
+
import AnalyticsHandle from './handle';
|
5
|
+
|
6
|
+
interface AnalyticsReact {
|
7
|
+
router: {
|
8
|
+
asPath: string;
|
9
|
+
events: { on: (_: string, __: () => void) => void; off: (_: string, __: () => void) => void };
|
10
|
+
replace: any;
|
11
|
+
query: any;
|
12
|
+
push: any;
|
13
|
+
};
|
14
|
+
children?: ReactNode;
|
15
|
+
}
|
16
|
+
|
17
|
+
const AnalyticsNext = ({ router, children }: AnalyticsReact) => {
|
18
|
+
return (
|
19
|
+
<>
|
20
|
+
<AnalyticsContextProvider>
|
21
|
+
<AnalyticsHandle router={router}>{children}</AnalyticsHandle>
|
22
|
+
</AnalyticsContextProvider>
|
23
|
+
</>
|
24
|
+
);
|
25
|
+
};
|
26
|
+
export default AnalyticsNext;
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import React, { ReactNode, useEffect, useState } from 'react';
|
2
|
+
import qs from 'query-string';
|
3
|
+
import { AnalyticsContext } from '../utils/AnalyticsContextProvider';
|
4
|
+
import { initTracker, startTracker, endTracker } from '../utils/index';
|
5
|
+
|
6
|
+
interface AnalyticsHandle {
|
7
|
+
location: { search: string; pathname: string };
|
8
|
+
history: { push: (_: object) => void };
|
9
|
+
children?: ReactNode;
|
10
|
+
}
|
11
|
+
|
12
|
+
const AnalyticsHandle = ({ location, history, children }: AnalyticsHandle) => {
|
13
|
+
const AnalyticsStore = React.useContext(AnalyticsContext);
|
14
|
+
const endPoint = process.env.REACT_APP_ENDPOINT_ANALYTICS_URL;
|
15
|
+
const [prevRoute, setPrevRoute] = useState<string>(null);
|
16
|
+
useEffect(() => {
|
17
|
+
const init = async () => {
|
18
|
+
if (AnalyticsStore.visitor_uuid_start) {
|
19
|
+
await endTracker(
|
20
|
+
endPoint,
|
21
|
+
AnalyticsStore.event_uuid_start,
|
22
|
+
AnalyticsStore.visitor_uuid_start
|
23
|
+
);
|
24
|
+
}
|
25
|
+
if (!AnalyticsStore.event_uuid && !AnalyticsStore.visitor_uuid) {
|
26
|
+
const urlParams = new URLSearchParams(window.location.search);
|
27
|
+
const event_uuid = urlParams.get('event_uuid');
|
28
|
+
const visitor_uuid = urlParams.get('visitor_uuid');
|
29
|
+
if (event_uuid && visitor_uuid) {
|
30
|
+
AnalyticsStore.setEventID(event_uuid);
|
31
|
+
AnalyticsStore.setUUID(visitor_uuid);
|
32
|
+
} else {
|
33
|
+
const responseInit = await initTracker(endPoint);
|
34
|
+
responseInit.event_uuid && AnalyticsStore.setEventID(responseInit.event_uuid);
|
35
|
+
AnalyticsStore.setUUID(responseInit.visitor_uuid);
|
36
|
+
// Add Params to URL
|
37
|
+
const queryParams = qs.parse(location.search);
|
38
|
+
const newQueries = {
|
39
|
+
...queryParams,
|
40
|
+
event_uuid: responseInit.event_uuid,
|
41
|
+
visitor_uuid: responseInit.visitor_uuid,
|
42
|
+
};
|
43
|
+
history.push({ search: qs.stringify(newQueries) });
|
44
|
+
}
|
45
|
+
} else {
|
46
|
+
// Add Params to URL
|
47
|
+
const queryParams = qs.parse(location.search);
|
48
|
+
const newQueries = {
|
49
|
+
...queryParams,
|
50
|
+
event_uuid: AnalyticsStore.event_uuid,
|
51
|
+
visitor_uuid: AnalyticsStore.visitor_uuid,
|
52
|
+
};
|
53
|
+
history.push({ search: qs.stringify(newQueries) });
|
54
|
+
|
55
|
+
const referrer = prevRoute ? prevRoute : '';
|
56
|
+
const responseStart = await startTracker(
|
57
|
+
endPoint,
|
58
|
+
AnalyticsStore.event_uuid,
|
59
|
+
AnalyticsStore.visitor_uuid,
|
60
|
+
referrer
|
61
|
+
);
|
62
|
+
responseStart.event_uuid && AnalyticsStore.setEventIDStart(responseStart.event_uuid);
|
63
|
+
responseStart.visitor_uuid && AnalyticsStore.setUUIDStart(responseStart.visitor_uuid);
|
64
|
+
setPrevRoute(location.pathname);
|
65
|
+
}
|
66
|
+
};
|
67
|
+
init();
|
68
|
+
}, [location.pathname, AnalyticsStore.visitor_uuid, history]);
|
69
|
+
|
70
|
+
return <>{children}</>;
|
71
|
+
};
|
72
|
+
export default AnalyticsHandle;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import React, { ReactNode } from 'react';
|
2
|
+
|
3
|
+
import { AnalyticsContextProvider } from '../utils/AnalyticsContextProvider';
|
4
|
+
import AnalyticsHandle from './handle';
|
5
|
+
|
6
|
+
interface AnalyticsReact {
|
7
|
+
location: { search: string; pathname: string };
|
8
|
+
history: { push: (_: object) => void };
|
9
|
+
children?: ReactNode;
|
10
|
+
}
|
11
|
+
|
12
|
+
const AnalyticsReact = ({ location, history, children }: AnalyticsReact) => {
|
13
|
+
return (
|
14
|
+
<AnalyticsContextProvider>
|
15
|
+
<AnalyticsHandle location={location} history={history}>
|
16
|
+
{children}
|
17
|
+
</AnalyticsHandle>
|
18
|
+
</AnalyticsContextProvider>
|
19
|
+
);
|
20
|
+
};
|
21
|
+
export default AnalyticsReact;
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import { endTracker, initTracker, startTracker, trackEvent } from './utils';
|
1
|
+
import { endTracker, initTracker, insertParam, startTracker, trackEvent } from './utils';
|
2
2
|
|
3
3
|
const AesirAnalytics = () => {
|
4
|
-
const hook = (_this, method, callback) => {
|
4
|
+
const hook = (_this: object, method: string, callback: (_: string) => void) => {
|
5
5
|
const orig = _this[method];
|
6
6
|
|
7
|
-
return (...args) => {
|
7
|
+
return (...args: []) => {
|
8
8
|
callback.apply(null, args);
|
9
9
|
|
10
10
|
return orig.apply(_this, args);
|
@@ -13,7 +13,7 @@ const AesirAnalytics = () => {
|
|
13
13
|
|
14
14
|
/* Handle history changes */
|
15
15
|
|
16
|
-
const handlePush = async (url) => {
|
16
|
+
const handlePush = async (url: string) => {
|
17
17
|
if (!url) return;
|
18
18
|
const { pathname, search, origin } = location;
|
19
19
|
url = `${origin}${pathname}${search}`;
|
@@ -33,12 +33,12 @@ const AesirAnalytics = () => {
|
|
33
33
|
|
34
34
|
/* Global */
|
35
35
|
|
36
|
-
if (!window
|
37
|
-
const tracker = (eventValue) => eventValue;
|
36
|
+
if (!window['tracker']) {
|
37
|
+
const tracker = (eventValue: string) => eventValue;
|
38
38
|
tracker.initTracker = initTracker;
|
39
39
|
tracker.startTracker = startTracker;
|
40
40
|
|
41
|
-
window
|
41
|
+
window['tracker'] = tracker;
|
42
42
|
}
|
43
43
|
|
44
44
|
/* Start */
|
@@ -46,7 +46,7 @@ const AesirAnalytics = () => {
|
|
46
46
|
history.pushState = hook(history, 'pushState', handlePush);
|
47
47
|
history.replaceState = hook(history, 'replaceState', handlePush);
|
48
48
|
|
49
|
-
const hostUrl = window
|
49
|
+
const hostUrl = window['aesirx1stparty'] ? window['aesirx1stparty'] : '';
|
50
50
|
|
51
51
|
const root = hostUrl ? hostUrl.replace(/\/$/, '') : '';
|
52
52
|
|
@@ -87,16 +87,16 @@ const AesirAnalytics = () => {
|
|
87
87
|
|
88
88
|
/* Handle events */
|
89
89
|
|
90
|
-
const addEvents = (node) => {
|
90
|
+
const addEvents = (node: Document) => {
|
91
91
|
const elements = node.querySelectorAll(eventSelect);
|
92
92
|
Array.prototype.forEach.call(elements, addEvent);
|
93
93
|
};
|
94
94
|
|
95
|
-
const addEvent = (element) => {
|
95
|
+
const addEvent = (element: HTMLInputElement) => {
|
96
96
|
element.addEventListener(
|
97
97
|
'click',
|
98
98
|
() => {
|
99
|
-
|
99
|
+
const attribute: object[] = [];
|
100
100
|
Object.keys(element.dataset).forEach((key) => {
|
101
101
|
if (key.startsWith('aesirxEventAttribute')) {
|
102
102
|
attribute.push({
|
@@ -105,7 +105,7 @@ const AesirAnalytics = () => {
|
|
105
105
|
});
|
106
106
|
}
|
107
107
|
});
|
108
|
-
trackEvent(root,
|
108
|
+
trackEvent(root, '', '', '', {
|
109
109
|
event_name: element.dataset.aesirxEventName,
|
110
110
|
event_type: element.dataset.aesirxEventType,
|
111
111
|
attributes: attribute,
|
@@ -117,18 +117,13 @@ const AesirAnalytics = () => {
|
|
117
117
|
|
118
118
|
update();
|
119
119
|
};
|
120
|
-
const insertParam = (key, value) => {
|
121
|
-
const url = new URL(window.location.href);
|
122
|
-
url.searchParams.set(key, value);
|
123
|
-
window.history.pushState({ path: url.href }, '', url.href);
|
124
|
-
};
|
125
120
|
|
126
121
|
const replaceUrl = () => {
|
127
122
|
const urlParams = new URLSearchParams(window.location.search);
|
128
123
|
const event_uuid = urlParams.get('event_uuid');
|
129
124
|
const visitor_uuid = urlParams.get('visitor_uuid');
|
130
125
|
|
131
|
-
|
126
|
+
const anchors = document.getElementsByTagName('a');
|
132
127
|
|
133
128
|
for (let i = 0; i < anchors.length; i++) {
|
134
129
|
const eventIdParams = getParameterByName('event_uuid', anchors[i].href);
|
@@ -142,9 +137,9 @@ const replaceUrl = () => {
|
|
142
137
|
}
|
143
138
|
};
|
144
139
|
|
145
|
-
const getParameterByName = (name, url = window.location.href) => {
|
140
|
+
const getParameterByName = (name: string, url = window.location.href) => {
|
146
141
|
if (url) {
|
147
|
-
|
142
|
+
const params = new URL(url);
|
148
143
|
if (params.origin === window.location.origin) {
|
149
144
|
return params.searchParams.get(name);
|
150
145
|
}
|
@@ -1,4 +1,4 @@
|
|
1
1
|
export { default as AnalyticsNext } from './AnalyticsNext';
|
2
2
|
export { default as AnalyticsReact } from './AnalyticsReact';
|
3
|
-
export { trackEvent } from './utils
|
3
|
+
export { trackEvent } from './utils';
|
4
4
|
export { AnalyticsContext } from './utils/AnalyticsContextProvider';
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
* @copyright Copyright (C) 2022 AesirX. All rights reserved.
|
3
|
+
* @license GNU General Public License version 3, see LICENSE.
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React, { Dispatch, ReactNode, SetStateAction, useState } from 'react';
|
7
|
+
|
8
|
+
interface Props {
|
9
|
+
children?: ReactNode;
|
10
|
+
}
|
11
|
+
|
12
|
+
interface AnalyticsContextType {
|
13
|
+
event_uuid: string;
|
14
|
+
visitor_uuid: string;
|
15
|
+
event_uuid_start: string;
|
16
|
+
visitor_uuid_start: string;
|
17
|
+
setEventID: Dispatch<SetStateAction<string>>;
|
18
|
+
setUUID: Dispatch<SetStateAction<string>>;
|
19
|
+
setEventIDStart: Dispatch<SetStateAction<string>>;
|
20
|
+
setUUIDStart: Dispatch<SetStateAction<string>>;
|
21
|
+
}
|
22
|
+
|
23
|
+
export const AnalyticsContext = React.createContext<AnalyticsContextType>({
|
24
|
+
event_uuid: undefined,
|
25
|
+
visitor_uuid: undefined,
|
26
|
+
event_uuid_start: undefined,
|
27
|
+
visitor_uuid_start: undefined,
|
28
|
+
setEventID: undefined,
|
29
|
+
setUUID: undefined,
|
30
|
+
setEventIDStart: undefined,
|
31
|
+
setUUIDStart: undefined,
|
32
|
+
});
|
33
|
+
|
34
|
+
const AnalyticsContextProvider: React.FC<Props> = ({ children }) => {
|
35
|
+
const [eventID, setEventID] = useState();
|
36
|
+
const [UUID, setUUID] = useState();
|
37
|
+
const [eventIDStart, setEventIDStart] = useState();
|
38
|
+
const [UUIDStart, setUUIDStart] = useState();
|
39
|
+
return (
|
40
|
+
<AnalyticsContext.Provider
|
41
|
+
value={{
|
42
|
+
event_uuid: eventID,
|
43
|
+
visitor_uuid: UUID,
|
44
|
+
event_uuid_start: eventIDStart,
|
45
|
+
visitor_uuid_start: UUIDStart,
|
46
|
+
setEventID: setEventID,
|
47
|
+
setUUID: setUUID,
|
48
|
+
setEventIDStart: setEventIDStart,
|
49
|
+
setUUIDStart: setUUIDStart,
|
50
|
+
}}
|
51
|
+
>
|
52
|
+
{children}
|
53
|
+
</AnalyticsContext.Provider>
|
54
|
+
);
|
55
|
+
};
|
56
|
+
|
57
|
+
export { AnalyticsContextProvider };
|
@@ -1,12 +1,17 @@
|
|
1
1
|
import { trackerService } from './services';
|
2
2
|
import Bowser from 'bowser';
|
3
3
|
|
4
|
-
const createRequest = (endpoint, task) => {
|
4
|
+
const createRequest = (endpoint: string, task: string) => {
|
5
5
|
return `${endpoint}/visitor/v1/${task}`;
|
6
6
|
};
|
7
7
|
|
8
8
|
/* FUNCTION */
|
9
|
-
const initTracker = async (
|
9
|
+
const initTracker = async (
|
10
|
+
endpoint: string,
|
11
|
+
url?: string,
|
12
|
+
referrer?: string,
|
13
|
+
user_agent?: string
|
14
|
+
) => {
|
10
15
|
const { document } = window;
|
11
16
|
const { pathname, search, origin } = location;
|
12
17
|
url = `${origin}${pathname}${search}`;
|
@@ -15,19 +20,19 @@ const initTracker = async (endpoint, url, referrer, user_agent) => {
|
|
15
20
|
const browser = Bowser.parse(window.navigator.userAgent);
|
16
21
|
const browser_name = browser?.browser?.name;
|
17
22
|
const browser_version = browser?.browser?.version;
|
18
|
-
const lang = window.navigator
|
23
|
+
const lang = window.navigator['userLanguage'] || window.navigator.language;
|
19
24
|
const device = browser?.platform?.model ?? browser?.platform?.type;
|
20
25
|
const domain = `${origin}`;
|
21
26
|
const queryString = window.location.search;
|
22
27
|
const urlParams = new URLSearchParams(queryString);
|
23
|
-
|
24
|
-
for (
|
28
|
+
const attributes = [];
|
29
|
+
for (const key of urlParams.keys()) {
|
25
30
|
if (key.startsWith('utm_')) {
|
26
31
|
urlParams.get(key) && attributes.push({ name: key, value: urlParams.get(key) });
|
27
32
|
}
|
28
33
|
}
|
29
34
|
if (!urlParams.get('event_uuid') && !urlParams.get('visitor_uuid')) {
|
30
|
-
|
35
|
+
const ip = '';
|
31
36
|
const response = await trackerService(createRequest(endpoint, 'init'), {
|
32
37
|
url: url,
|
33
38
|
referrer: referrer,
|
@@ -46,7 +51,12 @@ const initTracker = async (endpoint, url, referrer, user_agent) => {
|
|
46
51
|
}
|
47
52
|
};
|
48
53
|
|
49
|
-
const startTracker = async (
|
54
|
+
const startTracker = async (
|
55
|
+
endpoint: string,
|
56
|
+
event_uuid?: string,
|
57
|
+
visitor_uuid?: string,
|
58
|
+
referrer?: string
|
59
|
+
) => {
|
50
60
|
const { location, document } = window;
|
51
61
|
referrer = referrer
|
52
62
|
? location.protocol + '//' + location.host + referrer
|
@@ -74,7 +84,7 @@ const startTracker = async (endpoint, event_uuid, visitor_uuid, referrer) => {
|
|
74
84
|
return responseStart;
|
75
85
|
};
|
76
86
|
|
77
|
-
const endTracker = async (endpoint, event_uuid, visitor_uuid) => {
|
87
|
+
const endTracker = async (endpoint: string, event_uuid?: string, visitor_uuid?: string) => {
|
78
88
|
const queryString = window.location.search;
|
79
89
|
const urlParams = new URLSearchParams(queryString);
|
80
90
|
const responseEnd = await trackerService(createRequest(endpoint, 'end'), {
|
@@ -94,7 +104,13 @@ const endTracker = async (endpoint, event_uuid, visitor_uuid) => {
|
|
94
104
|
return responseEnd;
|
95
105
|
};
|
96
106
|
|
97
|
-
const trackEvent = async (
|
107
|
+
const trackEvent = async (
|
108
|
+
endpoint: string,
|
109
|
+
event_uuid: string,
|
110
|
+
visitor_uuid: string,
|
111
|
+
referrer?: string,
|
112
|
+
data?: object
|
113
|
+
) => {
|
98
114
|
const { location, document } = window;
|
99
115
|
referrer = referrer
|
100
116
|
? location.protocol + '//' + location.host + referrer
|
@@ -123,4 +139,10 @@ const trackEvent = async (endpoint, event_uuid, visitor_uuid, referrer, data) =>
|
|
123
139
|
return responseStart;
|
124
140
|
};
|
125
141
|
|
126
|
-
|
142
|
+
const insertParam = (key: string, value: string) => {
|
143
|
+
const url = new URL(window.location.href);
|
144
|
+
url.searchParams.set(key, value);
|
145
|
+
window.history.pushState({ path: url.href }, '', url.href);
|
146
|
+
};
|
147
|
+
|
148
|
+
export { initTracker, startTracker, endTracker, trackEvent, insertParam };
|
@@ -1,13 +1,13 @@
|
|
1
1
|
/* SERVICES */
|
2
|
-
let cache;
|
3
|
-
const assign = (a, b) => {
|
2
|
+
let cache: string;
|
3
|
+
const assign = (a: {}, b: {}) => {
|
4
4
|
Object.keys(b).forEach((key) => {
|
5
5
|
if (b[key] !== undefined) a[key] = b[key];
|
6
6
|
});
|
7
7
|
return a;
|
8
8
|
};
|
9
9
|
|
10
|
-
const trackerService = async (endpoint, payload) => {
|
10
|
+
const trackerService = async (endpoint: string, payload: object) => {
|
11
11
|
const fetchData = await fetch(endpoint, {
|
12
12
|
method: 'POST',
|
13
13
|
body: JSON.stringify(payload),
|