Skip to content

Commit 2fa1aa8

Browse files
committed
Removed old frontend auth method and implemented a GIS example
1 parent 24a7a97 commit 2fa1aa8

10 files changed

Lines changed: 72 additions & 90 deletions

File tree

packages/google-analytics-embed-react/src/DataChart.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import GoogleAnalyticsContext, { GoogleAnalyticsContextContent } from './GoogleAnalyticsContext';
2+
import GoogleAnalyticsContext, { GoogleAnalyticsState } from './GoogleAnalyticsContext';
33

44
export type DataChartProps<T> = {
55
/** Query */
@@ -24,12 +24,12 @@ export default class DataChart<O> extends React.Component<DataChartProps<O>> {
2424
}
2525

2626
componentDidUpdate() {
27-
const [gaState, _] = this.context as GoogleAnalyticsContextContent;
27+
const gaState = this.context as GoogleAnalyticsState;
2828
const { query, children, style, ...chartOptions } = this.props;
2929
// Rendering the component only if a user authenticated
3030
if (gaState == 'AUTH_SUCCESS') {
3131
// Updating the existing chart with new options if already rendered
32-
if (this.googleDataChart) {
32+
if (this.googleDataChart != null) {
3333
this.googleDataChart.set({
3434
query,
3535
chart: {
@@ -50,15 +50,17 @@ export default class DataChart<O> extends React.Component<DataChartProps<O>> {
5050
});
5151
this.googleDataChart.execute();
5252
}
53-
} else if (this.googleDataChart) {
53+
} else if (this.googleDataChart != null) {
5454
// Destroying the chart if the authentication method changed
5555
this.googleDataChart = null;
5656
}
5757
}
5858

5959
render(): React.ReactNode {
6060
return (
61-
<div ref={this.elementRef}>{!this.googleDataChart ? this.props.children : undefined}</div>
61+
<div ref={this.elementRef}>
62+
{this.googleDataChart == null ? this.props.children : undefined}
63+
</div>
6264
);
6365
}
6466
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import { createContext } from 'react';
22

33
// INITIALIZED -> LOADING -> PROCESSING -> READY
4-
// -> AUTHENTICATING -> AUTH_ERROR/AUTH_SUCCESS
4+
// -> AUTHENTICATING ->AUTH_SUCCESS
55
export type GoogleAnalyticsState =
66
| 'INITIALIZED'
77
| 'LOADING'
88
| 'PROCESSING'
99
| 'READY'
1010
| 'AUTHENTICATING'
11-
| 'SIGNOUT'
12-
| 'AUTH_ERROR'
1311
| 'AUTH_SUCCESS';
1412

15-
export type GoogleAnalyticsContextContent = [GoogleAnalyticsState, (el: HTMLElement | null) => void];
16-
const GoogleAnalyticsContext = createContext<GoogleAnalyticsContextContent | null>(null);
13+
const GoogleAnalyticsContext = createContext<GoogleAnalyticsState | null>(null);
1714
export default GoogleAnalyticsContext;

packages/google-analytics-embed-react/src/GoogleAnalyticsProvider.tsx

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@ import GoogleAnalyticsContext, { GoogleAnalyticsState } from './GoogleAnalyticsC
33

44
export interface GoogleAnalyticsProviderProps {
55
children: React.ReactNode;
6-
/** The client ID of your project in the developers console. */
7-
clientId?: string;
86
/**
9-
* If you already have a valid access token, you can pass it
10-
* to the authorize method directly and the user will not be
11-
* prompted to authorize.
7+
* Access token to authorize to the analytics service.
128
*/
139
accessToken?: string;
14-
/** Firing when a user failed to authenticate using the sign in button */
15-
onAuthError?: () => {};
16-
/** Firing when a user authenticated using the sign in button */
17-
onAuthSuccess?: () => {};
1810
/** Firing after the gapi script loaded and ready to use **/
19-
onReady?: () => {};
11+
onReady?: () => void;
12+
/** Firing after the authenitcated to analytics service using access token **/
13+
onAuthenticated?: () => void;
2014
/** A list of Google API auth scopes that your application is requesting **/
2115
scopes?: string[];
2216
/**
@@ -41,10 +35,10 @@ export interface GoogleAnalyticsProviderProps {
4135
const GoogleAnalyticsProvider: React.FC<GoogleAnalyticsProviderProps> = (
4236
props: GoogleAnalyticsProviderProps
4337
): React.ReactElement => {
44-
// For frontend authentication
45-
const [authButton, setAuthButton] = React.useState<null | HTMLElement>(null);
4638
// Internal state
4739
const [gaState, setGaState] = React.useState<GoogleAnalyticsState>('INITIALIZED');
40+
41+
const { onReady, onAuthenticated } = props;
4842
// Importing the google platform script and
4943
React.useEffect(() => {
5044
if (document.getElementById('gaScript') == null) {
@@ -75,6 +69,7 @@ const GoogleAnalyticsProvider: React.FC<GoogleAnalyticsProviderProps> = (
7569
if (gaState == 'PROCESSING') {
7670
window.gapi.analytics.ready(() => {
7771
setGaState('READY');
72+
onReady != null && onReady();
7873
});
7974
}
8075
}, [gaState]);
@@ -93,33 +88,12 @@ const GoogleAnalyticsProvider: React.FC<GoogleAnalyticsProviderProps> = (
9388
overwriteDefaultScopes: props.overwriteDefaultScopes
9489
});
9590
setGaState('AUTH_SUCCESS');
96-
} else if (props.clientId && authButton) {
97-
// button authorization
98-
setGaState('AUTHENTICATING');
99-
gapi.analytics.auth.authorize({
100-
clientid: props.clientId,
101-
container: authButton,
102-
userInfoLabel: props.userInfoLabel,
103-
scopes: props.scopes,
104-
overwriteDefaultScopes: props.overwriteDefaultScopes
105-
});
106-
107-
gapi.analytics.auth.on('signIn', () => {
108-
setGaState('AUTH_SUCCESS');
109-
});
110-
111-
gapi.analytics.auth.on('signOut', () => {
112-
setGaState('SIGNOUT');
113-
});
114-
115-
gapi.analytics.auth.on('error', () => {
116-
setGaState('AUTH_ERROR');
117-
});
91+
onAuthenticated != null && onAuthenticated();
11892
}
11993
}
120-
}, [props.accessToken, props.clientId, gaState, authButton]);
94+
}, [props.accessToken, gaState]);
12195
return (
122-
<GoogleAnalyticsContext.Provider value={[gaState, setAuthButton]}>
96+
<GoogleAnalyticsContext.Provider value={gaState}>
12397
<div>{props.children}</div>
12498
</GoogleAnalyticsContext.Provider>
12599
);

packages/google-analytics-embed-react/src/SignInButton.tsx

Lines changed: 0 additions & 28 deletions
This file was deleted.

packages/google-analytics-embed-react/src/ViewSelector.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import GoogleAnalyticsContext, { GoogleAnalyticsContextContent } from './GoogleAnalyticsContext';
2+
import GoogleAnalyticsContext, { GoogleAnalyticsState } from './GoogleAnalyticsContext';
33

44
export interface ViewSelectorProps {
55
/** Callback to fire after user changed the view */
@@ -18,7 +18,7 @@ export interface ViewSelectorProps {
1818
*/
1919
export default class ViewSelector extends React.Component<ViewSelectorProps> {
2020
public static contextType = GoogleAnalyticsContext;
21-
private elementRef: React.RefObject<HTMLDivElement>;
21+
private readonly elementRef: React.RefObject<HTMLDivElement>;
2222
private googleViewSelector: gapi.analytics.ViewSelector | null;
2323

2424
constructor(props: ViewSelectorProps) {
@@ -29,26 +29,26 @@ export default class ViewSelector extends React.Component<ViewSelectorProps> {
2929
}
3030

3131
componentDidUpdate() {
32-
const [gaState, _] = this.context as GoogleAnalyticsContextContent;
32+
const gaState = this.context as GoogleAnalyticsState;
3333
if (gaState == 'AUTH_SUCCESS') {
34-
if (!this.googleViewSelector) {
34+
if (this.googleViewSelector == null) {
3535
this.googleViewSelector = new gapi.analytics.ViewSelector({
3636
container: this.elementRef.current as HTMLElement
3737
});
3838
this.googleViewSelector.execute();
39-
if (this.props.onChange) {
39+
if (this.props.onChange != null) {
4040
this.googleViewSelector.on('change', this.props.onChange);
4141
}
4242
}
43-
} else if (this.googleViewSelector) {
43+
} else if (this.googleViewSelector != null) {
4444
this.googleViewSelector = null;
4545
}
4646
}
4747

4848
render(): React.ReactNode {
4949
return (
5050
<div style={this.props.style} className={this.props.className} ref={this.elementRef}>
51-
{!this.googleViewSelector ? this.props.children : undefined}
51+
{this.googleViewSelector == null ? this.props.children : undefined}
5252
</div>
5353
);
5454
}

packages/google-analytics-embed-react/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
import { default as DataChart, DataChartProps } from './DataChart';
12
export {
23
default as GoogleAnalyticsProvider,
34
GoogleAnalyticsProviderProps
45
} from './GoogleAnalyticsProvider';
5-
export { default as SignInButton } from './SignInButton';
6-
import { default as DataChart, DataChartProps } from './DataChart';
76
export { DataChartProps } from './DataChart';
87
export { default as ViewSelector, ViewSelectorProps } from './ViewSelector';
98

packages/google-analytics-embed-types/index.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
declare namespace gapi.analytics {
2-
export interface Response {
3-
[x: string]: any;
4-
}
2+
export type Response = Record<string, any>;
53

64
export interface AuthOptions {
75
clientid?: string;

sites/react-frontend-auth/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"react-dom": "^18.2.0"
1111
},
1212
"devDependencies": {
13+
"@types/google.accounts": "^0.0.5",
14+
"@types/node": "^18.11.18",
1315
"env-cmd": "^10.1.0",
1416
"react-scripts": "5.0.1",
1517
"typescript": "^4.9.4"

sites/react-frontend-auth/src/App.tsx

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,55 @@
11
import {
2+
GoogleAnalyticsLineChart,
23
GoogleAnalyticsProvider,
3-
SignInButton,
4+
ViewSelector,
45
} from "google-analytics-embed-react";
56
import * as React from "react";
67

8+
var client: google.accounts.oauth2.TokenClient | null = null;
9+
710
function App() {
8-
console.log(process.env.REACT_APP_CLIENT_ID);
11+
const [accessToken, setAccessToken] = React.useState<string | null>(null);
12+
13+
React.useEffect(() => {
14+
const js = document.createElement("script");
15+
const fs = document.getElementsByTagName("script")[0];
16+
js.src = "https://accounts.google.com/gsi/client";
17+
js.defer = true;
18+
js.async = true;
19+
fs.parentNode?.insertBefore(js, fs);
20+
js.onload = () => {
21+
const oauth2 = window.google.accounts.oauth2;
22+
window.google = undefined as any;
23+
client = oauth2.initTokenClient({
24+
client_id: process.env.REACT_APP_CLIENT_ID as string,
25+
scope: "https://www.googleapis.com/auth/analytics.readonly",
26+
callback: (tokenResponse) => {
27+
setAccessToken(tokenResponse.access_token);
28+
},
29+
});
30+
};
31+
}, []);
32+
33+
const getToken = () => client && client.requestAccessToken();
34+
935
return (
1036
<div>
11-
<GoogleAnalyticsProvider clientId={process.env.REACT_APP_CLIENT_ID}>
37+
<button onClick={getToken}> Get Access Token </button>
38+
<GoogleAnalyticsProvider accessToken={accessToken || undefined}>
1239
<div>
1340
My Analytics Component
1441
<hr />
15-
<SignInButton />
42+
<GoogleAnalyticsLineChart
43+
query={{
44+
ids: "ga:213762800", // <-- Replace with the ids value for your view.
45+
"start-date": "90daysAgo",
46+
"end-date": "today",
47+
metrics: "ga:sessions,ga:users",
48+
dimensions: "ga:date",
49+
}}
50+
width={500}
51+
/>
52+
<ViewSelector onChange={console.log} />
1653
</div>
1754
</GoogleAnalyticsProvider>
1855
</div>

sites/react-frontend-auth/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"dom.iterable",
77
"esnext"
88
],
9+
"types": ["google.accounts", "node"],
910
"allowJs": true,
1011
"skipLibCheck": true,
1112
"esModuleInterop": true,

0 commit comments

Comments
 (0)