ソースを参照

feat(invite): add basic analytics for AddPeople dialog (#2641)

* feat(invite): add basic analytics for AddPeople dialog

Analytics for opening the dialog, closing the dialog, the
count of invites sent, and the count of invites errored.

* squash: fix typo, change default count init, remove extra analytics param
master
virtuacoplenny 7年前
コミット
83f47c2df1

+ 10
- 5
react/features/analytics/AnalyticsEvents.js ファイルの表示

@@ -129,16 +129,21 @@ export function createFeedbackOpenEvent() {
129 129
 }
130 130
 
131 131
 /**
132
- * Creates an event which indicates that the invite dialog was closed. This is
133
- * not a TYPE_UI event, since it is not necessarily the result of a user
134
- * interaction.
132
+ * Creates an event for an action regarding the AddPeopleDialog (invites).
135 133
  *
134
+ * @param {string} action - The action that the event represents.
135
+ * @param {string} actionSubject - The subject that was acted upon.
136
+ * @param {boolean} attributes - Additional attributes to attach to the event.
136 137
  * @returns {Object} The event in a format suitable for sending via
137 138
  * sendAnalytics.
138 139
  */
139
-export function createInviteDialogClosedEvent() {
140
+export function createInviteDialogEvent(
141
+        action, actionSubject, attributes = {}) {
140 142
     return {
141
-        action: 'invite.dialog.closed'
143
+        action,
144
+        actionSubject,
145
+        attributes,
146
+        source: 'inviteDialog'
142 147
     };
143 148
 }
144 149
 

+ 68
- 1
react/features/invite/components/AddPeopleDialog.web.js ファイルの表示

@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
6 6
 import React, { Component } from 'react';
7 7
 import { connect } from 'react-redux';
8 8
 
9
+import { createInviteDialogEvent, sendAnalytics } from '../../analytics';
9 10
 import { getInviteURL } from '../../base/connection';
10 11
 import { Dialog, hideDialog } from '../../base/dialog';
11 12
 import { translate } from '../../base/i18n';
@@ -143,6 +144,17 @@ class AddPeopleDialog extends Component<*, *> {
143 144
         };
144 145
     }
145 146
 
147
+    /**
148
+     * Sends an analytics event to record the dialog has been shown.
149
+     *
150
+     * @inheritdoc
151
+     * @returns {void}
152
+     */
153
+    componentDidMount() {
154
+        sendAnalytics(createInviteDialogEvent(
155
+            'invite.dialog.opened', 'dialog'));
156
+    }
157
+
146 158
     /**
147 159
      * React Component method that executes once component is updated.
148 160
      *
@@ -162,6 +174,17 @@ class AddPeopleDialog extends Component<*, *> {
162 174
         }
163 175
     }
164 176
 
177
+    /**
178
+     * Sends an analytics event to record the dialog has been closed.
179
+     *
180
+     * @inheritdoc
181
+     * @returns {void}
182
+     */
183
+    componentWillUnmount() {
184
+        sendAnalytics(createInviteDialogEvent(
185
+            'invite.dialog.closed', 'dialog'));
186
+    }
187
+
165 188
     /**
166 189
      * Renders the content of this component.
167 190
      *
@@ -231,6 +254,32 @@ class AddPeopleDialog extends Component<*, *> {
231 254
         return text.replace(/\D/g, '');
232 255
     }
233 256
 
257
+    /**
258
+     * Helper for determining how many of each type of user is being invited.
259
+     * Used for logging and sending analytics related to invites.
260
+     *
261
+     * @param {Array} inviteItems - An array with the invite items, as created
262
+     * in {@link _parseQueryResults}.
263
+     * @private
264
+     * @returns {Object} An object with keys as user types and values as the
265
+     * number of invites for that type.
266
+     */
267
+    _getInviteTypeCounts(inviteItems = []) {
268
+        const inviteTypeCounts = {};
269
+
270
+        inviteItems.forEach(i => {
271
+            const type = i.item.type;
272
+
273
+            if (!inviteTypeCounts[type]) {
274
+                inviteTypeCounts[type] = 0;
275
+            }
276
+
277
+            inviteTypeCounts[type]++;
278
+        });
279
+
280
+        return inviteTypeCounts;
281
+    }
282
+
234 283
     _isAddDisabled: () => boolean;
235 284
 
236 285
     /**
@@ -313,6 +362,15 @@ class AddPeopleDialog extends Component<*, *> {
313 362
      * @returns {void}
314 363
      */
315 364
     _onSubmit() {
365
+        const inviteTypeCounts
366
+            = this._getInviteTypeCounts(this.state.inviteItems);
367
+
368
+        sendAnalytics(createInviteDialogEvent(
369
+            'clicked', 'inviteButton', {
370
+                ...inviteTypeCounts,
371
+                inviteAllowed: this._isAddDisabled()
372
+            }));
373
+
316 374
         if (this._isAddDisabled()) {
317 375
             return;
318 376
         }
@@ -393,7 +451,16 @@ class AddPeopleDialog extends Component<*, *> {
393 451
                 // If any invites are left that means something failed to send
394 452
                 // so treat it as an error.
395 453
                 if (invitesLeftToSend.length) {
396
-                    logger.error(`${invitesLeftToSend.length} invites failed`);
454
+                    const erroredInviteTypeCounts
455
+                        = this._getInviteTypeCounts(invitesLeftToSend);
456
+
457
+                    logger.error(`${invitesLeftToSend.length} invites failed`,
458
+                        erroredInviteTypeCounts);
459
+
460
+                    sendAnalytics(createInviteDialogEvent(
461
+                        'error', 'invite', {
462
+                            ...erroredInviteTypeCounts
463
+                        }));
397 464
 
398 465
                     this.setState({
399 466
                         addToCallInProgress: false,

読み込み中…
キャンセル
保存