From cabc458bc6cf98156aaf6491608d811b1e05ac43 Mon Sep 17 00:00:00 2001 From: Johnathon Roach Date: Fri, 24 Jun 2022 12:02:20 -0500 Subject: [PATCH] fix: explain api maintenance mode (#1545) * feat: add error handling to token context * feat: refine error messaging for token api errors * feat: add error messaging to token creator * feat: add error messaging to token manager --- .../components/contexts/tokensContext.js | 67 +++++++++++++++---- .../tokens/tokenCreator/tokenCreator.js | 38 ++++++----- .../tokens/tokensManager/tokensManager.js | 10 ++- .../tokens/tokensManager/tokensManager.scss | 6 ++ 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/packages/website/components/contexts/tokensContext.js b/packages/website/components/contexts/tokensContext.js index 240a261b80..c5812b3d41 100644 --- a/packages/website/components/contexts/tokensContext.js +++ b/packages/website/components/contexts/tokensContext.js @@ -13,6 +13,8 @@ import { deleteToken, getTokens, createToken } from 'lib/api'; * @property {boolean} isFetchingTokens Whether or not new Tokens are being fetched * @property {boolean} isCreating Whether or not a new token is being created * @property {number|undefined} fetchDate The date in which the last Tokens list fetch happened + * @property {string|undefined} errorMessage The error message if any + * @property {boolean} hasError Whether or not there was an error */ /** @@ -35,30 +37,69 @@ export const TokensProvider = ({ children }) => { const [isFetchingTokens, setIsFetchingTokens] = useState(false); const [isCreating, setIsCreating] = useState(false); const [fetchDate, setFetchDate] = useState(/** @type {number|undefined} */ (undefined)); + const [hasError, setHasError] = useState(/** @type {boolean} */ (false)); + const [errorMessage, setErrorMessage] = useState(/** @type {string} */ ('')); + + const processApiError = useCallback( + error => { + if (!error.message) { + setHasError(true); + setErrorMessage('An unknown error has occurred'); + return; + } + const errorObject = JSON.parse( + error.message.substring(error.message.indexOf('{'), error.message.lastIndexOf('}') + 1) + ); + setHasError(true); + if (errorObject.code === 'ERROR_MAINTENANCE') { + setErrorMessage('Tokens API undergoing maintenance. Please try again later.'); + return; + } + + setErrorMessage('Tokens API error has occurred. Please try again later.'); + }, + [setErrorMessage, setHasError] + ); const getTokensCallback = useCallback( /** @type {() => Promise}} */ async () => { - setIsFetchingTokens(true); - const updatedTokens = await getTokens(); - setTokens(updatedTokens); - setIsFetchingTokens(false); - setFetchDate(Date.now()); + try { + setIsFetchingTokens(true); + const updatedTokens = await getTokens(); + setTokens(updatedTokens); + setIsFetchingTokens(false); + setFetchDate(Date.now()); + + return updatedTokens; + } catch (e) { + processApiError(e); - return updatedTokens; + return new Promise((resolve, reject) => { + reject(errorMessage); + }); + } }, - [setTokens, setFetchDate, setIsFetchingTokens] + [setTokens, setFetchDate, setIsFetchingTokens, processApiError, errorMessage] ); const createTokensCallback = useCallback( /** @type {(name: string) => Promise}} */ async name => { - setIsCreating(true); - const newToken = await createToken(name); - setIsCreating(false); - return newToken; + try { + setIsCreating(true); + const newToken = await createToken(name); + setIsCreating(false); + return newToken; + } catch (e) { + processApiError(e); + + return new Promise((resolve, reject) => { + reject(errorMessage); + }); + } }, - [setIsCreating] + [setIsCreating, processApiError, errorMessage] ); return ( @@ -66,6 +107,8 @@ export const TokensProvider = ({ children }) => { value={ /** @type {TokensContextProps} */ ({ + hasError, + errorMessage, deleteToken, createToken: createTokensCallback, getTokens: getTokensCallback, diff --git a/packages/website/components/tokens/tokenCreator/tokenCreator.js b/packages/website/components/tokens/tokenCreator/tokenCreator.js index 499e04f548..218bf0ee32 100644 --- a/packages/website/components/tokens/tokenCreator/tokenCreator.js +++ b/packages/website/components/tokens/tokenCreator/tokenCreator.js @@ -22,7 +22,7 @@ const TokenCreator = ({ content }) => { const [inputHasValue, setInputHasValue] = useState(/** @type {boolean} */ (false)); const { query, push, replace } = useRouter(); - const { tokens, createToken, isCreating, getTokens } = useTokens(); + const { tokens, createToken, isCreating, getTokens, hasError, errorMessage } = useTokens(); const user = useUser(); @@ -98,9 +98,9 @@ const TokenCreator = ({ content }) => { }; return ( -
+
{isCreating ? ( - content.loading_message + <> {hasError ? ⚠ {errorMessage} : content.loading_message} ) : ( <>
@@ -116,20 +116,24 @@ const TokenCreator = ({ content }) => { />
- + {hasError ? ( + <>⚠ {errorMessage} + ) : ( + + )} )}
diff --git a/packages/website/components/tokens/tokensManager/tokensManager.js b/packages/website/components/tokens/tokensManager/tokensManager.js index 4e9e50ad7a..791e519b32 100644 --- a/packages/website/components/tokens/tokensManager/tokensManager.js +++ b/packages/website/components/tokens/tokensManager/tokensManager.js @@ -30,7 +30,7 @@ const defaultQueryOrder = 'a-z'; * @returns */ const TokensManager = ({ content }) => { - const { tokens, fetchDate, isFetchingTokens, deleteToken, getTokens, isCreating } = useTokens(); + const { tokens, fetchDate, isFetchingTokens, deleteToken, getTokens, isCreating, hasError, errorMessage } = useTokens(); const [deletingTokenId, setDeletingTokenId] = useState(''); const { query, replace } = useRouter(); const queryClient = useQueryClient(); @@ -128,7 +128,13 @@ const TokensManager = ({ content }) => {
{isFetchingTokens || !fetchDate ? ( - + <> + {hasError ? ( +
⚠ {errorMessage}
+ ) : ( + + )} + ) : !tokens.length ? ( {content.table.message} diff --git a/packages/website/components/tokens/tokensManager/tokensManager.scss b/packages/website/components/tokens/tokensManager/tokensManager.scss index 1c59c4d116..360a881390 100644 --- a/packages/website/components/tokens/tokensManager/tokensManager.scss +++ b/packages/website/components/tokens/tokensManager/tokensManager.scss @@ -74,6 +74,12 @@ min-height: auto; } + .table-error { + padding: 1.875rem; + text-align: center; + color: $cyan; + } + .tokens-manager-upload-cta { position: relative; top: 1.5625rem;