Переглянути джерело

fix(calendar): show error message if authorization fails on event fetch

j8
Leonard Kim 6 роки тому
джерело
коміт
7a2c465c4a

+ 7
- 1
css/_meetings_list.scss Переглянути файл

@@ -29,13 +29,19 @@
29 29
         background: #0074E0;
30 30
         border-radius: 4px;
31 31
         color: #FFFFFF;
32
-        display: flex;
32
+        display: inline-block;
33 33
         justify-content: center;
34 34
         align-items: center;
35 35
         padding: 5px 10px;
36 36
         cursor: pointer;
37 37
     }
38 38
 
39
+    .calendar-action-buttons {
40
+        .button {
41
+            margin: 0px 10px;
42
+        }
43
+    }
44
+
39 45
     .item {
40 46
         background: rgba(255,255,255,0.50);
41 47
         box-sizing: border-box;

+ 5
- 0
lang/main.json Переглянути файл

@@ -662,6 +662,11 @@
662 662
         "addMeetingURL": "Add a meeting link",
663 663
         "confirmAddLink": "Do you want to add a Jitsi link to this event?",
664 664
         "confirmAddLinkTitle": "Calendar",
665
+        "error": {
666
+            "appConfiguration": "Calendar integration is not properly configured.",
667
+            "generic": "An error has occurred. Please check your calendar settings or try refreshing the calendar.",
668
+            "notSignedIn": "An error occurred while authenticating to see calendar events. Please check your calendar settings and try logging in again."
669
+        },
665 670
         "join": "Join",
666 671
         "joinTooltip": "Join the meeting",
667 672
         "nextMeeting": "next meeting",

+ 11
- 0
react/features/calendar-sync/actionTypes.js Переглянути файл

@@ -33,6 +33,17 @@ export const REFRESH_CALENDAR = Symbol('REFRESH_CALENDAR');
33 33
  */
34 34
 export const SET_CALENDAR_AUTHORIZATION = Symbol('SET_CALENDAR_AUTHORIZATION');
35 35
 
36
+/**
37
+ * Action to update the last error that occurred while trying to authenticate
38
+ * with or fetch data from the calendar integration.
39
+ *
40
+ * {
41
+ *     type: SET_CALENDAR_ERROR,
42
+ *     error: ?Object
43
+ * }
44
+ */
45
+export const SET_CALENDAR_ERROR = Symbol('SET_CALENDAR_ERROR');
46
+
36 47
 /**
37 48
  * Action to update the current calendar entry list in the store.
38 49
  *

+ 17
- 0
react/features/calendar-sync/actions.web.js Переглянути файл

@@ -8,6 +8,7 @@ import { createCalendarConnectedEvent, sendAnalytics } from '../analytics';
8 8
 import {
9 9
     CLEAR_CALENDAR_INTEGRATION,
10 10
     SET_CALENDAR_AUTH_STATE,
11
+    SET_CALENDAR_ERROR,
11 12
     SET_CALENDAR_INTEGRATION,
12 13
     SET_CALENDAR_PROFILE_EMAIL,
13 14
     SET_LOADING_CALENDAR_EVENTS
@@ -119,6 +120,22 @@ export function setCalendarAPIAuthState(newState: ?Object) {
119 120
     };
120 121
 }
121 122
 
123
+/**
124
+ * Sends an action to update the calendar error state in redux.
125
+ *
126
+ * @param {Object} error - An object with error details.
127
+ * @returns {{
128
+ *     type: SET_CALENDAR_ERROR,
129
+ *     error: Object
130
+ * }}
131
+ */
132
+export function setCalendarError(error: ?Object) {
133
+    return {
134
+        type: SET_CALENDAR_ERROR,
135
+        error
136
+    };
137
+}
138
+
122 139
 /**
123 140
  * Sends an action to update the current calendar profile email state in redux.
124 141
  *

+ 70
- 3
react/features/calendar-sync/components/CalendarList.web.js Переглянути файл

@@ -13,6 +13,7 @@ import {
13 13
 } from '../../analytics';
14 14
 
15 15
 import { refreshCalendar } from '../actions';
16
+import { ERRORS } from '../constants';
16 17
 import { isCalendarEnabled } from '../functions';
17 18
 
18 19
 import CalendarListContent from './CalendarListContent';
@@ -24,6 +25,12 @@ declare var interfaceConfig: Object;
24 25
  */
25 26
 type Props = {
26 27
 
28
+    /**
29
+     * The error object containing details about any error that has occurred
30
+     * while interacting with calendar integration.
31
+     */
32
+    _calendarError: ?Object,
33
+
27 34
     /**
28 35
      * Whether or not a calendar may be connected for fetching calendar events.
29 36
      */
@@ -87,6 +94,54 @@ class CalendarList extends AbstractPage<Props> {
87 94
         );
88 95
     }
89 96
 
97
+    /**
98
+     * Returns a component for showing the error message related to calendar
99
+     * sync.
100
+     *
101
+     * @private
102
+     * @returns {React$Component}
103
+     */
104
+    _getErrorMessage() {
105
+        const { _calendarError = {}, t } = this.props;
106
+
107
+        let errorMessageKey = 'calendarSync.error.generic';
108
+        let showRefreshButton = true;
109
+        let showSettingsButton = true;
110
+
111
+        if (_calendarError.error === ERRORS.GOOGLE_APP_MISCONFIGURED) {
112
+            errorMessageKey = 'calendarSync.error.appConfiguration';
113
+            showRefreshButton = false;
114
+            showSettingsButton = false;
115
+        } else if (_calendarError.error === ERRORS.AUTH_FAILED) {
116
+            errorMessageKey = 'calendarSync.error.notSignedIn';
117
+            showRefreshButton = false;
118
+        }
119
+
120
+        return (
121
+            <div className = 'meetings-list-empty'>
122
+                <p className = 'description'>
123
+                    { t(errorMessageKey) }
124
+                </p>
125
+                <div className = 'calendar-action-buttons'>
126
+                    { showSettingsButton
127
+                        && <div
128
+                            className = 'button'
129
+                            onClick = { this._onOpenSettings }>
130
+                            { t('calendarSync.permissionButton') }
131
+                        </div>
132
+                    }
133
+                    { showRefreshButton
134
+                        && <div
135
+                            className = 'button'
136
+                            onClick = { this._onRefreshEvents }>
137
+                            { t('calendarSync.refresh') }
138
+                        </div>
139
+                    }
140
+                </div>
141
+            </div>
142
+        );
143
+    }
144
+
90 145
     _getRenderListEmptyComponent: () => Object;
91 146
 
92 147
     /**
@@ -97,12 +152,21 @@ class CalendarList extends AbstractPage<Props> {
97 152
      * @returns {React$Component}
98 153
      */
99 154
     _getRenderListEmptyComponent() {
100
-        const { _hasIntegrationSelected, _hasLoadedEvents, t } = this.props;
155
+        const {
156
+            _calendarError,
157
+            _hasIntegrationSelected,
158
+            _hasLoadedEvents,
159
+            t
160
+        } = this.props;
101 161
 
102
-        if (_hasIntegrationSelected && _hasLoadedEvents) {
162
+        if (_calendarError) {
163
+            return this._getErrorMessage();
164
+        } else if (_hasIntegrationSelected && _hasLoadedEvents) {
103 165
             return (
104 166
                 <div className = 'meetings-list-empty'>
105
-                    <div>{ t('calendarSync.noEvents') }</div>
167
+                    <p className = 'description'>
168
+                        { t('calendarSync.noEvents') }
169
+                    </p>
106 170
                     <div
107 171
                         className = 'button'
108 172
                         onClick = { this._onRefreshEvents }>
@@ -172,18 +236,21 @@ class CalendarList extends AbstractPage<Props> {
172 236
  * @param {Object} state - The Redux state.
173 237
  * @private
174 238
  * @returns {{
239
+ *     _calendarError: Object,
175 240
  *     _hasIntegrationSelected: boolean,
176 241
  *     _hasLoadedEvents: boolean
177 242
  * }}
178 243
  */
179 244
 function _mapStateToProps(state) {
180 245
     const {
246
+        error,
181 247
         events,
182 248
         integrationType,
183 249
         isLoadingEvents
184 250
     } = state['features/calendar-sync'];
185 251
 
186 252
     return {
253
+        _calendarError: error,
187 254
         _hasIntegrationSelected: Boolean(integrationType),
188 255
         _hasLoadedEvents: Boolean(events) || !isLoadingEvents
189 256
     };

+ 11
- 0
react/features/calendar-sync/constants.js Переглянути файл

@@ -10,6 +10,17 @@ export const CALENDAR_TYPE = {
10 10
     MICROSOFT: 'microsoft'
11 11
 };
12 12
 
13
+/**
14
+ * An enumeration of known errors that can occur while interacting with the
15
+ * calendar integration.
16
+ *
17
+ * @enum {string}
18
+ */
19
+export const ERRORS = {
20
+    AUTH_FAILED: 'sign_in_failed',
21
+    GOOGLE_APP_MISCONFIGURED: 'idpiframe_initialization_failed'
22
+};
23
+
13 24
 /**
14 25
  * The number of days to fetch.
15 26
  */

+ 20
- 4
react/features/calendar-sync/functions.web.js Переглянути файл

@@ -1,10 +1,15 @@
1 1
 // @flow
2 2
 
3
-import { setLoadingCalendarEvents } from './actions';
3
+import {
4
+    clearCalendarIntegration,
5
+    setCalendarError,
6
+    setLoadingCalendarEvents
7
+} from './actions';
4 8
 export * from './functions.any';
5 9
 
6 10
 import {
7 11
     CALENDAR_TYPE,
12
+    ERRORS,
8 13
     FETCH_END_DAYS,
9 14
     FETCH_START_DAYS
10 15
 } from './constants';
@@ -66,7 +71,9 @@ export function _fetchCalendarEntries(
66 71
                 return Promise.resolve();
67 72
             }
68 73
 
69
-            return Promise.reject('Not authorized, please sign in!');
74
+            return Promise.reject({
75
+                error: ERRORS.AUTH_FAILED
76
+            });
70 77
         })
71 78
         .then(() => dispatch(integration.getCalendarEntries(
72 79
             FETCH_START_DAYS, FETCH_END_DAYS)))
@@ -74,8 +81,17 @@ export function _fetchCalendarEntries(
74 81
             dispatch,
75 82
             getState
76 83
         }, events))
77
-        .catch(error =>
78
-            logger.error('Error fetching calendar.', error))
84
+        .then(() => {
85
+            dispatch(setCalendarError());
86
+        }, error => {
87
+            logger.error('Error fetching calendar.', error);
88
+
89
+            if (error.error === ERRORS.AUTH_FAILED) {
90
+                dispatch(clearCalendarIntegration());
91
+            }
92
+
93
+            dispatch(setCalendarError(error));
94
+        })
79 95
         .then(() => dispatch(setLoadingCalendarEvents(false)));
80 96
 }
81 97
 

+ 4
- 0
react/features/calendar-sync/reducer.js Переглянути файл

@@ -8,6 +8,7 @@ import {
8 8
     CLEAR_CALENDAR_INTEGRATION,
9 9
     SET_CALENDAR_AUTH_STATE,
10 10
     SET_CALENDAR_AUTHORIZATION,
11
+    SET_CALENDAR_ERROR,
11 12
     SET_CALENDAR_EVENTS,
12 13
     SET_CALENDAR_INTEGRATION,
13 14
     SET_CALENDAR_PROFILE_EMAIL,
@@ -86,6 +87,9 @@ isCalendarEnabled()
86 87
         case SET_CALENDAR_AUTHORIZATION:
87 88
             return set(state, 'authorization', action.authorization);
88 89
 
90
+        case SET_CALENDAR_ERROR:
91
+            return set(state, 'error', action.error);
92
+
89 93
         case SET_CALENDAR_EVENTS:
90 94
             return set(state, 'events', action.events);
91 95
 

Завантаження…
Відмінити
Зберегти