diff --git a/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.spec.ts b/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.spec.ts new file mode 100644 index 000000000000..9e70d0cde700 --- /dev/null +++ b/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.spec.ts @@ -0,0 +1,50 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { expectSaga } from "redux-saga-test-plan"; +import sinon from "sinon"; +import Analytics from "analytics-node"; + +import { signUpEmailSubscription } from "./customAnalyticsSagas"; +import { + completeEmailSubscriptionSignUp, + signUpForEmailSubscription, +} from "./customAnanlyticsActions"; + +const sandbox = sinon.createSandbox(); + +describe("customAnalyticsSagas", () => { + describe("signUpEmailSubscription generator", () => { + afterEach(() => { + sandbox.reset(); + }); + + it("calls analytics#identify with user email in args ", () => { + const analyticsIdentifyFn = sandbox.stub(Analytics.prototype, "identify"); + const clusterId = "cluster-1"; + const email = "foo@bar.com"; + const action = signUpForEmailSubscription(clusterId, email); + + return expectSaga(signUpEmailSubscription, action) + .put(completeEmailSubscriptionSignUp()) + .dispatch(action) + .run() + .then(() => { + const expectedAnalyticsMessage = { + userId: clusterId, + traits: { + email, + }, + }; + analyticsIdentifyFn.calledOnceWith(expectedAnalyticsMessage); + }); + }); + }); +}); diff --git a/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.ts b/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.ts new file mode 100644 index 000000000000..1ced91ad9dad --- /dev/null +++ b/pkg/ui/src/redux/customAnalytics/customAnalyticsSagas.ts @@ -0,0 +1,54 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { call, put, takeEvery } from "redux-saga/effects"; +import Analytics from "analytics-node"; + +import { PayloadAction } from "src/interfaces/action"; +import { COCKROACHLABS_ADDR } from "src/util/cockroachlabsAPI"; +import { + completeEmailSubscriptionSignUp, + EMAIL_SUBSCRIPTION_SIGN_UP, + EmailSubscriptionSignUpPayload, +} from "./customAnanlyticsActions"; + +export type AnalyticsClientTarget = "email_sign_up"; + +// TODO (koorosh): has to be moved out from code base +const EMAIL_SIGN_UP_CLIENT_KEY = "72EEC0nqQKfoLWq0ZcGoTkJFIG9G9SII"; + +const analyticsOpts = { + host: COCKROACHLABS_ADDR + "/api/segment", +}; + +export function getAnalyticsClientFor(target: AnalyticsClientTarget): Analytics { + switch (target) { + case "email_sign_up": + return new Analytics(EMAIL_SIGN_UP_CLIENT_KEY, analyticsOpts); + default: + throw new Error("Unrecognized Analytics Client target."); + } +} + +export function* signUpEmailSubscription(action: PayloadAction) { + const client = getAnalyticsClientFor("email_sign_up"); + const { clusterId, email } = action.payload; + yield call([client, client.identify], { + userId: clusterId, + traits: { + email, + }, + }); + yield put(completeEmailSubscriptionSignUp()); +} + +export function* customAnalyticsSaga() { + yield takeEvery(EMAIL_SUBSCRIPTION_SIGN_UP, signUpEmailSubscription); +} diff --git a/pkg/ui/src/redux/customAnalytics/customAnanlyticsActions.ts b/pkg/ui/src/redux/customAnalytics/customAnanlyticsActions.ts new file mode 100644 index 000000000000..38631b237fbc --- /dev/null +++ b/pkg/ui/src/redux/customAnalytics/customAnanlyticsActions.ts @@ -0,0 +1,37 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { Action } from "redux"; + +import { PayloadAction } from "src/interfaces/action"; + +export const EMAIL_SUBSCRIPTION_SIGN_UP = "cockroachui/customanalytics/EMAIL_SUBSCRIPTION_SIGN_UP"; +export const EMAIL_SUBSCRIPTION_SIGN_UP_COMPLETE = "cockroachui/customanalytics/EMAIL_SUBSCRIPTION_SIGN_UP_COMPLETE"; + +export type EmailSubscriptionSignUpPayload = { + email: string; + clusterId: string; +}; + +export function signUpForEmailSubscription(clusterId: string, email: string): PayloadAction { + return { + type: EMAIL_SUBSCRIPTION_SIGN_UP, + payload: { + email, + clusterId, + }, + }; +} + +export function completeEmailSubscriptionSignUp(): Action { + return { + type: EMAIL_SUBSCRIPTION_SIGN_UP_COMPLETE, + }; +} diff --git a/pkg/ui/src/redux/customAnalytics/index.ts b/pkg/ui/src/redux/customAnalytics/index.ts new file mode 100644 index 000000000000..a6ad48640fd2 --- /dev/null +++ b/pkg/ui/src/redux/customAnalytics/index.ts @@ -0,0 +1,12 @@ +// Copyright 2020 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +export * from "./customAnalyticsSagas"; +export * from "./customAnanlyticsActions"; diff --git a/pkg/ui/src/redux/sagas.ts b/pkg/ui/src/redux/sagas.ts index eaeb6001774c..7dd5610e6724 100644 --- a/pkg/ui/src/redux/sagas.ts +++ b/pkg/ui/src/redux/sagas.ts @@ -12,10 +12,12 @@ import { all, fork } from "redux-saga/effects"; import { queryMetricsSaga } from "./metrics"; import { localSettingsSaga } from "./localsettings"; +import { customAnalyticsSaga } from "./customAnalytics"; export default function* rootSaga() { yield all([ fork(queryMetricsSaga), fork(localSettingsSaga), + fork(customAnalyticsSaga), ]); }