diff --git a/app/containers/LoginServices.js b/app/containers/LoginServices.js index 11ffc6d9..31c8bbaf 100644 --- a/app/containers/LoginServices.js +++ b/app/containers/LoginServices.js @@ -15,6 +15,7 @@ import OrSeparator from './OrSeparator'; import Touch from '../utils/touch'; import I18n from '../i18n'; import random from '../utils/random'; +import { logEvent, events } from '../utils/log'; import RocketChat from '../lib/rocketchat'; const BUTTON_HEIGHT = 48; @@ -77,6 +78,7 @@ class LoginServices extends React.PureComponent { } onPressFacebook = () => { + logEvent(events.LOGIN_WITH_FACEBOOK); const { services, server } = this.props; const { clientId } = services.facebook; const endpoint = 'https://m.facebook.com/v2.9/dialog/oauth'; @@ -88,6 +90,7 @@ class LoginServices extends React.PureComponent { } onPressGithub = () => { + logEvent(events.LOGIN_WITH_GITHUB); const { services, server } = this.props; const { clientId } = services.github; const endpoint = `https://github.com/login?client_id=${ clientId }&return_to=${ encodeURIComponent('/login/oauth/authorize') }`; @@ -99,6 +102,7 @@ class LoginServices extends React.PureComponent { } onPressGitlab = () => { + logEvent(events.LOGIN_WITH_GITLAB); const { services, server, Gitlab_URL } = this.props; const { clientId } = services.gitlab; const baseURL = Gitlab_URL ? Gitlab_URL.trim().replace(/\/*$/, '') : 'https://gitlab.com'; @@ -111,6 +115,7 @@ class LoginServices extends React.PureComponent { } onPressGoogle = () => { + logEvent(events.LOGIN_WITH_GOOGLE); const { services, server } = this.props; const { clientId } = services.google; const endpoint = 'https://accounts.google.com/o/oauth2/auth'; @@ -122,6 +127,7 @@ class LoginServices extends React.PureComponent { } onPressLinkedin = () => { + logEvent(events.LOGIN_WITH_LINKEDIN); const { services, server } = this.props; const { clientId } = services.linkedin; const endpoint = 'https://www.linkedin.com/oauth/v2/authorization'; @@ -133,6 +139,7 @@ class LoginServices extends React.PureComponent { } onPressMeteor = () => { + logEvent(events.LOGIN_WITH_METEOR); const { services, server } = this.props; const { clientId } = services['meteor-developer']; const endpoint = 'https://www.meteor.com/oauth2/authorize'; @@ -143,6 +150,7 @@ class LoginServices extends React.PureComponent { } onPressTwitter = () => { + logEvent(events.LOGIN_WITH_TWITTER); const { server } = this.props; const state = this.getOAuthState(); const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`; @@ -150,6 +158,7 @@ class LoginServices extends React.PureComponent { } onPressWordpress = () => { + logEvent(events.LOGIN_WITH_WORDPRESS); const { services, server } = this.props; const { clientId, serverURL } = services.wordpress; const endpoint = `${ serverURL }/oauth/authorize`; @@ -161,6 +170,7 @@ class LoginServices extends React.PureComponent { } onPressCustomOAuth = (loginService) => { + logEvent(events.LOGIN_WITH_CUSTOM_OAUTH); const { server } = this.props; const { serverURL, authorizePath, clientId, scope, service @@ -175,6 +185,7 @@ class LoginServices extends React.PureComponent { } onPressSaml = (loginService) => { + logEvent(events.LOGIN_WITH_SAML); const { server } = this.props; const { clientConfig } = loginService; const { provider } = clientConfig; @@ -184,6 +195,7 @@ class LoginServices extends React.PureComponent { } onPressCas = () => { + logEvent(events.LOGIN_WITH_CAS); const { server, CAS_login_url } = this.props; const ssoToken = random(17); const url = `${ CAS_login_url }?service=${ server }/_cas/${ ssoToken }`; diff --git a/app/sagas/login.js b/app/sagas/login.js index 587b9b7b..19995219 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -17,7 +17,7 @@ import { import { roomsRequest } from '../actions/rooms'; import { toMomentLocale } from '../utils/moment'; import RocketChat from '../lib/rocketchat'; -import log from '../utils/log'; +import log, { logEvent, events } from '../utils/log'; import I18n from '../i18n'; import database from '../lib/database'; import EventEmitter from '../utils/events'; @@ -32,6 +32,7 @@ const loginCall = args => RocketChat.login(args); const logoutCall = args => RocketChat.logout(args); const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false }) { + logEvent(events.DEFAULT_LOGIN); try { let result; if (credentials.resume) { @@ -52,6 +53,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE if (logoutOnError && (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message))) { yield put(logout(true)); } else { + logEvent(events.DEFAULT_LOGIN_FAIL); yield put(loginFailure(e)); } } diff --git a/app/utils/log/events.js b/app/utils/log/events.js new file mode 100644 index 00000000..01297cd2 --- /dev/null +++ b/app/utils/log/events.js @@ -0,0 +1,24 @@ +export default { + JOIN_A_WORKSPACE: 'join_a_workspace', + CREATE_NEW_WORKSPACE: 'create_new_workspace', + CREATE_NEW_WORKSPACE_FAIL: 'create_new_workspace_fail', + CONNECT_TO_WORKSPACE: 'connect_to_workspace', + CONNECT_TO_WORKSPACE_FAIL: 'connect_to_workspace_fail', + JOIN_OPEN_WORKSPACE: 'join_open_workspace', + DEFAULT_LOGIN: 'default_login', + DEFAULT_LOGIN_FAIL: 'default_login_fail', + DEFAULT_SIGN_UP: 'default_sign_up', + DEFAULT_SIGN_UP_FAIL: 'default_sign_up_fail', + FORGOT_PASSWORD: 'forgot_password', + LOGIN_WITH_FACEBOOK: 'login_with_facebook', + LOGIN_WITH_GITHUB: 'login_with_github', + LOGIN_WITH_GITLAB: 'login_with_gitlab', + LOGIN_WITH_LINKEDIN: 'login_with_linkedin', + LOGIN_WITH_GOOGLE: 'login_with_google', + LOGIN_WITH_METEOR: 'login_with_meteor', + LOGIN_WITH_TWITTER: 'login_with_twitter', + LOGIN_WITH_WORDPRESS: 'login_with_wordpress', + LOGIN_WITH_CUSTOM_OAUTH: 'login_with_custom_oauth', + LOGIN_WITH_SAML: 'login_with_saml', + LOGIN_WITH_CAS: 'login_with_cas' +}; diff --git a/app/utils/log.js b/app/utils/log/index.js similarity index 77% rename from app/utils/log.js rename to app/utils/log/index.js index f2d0fe2f..2a8b6720 100644 --- a/app/utils/log.js +++ b/app/utils/log/index.js @@ -1,12 +1,14 @@ import { Client } from 'bugsnag-react-native'; import firebase from 'react-native-firebase'; -import config from '../../config'; +import config from '../../../config'; +import events from './events'; const bugsnag = new Client(config.BUGSNAG_API_KEY); export const { analytics } = firebase; export const loggerConfig = bugsnag.config; export const { leaveBreadcrumb } = bugsnag; +export { events }; let metadata = {}; @@ -16,6 +18,11 @@ export const logServerVersion = (serverVersion) => { }; }; +export const logEvent = (eventName, payload) => { + analytics().logEvent(eventName, payload); + leaveBreadcrumb(eventName, payload); +}; + export const setCurrentScreen = (currentScreen) => { analytics().setCurrentScreen(currentScreen); leaveBreadcrumb(currentScreen, { type: 'navigation' }); diff --git a/app/views/LoginView.js b/app/views/LoginView.js index abc90127..9e566b5b 100644 --- a/app/views/LoginView.js +++ b/app/views/LoginView.js @@ -6,7 +6,7 @@ import { import { connect } from 'react-redux'; import equal from 'deep-equal'; -import { analytics } from '../utils/log'; +import { logEvent, events } from '../utils/log'; import sharedStyles from './Styles'; import Button from '../containers/Button'; import I18n from '../i18n'; @@ -103,6 +103,7 @@ class LoginView extends React.Component { } forgotPassword = () => { + logEvent(events.FORGOT_PASSWORD); const { navigation, Site_Name } = this.props; navigation.navigate('ForgotPasswordView', { title: Site_Name }); } @@ -121,7 +122,6 @@ class LoginView extends React.Component { const { loginRequest } = this.props; Keyboard.dismiss(); loginRequest({ user, password }); - analytics().logEvent('login'); } renderUserForm = () => { diff --git a/app/views/NewServerView.js b/app/views/NewServerView.js index cd443781..f49ddbab 100644 --- a/app/views/NewServerView.js +++ b/app/views/NewServerView.js @@ -20,7 +20,7 @@ import FormContainer, { FormContainerInner } from '../containers/FormContainer'; import I18n from '../i18n'; import { isIOS } from '../utils/deviceInfo'; import { themes } from '../constants/colors'; -import log from '../utils/log'; +import log, { logEvent, events } from '../utils/log'; import { animateNextTransition } from '../utils/layoutAnimation'; import { withTheme } from '../theme'; import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch'; @@ -124,6 +124,7 @@ class NewServerView extends React.Component { } submit = async() => { + logEvent(events.CONNECT_TO_WORKSPACE); const { text, certificate } = this.state; const { connectServer } = this.props; let cert = null; @@ -135,6 +136,7 @@ class NewServerView extends React.Component { try { await FileSystem.copyAsync({ from: certificate.path, to: certificatePath }); } catch (e) { + logEvent(events.CONNECT_TO_WORKSPACE_FAIL); log(e); } cert = { @@ -152,6 +154,7 @@ class NewServerView extends React.Component { } connectOpen = () => { + logEvent(events.JOIN_OPEN_WORKSPACE); this.setState({ connectingOpen: true }); const { connectServer } = this.props; connectServer('https://open.rocket.chat'); diff --git a/app/views/OnboardingView/index.js b/app/views/OnboardingView/index.js index 0a1ac738..0d509e0d 100644 --- a/app/views/OnboardingView/index.js +++ b/app/views/OnboardingView/index.js @@ -14,6 +14,7 @@ import { isTablet } from '../../utils/deviceInfo'; import { themes } from '../../constants/colors'; import { withTheme } from '../../theme'; import FormContainer, { FormContainerInner } from '../../containers/FormContainer'; +import { logEvent, events } from '../../utils/log'; class OnboardingView extends React.Component { static navigationOptions = { @@ -69,15 +70,17 @@ class OnboardingView extends React.Component { } connectServer = () => { + logEvent(events.JOIN_A_WORKSPACE); const { navigation } = this.props; navigation.navigate('NewServerView'); } createWorkspace = async() => { + logEvent(events.CREATE_NEW_WORKSPACE); try { await Linking.openURL('https://cloud.rocket.chat/trial'); } catch { - // do nothing + logEvent(events.CREATE_NEW_WORKSPACE_FAIL); } } diff --git a/app/views/RegisterView.js b/app/views/RegisterView.js index 1e0ce265..d95fb793 100644 --- a/app/views/RegisterView.js +++ b/app/views/RegisterView.js @@ -6,7 +6,7 @@ import { import { connect } from 'react-redux'; import RNPickerSelect from 'react-native-picker-select'; -import log from '../utils/log'; +import log, { logEvent, events } from '../utils/log'; import sharedStyles from './Styles'; import Button from '../containers/Button'; import I18n from '../i18n'; @@ -114,6 +114,7 @@ class RegisterView extends React.Component { } submit = async() => { + logEvent(events.DEFAULT_SIGN_UP); if (!this.valid()) { return; } @@ -149,6 +150,7 @@ class RegisterView extends React.Component { return loginRequest({ user: email, password }); } if (e.data?.error) { + logEvent(events.DEFAULT_SIGN_UP_FAIL); showErrorAlert(e.data.error, I18n.t('Oops')); } }