web/satellite: add tracking event for segment.io (#3641)

This commit is contained in:
Malcolm Bouzi 2019-12-11 15:07:15 -05:00 committed by Yingrong Zhao
parent 6ce22be744
commit 0253eff2ec
21 changed files with 139 additions and 16 deletions

View File

@ -1073,7 +1073,8 @@
"@types/segment-analytics": { "@types/segment-analytics": {
"version": "0.0.32", "version": "0.0.32",
"resolved": "https://registry.npmjs.org/@types/segment-analytics/-/segment-analytics-0.0.32.tgz", "resolved": "https://registry.npmjs.org/@types/segment-analytics/-/segment-analytics-0.0.32.tgz",
"integrity": "sha512-p0SHnfHfZwemTeaISvu8WUXtw81A4AOU4GEr7B9S9jLx2iu/z/4aLT0flRJtHVusVAlMeJSdobn0uD/oR1sFEw==" "integrity": "sha512-p0SHnfHfZwemTeaISvu8WUXtw81A4AOU4GEr7B9S9jLx2iu/z/4aLT0flRJtHVusVAlMeJSdobn0uD/oR1sFEw==",
"dev": true
}, },
"@types/sinon": { "@types/sinon": {
"version": "7.0.13", "version": "7.0.13",

View File

@ -10,7 +10,6 @@
"dev": "vue-cli-service build --mode development" "dev": "vue-cli-service build --mode development"
}, },
"dependencies": { "dependencies": {
"@types/segment-analytics": "0.0.32",
"apollo-cache-inmemory": "1.6.3", "apollo-cache-inmemory": "1.6.3",
"apollo-client": "2.6.4", "apollo-client": "2.6.4",
"apollo-link": "1.2.12", "apollo-link": "1.2.12",
@ -37,6 +36,7 @@
"@vue/cli-plugin-typescript": "3.11.0", "@vue/cli-plugin-typescript": "3.11.0",
"@vue/cli-plugin-unit-jest": "3.11.0", "@vue/cli-plugin-unit-jest": "3.11.0",
"@vue/cli-service": "3.11.0", "@vue/cli-service": "3.11.0",
"@types/segment-analytics": "0.0.32",
"@vue/test-utils": "1.0.0-beta.29", "@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0", "babel-core": "7.0.0-bridge.0",
"compression-webpack-plugin": "3.0.0", "compression-webpack-plugin": "3.0.0",

View File

@ -10,8 +10,8 @@
</div> </div>
<div class='delete-account__form-container'> <div class='delete-account__form-container'>
<p class='delete-account__form-container__confirmation-text'>Are you sure you want to delete your account? If you do so, all your information, projects and API Keys will be deleted forever (drop from the satellite).</p> <p class='delete-account__form-container__confirmation-text'>Are you sure you want to delete your account? If you do so, all your information, projects and API Keys will be deleted forever (drop from the satellite).</p>
<HeaderedInput <HeaderedInput
label='Enter your password' label='Enter your password'
placeholder='Your Password' placeholder='Your Password'
class='full-input' class='full-input'
width='100%' width='100%'
@ -55,7 +55,9 @@ import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { AuthToken } from '@/utils/authToken'; import { AuthToken } from '@/utils/authToken';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { validatePassword } from '@/utils/validation'; import { validatePassword } from '@/utils/validation';
import { LocalData } from '../../utils/localData';
@Component({ @Component({
components: { components: {
@ -94,6 +96,9 @@ export default class DeleteAccountPopup extends Vue {
try { try {
await this.auth.delete(this.password); await this.auth.delete(this.password);
await this.$notify.success('Account was successfully deleted'); await this.$notify.success('Account was successfully deleted');
this.$segment.track(SegmentEvent.USER_DELETED, {
email: this.$store.getters.user.email,
});
AuthToken.remove(); AuthToken.remove();

View File

@ -37,6 +37,7 @@ import VPagination from '@/components/common/VPagination.vue';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { BillingHistoryItem } from '@/types/payments'; import { BillingHistoryItem } from '@/types/payments';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
@Component({ @Component({
components: { components: {
@ -46,6 +47,13 @@ import { BillingHistoryItem } from '@/types/payments';
}, },
}) })
export default class BillingHistory extends Vue { export default class BillingHistory extends Vue {
public mounted(): void {
this.$segment.track(SegmentEvent.BILLING_HISTORY_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
invoice_count: this.$store.state.paymentsModule.billingHistory.length,
});
}
public get billingHistoryItems(): BillingHistoryItem[] { public get billingHistoryItems(): BillingHistoryItem[] {
return this.$store.state.paymentsModule.billingHistory; return this.$store.state.paymentsModule.billingHistory;
} }

View File

@ -79,6 +79,7 @@ import VButton from '@/components/common/VButton.vue';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments'; import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { CreditCard } from '@/types/payments'; import { CreditCard } from '@/types/payments';
import { NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames'; import { NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { PaymentMethodsBlockState } from '@/utils/constants/billingEnums'; import { PaymentMethodsBlockState } from '@/utils/constants/billingEnums';
const { const {
@ -109,6 +110,9 @@ export default class PaymentMethods extends Vue {
public mounted() { public mounted() {
try { try {
this.$segment.track(SegmentEvent.PAYMENT_METHODS_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
});
this.$store.dispatch(GET_CREDIT_CARDS); this.$store.dispatch(GET_CREDIT_CARDS);
} catch (error) { } catch (error) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message); this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
@ -178,6 +182,10 @@ export default class PaymentMethods extends Vue {
await this.$notify.error(error.message); await this.$notify.error(error.message);
} }
this.$segment.track(SegmentEvent.PAYMENT_METHOD_ADDED, {
project_id: this.$store.getters.selectedProject.id,
});
this.tokenDepositValue = this.DEFAULT_TOKEN_DEPOSIT_VALUE; this.tokenDepositValue = this.DEFAULT_TOKEN_DEPOSIT_VALUE;
try { try {
await this.$store.dispatch(GET_BILLING_HISTORY); await this.$store.dispatch(GET_BILLING_HISTORY);
@ -190,6 +198,9 @@ export default class PaymentMethods extends Vue {
public async onConfirmAddStripe(): Promise<void> { public async onConfirmAddStripe(): Promise<void> {
await this.$refs.stripeCardInput.onSubmit(); await this.$refs.stripeCardInput.onSubmit();
this.$segment.track(SegmentEvent.PAYMENT_METHOD_ADDED, {
project_id: this.$store.getters.selectedProject.id,
});
} }
public async addCard(token: string) { public async addCard(token: string) {
@ -210,6 +221,9 @@ export default class PaymentMethods extends Vue {
} }
await this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Card successfully added'); await this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Card successfully added');
this.$segment.track(SegmentEvent.PAYMENT_METHOD_ADDED, {
project_id: this.$store.getters.selectedProject.id,
});
try { try {
await this.$store.dispatch(GET_CREDIT_CARDS); await this.$store.dispatch(GET_CREDIT_CARDS);
} catch (error) { } catch (error) {

View File

@ -123,6 +123,7 @@ import EmptySearchResultIcon from '@/../static/images/common/emptySearchResult.s
import { ApiKey, ApiKeyOrderBy } from '@/types/apiKeys'; import { ApiKey, ApiKeyOrderBy } from '@/types/apiKeys';
import { SortDirection } from '@/types/common'; import { SortDirection } from '@/types/common';
import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames'; import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages'; import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
import ApiKeysCopyPopup from './ApiKeysCopyPopup.vue'; import ApiKeysCopyPopup from './ApiKeysCopyPopup.vue';
@ -179,6 +180,10 @@ export default class ApiKeysArea extends Vue {
public async mounted(): Promise<void> { public async mounted(): Promise<void> {
await this.$store.dispatch(FETCH, 1); await this.$store.dispatch(FETCH, 1);
this.$segment.track(SegmentEvent.API_KEYS_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
api_keys_count: this.selectedAPIKeysCount,
});
} }
public async beforeDestroy(): Promise<void> { public async beforeDestroy(): Promise<void> {
@ -220,6 +225,9 @@ export default class ApiKeysArea extends Vue {
try { try {
await this.$store.dispatch(DELETE); await this.$store.dispatch(DELETE);
await this.$notify.success(`API keys deleted successfully`); await this.$notify.success(`API keys deleted successfully`);
this.$segment.track(SegmentEvent.API_KEY_DELETED, {
project_id: this.$store.getters.selectedProject.id,
});
} catch (error) { } catch (error) {
await this.$notify.error(error.message); await this.$notify.error(error.message);
} }

View File

@ -35,6 +35,7 @@ import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
import { ApiKey } from '@/types/apiKeys'; import { ApiKey } from '@/types/apiKeys';
import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames'; import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
const CREATE = API_KEYS_ACTIONS.CREATE; const CREATE = API_KEYS_ACTIONS.CREATE;
@ -95,6 +96,10 @@ export default class ApiKeysCreationPopup extends Vue {
this.isLoading = false; this.isLoading = false;
this.name = ''; this.name = '';
this.$segment.track(SegmentEvent.API_KEY_CREATED, {
project_id: this.$store.getters.selectedProject.id,
});
try { try {
await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, this.FIRST_PAGE); await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, this.FIRST_PAGE);
} catch (error) { } catch (error) {

View File

@ -18,7 +18,7 @@
</div> </div>
<input <input
class="delete-project-input" class="delete-project-input"
type="text" type="text"
placeholder="Enter Project Name" placeholder="Enter Project Name"
v-model="projectName" v-model="projectName"
@keyup="resetError" @keyup="resetError"
@ -34,8 +34,8 @@
/> />
<VButton <VButton
label="Delete" label="Delete"
width="205px" width="205px"
height="48px" height="48px"
class="red" class="red"
:on-press="onDeleteProjectClick" :on-press="onDeleteProjectClick"
:is-disabled="isDeleteButtonDisabled" :is-disabled="isDeleteButtonDisabled"
@ -66,6 +66,7 @@ import {
APP_STATE_ACTIONS, APP_STATE_ACTIONS,
PM_ACTIONS, PM_ACTIONS,
} from '@/utils/constants/actionNames'; } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
@Component({ @Component({
components: { components: {
@ -97,7 +98,9 @@ export default class DeleteProjectPopup extends Vue {
try { try {
await this.$store.dispatch(PROJECTS_ACTIONS.DELETE, this.$store.getters.selectedProject.id); await this.$store.dispatch(PROJECTS_ACTIONS.DELETE, this.$store.getters.selectedProject.id);
this.$segment.track(SegmentEvent.PROJECT_DELETED, {
project_id: this.$store.getters.selectedProject.id,
});
await this.$notify.success('Project was successfully deleted'); await this.$notify.success('Project was successfully deleted');
await this.selectProject(); await this.selectProject();

View File

@ -70,6 +70,7 @@ import {
APP_STATE_ACTIONS, APP_STATE_ACTIONS,
PM_ACTIONS, PM_ACTIONS,
} from '@/utils/constants/actionNames'; } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
@Component({ @Component({
components: { components: {
@ -115,6 +116,9 @@ export default class NewProjectPopup extends Vue {
try { try {
const project = await this.createProject(); const project = await this.createProject();
this.createdProjectId = project.id; this.createdProjectId = project.id;
this.$segment.track(SegmentEvent.PROJECT_CREATED, {
project_id: this.createdProjectId,
});
} catch (e) { } catch (e) {
this.isLoading = false; this.isLoading = false;
await this.$notify.error(e.message); await this.$notify.error(e.message);

View File

@ -67,6 +67,7 @@ import { RouteConfig } from '@/router';
import { PROJECTS_ACTIONS } from '@/store/modules/projects'; import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { UpdateProjectModel } from '@/types/projects'; import { UpdateProjectModel } from '@/types/projects';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { LocalData } from '@/utils/localData'; import { LocalData } from '@/utils/localData';
@Component({ @Component({
@ -85,6 +86,9 @@ export default class ProjectDetailsArea extends Vue {
public async mounted(): Promise<void> { public async mounted(): Promise<void> {
try { try {
await this.$store.dispatch(PROJECTS_ACTIONS.FETCH); await this.$store.dispatch(PROJECTS_ACTIONS.FETCH);
this.$segment.track(SegmentEvent.PROJECT_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
});
} catch (error) { } catch (error) {
await this.$notify.error(error.message); await this.$notify.error(error.message);
} }

View File

@ -66,6 +66,7 @@ import DownloadReportIcon from '@/../static/images/project/downloadReport.svg';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { PROJECT_USAGE_ACTIONS } from '@/store/modules/usage'; import { PROJECT_USAGE_ACTIONS } from '@/store/modules/usage';
import { DateRange } from '@/types/usage'; import { DateRange } from '@/types/usage';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { DateFormat } from '@/utils/datepicker'; import { DateFormat } from '@/utils/datepicker';
import { toUnixTimestamp } from '@/utils/time'; import { toUnixTimestamp } from '@/utils/time';
@ -126,6 +127,11 @@ export default class UsageReport extends Vue {
public async mounted(): Promise<void> { public async mounted(): Promise<void> {
try { try {
this.$segment.track(SegmentEvent.REPORT_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_CURRENT_ROLLUP); await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_CURRENT_ROLLUP);
} catch (error) { } catch (error) {
await this.$notify.error(`Unable to fetch project usage. ${error.message}`); await this.$notify.error(`Unable to fetch project usage. ${error.message}`);
@ -156,6 +162,11 @@ export default class UsageReport extends Vue {
this.onButtonClickAction(event); this.onButtonClickAction(event);
try { try {
this.$segment.track(SegmentEvent.REPORT_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_CURRENT_ROLLUP); await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_CURRENT_ROLLUP);
} catch (error) { } catch (error) {
await this.$notify.error(`Unable to fetch project usage. ${error.message}`); await this.$notify.error(`Unable to fetch project usage. ${error.message}`);
@ -166,6 +177,11 @@ export default class UsageReport extends Vue {
this.onButtonClickAction(event); this.onButtonClickAction(event);
try { try {
this.$segment.track(SegmentEvent.REPORT_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_PREVIOUS_ROLLUP); await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH_PREVIOUS_ROLLUP);
} catch (error) { } catch (error) {
await this.$notify.error(`Unable to fetch project usage. ${error.message}`); await this.$notify.error(`Unable to fetch project usage. ${error.message}`);
@ -175,6 +191,11 @@ export default class UsageReport extends Vue {
public onCustomDateClick(event: any): void { public onCustomDateClick(event: any): void {
(this as any).$refs.datePicker.showCheck(); (this as any).$refs.datePicker.showCheck();
this.onButtonClickAction(event); this.onButtonClickAction(event);
this.$segment.track(SegmentEvent.REPORT_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
} }
public onReportClick(): void { public onReportClick(): void {
@ -189,6 +210,12 @@ export default class UsageReport extends Vue {
url.searchParams.append('since', toUnixTimestamp(startDate).toString()); url.searchParams.append('since', toUnixTimestamp(startDate).toString());
url.searchParams.append('before', toUnixTimestamp(endDate).toString()); url.searchParams.append('before', toUnixTimestamp(endDate).toString());
this.$segment.track(SegmentEvent.REPORT_DOWNLOADED, {
start_date: startDate,
end_date: endDate,
project_id: projectID,
});
window.open(url.href, '_blank'); window.open(url.href, '_blank');
} }

View File

@ -86,6 +86,7 @@ import DeleteFieldIcon from '@/../static/images/team/deleteField.svg';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { EmailInput } from '@/types/EmailInput'; import { EmailInput } from '@/types/EmailInput';
import { APP_STATE_ACTIONS, PM_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS, PM_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { validateEmail } from '@/utils/validation'; import { validateEmail } from '@/utils/validation';
@Component({ @Component({
@ -173,6 +174,11 @@ export default class AddUserPopup extends Vue {
return; return;
} }
this.$segment.track(SegmentEvent.TEAM_MEMBER_INVITED, {
project_id: this.$store.getters.selectedProject.id,
invited_emails: emailArray,
});
await this.$notify.success('Members successfully added to project!'); await this.$notify.success('Members successfully added to project!');
this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, ''); this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');

View File

@ -48,6 +48,7 @@ import EmptySearchResultIcon from '@/../static/images/common/emptySearchResult.s
import { SortDirection } from '@/types/common'; import { SortDirection } from '@/types/common';
import { ProjectMember, ProjectMemberHeaderState, ProjectMemberOrderBy } from '@/types/projectMembers'; import { ProjectMember, ProjectMemberHeaderState, ProjectMemberOrderBy } from '@/types/projectMembers';
import { PM_ACTIONS } from '@/utils/constants/actionNames'; import { PM_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
const { const {
FETCH, FETCH,
@ -82,6 +83,10 @@ export default class ProjectMembersArea extends Vue {
public async mounted(): Promise<void> { public async mounted(): Promise<void> {
await this.$store.dispatch(FETCH, 1); await this.$store.dispatch(FETCH, 1);
this.$segment.track(SegmentEvent.TEAM_VIEWED, {
project_id: this.$store.getters.selectedProject.id,
team_member_count: this.projectMembersTotalCount,
});
} }
public onMemberClick(member: ProjectMember): void { public onMemberClick(member: ProjectMember): void {

View File

@ -2,7 +2,20 @@
// See LICENSE for copying information. // See LICENSE for copying information.
export enum SegmentEvent { export enum SegmentEvent {
CLICKED_LOGO = 'clicked-on-logo', PROJECT_CREATED= 'Project Created',
CLICKED_LOGIN = 'clicked-on-login', PROJECT_DELETED= 'Project Deleted',
CLICKED_BACK_TO_LOGIN = 'clicked-on-back-to-login', PROJECT_VIEWED= 'Project Viewed',
USER_DELETED= 'User Deleted',
USER_LOGGED_IN= 'User Logged In',
EMAIL_VERIFIED= 'Email Verified',
API_KEY_CREATED= 'API Key Created',
API_KEY_DELETED= 'API Key Deleted',
API_KEYS_VIEWED= 'API Key Viewed',
PAYMENT_METHODS_VIEWED= 'Payment Methods Viewed',
PAYMENT_METHOD_ADDED= 'Payment Method Added',
REPORT_DOWNLOADED= 'Report Downloaded',
REPORT_VIEWED= 'Report Viewed',
BILLING_HISTORY_VIEWED= 'Billing History Viewed',
TEAM_MEMBER_INVITED= 'Team Member Invited',
TEAM_VIEWED= 'Team Viewed',
} }

View File

@ -9,7 +9,7 @@ import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
* Segmentio is a wrapper around segment.io analytics package * Segmentio is a wrapper around segment.io analytics package
*/ */
export class Segmentio { export class Segmentio {
analytics: SegmentAnalytics.AnalyticsJS; private analytics: SegmentAnalytics.AnalyticsJS;
public init(key: string) { public init(key: string) {
if (this.analytics || key.length === 0 || key.includes('SegmentIOPublicKey')) { if (this.analytics || key.length === 0 || key.includes('SegmentIOPublicKey')) {
return; return;
@ -34,12 +34,12 @@ export class Segmentio {
this.analytics.page(); this.analytics.page();
} }
public identify() { public identify(userId: string, traits?: Object, options?: SegmentAnalytics.SegmentOpts, callback?: () => void) {
if (!this.analytics) { if (!this.analytics) {
return; return;
} }
this.analytics.identify(); this.analytics.identify(userId, traits, options, callback);
} }
public track(event: SegmentEvent, properties?: Object, options?: SegmentAnalytics.SegmentOpts, callback?: () => void) { public track(event: SegmentEvent, properties?: Object, options?: SegmentAnalytics.SegmentOpts, callback?: () => void) {

View File

@ -13,6 +13,7 @@ import LogoIcon from '@/../static/images/Logo.svg';
import { AuthHttpApi } from '@/api/auth'; import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { LOADING_CLASSES } from '@/utils/constants/classConstants'; import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { validateEmail } from '@/utils/validation'; import { validateEmail } from '@/utils/validation';
@ -51,11 +52,11 @@ export default class ForgotPassword extends Vue {
} }
public onBackToLoginClick(): void { public onBackToLoginClick(): void {
this.$router.push(RouteConfig.Login.path); this.$router.push(RouteConfig.Login.path);
} }
public onLogoClick(): void { public onLogoClick(): void {
location.reload(); location.reload();
} }
private validateFields(): boolean { private validateFields(): boolean {

View File

@ -16,6 +16,7 @@ import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { AuthToken } from '@/utils/authToken'; import { AuthToken } from '@/utils/authToken';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { AppState } from '@/utils/constants/appStateEnum'; import { AppState } from '@/utils/constants/appStateEnum';
import { LOADING_CLASSES } from '@/utils/constants/classConstants'; import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { validateEmail, validatePassword } from '@/utils/validation'; import { validateEmail, validatePassword } from '@/utils/validation';
@ -78,6 +79,9 @@ export default class Login extends Vue {
try { try {
this.authToken = await this.auth.token(this.email, this.password); this.authToken = await this.auth.token(this.email, this.password);
AuthToken.set(this.authToken); AuthToken.set(this.authToken);
this.$segment.track(SegmentEvent.USER_LOGGED_IN, {
email: this.email,
});
} catch (error) { } catch (error) {
await this.$notify.error(error.message); await this.$notify.error(error.message);
this.isLoading = false; this.isLoading = false;

View File

@ -17,6 +17,7 @@ import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { User } from '@/types/users'; import { User } from '@/types/users';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { LOADING_CLASSES } from '@/utils/constants/classConstants'; import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { LocalData } from '@/utils/localData'; import { LocalData } from '@/utils/localData';
import { validateEmail, validatePassword } from '@/utils/validation'; import { validateEmail, validatePassword } from '@/utils/validation';
@ -176,6 +177,11 @@ export default class RegisterArea extends Vue {
LocalData.setUserId(this.userId); LocalData.setUserId(this.userId);
this.$segment.identify(this.userId, {
email: this.$store.getters.user.email,
referralToken: this.referralToken,
});
// TODO: improve it // TODO: improve it
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SUCCESSFUL_REGISTRATION_POPUP); this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SUCCESSFUL_REGISTRATION_POPUP);
const registrationSuccessPopupRef = this.$refs['register_success_popup']; const registrationSuccessPopupRef = this.$refs['register_success_popup'];

View File

@ -10,13 +10,16 @@ import { makeNotificationsModule } from '@/store/modules/notifications';
import { makeProjectsModule } from '@/store/modules/projects'; import { makeProjectsModule } from '@/store/modules/projects';
import { ApiKey, ApiKeysPage } from '@/types/apiKeys'; import { ApiKey, ApiKeysPage } from '@/types/apiKeys';
import { Project } from '@/types/projects'; import { Project } from '@/types/projects';
import { SegmentioPlugin } from '@/utils/plugins/segment';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { ApiKeysMock } from '../mock/api/apiKeys'; import { ApiKeysMock } from '../mock/api/apiKeys';
import { ProjectsApiMock } from '../mock/api/projects'; import { ProjectsApiMock } from '../mock/api/projects';
const localVue = createLocalVue(); const localVue = createLocalVue();
const segmentioPlugin = new SegmentioPlugin();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(segmentioPlugin);
const apiKeysApi = new ApiKeysMock(); const apiKeysApi = new ApiKeysMock();
const apiKeysModule = makeApiKeysModule(apiKeysApi); const apiKeysModule = makeApiKeysModule(apiKeysApi);

View File

@ -14,12 +14,15 @@ import { ApiKey } from '@/types/apiKeys';
import { Project } from '@/types/projects'; import { Project } from '@/types/projects';
import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames'; import { API_KEYS_ACTIONS } from '@/utils/constants/actionNames';
import { NotificatorPlugin } from '@/utils/plugins/notificator'; import { NotificatorPlugin } from '@/utils/plugins/notificator';
import { SegmentioPlugin } from '@/utils/plugins/segment';
import { createLocalVue, mount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
const notificationPlugin = new NotificatorPlugin(); const notificationPlugin = new NotificatorPlugin();
const segmentioPlugin = new SegmentioPlugin();
localVue.use(notificationPlugin); localVue.use(notificationPlugin);
localVue.use(segmentioPlugin);
const apiKeysApi = new ApiKeysApiGql(); const apiKeysApi = new ApiKeysApiGql();
const apiKeysModule = makeApiKeysModule(apiKeysApi); const apiKeysModule = makeApiKeysModule(apiKeysApi);
const projectsApi = new ProjectsApiGql(); const projectsApi = new ProjectsApiGql();

View File

@ -10,13 +10,16 @@ import { makeProjectMembersModule, PROJECT_MEMBER_MUTATIONS } from '@/store/modu
import { makeProjectsModule } from '@/store/modules/projects'; import { makeProjectsModule } from '@/store/modules/projects';
import { ProjectMember, ProjectMembersPage } from '@/types/projectMembers'; import { ProjectMember, ProjectMembersPage } from '@/types/projectMembers';
import { Project } from '@/types/projects'; import { Project } from '@/types/projects';
import { SegmentioPlugin } from '@/utils/plugins/segment';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { ProjectMembersApiMock } from '../mock/api/projectMembers'; import { ProjectMembersApiMock } from '../mock/api/projectMembers';
import { ProjectsApiMock } from '../mock/api/projects'; import { ProjectsApiMock } from '../mock/api/projects';
const localVue = createLocalVue(); const localVue = createLocalVue();
const segmentioPlugin = new SegmentioPlugin();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(segmentioPlugin);
const pmApi = new ProjectMembersApiMock(); const pmApi = new ProjectMembersApiMock();
const projectMembersModule = makeProjectMembersModule(pmApi); const projectMembersModule = makeProjectMembersModule(pmApi);