Skip to content

Commit 291e3ae

Browse files
committed
Initial commit
0 parents  commit 291e3ae

47 files changed

Lines changed: 13522 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
service_account_key.json
2+
oauth_key.json
3+
node_modules/
4+
sites/*/node_modules
5+
sites/*/dist
6+
sites/*/package-lock.json
7+
packages/*/node_modules
8+
packages/*/dist
9+
packages/*/package-lock.json

package-lock.json

Lines changed: 8554 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "google-analytics-embed-react",
3+
"private": true,
4+
"workspaces": {
5+
"packages": [
6+
"packages/*",
7+
"sites/*"
8+
]
9+
},
10+
"devDependencies": {
11+
"mkdirp": "^1.0.4"
12+
}
13+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "google-analytics-embed-react",
3+
"version": "0.0.1",
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "mkdirp dist && tsc && vite build",
8+
"pre-bundle": "cp package.json dist"
9+
},
10+
"devDependencies": {
11+
"@types/google.visualization": "^0.0.68",
12+
"@types/react": "^18.0.26",
13+
"@types/react-dom": "^18.0.9",
14+
"@vitejs/plugin-react": "^3.0.0",
15+
"copy": "^0.3.2",
16+
"mkdirp": "^1.0.4",
17+
"typescript": "^4.9.3",
18+
"vite": "^4.0.0",
19+
"vite-plugin-dts": "^1.7.1"
20+
},
21+
"peerDependencies": {
22+
"react": "*",
23+
"react-dom": "*"
24+
}
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
printWidth: 100,
3+
singleQuote: true,
4+
trailingComma: 'all'
5+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
export default class DataChart {
3+
4+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { createContext } from "react";
2+
3+
interface AuthenticateUsingButton {
4+
type: "button";
5+
clientId: string;
6+
userInfoLabel?: string;
7+
scopes?: string[];
8+
overwriteDefaultScopes?: boolean;
9+
}
10+
11+
interface AuthenticateUsingServer {
12+
type: "server";
13+
access_token: string;
14+
scopes?: string[];
15+
overwriteDefaultScopes?: boolean;
16+
}
17+
18+
type AuthenticateMethod = AuthenticateUsingButton | AuthenticateUsingServer;
19+
20+
export type AuthenticationState =
21+
| "AUTHENTICATING"
22+
| "AUTH_ERROR"
23+
| "AUTH_SUCCESS"
24+
| "NOT_AUTHENTICATED";
25+
26+
export class GoogleContext {
27+
protected authButton?: string | HTMLElement = undefined;
28+
29+
setAuthButton(button: HTMLElement) {
30+
this.authButton = button;
31+
}
32+
33+
authenticate(method: AuthenticateMethod): Promise<null> {
34+
const authContainer = this.authButton;
35+
return new Promise((res, rej) => {
36+
window.gapi.analytics.auth.once("error", (res) => {
37+
rej(res);
38+
});
39+
window.gapi.analytics.auth.once("signIn", () => {
40+
res(null);
41+
});
42+
if (method.type === "server") {
43+
const rest = window.gapi.analytics.auth.authorize({
44+
scopes: method.scopes,
45+
overwriteDefaultScopes: method.overwriteDefaultScopes,
46+
serverAuth: {
47+
access_token: method.access_token,
48+
},
49+
});
50+
console.log(rest);
51+
res(null);
52+
} else {
53+
console.log(method.clientId);
54+
window.gapi.analytics.auth.authorize({
55+
container: authContainer,
56+
clientid: method.clientId,
57+
scopes: method.scopes,
58+
overwriteDefaultScopes: method.overwriteDefaultScopes,
59+
userInfoLabel: method.userInfoLabel,
60+
});
61+
}
62+
});
63+
}
64+
}
65+
66+
export const googleContext = new GoogleContext();
67+
68+
export type GoogleAnalyticsContextContent = [AuthenticationState];
69+
const GoogleAnalyticsContext =
70+
createContext<GoogleAnalyticsContextContent | null>(null);
71+
export default GoogleAnalyticsContext;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import * as React from "react";
2+
import GoogleAnalyticsContext, {
3+
AuthenticationState,
4+
googleContext
5+
} from "./GoogleAnalyticsContext";
6+
7+
export interface GoogleAnalyticsProviderProps {
8+
children: React.ReactNode;
9+
clientId?: string;
10+
accessToken?: string;
11+
onAuthError?: () => {};
12+
onAuthSuccess?: () => {};
13+
scopes?: string[];
14+
overwriteDefaultScopes?: boolean;
15+
userInfoLabel?: string;
16+
}
17+
const googleAnalyticsImport = () => {
18+
return new Promise((res, _rej) => {
19+
if (!document.getElementById("gaScript")) {
20+
const g = window.gapi || (window.gapi = {} as any);
21+
g.analytics = {
22+
q: [],
23+
ready(f: any) {
24+
this.q.push(f);
25+
},
26+
} as any;
27+
const js = document.createElement("script");
28+
const fs = document.getElementsByTagName("script")[0];
29+
js.src = "https://apis.google.com/js/platform.js";
30+
js.id = "gaScript";
31+
fs.parentNode?.insertBefore(js, fs);
32+
js.onload = () => {
33+
(g as any).load("analytics");
34+
window.gapi.analytics.ready(() => {
35+
res(null);
36+
});
37+
};
38+
} else {
39+
window.gapi.analytics.ready(() => {
40+
res(null);
41+
});
42+
}
43+
});
44+
};
45+
46+
const GoogleAnalyticsProvider: React.FC<GoogleAnalyticsProviderProps> = (
47+
props: GoogleAnalyticsProviderProps
48+
): React.ReactElement => {
49+
const [authStatus, setAuthStatus] =
50+
React.useState<AuthenticationState>("NOT_AUTHENTICATED");
51+
React.useEffect(() => {
52+
googleAnalyticsImport().then(() => {
53+
let auth = null;
54+
if (props.clientId) {
55+
auth = googleContext.authenticate({
56+
type: "button",
57+
clientId: props.clientId,
58+
scopes: props.scopes,
59+
overwriteDefaultScopes: props.overwriteDefaultScopes,
60+
userInfoLabel: props.userInfoLabel,
61+
});
62+
} else if (props.accessToken) {
63+
auth = googleContext.authenticate({
64+
type: "server",
65+
access_token: props.accessToken,
66+
scopes: props.scopes,
67+
overwriteDefaultScopes: props.overwriteDefaultScopes,
68+
});
69+
}
70+
71+
if (auth) {
72+
setAuthStatus("AUTHENTICATING");
73+
auth
74+
.then(() => {
75+
console.log("Google authenticated");
76+
setAuthStatus("AUTH_SUCCESS");
77+
})
78+
.catch((res) => {
79+
console.error("Google auth error", res);
80+
setAuthStatus("AUTH_ERROR");
81+
});
82+
}
83+
});
84+
}, [props.accessToken, props.clientId]);
85+
return (
86+
<GoogleAnalyticsContext.Provider value={[authStatus]}>
87+
<div>{props.children}</div>
88+
</GoogleAnalyticsContext.Provider>
89+
);
90+
};
91+
92+
export default GoogleAnalyticsProvider;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { googleContext } from "./GoogleAnalyticsContext";
2+
import * as React from "react";
3+
4+
class SignInButton extends React.Component {
5+
protected container: React.RefObject<HTMLDivElement>;
6+
7+
constructor(props: any) {
8+
super(props);
9+
10+
this.container = React.createRef();
11+
}
12+
13+
componentDidMount() {
14+
googleContext.setAuthButton(this.container.current as HTMLElement);
15+
}
16+
17+
render(): React.ReactNode {
18+
return <div ref={this.container}></div>;
19+
}
20+
}
21+
22+
export default SignInButton;

0 commit comments

Comments
 (0)