mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-05-27 07:36:18 +00:00
Added some metrics to monitor in Google Analytics
This commit is contained in:
4
src/analytics.ts
Normal file
4
src/analytics.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/** Sends an event to Google Analytics. */
|
||||||
|
export function analyticsEvent(action: string, data?: any) {
|
||||||
|
(window as any).gtag('event', action, data);
|
||||||
|
}
|
||||||
34
src/app.tsx
34
src/app.tsx
@@ -1,5 +1,6 @@
|
|||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import {analyticsEvent} from './analytics';
|
||||||
import {Chart} from './chart';
|
import {Chart} from './chart';
|
||||||
import {Details} from './details';
|
import {Details} from './details';
|
||||||
import {getSelection, loadFromUrl, loadGedcom} from './load_data';
|
import {getSelection, loadFromUrl, loadGedcom} from './load_data';
|
||||||
@@ -8,7 +9,7 @@ import {Intro} from './intro';
|
|||||||
import {Loader, Message, Responsive} from 'semantic-ui-react';
|
import {Loader, Message, Responsive} from 'semantic-ui-react';
|
||||||
import {Redirect, Route, RouteComponentProps, Switch} from 'react-router-dom';
|
import {Redirect, Route, RouteComponentProps, Switch} from 'react-router-dom';
|
||||||
import {TopBar} from './top_bar';
|
import {TopBar} from './top_bar';
|
||||||
import {TopolaData} from './gedcom_util';
|
import {TopolaData, getSoftware} from './gedcom_util';
|
||||||
|
|
||||||
/** Shows an error message. */
|
/** Shows an error message. */
|
||||||
export function ErrorMessage(props: {message: string}) {
|
export function ErrorMessage(props: {message: string}) {
|
||||||
@@ -92,6 +93,15 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
|||||||
const data = hash
|
const data = hash
|
||||||
? await loadGedcom(hash, gedcom, images)
|
? await loadGedcom(hash, gedcom, images)
|
||||||
: await loadFromUrl(url!, handleCors);
|
: await loadFromUrl(url!, handleCors);
|
||||||
|
analyticsEvent(hash ? 'upload_file_loaded' : 'url_file_loaded');
|
||||||
|
if (images && images.size) {
|
||||||
|
analyticsEvent('images_uploaded');
|
||||||
|
}
|
||||||
|
const software = getSoftware(data.gedcom.head);
|
||||||
|
if (software) {
|
||||||
|
analyticsEvent('gedcom_software', {event_label: software});
|
||||||
|
}
|
||||||
|
|
||||||
// Set state with data.
|
// Set state with data.
|
||||||
this.setState(
|
this.setState(
|
||||||
Object.assign({}, this.state, {
|
Object.assign({}, this.state, {
|
||||||
@@ -105,6 +115,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
analyticsEvent(hash ? 'upload_file_error' : 'url_file_error');
|
||||||
// Set error state.
|
// Set error state.
|
||||||
this.setState(
|
this.setState(
|
||||||
Object.assign({}, this.state, {
|
Object.assign({}, this.state, {
|
||||||
@@ -138,6 +149,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
|||||||
* Updates the browser URL.
|
* Updates the browser URL.
|
||||||
*/
|
*/
|
||||||
private onSelection = (selection: IndiInfo) => {
|
private onSelection = (selection: IndiInfo) => {
|
||||||
|
analyticsEvent('selection_changed');
|
||||||
const location = this.props.location;
|
const location = this.props.location;
|
||||||
const search = queryString.parse(location.search);
|
const search = queryString.parse(location.search);
|
||||||
search.indi = selection.id;
|
search.indi = selection.id;
|
||||||
@@ -187,10 +199,22 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
|||||||
this.state.selection
|
this.state.selection
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onPrint={() => this.chartRef && this.chartRef.print()}
|
onPrint={() => {
|
||||||
onDownloadPdf={() => this.chartRef && this.chartRef.downloadPdf()}
|
analyticsEvent('print');
|
||||||
onDownloadPng={() => this.chartRef && this.chartRef.downloadPng()}
|
this.chartRef && this.chartRef.print();
|
||||||
onDownloadSvg={() => this.chartRef && this.chartRef.downloadSvg()}
|
}}
|
||||||
|
onDownloadPdf={() => {
|
||||||
|
analyticsEvent('download_pdf');
|
||||||
|
this.chartRef && this.chartRef.downloadPdf();
|
||||||
|
}}
|
||||||
|
onDownloadPng={() => {
|
||||||
|
analyticsEvent('download_png');
|
||||||
|
this.chartRef && this.chartRef.downloadPng();
|
||||||
|
}}
|
||||||
|
onDownloadSvg={() => {
|
||||||
|
analyticsEvent('download_svg');
|
||||||
|
this.chartRef && this.chartRef.downloadSvg();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -163,3 +163,11 @@ export function convertGedcom(
|
|||||||
gedcom: prepareGedcom(entries),
|
gedcom: prepareGedcom(entries),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSoftware(head: GedcomEntry): string | null {
|
||||||
|
const sour =
|
||||||
|
head && head.tree && head.tree.find((entry) => entry.tag === 'SOUR');
|
||||||
|
const name =
|
||||||
|
sour && sour.tree && sour.tree.find((entry) => entry.tag === 'NAME');
|
||||||
|
return (name && name.data) || null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import md5 from 'md5';
|
import md5 from 'md5';
|
||||||
|
import {analyticsEvent} from './analytics';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import {RouteComponentProps} from 'react-router-dom';
|
import {RouteComponentProps} from 'react-router-dom';
|
||||||
@@ -59,6 +60,9 @@ export class TopBar extends React.Component<
|
|||||||
}
|
}
|
||||||
const filesArray = Array.from(files);
|
const filesArray = Array.from(files);
|
||||||
(event.target as HTMLInputElement).value = ''; // Reset the file input.
|
(event.target as HTMLInputElement).value = ''; // Reset the file input.
|
||||||
|
analyticsEvent('upload_files_selected', {
|
||||||
|
event_value: files.length,
|
||||||
|
});
|
||||||
|
|
||||||
const gedcomFile =
|
const gedcomFile =
|
||||||
files.length === 1
|
files.length === 1
|
||||||
@@ -114,6 +118,7 @@ export class TopBar extends React.Component<
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if (this.state.url) {
|
if (this.state.url) {
|
||||||
|
analyticsEvent('url_selected');
|
||||||
this.props.history.push({
|
this.props.history.push({
|
||||||
pathname: '/view',
|
pathname: '/view',
|
||||||
search: queryString.stringify({url: this.state.url}),
|
search: queryString.stringify({url: this.state.url}),
|
||||||
|
|||||||
Reference in New Issue
Block a user