diff --git a/src/App.tsx b/src/App.tsx index 9848d06..15fc5ea 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import { ErrorBar } from '@/components/ErrorBar'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { errorMessage } from './utils/errorMessage'; const ROUTES = [ { @@ -87,7 +88,6 @@ export const App = () => { } }) .catch((error) => { - let errorMsg; if (error.response.status === 401 || error.response.status === 400) { setAuthorization(null); navigate('/'); @@ -95,14 +95,7 @@ export const App = () => { return; } - if (error.response.status === 404) { - errorMsg = - error.response.data + ". If you can't log in again, please contact our support or try again later!"; - } else { - errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please, try again later!'; - } - - setError(errorMsg); + setError(errorMessage(error.response.data)); setLoading(false); }); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/components/AccountSummary/AccountSummary.tsx b/src/components/AccountSummary/AccountSummary.tsx index 4218225..bba6df4 100644 --- a/src/components/AccountSummary/AccountSummary.tsx +++ b/src/components/AccountSummary/AccountSummary.tsx @@ -8,6 +8,7 @@ import { getUser } from '@/api'; import { Loader } from '@/components/Loader'; import { ErrorBar } from '@/components/ErrorBar'; import { convertSatToBsv } from '@/utils/helpers/convertSatToBsv'; +import { errorMessage } from '@/utils/errorMessage'; interface CurrencyRates { usd?: number; @@ -40,16 +41,7 @@ export const AccountSummary = () => { setDetails(accountDetails); }) .catch((error) => { - let errorMsg; - - if (error.response.status === 404) { - errorMsg = - "User's account details not found. If you can't log in again, please contact our support or try again later!"; - } else { - errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please, try again later!'; - } - - setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); }) .finally(() => { setLoading(false); diff --git a/src/components/ContactsList/AcceptReject/AcceptReject.tsx b/src/components/ContactsList/AcceptReject/AcceptReject.tsx index e197c35..aa39dd6 100644 --- a/src/components/ContactsList/AcceptReject/AcceptReject.tsx +++ b/src/components/ContactsList/AcceptReject/AcceptReject.tsx @@ -1,6 +1,7 @@ import { acceptContact, rejectContact } from '@/api/requests'; import { SmallButton } from '@/components/Button'; import { ConfirmationModal } from '@/components/Modal'; +import { errorMessage } from '@/utils/errorMessage'; import { FC, useState } from 'react'; type AcceptRejectProps = { @@ -12,7 +13,7 @@ type AcceptRejectProps = { export const AcceptReject: FC = ({ paymail, onAccept, onReject }) => { const [state, setState] = useState<'none' | 'accept' | 'reject'>('none'); const [loading, setLoading] = useState(false); - const [error, setError] = useState(false); + const [error, setError] = useState(''); const submitAccept = async () => { await acceptContact(paymail); @@ -26,18 +27,23 @@ export const AcceptReject: FC = ({ paymail, onAccept, onRejec const onConfirm = async () => { const submit = state === 'accept' ? submitAccept : submitReject; - setError(false); + setError(''); setLoading(true); try { await submit(); - } catch { - setError(true); + setState('none'); + } catch (error: unknown) { + setError(errorMessage(error)); } finally { setLoading(false); - setState('none'); } }; + const onCancel = () => { + setState('none'); + setError(''); + }; + return ( <> setState('accept')}> @@ -51,9 +57,9 @@ export const AcceptReject: FC = ({ paymail, onAccept, onRejec subtitle={`Are you sure you want to ${state === 'accept' ? 'accept' : 'reject'} this contact invitation?`} open={state !== 'none'} loading={loading} - error={error ? 'Error during performing the action' : undefined} + error={error || undefined} onConfirm={onConfirm} - onCancel={() => setState('none')} + onCancel={onCancel} /> ); diff --git a/src/components/ContactsList/ContactsTable.tsx/ContactsTable.tsx b/src/components/ContactsList/ContactsTable.tsx/ContactsTable.tsx index 1663ff9..8e7465d 100644 --- a/src/components/ContactsList/ContactsTable.tsx/ContactsTable.tsx +++ b/src/components/ContactsList/ContactsTable.tsx/ContactsTable.tsx @@ -38,7 +38,7 @@ export const ContactsTable: FC = () => { const sortedContacts = useSortedContacts(contacts); if (error) { - return ; + return ; } return ( diff --git a/src/components/ContactsList/_modals/ContactUpsertModal/ContactAddModal.tsx b/src/components/ContactsList/_modals/ContactUpsertModal/ContactAddModal.tsx index f45219c..2085ea3 100644 --- a/src/components/ContactsList/_modals/ContactUpsertModal/ContactAddModal.tsx +++ b/src/components/ContactsList/_modals/ContactUpsertModal/ContactAddModal.tsx @@ -14,7 +14,6 @@ export const ContactAddModal: FC = ({ onSubmitted, onCance onCancel={onCancel} onSubmitted={onSubmitted} successMsg="Contact added successfully!" - errorMsg="Error occurred while adding a contact." modalTitle="Add contact" modalSubtitle="Please double check the paymail address on which the invitation will be sent" fields={fields} diff --git a/src/components/ContactsList/_modals/ContactUpsertModal/ContactEditModal.tsx b/src/components/ContactsList/_modals/ContactUpsertModal/ContactEditModal.tsx index 97aa047..97af0d4 100644 --- a/src/components/ContactsList/_modals/ContactUpsertModal/ContactEditModal.tsx +++ b/src/components/ContactsList/_modals/ContactUpsertModal/ContactEditModal.tsx @@ -24,7 +24,6 @@ export const ContactEditModal: FC = ({ onSubmitted, onCan onCancel={onCancel} onSubmitted={onSubmitted} successMsg="Contact edited successfully!" - errorMsg="Error occurred while editing a contact." modalTitle="Edit contact" modalSubtitle="" fields={fields} diff --git a/src/components/ContactsList/_modals/ContactUpsertModal/ContactUpsertModal.tsx b/src/components/ContactsList/_modals/ContactUpsertModal/ContactUpsertModal.tsx index 8d98570..2d00822 100644 --- a/src/components/ContactsList/_modals/ContactUpsertModal/ContactUpsertModal.tsx +++ b/src/components/ContactsList/_modals/ContactUpsertModal/ContactUpsertModal.tsx @@ -10,12 +10,12 @@ import { ErrorBar } from '@/components/ErrorBar'; import { isValidPhone } from '@/utils/helpers/validatePhone'; import { ContactFields } from './useContactFields'; import { EMAIL_REGEX } from '@/utils/constants'; +import { errorMessage } from '@/utils/errorMessage'; type ContactUpsertModal = { onSubmitted: () => void; onCancel: () => void; successMsg: string; - errorMsg: string; modalTitle: string; modalSubtitle: string; fields: ContactFields; @@ -26,7 +26,6 @@ export const ContactUpsertModal: FC = ({ onSubmitted, onCancel, fields, - errorMsg, successMsg, modalTitle, modalSubtitle, @@ -62,8 +61,7 @@ export const ContactUpsertModal: FC = ({ await upsertContact(paymail, name, phone ? { phoneNumber: phone } : undefined); onSuccess(); } catch (error) { - console.error('error', error); - setError(errorMsg); + setError(errorMessage(error)); } finally { setLoading(false); } diff --git a/src/components/ContactsList/_modals/VerifyModal/PeerTOTP.tsx b/src/components/ContactsList/_modals/VerifyModal/PeerTOTP.tsx index da5ed9d..730eace 100644 --- a/src/components/ContactsList/_modals/VerifyModal/PeerTOTP.tsx +++ b/src/components/ContactsList/_modals/VerifyModal/PeerTOTP.tsx @@ -1,6 +1,7 @@ import { Contact, confirmContactWithTOTP } from '@/api'; import { ErrorBar } from '@/components/ErrorBar'; import { Input } from '@/components/Input'; +import { errorMessage } from '@/utils/errorMessage'; import { FC, useMemo, useState } from 'react'; const TOTP_VALID_REGEX = /^\d{2}$/; @@ -8,7 +9,7 @@ const TOTP_VALID_REGEX = /^\d{2}$/; export const usePeerTOTP = (peer: Contact, onConfirmed: () => void) => { const [value, setValue] = useState(''); const [loading, setLoading] = useState(false); - const [error, setError] = useState(false); + const [error, setError] = useState(''); const valid = useMemo(() => { return TOTP_VALID_REGEX.test(value); @@ -16,11 +17,11 @@ export const usePeerTOTP = (peer: Contact, onConfirmed: () => void) => { const onConfirm = async () => { setLoading(true); - setError(false); + setError(''); try { await confirmContactWithTOTP(peer, value); - } catch { - setError(true); + } catch (error: unknown) { + setError(errorMessage(error)); } finally { setLoading(false); onConfirmed(); @@ -38,7 +39,7 @@ export const PeerTOTP: FC = ({ value, setValue, valid, peerName, return (

- {error && } + {error && } = ({ secondaryButton={{ text: 'Yes', variant: 'accept', onClick: onConfirm, loading: loading, disabled: loading }} onCloseByEsc={onCancel} > - {error && } + {error && } ); }; diff --git a/src/components/Modal/_modals/TransactionConfirmModal/TransactionConfirmModal.tsx b/src/components/Modal/_modals/TransactionConfirmModal/TransactionConfirmModal.tsx index d03797f..dc21ea9 100644 --- a/src/components/Modal/_modals/TransactionConfirmModal/TransactionConfirmModal.tsx +++ b/src/components/Modal/_modals/TransactionConfirmModal/TransactionConfirmModal.tsx @@ -13,6 +13,7 @@ import { useAutoupdate } from '@/providers/autoupdate'; import { convertSatToBsv } from '@/utils/helpers/convertSatToBsv'; import { PasswordInput } from '@/components/Input/PasswordInput'; import { modalCloseTimeout } from '../../modalCloseTimeout'; +import { errorMessage } from '@/utils/errorMessage'; export interface TransactionData { paymail: string; @@ -82,17 +83,11 @@ export const TransactionConfirmModal: FC = ({ return; } - if (error.response.status === 400) { - setErrors( - 'Transfer was not sent. Probably you filled the form with incorrect data. Please try once again!', - ); - return; - } - setErrors( - error.response.data - ? error.response.data - : 'Transfer was not sent. Please verify transfer data and try once again. If problem will happen again, contact with our support.', + errorMessage( + error.response.data, + 'Transfer was not sent. Please verify transfer data and try once again. If problem will happen again, contact with our support.', + ), ); } }) diff --git a/src/components/Modal/_modals/TransactionDetailsModal/TransactionDetailsModal.tsx b/src/components/Modal/_modals/TransactionDetailsModal/TransactionDetailsModal.tsx index b1a004c..d337b26 100644 --- a/src/components/Modal/_modals/TransactionDetailsModal/TransactionDetailsModal.tsx +++ b/src/components/Modal/_modals/TransactionDetailsModal/TransactionDetailsModal.tsx @@ -14,6 +14,7 @@ import { Loader } from '@/components/Loader'; import { ErrorBar } from '@/components/ErrorBar'; import { convertSatToBsv } from '@/utils/helpers/convertSatToBsv'; import { SetPaymailButton } from '@/components/TransferForm/SetPaymailButton'; +import { errorMessage } from '@/utils/errorMessage'; type TransactionDetailsProps = { open: boolean; @@ -33,8 +34,7 @@ export const TransactionDetailsModal: FC = ({ open, onC setTransactionData(response); }) .catch((error) => { - const errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please try again later'; - errorMsg && setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); }) .finally(() => { setLoading(false); diff --git a/src/components/TransactionHistory/TransactionTable/TransactionTable.tsx b/src/components/TransactionHistory/TransactionTable/TransactionTable.tsx index efb32c2..395b873 100644 --- a/src/components/TransactionHistory/TransactionTable/TransactionTable.tsx +++ b/src/components/TransactionHistory/TransactionTable/TransactionTable.tsx @@ -30,6 +30,7 @@ import { useAutoupdate } from '@/providers/autoupdate'; import _ from 'lodash'; import { convertSatToBsv } from '@/utils/helpers/convertSatToBsv'; import { PaginationParams } from '@/api/types/pagination'; +import { errorMessage } from '@/utils/errorMessage'; const KEY_NAME_ENTER = 'Enter'; const KEY_NAME_SPACE = 'Space'; @@ -91,8 +92,7 @@ export const TransactionTable = () => { setTransactionsList(transactions.transactions); }) .catch((error) => { - const errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please try again later'; - setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); }) .finally(() => { setLoading(false); diff --git a/src/components/UserMenu/UserMenu.tsx b/src/components/UserMenu/UserMenu.tsx index 562a5d8..92a7438 100644 --- a/src/components/UserMenu/UserMenu.tsx +++ b/src/components/UserMenu/UserMenu.tsx @@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom'; import { useAuthorization } from '@/providers'; import { logoutUser } from '@/api/requests'; import { BsvLogo } from '@/components/BsvLogo'; +import { errorMessage } from '@/utils/errorMessage'; interface MenuProps { userEmail?: string; @@ -54,8 +55,7 @@ export const UserMenu: FC = ({ userEmail }) => { Navigate('/'); }) .catch((error) => { - const errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please try again!'; - errorMsg && setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); }) .finally(() => { setLoading(false); diff --git a/src/providers/contacts/provider.tsx b/src/providers/contacts/provider.tsx index 50ae736..61c3a94 100644 --- a/src/providers/contacts/provider.tsx +++ b/src/providers/contacts/provider.tsx @@ -4,21 +4,22 @@ import { PaginationParams } from '@/api/types'; import { usePikeContactsEnabled } from '@/hooks/useFeatureFlags'; import { FC, PropsWithChildren, createContext, useCallback, useEffect, useMemo, useState } from 'react'; import { useAuthorization } from '../authorization'; +import { errorMessage } from '@/utils/errorMessage'; type ContactsContextValue = { contacts: Contact[] | null; refresh: () => void; loading: boolean; - error: boolean; + error: string; }; export const ContactsContext = createContext(null as never); export const ContactsProvider: FC = ({ children }) => { const [loading, setLoading] = useState(false); - const [error, setError] = useState(false); + const [error, setError] = useState(''); const [contacts, setContacts] = useState(null); - const pikeContactsEnabled = usePikeContactsEnabled() + const pikeContactsEnabled = usePikeContactsEnabled(); const { authorization } = useAuthorization(); const load = useCallback(async () => { @@ -27,17 +28,17 @@ export const ContactsProvider: FC = ({ children }) => { } setLoading(true); try { - const paginationParams : PaginationParams = { + const paginationParams: PaginationParams = { page: 1, page_size: 1000, order: 'paymail', sort: 'asc', - } + }; const contactsResponse = await searchContacts(paginationParams); setContacts(contactsResponse.content); - } catch { + } catch (e: unknown) { setContacts(null); - setError(true); + setError(errorMessage(e)); } finally { setLoading(false); } diff --git a/src/utils/errorMessage.ts b/src/utils/errorMessage.ts new file mode 100644 index 0000000..ead1ff4 --- /dev/null +++ b/src/utils/errorMessage.ts @@ -0,0 +1,19 @@ +import { AxiosError } from 'axios'; + +type SPVError = { + message: string; + code: string; +}; + +const isSPVError = (error: unknown): error is SPVError => { + return (error as SPVError).code !== undefined && (error as SPVError).message !== undefined; +}; + +const DEFAULT_ERROR_MESSAGE = 'Something went wrong... Please, try again later!'; + +export const errorMessage = (error: SPVError | AxiosError | unknown, fallbackMessage = DEFAULT_ERROR_MESSAGE) => { + if (error instanceof AxiosError) { + error = error.response?.data ?? error.message; + } + return isSPVError(error) ? error.message : fallbackMessage; +}; diff --git a/src/views/LoginPage/LoginPage.tsx b/src/views/LoginPage/LoginPage.tsx index 47cd919..51c3764 100644 --- a/src/views/LoginPage/LoginPage.tsx +++ b/src/views/LoginPage/LoginPage.tsx @@ -10,6 +10,7 @@ import { useAuthorization } from '@/providers'; import { useNavigate } from 'react-router-dom'; import { LoggedInUser, loginUser } from '@/api'; import { PasswordInput } from '@/components/Input/PasswordInput'; +import { errorMessage } from '@/utils/errorMessage'; export const LoginPage = () => { const [email, setEmail] = useState(''); @@ -50,8 +51,7 @@ export const LoginPage = () => { setLoading(false); }) .catch((error) => { - const errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please, try again later!'; - setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); setLoading(false); }); }; diff --git a/src/views/SignupPage/SignupPage.tsx b/src/views/SignupPage/SignupPage.tsx index 23d41ff..a564f42 100644 --- a/src/views/SignupPage/SignupPage.tsx +++ b/src/views/SignupPage/SignupPage.tsx @@ -12,6 +12,7 @@ import { AfterRegistrationSteps } from '@/components/StepsList/_lists/AfterRegis import { RegisterNewUserDto } from '@/api/types/user'; import { registerUser } from '@/api'; import { PasswordInput } from '@/components/Input/PasswordInput'; +import { errorMessage } from '@/utils/errorMessage'; export const SignupPage = () => { const [email, setEmail] = useState(''); @@ -64,8 +65,7 @@ export const SignupPage = () => { setLoading(false); }) .catch((error) => { - const errorMsg = error.response.data ? error.response.data : 'Something went wrong... Please, try again later!'; - setErrors(errorMsg); + setErrors(errorMessage(error.response.data)); setRegistered(false); setLoading(false); });