Skip to content

Commit

Permalink
Merge pull request #201 from TokenScript/jf/analytics
Browse files Browse the repository at this point in the history
Setup BC analytics to collect data for Salesforce integration demo
  • Loading branch information
JustinFeng authored May 6, 2023
2 parents fa5116d + 1a02be6 commit ac731fb
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ecommerce-store-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
cd ecommerce-store-website
npm ci
export BASE_PATH=/demo
export ANALYTICS_URL=https://analytics-api-stage.smarttokenlabs.com
export ANALYTICS_JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJicmFuZCI6IkJyYW5kIENvbm5lY3RvciIsImNhbXBhaWduIjoiRGVtbyIsImNsaWVudF9pZCI6IlNUTCIsImlhdCI6MTY4MzE3MDk5Nn0.HhW_sUtU0LKLpK2_puK7pj63CkaXmFa5sJ_wfx1ASR8
npm run build
short_sha="${GITHUB_SHA:0:7}"
build_version="${GITHUB_REF_NAME}-${short_sha}"
Expand Down
3 changes: 3 additions & 0 deletions ecommerce-store-website/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ BASE_PATH=/
MC_API_URL=
MC_API_KEY=
MC_LIST_ID=

ANALYTICS_URL=
ANALYTICS_JWT=
2 changes: 2 additions & 0 deletions ecommerce-store-website/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ module.exports = phase => {
APP_VERSION: PKG.version,
APP_HOST: process.env.APP_HOST ?? process.env.VERCEL_URL,
BASE_PATH: process.env.BASE_PATH,
ANALYTICS_URL: process.env.ANALYTICS_URL,
ANALYTICS_JWT: process.env.ANALYTICS_JWT,
};

const basePath = process.env.BASE_PATH ?? "";
Expand Down
78 changes: 78 additions & 0 deletions ecommerce-store-website/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ecommerce-store-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@react-spring/web": "^9.3.1",
"@tokenscript/analytics-client": "^0.4.0",
"@tokenscript/token-negotiator": "2.5.0",
"@use-gesture/react": "^10.1.6",
"body-scroll-lock": "^4.0.0-beta.0",
Expand Down
67 changes: 67 additions & 0 deletions ecommerce-store-website/src/base/utils/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Analytics from '@tokenscript/analytics-client';

const analyticsUrl = process.env.ANALYTICS_URL;
const jwtToken = process.env.ANALYTICS_JWT;

const analyticsClient = new Analytics(analyticsUrl, jwtToken).client;

// TODO: all the following event reporting functions can be replaced
// with `Analytics.connectTokenNegotiator` once TN supports multiple event hooks
export function sendWalletConnectedEvent({
providerType,
blockchain,
chainId,
address,
}) {
analyticsClient.event({
name: 'wallet-connected',
eventProperties: {
provider_type: providerType,
blockchain,
chain_id: chainId,
address,
},
});
}

export function sendTokensSelectedEvent({ selectedTokens }) {
const eventProperties = Object.fromEntries(
Object.entries(selectedTokens).map(([collectionId, { tokens }]) => [
collectionId,
tokens.map((token) => token.ticketIdNumber ?? token.tokenId),
])
);

analyticsClient.event({
name: 'token-selected',
eventProperties,
});
}

export function sendTokenProofEvent({
data: { address, messageToSign, signature },
error,
}) {
const eventProperties = error
? { error }
: {
address,
messageToSign,
signature,
};

analyticsClient.event({
name: 'token-proof',
eventProperties,
});
}

const AGREE_TO_STATS_KEY = 'bc-agree-stats';

export function loadAgreeToStats() {
return localStorage.getItem(AGREE_TO_STATS_KEY) === 'true';
}

export function storeAgreeToStats(value) {
localStorage.setItem(AGREE_TO_STATS_KEY, value);
}
16 changes: 13 additions & 3 deletions ecommerce-store-website/src/providers/TokenContextProvider.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {createContext, useState, useEffect, useMemo} from "react";
import React, {createContext, useState, useEffect, useMemo, useRef} from "react";
import { chainMap } from "src/base/utils/network";
import {sendTokensSelectedEvent, sendTokenProofEvent, sendWalletConnectedEvent, loadAgreeToStats, storeAgreeToStats} from "src/base/utils/stats";

const TokenContext = createContext({
tokens: {},
Expand Down Expand Up @@ -66,6 +67,12 @@ const TokenContextProvider = (props) => {
const [wallet, setWallet] = useState();
const [walletStatus, setWalletStatus] = useState('');
const [ chainId, setChainId ] = useState('');
const [ agreeToStats, setAgreeToStats ] = useState(false);
const agreeToStatsValue = useRef();
agreeToStatsValue.current = agreeToStats;

useEffect(() => { setAgreeToStats(loadAgreeToStats()) }, []);
useEffect(() => { storeAgreeToStats(agreeToStats) }, [agreeToStats]);

useEffect(() => {

Expand Down Expand Up @@ -94,15 +101,18 @@ const TokenContextProvider = (props) => {
window.negotiator = newNegotiator;

newNegotiator.on("tokens-selected", (tokens) => {
if (agreeToStatsValue.current) sendTokensSelectedEvent(tokens);
setTokens({...tokens.selectedTokens});
});

newNegotiator.on("token-proof", (result) => {
if (agreeToStatsValue.current) sendTokenProofEvent(result);
setProof(result.data);
});

newNegotiator.on("connected-wallet", (connectedWallet) => {
if (connectedWallet) {
if (agreeToStatsValue.current) sendWalletConnectedEvent(connectedWallet)
setWallet(connectedWallet);
resetIssuers(connectedWallet.chainId);
setWalletStatus(undefined);
Expand Down Expand Up @@ -159,8 +169,8 @@ const TokenContextProvider = (props) => {
}

const tokenContextProviderValue = useMemo(
() => ({ tokens, negotiator, wallet, proof, walletStatus, chainId, switchChain }),
[tokens, negotiator, wallet, proof, walletStatus, chainId, switchChain]
() => ({ tokens, negotiator, wallet, proof, walletStatus, chainId, agreeToStats, setAgreeToStats, switchChain }),
[tokens, negotiator, wallet, proof, walletStatus, chainId, agreeToStats, switchChain]
);

return (
Expand Down
2 changes: 2 additions & 0 deletions ecommerce-store-website/src/ui/app/layout/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import clsx from 'clsx';
// App
import { Footer, Header } from 'ui/app';
import { LabsBanner } from 'ui/sections';
import { StatsDisclaimer } from 'ui/sections';


//
Expand All @@ -16,6 +17,7 @@ import { LabsBanner } from 'ui/sections';
export default function Layout({ className, children }) {
return (
<div className={ clsx( 'a-layout', className ) }>
<StatsDisclaimer />
<Header />
<main>
{ children }
Expand Down
1 change: 1 addition & 0 deletions ecommerce-store-website/src/ui/sections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as DemoHeader } from './demo-header';
export { default as DemoHero } from './demo-hero';
export { default as Hero } from './hero';
export { default as LabsBanner } from './labs-banner';
export { default as StatsDisclaimer } from './stats-disclaimer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@


//
// Brand Connector Demo / UI / Sections / Stats Disclaimer
//


export { default } from './stats-disclaimer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@


// Dependencies
import React, { useContext } from 'react';
import clsx from 'clsx';

// App
import { TokenContext } from 'src/providers/TokenContextProvider';
import { Button } from 'ui/components';

// Styles
import styles from "./stats-disclaimer.module.scss";


//
// Brand Connector Demo / UI / Sections / Stats Disclaimer
//


export default function StatsDisclaimer() {
const { agreeToStats, setAgreeToStats } = useContext(TokenContext);

const handleOnClick = () => {
setAgreeToStats(true);
};

return !agreeToStats && (
<div className={ styles[ 's-stats-disclaimer' ] }>
<span className={ styles[ 's-stats-disclaimer_desc' ] }>
This page collect data for analytics purposes.
</span>
<Button
className={ clsx( styles[ 's-stats-disclaimer_button' ], '-style-light-outline' ) }
onClick={handleOnClick}>
Agree
</Button>
</div>
);
}
Loading

0 comments on commit ac731fb

Please sign in to comment.