Skip to content

Commit 7b6385e

Browse files
committed
Handle subscription errors more clearly
1 parent b4f4aa1 commit 7b6385e

File tree

3 files changed

+77
-45
lines changed

3 files changed

+77
-45
lines changed

packages/app/src/app/overmind/internalActions.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,46 @@ export const closeTabByIndex: Action<number> = ({ state }, tabIndex) => {
340340
state.editor.tabs.splice(tabIndex, 1);
341341
};
342342

343+
export const getErrorMessage: Action<{ error: ApiError | Error }, string> = (
344+
context,
345+
{ error }
346+
) => {
347+
const isGenericError = !('response' in error) || error.response.status >= 500;
348+
349+
if (isGenericError) {
350+
return error.message;
351+
}
352+
353+
const { response } = error as ApiError;
354+
/*
355+
Update error message with what is coming from the server
356+
*/
357+
const result = response.data;
358+
359+
if (result) {
360+
if (typeof result === 'string') {
361+
return result;
362+
}
363+
if ('errors' in result) {
364+
const errors = values(result.errors)[0];
365+
const fields = Object.keys(result.errors);
366+
if (Array.isArray(errors)) {
367+
if (errors[0]) {
368+
return `${fields[0]}: ${errors[0]}`; // eslint-disable-line no-param-reassign,prefer-destructuring
369+
}
370+
} else {
371+
return errors; // eslint-disable-line no-param-reassign
372+
}
373+
} else if (result.error) {
374+
return result.error; // eslint-disable-line no-param-reassign
375+
} else if (response.status === 413) {
376+
return 'File too large, upload limit is 5MB.';
377+
}
378+
}
379+
380+
return error.message;
381+
};
382+
343383
export const handleError: Action<{
344384
/*
345385
The message that will show as title of the notification
@@ -386,30 +426,7 @@ export const handleError: Action<{
386426
return;
387427
}
388428

389-
/*
390-
Update error message with what is coming from the server
391-
*/
392-
const result = response.data;
393-
394-
if (result) {
395-
if (typeof result === 'string') {
396-
error.message = result;
397-
} else if ('errors' in result) {
398-
const errors = values(result.errors)[0];
399-
const fields = Object.keys(result.errors);
400-
if (Array.isArray(errors)) {
401-
if (errors[0]) {
402-
error.message = `${fields[0]}: ${errors[0]}`; // eslint-disable-line no-param-reassign,prefer-destructuring
403-
}
404-
} else {
405-
error.message = errors; // eslint-disable-line no-param-reassign
406-
}
407-
} else if (result.error) {
408-
error.message = result.error; // eslint-disable-line no-param-reassign
409-
} else if (response.status === 413) {
410-
error.message = 'File too large, upload limit is 5MB.';
411-
}
412-
}
429+
error.message = actions.internal.getErrorMessage({ error });
413430

414431
const notificationActions = {
415432
primary: [],

packages/app/src/app/overmind/namespaces/patron/actions.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const priceChanged: Action<{ price: number }> = (
1414
export const createSubscriptionClicked: AsyncAction<{
1515
token: string;
1616
coupon: string;
17-
}> = async ({ state, effects }, { token, coupon }) => {
17+
}> = async ({ state, effects, actions }, { token, coupon }) => {
1818
effects.analytics.track('Create Patron Subscription');
1919
state.patron.error = null;
2020
state.patron.isUpdatingSubscription = true;
@@ -32,17 +32,28 @@ export const createSubscriptionClicked: AsyncAction<{
3232
) {
3333
try {
3434
await effects.stripe.handleCardPayment(error.data.client_secret);
35-
3635
state.user = await effects.api.getCurrentUser();
3736
state.patron.error = null;
3837
} catch (e) {
38+
actions.internal.handleError({
39+
message: 'Could not create subscription',
40+
error: e,
41+
});
42+
3943
state.patron.error = e.message;
44+
4045
effects.analytics.track('Create Subscription Error', {
4146
error: e.message,
4247
});
4348
}
4449
} else {
50+
actions.internal.handleError({
51+
message: 'Could not create subscription',
52+
error,
53+
});
54+
4555
state.patron.error = error.message;
56+
4657
effects.analytics.track('Create Subscription Error', {
4758
error: error.message,
4859
});

packages/common/src/utils/analytics/amplitude.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ const markLastTimeEventSent = () => {
1818
localStorage.setItem('csb-last-event-sent', Date.now().toString());
1919
};
2020

21-
const amplitudePromise = async () => {
21+
const getAmplitude = async (): Promise<any | false> => {
22+
if (process.env.NODE_ENV !== 'production') {
23+
return false;
24+
}
25+
2226
for (let i = 0; i < 10; i++) {
2327
if (
2428
typeof global.amplitude !== 'undefined' &&
2529
global.amplitude.getInstance()._storageSuffix
2630
) {
27-
return true;
31+
return global.amplitude;
2832
}
2933

3034
// eslint-disable-next-line no-await-in-loop
@@ -35,59 +39,59 @@ const amplitudePromise = async () => {
3539
};
3640

3741
export const identify = async (key: string, value: any) => {
38-
await amplitudePromise();
39-
if (typeof global.amplitude !== 'undefined') {
40-
const identity = new global.amplitude.Identify();
42+
const amplitude = await getAmplitude();
43+
if (amplitude) {
44+
const identity = new amplitude.Identify();
4145
identity.set(key, value);
42-
global.amplitude.identify(identity);
46+
amplitude.identify(identity);
4347
debug('[Amplitude] Identifying', key, value);
4448
} else {
4549
debug('[Amplitude] NOT identifying because Amplitude is not loaded');
4650
}
4751
};
4852

4953
export const setUserId = async (userId: string) => {
50-
await amplitudePromise();
51-
if (typeof global.amplitude !== 'undefined') {
54+
const amplitude = await getAmplitude();
55+
if (amplitude) {
5256
debug('[Amplitude] Setting User ID', userId);
5357
identify('userId', userId);
5458

55-
global.amplitude.getInstance().setUserId(userId);
59+
amplitude.getInstance().setUserId(userId);
5660
} else {
5761
debug('[Amplitude] NOT setting userid because Amplitude is not loaded');
5862
}
5963
};
6064

6165
export const resetUserId = async () => {
62-
await amplitudePromise();
63-
if (typeof global.amplitude !== 'undefined') {
66+
const amplitude = await getAmplitude();
67+
if (amplitude) {
6468
debug('[Amplitude] Resetting User ID');
6569
identify('userId', null);
6670

6771
if (
68-
global.amplitude.getInstance().options &&
69-
global.amplitude.getInstance().options.userId
72+
amplitude.getInstance().options &&
73+
amplitude.getInstance().options.userId
7074
) {
71-
global.amplitude.getInstance().setUserId(null);
72-
global.amplitude.getInstance().regenerateDeviceId();
75+
amplitude.getInstance().setUserId(null);
76+
amplitude.getInstance().regenerateDeviceId();
7377
}
7478
} else {
7579
debug('[Amplitude] NOT resetting user id because Amplitude is not loaded');
7680
}
7781
};
7882

7983
export const track = async (eventName: string, data: any) => {
80-
await amplitudePromise();
81-
if (typeof global.amplitude !== 'undefined') {
84+
const amplitude = await getAmplitude();
85+
if (amplitude) {
8286
const currentTime = Date.now();
8387
if (currentTime - getLastTimeEventSent() > NEW_SESSION_TIME) {
8488
// We send a separate New Session event if people have been inactive for a while
85-
global.amplitude.logEvent('New Session');
89+
amplitude.logEvent('New Session');
8690
}
8791
markLastTimeEventSent();
8892

8993
debug('[Amplitude] Tracking', eventName, data);
90-
global.amplitude.logEvent(eventName, data);
94+
amplitude.logEvent(eventName, data);
9195
} else {
9296
debug(
9397
'[Amplitude] NOT tracking because Amplitude is not loaded',

0 commit comments

Comments
 (0)