Skip to content

Commit 0bc30de

Browse files
authored
Merge pull request #617 from appirio-tech/feature/metrics
Feature/metrics
2 parents 63c4d84 + 40254fd commit 0bc30de

File tree

10 files changed

+108
-31
lines changed

10 files changed

+108
-31
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"recompose": "^0.20.2",
6363
"redux": "^3.5.2",
6464
"redux-promise-middleware": "^4.0.0",
65+
"redux-segment": "^1.6.1",
6566
"redux-thunk": "^2.1.0",
6667
"tc-accounts": "https://github.com/appirio-tech/accounts-app.git#dev",
6768
"tc-ui": "https://github.com/appirio-tech/tc-ui.git#feature/connectv2"

src/actions/loadUser.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import _ from 'lodash'
2-
// import { fetchJSON } from '../helpers'
3-
import { ACCOUNTS_APP_CONNECTOR_URL, LOAD_USER_SUCCESS, LOAD_USER_FAILURE } from '../config/constants'
2+
import { ACCOUNTS_APP_CONNECTOR_URL, LOAD_USER_SUCCESS, LOAD_USER_FAILURE, ROLE_ADMINISTRATOR, ROLE_CONNECT_COPILOT, ROLE_TOPCODER_USER, ROLE_CONNECT_MANAGER } from '../config/constants'
43
import { getFreshToken, configureConnector, decodeToken } from 'tc-accounts'
54
import { getUserProfile } from '../api/users'
5+
import { EventTypes } from 'redux-segment'
66

77
configureConnector({
88
connectorUrl: ACCOUNTS_APP_CONNECTOR_URL,
@@ -42,7 +42,53 @@ export function loadUserSuccess(dispatch, token) {
4242
currentUser = _.assign(currentUser, profile)
4343
// keeping profile for backward compaitability
4444
currentUser.profile = profile
45-
dispatch({ type: LOAD_USER_SUCCESS, user : currentUser })
45+
// determine user role
46+
let userRole
47+
if (_.indexOf(currentUser.roles, ROLE_ADMINISTRATOR) > -1) {
48+
userRole = ROLE_ADMINISTRATOR
49+
} else if (_.indexOf(currentUser.roles, ROLE_CONNECT_MANAGER) > -1) {
50+
userRole = ROLE_CONNECT_MANAGER
51+
} else if (_.indexOf(currentUser.roles, ROLE_CONNECT_COPILOT) > -1) {
52+
userRole = ROLE_CONNECT_COPILOT
53+
} else {
54+
userRole = ROLE_TOPCODER_USER
55+
}
56+
57+
58+
const analyticsEvents = [{
59+
eventType: EventTypes.identify,
60+
eventPayload: {
61+
userId: currentUser.id,
62+
traits: {
63+
id: currentUser.id,
64+
role: userRole,
65+
username: currentUser.handle,
66+
firstName: currentUser.firstName,
67+
lastName: currentUser.lastName,
68+
email: currentUser.email,
69+
createdAt: currentUser.createdAt
70+
}
71+
}
72+
}]
73+
if (window.analytics) {
74+
const anonymousId = window.analtyics.user().anonymousId()
75+
if (anonymousId) {
76+
analyticsEvents.push({
77+
eventType: EventTypes.alias,
78+
eventPayload: {
79+
userId: currentUser.id,
80+
previousId: anonymousId
81+
}
82+
})
83+
}
84+
}
85+
dispatch({
86+
type: LOAD_USER_SUCCESS,
87+
user : currentUser,
88+
meta: {
89+
analytics: analyticsEvents
90+
}
91+
})
4692
})
4793
.catch((err) => {
4894
// if we fail to load user's profile, still dispatch user load success

src/components/TopBar/TopBar.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,23 @@ class TopBar extends Component {
5252
userHandle, userImage, userName, domain, criteria, onNewProjectIntent, applyFilters, isProjectDetails, project,
5353
isPowerUser, loginUrl, registerUrl, isFilterVisible
5454
} = this.props
55-
const homePageUrl = window.location.protocol + '//' + window.location.hostname
56-
const logoutLink = 'https://accounts.' + domain + '/#!/logout?retUrl=' + homePageUrl
55+
const homePageUrl = `${window.location.protocol}//${window.location.host}/`
56+
const logoutLink = `https://accounts.${domain}/#!/logout?retUrl=${homePageUrl}`
5757
const isLoggedIn = !!userHandle
5858
const logoTargetUrl = isLoggedIn ? '/projects' : '/'
5959

60+
const logoutClick = () => {
61+
window.analytics.reset()
62+
window.location = logoutLink
63+
64+
}
65+
6066
const userMenuItems = [
6167
[
6268
{ label: 'Help', link: 'https://help.topcoder.com/hc/en-us', absolute: true, id: 0 }
6369
],
6470
[
65-
{ label: 'Log out', link: logoutLink, absolute: true, id: 0 }
71+
{ label: 'Log out', onClick: logoutClick, absolute: true, id: 0 }
6672
]
6773
]
6874
const logo = (

src/config/constants.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,23 @@ export const THREAD_MESSAGES_PAGE_SIZE = 3
147147
* Project status
148148
*/
149149
export const PROJECT_STATUS_DRAFT = 'draft'
150+
export const PROJECT_STATUS_IN_REVIEW = 'in_review'
151+
export const PROJECT_STATUS_REVIEWED = 'reviewed'
152+
export const PROJECT_STATUS_ACTIVE = 'active'
153+
export const PROJECT_STATUS_COMPLETED = 'completed'
154+
export const PROJECT_STATUS_CANCELLED = 'cancelled'
155+
export const PROJECT_STATUS_PAUSED = 'paused'
156+
157+
export const PROJECT_STATUS = [
158+
{color: 'gray', name: 'Draft', value: PROJECT_STATUS_DRAFT },
159+
{color: 'gray', name: 'In Review', value: PROJECT_STATUS_IN_REVIEW },
160+
{color: 'gray', name: 'Reviewed', value: PROJECT_STATUS_REVIEWED },
161+
{color: 'green', name: 'Active', value: PROJECT_STATUS_ACTIVE },
162+
{color: 'black', name: 'Completed', value: PROJECT_STATUS_COMPLETED },
163+
{color: 'black', name: 'Cancelled', value: PROJECT_STATUS_CANCELLED },
164+
{color: 'red', name: 'Paused', value: PROJECT_STATUS_PAUSED }
165+
]
166+
150167

151168
/*
152169
* Project member role
@@ -174,6 +191,7 @@ export const FILE_PICKER_API_KEY = process.env.FILE_PICKER_API_KEY || 'AzFINuQoq
174191
export const FILE_PICKER_SUBMISSION_CONTAINER_NAME = process.env.FILE_PICKER_SUBMISSION_CONTAINER_NAME || 'submission-staging-dev'
175192
export const PROJECT_ATTACHMENTS_FOLDER = process.env.PROJECT_ATTACHMENTS_FOLDER || 'PROJECT_ATTACHMENTS'
176193

194+
export const SEGMENT_KEY = process.env.CONNECT_SEGMENT_KEY
177195
/*
178196
* URLs
179197
*/
@@ -189,19 +207,6 @@ export const SALESFORCE_PROJECT_LEAD_LINK = process.env.SALESFORCE_PROJECT_LEAD_
189207

190208
export const PROJECT_NAME_MAX_LENGTH = 255
191209

192-
export const PROJECT_STATUS_COMPLETED = 'completed'
193-
export const PROJECT_STATUS_CANCELLED = 'cancelled'
194-
195-
export const PROJECT_STATUS = [
196-
{color: 'gray', name: 'Draft', value: 'draft'},
197-
{color: 'gray', name: 'In Review', value: 'in_review'},
198-
{color: 'gray', name: 'Reviewed', value: 'reviewed'},
199-
{color: 'green', name: 'Active', value: 'active'},
200-
{color: 'black', name: 'Completed', value: PROJECT_STATUS_COMPLETED },
201-
{color: 'black', name: 'Cancelled', value: PROJECT_STATUS_CANCELLED },
202-
{color: 'red', name: 'Paused', value: 'paused'}
203-
]
204-
205210
export const PROJECT_FEED_TYPE_PRIMARY = 'PRIMARY'
206211
export const PROJECT_FEED_TYPE_MESSAGES = 'MESSAGES'
207212

src/config/store.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ import thunk from 'redux-thunk'
22
import { createStore, applyMiddleware, compose } from 'redux'
33
import reducers from '../reducers'
44
import promiseMiddleware from 'redux-promise-middleware'
5+
import { createTracker } from 'redux-segment'
6+
7+
const tracker = createTracker()
58

69
const middleware = [
710
promiseMiddleware({
811
promiseTypeSuffixes: ['PENDING', 'SUCCESS', 'FAILURE']
912
}),
10-
thunk
13+
thunk,
14+
tracker
1115
]
1216

1317
if (process.env.ENV === 'DEV') {

src/helpers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import fetch from 'isomorphic-fetch'
33
import tcEmitter from './emitter'
44

55
export const TCEmitter = tcEmitter
6+
export const titleCase = (str) => _.startCase(_.camelCase(str))
7+
68

79
// Fetch helpers
810
export function status(response) {

src/index.jsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,26 @@ import { Provider } from 'react-redux'
55
import browserHistory from 'react-router/lib/browserHistory'
66
import Router from 'react-router/lib/Router'
77

8+
import _ from 'lodash'
89
import store from './config/store'
910
import routes from './routes'
1011
import { TCEmitter } from './helpers'
11-
import { EVENT_ROUTE_CHANGE, HEAP_ANALYTICS_APP_ID } from './config/constants'
12+
import { EVENT_ROUTE_CHANGE, SEGMENT_KEY } from './config/constants'
1213

1314
const mountNode = document.getElementById('root')
1415
const onRouteChange = () => {
1516
TCEmitter.emit(EVENT_ROUTE_CHANGE, window.location.pathname)
1617
}
1718

1819
/* eslint-disable */
19-
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","removeEventProperty","setEventProperties","track","unsetEventProperty"],c=0;c<p.length;c++)heap[p[c]]=o(p[c])};
20-
heap.load(HEAP_ANALYTICS_APP_ID);
20+
if (!_.isEmpty(SEGMENT_KEY)) {
21+
!!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="4.0.0";
22+
analytics.load(SEGMENT_KEY);
23+
analytics.page();
24+
// analytics.debug()
25+
}}();
26+
}
27+
2128
/* eslint-enable */
2229

2330
render((

src/projects/list/components/Projects/Projects.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class Projects extends Component {
2525
}
2626

2727
componentWillReceiveProps(nextProps) {
28-
console.log(nextProps)
2928
const prevQueryParams = _.get(this.props, 'location.query', null)
3029
const queryParams = _.get(nextProps, 'location.query', null)
3130
if (!_.isEqual(prevQueryParams, queryParams)) {

src/routes.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import { Route, IndexRoute } from 'react-router'
2+
import { Route, IndexRoute, browserHistory } from 'react-router'
33
import { withProps } from 'recompose'
44
import App from './components/App/App'
55
import Home from './components/Home/Home'
@@ -13,6 +13,13 @@ import { getFreshToken } from 'tc-accounts'
1313

1414
// import reportsListRoutes from './reports/routes.jsx'
1515

16+
// Tracking
17+
browserHistory.listen( () => {
18+
if (window.analytics) {
19+
window.analytics.page()
20+
}
21+
})
22+
1623
const LoginRedirect = withProps({
1724
redirectTo: `${ACCOUNTS_APP_LOGIN_URL}?retUrl=${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}`
1825
})(RedirectComponent)
@@ -71,4 +78,4 @@ export default (
7178
<Route path="/error" component={ () => <PageError code={500} /> }/>
7279
<Route path="*" component={ () => <PageError code={404} /> }/>
7380
</Route>
74-
)
81+
)

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3767,18 +3767,14 @@ minimatch@~0.2.11:
37673767
lru-cache "2"
37683768
sigmund "~1.0.0"
37693769

3770-
minimist@0.0.8:
3770+
minimist@0.0.8, minimist@~0.0.1:
37713771
version "0.0.8"
37723772
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
37733773

37743774
minimist@^1.1.3, minimist@^1.2.0:
37753775
version "1.2.0"
37763776
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
37773777

3778-
minimist@~0.0.1:
3779-
version "0.0.10"
3780-
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
3781-
37823778
mkdirp@0.3.0:
37833779
version "0.3.0"
37843780
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
@@ -5047,6 +5043,10 @@ redux-router@^1.0.0-beta3:
50475043
dependencies:
50485044
deep-equal "^1.0.1"
50495045

5046+
redux-segment@^1.6.1:
5047+
version "1.6.1"
5048+
resolved "https://registry.yarnpkg.com/redux-segment/-/redux-segment-1.6.1.tgz#813d0734ae7b5de14e863202afd20c24de79022e"
5049+
50505050
redux-thunk@^0.1.0:
50515051
version "0.1.0"
50525052
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-0.1.0.tgz#8e347606808b35bf8a927df4616f6fed101826e5"

0 commit comments

Comments
 (0)