[NEW] Log events from Onboarding, NewServer, Login and Register screens (#2169)
* Create method to track user event to isolate the logic to improve future refactoring * Track Onboarding view * Track NewServer view * Refactor track method due to firebase already send the current screen * Track default login and all the oAuth options * Track default sign up in RegisterView * Change trackUserEvent signature and update all the files * Track the remaining login services * Resolve requests to improve the importing logs and events * Leave a bugsnag breadcrumb when logging an event * Move all logEvent to the top of code block and log remaining fail events Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
df6c2c5424
commit
fc324edafe
|
@ -15,6 +15,7 @@ import OrSeparator from './OrSeparator';
|
||||||
import Touch from '../utils/touch';
|
import Touch from '../utils/touch';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import random from '../utils/random';
|
import random from '../utils/random';
|
||||||
|
import { logEvent, events } from '../utils/log';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
|
||||||
const BUTTON_HEIGHT = 48;
|
const BUTTON_HEIGHT = 48;
|
||||||
|
@ -77,6 +78,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressFacebook = () => {
|
onPressFacebook = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_FACEBOOK);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId } = services.facebook;
|
const { clientId } = services.facebook;
|
||||||
const endpoint = 'https://m.facebook.com/v2.9/dialog/oauth';
|
const endpoint = 'https://m.facebook.com/v2.9/dialog/oauth';
|
||||||
|
@ -88,6 +90,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressGithub = () => {
|
onPressGithub = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_GITHUB);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId } = services.github;
|
const { clientId } = services.github;
|
||||||
const endpoint = `https://github.com/login?client_id=${ clientId }&return_to=${ encodeURIComponent('/login/oauth/authorize') }`;
|
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 = () => {
|
onPressGitlab = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_GITLAB);
|
||||||
const { services, server, Gitlab_URL } = this.props;
|
const { services, server, Gitlab_URL } = this.props;
|
||||||
const { clientId } = services.gitlab;
|
const { clientId } = services.gitlab;
|
||||||
const baseURL = Gitlab_URL ? Gitlab_URL.trim().replace(/\/*$/, '') : 'https://gitlab.com';
|
const baseURL = Gitlab_URL ? Gitlab_URL.trim().replace(/\/*$/, '') : 'https://gitlab.com';
|
||||||
|
@ -111,6 +115,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressGoogle = () => {
|
onPressGoogle = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_GOOGLE);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId } = services.google;
|
const { clientId } = services.google;
|
||||||
const endpoint = 'https://accounts.google.com/o/oauth2/auth';
|
const endpoint = 'https://accounts.google.com/o/oauth2/auth';
|
||||||
|
@ -122,6 +127,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressLinkedin = () => {
|
onPressLinkedin = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_LINKEDIN);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId } = services.linkedin;
|
const { clientId } = services.linkedin;
|
||||||
const endpoint = 'https://www.linkedin.com/oauth/v2/authorization';
|
const endpoint = 'https://www.linkedin.com/oauth/v2/authorization';
|
||||||
|
@ -133,6 +139,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressMeteor = () => {
|
onPressMeteor = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_METEOR);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId } = services['meteor-developer'];
|
const { clientId } = services['meteor-developer'];
|
||||||
const endpoint = 'https://www.meteor.com/oauth2/authorize';
|
const endpoint = 'https://www.meteor.com/oauth2/authorize';
|
||||||
|
@ -143,6 +150,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressTwitter = () => {
|
onPressTwitter = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_TWITTER);
|
||||||
const { server } = this.props;
|
const { server } = this.props;
|
||||||
const state = this.getOAuthState();
|
const state = this.getOAuthState();
|
||||||
const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`;
|
const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`;
|
||||||
|
@ -150,6 +158,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressWordpress = () => {
|
onPressWordpress = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_WORDPRESS);
|
||||||
const { services, server } = this.props;
|
const { services, server } = this.props;
|
||||||
const { clientId, serverURL } = services.wordpress;
|
const { clientId, serverURL } = services.wordpress;
|
||||||
const endpoint = `${ serverURL }/oauth/authorize`;
|
const endpoint = `${ serverURL }/oauth/authorize`;
|
||||||
|
@ -161,6 +170,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressCustomOAuth = (loginService) => {
|
onPressCustomOAuth = (loginService) => {
|
||||||
|
logEvent(events.LOGIN_WITH_CUSTOM_OAUTH);
|
||||||
const { server } = this.props;
|
const { server } = this.props;
|
||||||
const {
|
const {
|
||||||
serverURL, authorizePath, clientId, scope, service
|
serverURL, authorizePath, clientId, scope, service
|
||||||
|
@ -175,6 +185,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressSaml = (loginService) => {
|
onPressSaml = (loginService) => {
|
||||||
|
logEvent(events.LOGIN_WITH_SAML);
|
||||||
const { server } = this.props;
|
const { server } = this.props;
|
||||||
const { clientConfig } = loginService;
|
const { clientConfig } = loginService;
|
||||||
const { provider } = clientConfig;
|
const { provider } = clientConfig;
|
||||||
|
@ -184,6 +195,7 @@ class LoginServices extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressCas = () => {
|
onPressCas = () => {
|
||||||
|
logEvent(events.LOGIN_WITH_CAS);
|
||||||
const { server, CAS_login_url } = this.props;
|
const { server, CAS_login_url } = this.props;
|
||||||
const ssoToken = random(17);
|
const ssoToken = random(17);
|
||||||
const url = `${ CAS_login_url }?service=${ server }/_cas/${ ssoToken }`;
|
const url = `${ CAS_login_url }?service=${ server }/_cas/${ ssoToken }`;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
import { roomsRequest } from '../actions/rooms';
|
import { roomsRequest } from '../actions/rooms';
|
||||||
import { toMomentLocale } from '../utils/moment';
|
import { toMomentLocale } from '../utils/moment';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import log from '../utils/log';
|
import log, { logEvent, events } from '../utils/log';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import database from '../lib/database';
|
import database from '../lib/database';
|
||||||
import EventEmitter from '../utils/events';
|
import EventEmitter from '../utils/events';
|
||||||
|
@ -32,6 +32,7 @@ const loginCall = args => RocketChat.login(args);
|
||||||
const logoutCall = args => RocketChat.logout(args);
|
const logoutCall = args => RocketChat.logout(args);
|
||||||
|
|
||||||
const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false }) {
|
const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false }) {
|
||||||
|
logEvent(events.DEFAULT_LOGIN);
|
||||||
try {
|
try {
|
||||||
let result;
|
let result;
|
||||||
if (credentials.resume) {
|
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))) {
|
if (logoutOnError && (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message))) {
|
||||||
yield put(logout(true));
|
yield put(logout(true));
|
||||||
} else {
|
} else {
|
||||||
|
logEvent(events.DEFAULT_LOGIN_FAIL);
|
||||||
yield put(loginFailure(e));
|
yield put(loginFailure(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
||||||
|
};
|
|
@ -1,12 +1,14 @@
|
||||||
import { Client } from 'bugsnag-react-native';
|
import { Client } from 'bugsnag-react-native';
|
||||||
import firebase from 'react-native-firebase';
|
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);
|
const bugsnag = new Client(config.BUGSNAG_API_KEY);
|
||||||
|
|
||||||
export const { analytics } = firebase;
|
export const { analytics } = firebase;
|
||||||
export const loggerConfig = bugsnag.config;
|
export const loggerConfig = bugsnag.config;
|
||||||
export const { leaveBreadcrumb } = bugsnag;
|
export const { leaveBreadcrumb } = bugsnag;
|
||||||
|
export { events };
|
||||||
|
|
||||||
let metadata = {};
|
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) => {
|
export const setCurrentScreen = (currentScreen) => {
|
||||||
analytics().setCurrentScreen(currentScreen);
|
analytics().setCurrentScreen(currentScreen);
|
||||||
leaveBreadcrumb(currentScreen, { type: 'navigation' });
|
leaveBreadcrumb(currentScreen, { type: 'navigation' });
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
|
|
||||||
import { analytics } from '../utils/log';
|
import { logEvent, events } from '../utils/log';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
@ -103,6 +103,7 @@ class LoginView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
forgotPassword = () => {
|
forgotPassword = () => {
|
||||||
|
logEvent(events.FORGOT_PASSWORD);
|
||||||
const { navigation, Site_Name } = this.props;
|
const { navigation, Site_Name } = this.props;
|
||||||
navigation.navigate('ForgotPasswordView', { title: Site_Name });
|
navigation.navigate('ForgotPasswordView', { title: Site_Name });
|
||||||
}
|
}
|
||||||
|
@ -121,7 +122,6 @@ class LoginView extends React.Component {
|
||||||
const { loginRequest } = this.props;
|
const { loginRequest } = this.props;
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
loginRequest({ user, password });
|
loginRequest({ user, password });
|
||||||
analytics().logEvent('login');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUserForm = () => {
|
renderUserForm = () => {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { isIOS } from '../utils/deviceInfo';
|
import { isIOS } from '../utils/deviceInfo';
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import log from '../utils/log';
|
import log, { logEvent, events } from '../utils/log';
|
||||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch';
|
import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch';
|
||||||
|
@ -124,6 +124,7 @@ class NewServerView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit = async() => {
|
submit = async() => {
|
||||||
|
logEvent(events.CONNECT_TO_WORKSPACE);
|
||||||
const { text, certificate } = this.state;
|
const { text, certificate } = this.state;
|
||||||
const { connectServer } = this.props;
|
const { connectServer } = this.props;
|
||||||
let cert = null;
|
let cert = null;
|
||||||
|
@ -135,6 +136,7 @@ class NewServerView extends React.Component {
|
||||||
try {
|
try {
|
||||||
await FileSystem.copyAsync({ from: certificate.path, to: certificatePath });
|
await FileSystem.copyAsync({ from: certificate.path, to: certificatePath });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
logEvent(events.CONNECT_TO_WORKSPACE_FAIL);
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
cert = {
|
cert = {
|
||||||
|
@ -152,6 +154,7 @@ class NewServerView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectOpen = () => {
|
connectOpen = () => {
|
||||||
|
logEvent(events.JOIN_OPEN_WORKSPACE);
|
||||||
this.setState({ connectingOpen: true });
|
this.setState({ connectingOpen: true });
|
||||||
const { connectServer } = this.props;
|
const { connectServer } = this.props;
|
||||||
connectServer('https://open.rocket.chat');
|
connectServer('https://open.rocket.chat');
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { isTablet } from '../../utils/deviceInfo';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { withTheme } from '../../theme';
|
||||||
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||||
|
import { logEvent, events } from '../../utils/log';
|
||||||
|
|
||||||
class OnboardingView extends React.Component {
|
class OnboardingView extends React.Component {
|
||||||
static navigationOptions = {
|
static navigationOptions = {
|
||||||
|
@ -69,15 +70,17 @@ class OnboardingView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectServer = () => {
|
connectServer = () => {
|
||||||
|
logEvent(events.JOIN_A_WORKSPACE);
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
navigation.navigate('NewServerView');
|
navigation.navigate('NewServerView');
|
||||||
}
|
}
|
||||||
|
|
||||||
createWorkspace = async() => {
|
createWorkspace = async() => {
|
||||||
|
logEvent(events.CREATE_NEW_WORKSPACE);
|
||||||
try {
|
try {
|
||||||
await Linking.openURL('https://cloud.rocket.chat/trial');
|
await Linking.openURL('https://cloud.rocket.chat/trial');
|
||||||
} catch {
|
} catch {
|
||||||
// do nothing
|
logEvent(events.CREATE_NEW_WORKSPACE_FAIL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import RNPickerSelect from 'react-native-picker-select';
|
import RNPickerSelect from 'react-native-picker-select';
|
||||||
|
|
||||||
import log from '../utils/log';
|
import log, { logEvent, events } from '../utils/log';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
@ -114,6 +114,7 @@ class RegisterView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit = async() => {
|
submit = async() => {
|
||||||
|
logEvent(events.DEFAULT_SIGN_UP);
|
||||||
if (!this.valid()) {
|
if (!this.valid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -149,6 +150,7 @@ class RegisterView extends React.Component {
|
||||||
return loginRequest({ user: email, password });
|
return loginRequest({ user: email, password });
|
||||||
}
|
}
|
||||||
if (e.data?.error) {
|
if (e.data?.error) {
|
||||||
|
logEvent(events.DEFAULT_SIGN_UP_FAIL);
|
||||||
showErrorAlert(e.data.error, I18n.t('Oops'));
|
showErrorAlert(e.data.error, I18n.t('Oops'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue