Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Integrate Heap analytics into the website #866

Merged
merged 8 commits into from
Jul 13, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions packages/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@
"clean": "shx rm -f public/bundle*",
"lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
"watch_without_deps": "webpack-dev-server --content-base public --https",
"deploy_dogfood":
"npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"deploy_staging":
"npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"deploy_live":
"npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js"
"deploy_dogfood": "npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"deploy_live": "npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js"
},
"author": "Fabio Berger",
"license": "Apache-2.0",
Expand Down Expand Up @@ -49,7 +46,6 @@
"react-copy-to-clipboard": "^4.2.3",
"react-document-title": "^2.0.3",
"react-dom": "15.6.1",
"react-ga": "^2.4.1",
"react-popper": "^1.0.0-beta.6",
"react-redux": "^5.0.3",
"react-router-dom": "^4.1.1",
Expand Down
6 changes: 6 additions & 0 deletions packages/website/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
</head>

<body style="margin: 0px; min-width: 355px;">
<!-- Heap SDK -->
<script type="text/javascript">
window.heap = window.heap || [], heap.load = function (e, t) { window.heap.appid = e, window.heap.config = t = t || {}; var r = t.forceSSL || "https:" === document.location.protocol, a = document.createElement("script"); a.type = "text/javascript", a.async = !0, a.src = (r ? "https:" : "http:") + "//cdn.heapanalytics.com/js/heap-" + e + ".js"; var n = document.getElementsByTagName("script")[0]; n.parentNode.insertBefore(a, n); for (var o = function (e) { return function () { heap.push([e].concat(Array.prototype.slice.call(arguments, 0))) } }, p = ["addEventProperties", "addUserProperties", "clearEventProperties", "identify", "resetIdentity", "removeEventProperty", "setEventProperties", "track", "unsetEventProperty"], c = 0; c < p.length; c++)heap[p[c]] = o(p[c]) };
heap.load("410099666");
</script>
<!-- End Heap SDK -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
<script>
Expand Down
2 changes: 1 addition & 1 deletion packages/website/ts/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ export class Blockchain {
return tokenByAddress;
}
private async _onPageLoadInitFireAndForgetAsync(): Promise<void> {
await utils.onPageLoadAsync(); // wait for page to load
await utils.onPageLoadPromise; // wait for page to load
const networkIdIfExists = await Blockchain._getInjectedWeb3ProviderNetworkIdIfExistsAsync();
this.networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : constants.NETWORK_ID_MAINNET;
const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
Expand Down
18 changes: 9 additions & 9 deletions packages/website/ts/components/fill_order.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getOrderHashHex, isValidSignature } from '@0xproject/order-utils';
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { colors } from '@0xproject/react-shared';
import { Order as ZeroExOrder } from '@0xproject/types';
import { BigNumber, logUtils } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
Expand Down Expand Up @@ -506,6 +506,10 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {

await this._checkForUntrackedTokensAndAskToAddAsync();
}
private _trackOrderEvent(eventName: string): void {
const parsedOrder = this.state.parsedOrder;
analytics.trackOrderEvent(eventName, parsedOrder);
}
private async _onFillOrderClickFireAndForgetAsync(): Promise<void> {
if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) {
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
Expand Down Expand Up @@ -552,14 +556,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
});
return;
}
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${parsedOrder.metadata.takerToken.symbol}-${networkName}`;
try {
const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync(
signedOrder,
this.props.orderFillAmount,
);
analytics.logEvent('Portal', 'Fill Order Success', eventLabel, parsedOrder.signedOrder.takerTokenAmount);
this._trackOrderEvent('Fill Order Success');
// After fill completes, let's force fetch the token balances
this.props.dispatcher.forceTokenStateRefetch();
this.setState({
Expand All @@ -573,7 +575,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
this.setState({
isFilling: false,
});
analytics.logEvent('Portal', 'Fill Order Failure', eventLabel, parsedOrder.signedOrder.takerTokenAmount);
this._trackOrderEvent('Fill Order Failure');
const errMsg = `${err}`;
if (utils.didUserDenyWeb3Request(errMsg)) {
return;
Expand Down Expand Up @@ -628,8 +630,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
});
return;
}
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${parsedOrder.metadata.makerToken.symbol}-${networkName}`;
try {
await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount);
this.setState({
Expand All @@ -638,7 +638,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
globalErrMsg: '',
unavailableTakerAmount: takerTokenAmount,
});
analytics.logEvent('Portal', 'Cancel Order Success', eventLabel, parsedOrder.signedOrder.makerTokenAmount);
this._trackOrderEvent('Cancel Order Success');
return;
} catch (err) {
this.setState({
Expand All @@ -648,7 +648,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
if (utils.didUserDenyWeb3Request(errMsg)) {
return;
}
analytics.logEvent('Portal', 'Cancel Order Failure', eventLabel, parsedOrder.signedOrder.makerTokenAmount);
this._trackOrderEvent('Cancel Order Failure');
globalErrMsg = 'Failed to cancel order, please refresh and try again';
logUtils.log(`${err}`);
this.setState({
Expand Down
4 changes: 4 additions & 0 deletions packages/website/ts/components/forms/subscribe_form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Button } from 'ts/components/ui/button';
import { Container } from 'ts/components/ui/container';
import { Input } from 'ts/components/ui/input';
import { Text } from 'ts/components/ui/text';
import { analytics } from 'ts/utils/analytics';
import { backendClient } from 'ts/utils/backend_client';

export interface SubscribeFormProps {}
Expand Down Expand Up @@ -112,6 +113,9 @@ export class SubscribeForm extends React.Component<SubscribeFormProps, Subscribe
try {
const response = await backendClient.subscribeToNewsletterAsync(this.state.emailText);
const status = response.status === 200 ? SubscribeFormStatus.Success : SubscribeFormStatus.Error;
if (status === SubscribeFormStatus.Success) {
analytics.indentify(this.state.emailText, 'email');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo? "identify"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow. Great catch

}
this.setState({ status, emailText: '' });
} catch (error) {
this._setStatus(SubscribeFormStatus.Error);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { generatePseudoRandomSalt, getOrderHashHex } from '@0xproject/order-utils';
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { ECSignature, Order } from '@0xproject/types';
import { colors } from '@0xproject/react-shared';
import { ECSignature, Order as ZeroExOrder } from '@0xproject/types';
import { BigNumber, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import Dialog from 'material-ui/Dialog';
Expand All @@ -20,7 +20,7 @@ import { SwapIcon } from 'ts/components/ui/swap_icon';
import { Dispatcher } from 'ts/redux/dispatcher';
import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { validator } from 'ts/schemas/validator';
import { AlertTypes, BlockchainErrs, HashData, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
import { AlertTypes, BlockchainErrs, HashData, Order, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types';
import { analytics } from 'ts/utils/analytics';
import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter';
Expand Down Expand Up @@ -254,7 +254,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
userAddressIfExists,
debitToken.address,
);
const receiveAmount = this.props.sideToAssetToken[Side.Receive].amount;
const receiveToken = this.props.sideToAssetToken[Side.Receive];
const receiveAmount = receiveToken.amount;
if (
!_.isUndefined(debitToken.amount) &&
!_.isUndefined(receiveAmount) &&
Expand All @@ -264,32 +265,36 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
debitBalance.gte(debitToken.amount) &&
debitAllowance.gte(debitToken.amount)
) {
const didSignSuccessfully = await this._signTransactionAsync();
if (didSignSuccessfully) {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${this.props.tokenByAddress[debitToken.address].symbol}-${networkName}`;
analytics.logEvent('Portal', 'Sign Order Success', eventLabel, debitToken.amount.toNumber());
const signedOrder = await this._signTransactionAsync();
const doesSignedOrderExist = !_.isUndefined(signedOrder);
if (doesSignedOrderExist) {
analytics.trackOrderEvent('Sign Order Success', signedOrder);
this.setState({
globalErrMsg: '',
shouldShowIncompleteErrs: false,
});
}
return didSignSuccessfully;
return doesSignedOrderExist;
} else {
let globalErrMsg = 'You must fix the above errors in order to generate a valid order';
if (this.props.userAddress === '') {
globalErrMsg = 'You must enable wallet communication';
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
}
analytics.logEvent('Portal', 'Sign Order Failure', globalErrMsg);
analytics.track('Sign Order Failure', {
makerTokenAmount: debitToken.amount.toString(),
makerToken: this.props.tokenByAddress[debitToken.address].symbol,
takerTokenAmount: receiveToken.amount.toString(),
takerToken: this.props.tokenByAddress[receiveToken.address].symbol,
});
this.setState({
globalErrMsg,
shouldShowIncompleteErrs: true,
});
return false;
}
}
private async _signTransactionAsync(): Promise<boolean> {
private async _signTransactionAsync(): Promise<Order | undefined> {
this.setState({
signingState: SigningState.SIGNING,
});
Expand All @@ -299,11 +304,11 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
this.setState({
signingState: SigningState.UNSIGNED,
});
return false;
return undefined;
}
const hashData = this.props.hashData;

const zeroExOrder: Order = {
const zeroExOrder: ZeroExOrder = {
exchangeContractAddress: exchangeContractAddr,
expirationUnixTimestampSec: hashData.orderExpiryTimestamp,
feeRecipient: hashData.feeRecipientAddress,
Expand All @@ -320,9 +325,10 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
const orderHash = getOrderHashHex(zeroExOrder);

let globalErrMsg = '';
let order;
try {
const ecSignature = await this.props.blockchain.signOrderHashAsync(orderHash);
const order = utils.generateOrder(
order = utils.generateOrder(
exchangeContractAddr,
this.props.sideToAssetToken,
hashData.orderExpiryTimestamp,
Expand Down Expand Up @@ -356,7 +362,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
signingState: globalErrMsg === '' ? SigningState.SIGNED : SigningState.UNSIGNED,
globalErrMsg,
});
return globalErrMsg === '';
return order;
}
private _updateOrderAddress(address?: string): void {
if (!_.isUndefined(address)) {
Expand Down
12 changes: 7 additions & 5 deletions packages/website/ts/components/inputs/allowance_toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
import { Styles } from '@0xproject/react-shared';
import { BigNumber, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import Toggle from 'material-ui/Toggle';
Expand Down Expand Up @@ -111,14 +111,16 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
if (!this._isAllowanceSet()) {
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
}
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${this.props.token.symbol}-${networkName}`;
const logData = {
tokenSymbol: this.props.token.symbol,
newAllowance: newAllowanceAmountInBaseUnits.toNumber(),
};
try {
await this.props.blockchain.setProxyAllowanceAsync(this.props.token, newAllowanceAmountInBaseUnits);
analytics.logEvent('Portal', 'Set Allowance Success', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
analytics.track('Set Allowances Success', logData);
await this.props.refetchTokenStateAsync();
} catch (err) {
analytics.logEvent('Portal', 'Set Allowance Failure', eventLabel, newAllowanceAmountInBaseUnits.toNumber());
analytics.track('Set Allowance Failure', logData);
this.setState({
isSpinnerVisible: false,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { constants as sharedConstants } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
Expand Down Expand Up @@ -225,20 +224,21 @@ class PlainPortalOnboardingFlow extends React.Component<PortalOnboardingFlowProp
(this.props.stepIndex === 0 && !this.props.isRunning && this.props.blockchainIsLoaded) ||
(!this.props.isRunning && !this.props.hasBeenClosed && this.props.blockchainIsLoaded)
) {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
analytics.logEvent('Portal', 'Onboarding Started - Automatic', networkName, this.props.stepIndex);
analytics.track('Onboarding Started', {
reason: 'automatic',
stepIndex: this.props.stepIndex,
});
this.props.updateIsRunning(true);
}
}
private _updateOnboardingStep(stepIndex: number): void {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
this.props.updateOnboardingStep(stepIndex);
analytics.logEvent('Portal', 'Update Onboarding Step', networkName, stepIndex);
}
private _closeOnboarding(): void {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
this.props.updateIsRunning(false);
analytics.logEvent('Portal', 'Onboarding Closed', networkName, this.props.stepIndex);
analytics.track('OnboardingClosed', {
stepIndex: this.props.stepIndex,
});
}
private _renderZrxAllowanceToggle(): React.ReactNode {
const zrxToken = utils.getZrxToken(this.props.tokenByAddress);
Expand Down
9 changes: 5 additions & 4 deletions packages/website/ts/components/portal/portal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { colors } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import * as React from 'react';
Expand Down Expand Up @@ -388,10 +388,11 @@ export class Portal extends React.Component<PortalProps, PortalState> {
startOnboarding
);
}

private _startOnboarding(): void {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
analytics.logEvent('Portal', 'Onboarding Started - Manual', networkName, this.props.portalOnboardingStep);
analytics.track('Onboarding Started', {
reason: 'manual',
stepIndex: this.props.portalOnboardingStep,
});
this.props.dispatcher.updatePortalOnboardingShowing(true);
}
private _renderWalletSection(): React.ReactNode {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { constants as sharedConstants, Styles } from '@0xproject/react-shared';
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import { GridTile as PlainGridTile } from 'material-ui/GridList';
import * as React from 'react';
Expand Down Expand Up @@ -64,10 +64,10 @@ export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (
const link = props.relayerInfo.appUrl || props.relayerInfo.url;
const topTokens = props.relayerInfo.topTokens;
const weeklyTxnVolume = props.relayerInfo.weeklyTxnVolume;
const networkName = sharedConstants.NETWORK_NAME_BY_ID[props.networkId];
const eventLabel = `${props.relayerInfo.name}-${networkName}`;
const onClick = () => {
analytics.logEvent('Portal', 'Relayer Click', eventLabel);
analytics.track('Relayer Click', {
name: props.relayerInfo.name,
});
utils.openUrl(link);
};
const headerImageUrl = props.relayerInfo.logoImgUrl;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
colors,
constants as sharedConstants,
EtherscanLinkSuffixes,
utils as sharedUtils,
} from '@0xproject/react-shared';
import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';

Expand Down Expand Up @@ -46,11 +41,11 @@ class TokenLink extends React.Component<TokenLinkProps, TokenLinkState> {
};
}
public render(): React.ReactNode {
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
const eventLabel = `${this.props.tokenInfo.symbol}-${networkName}`;
const onClick = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
analytics.logEvent('Portal', 'Token Click', eventLabel);
analytics.track('Token Click', {
tokenSymbol: this.props.tokenInfo.symbol,
});
const tokenLink = this._tokenLinkFromToken(this.props.tokenInfo, this.props.networkId);
utils.openUrl(tokenLink);
};
Expand Down
Loading