@@ -201,7 +176,6 @@ const TokenHeader = ({
)
}
- const { emailHash } = data
return (
@@ -213,24 +187,7 @@ const TokenHeader = ({
/>
)}
-
- {loading ? : renderHeaderContent()}
-
+
{renderHeaderContent()}
)
}
-
-export default connect(
- (state: any) => ({
- loading: state.tokenHeader.loading,
- data: state.tokenHeader.data,
- }),
- (dispatch) => ({
- actions: bindActionCreators(
- {
- loadTokenState,
- },
- dispatch,
- ),
- }),
-)(TokenHeader)
diff --git a/src/containers/Token/TokenHeader/reducer.js b/src/containers/Token/TokenHeader/reducer.js
deleted file mode 100644
index b4768d53b..000000000
--- a/src/containers/Token/TokenHeader/reducer.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as actionTypes from './actionTypes'
-
-export const initialState = {
- loading: false,
- data: {},
- error: '',
- status: null,
-}
-
-// eslint-disable-next-line default-param-last
-const tokenReducer = (state = initialState, action) => {
- switch (action.type) {
- case actionTypes.START_LOADING_ACCOUNT_STATE:
- return { ...state, loading: true }
- case actionTypes.FINISHED_LOADING_ACCOUNT_STATE:
- return { ...state, loading: false }
- case actionTypes.ACCOUNT_STATE_LOAD_SUCCESS:
- return { ...state, error: '', data: action.data }
- case actionTypes.ACCOUNT_STATE_LOAD_FAIL:
- return {
- ...state,
- error: action.error,
- status: action.status,
- data: state.data.length ? state.data : {},
- }
- case 'persist/REHYDRATE':
- return { ...initialState }
- default:
- return state
- }
-}
-
-export default tokenReducer
diff --git a/src/containers/Token/TokenHeader/test/actions.test.js b/src/containers/Token/TokenHeader/test/actions.test.js
deleted file mode 100644
index bfae5b48a..000000000
--- a/src/containers/Token/TokenHeader/test/actions.test.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import configureMockStore from 'redux-mock-store'
-import thunk from 'redux-thunk'
-import * as actions from '../actions'
-import * as actionTypes from '../actionTypes'
-import { initialState } from '../reducer'
-import { NOT_FOUND, BAD_REQUEST, SERVER_ERROR } from '../../../shared/utils'
-import rippledResponses from './rippledResponses.json'
-import actNotFound from './actNotFound.json'
-import MockWsClient from '../../../test/mockWsClient'
-
-const TEST_ADDRESS = 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv'
-const TEST_CURRENCY = 'abc'
-
-describe('TokenHeader Actions', () => {
- jest.setTimeout(10000)
-
- const middlewares = [thunk]
- const mockStore = configureMockStore(middlewares)
- let client
- beforeEach(() => {
- client = new MockWsClient()
- })
-
- afterEach(() => {
- client.close()
- })
-
- it('should dispatch correct actions on successful loadTokenState', () => {
- client.addResponses(rippledResponses)
- const expectedData = {
- name: undefined,
- obligations: '100',
- sequence: 2148991,
- reserve: 10,
- rate: undefined,
- domain: undefined,
- emailHash: undefined,
- flags: [],
- balance: '123456000',
- previousTxn:
- '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82',
- previousLedger: 68990183,
- }
- const expectedActions = [
- { type: actionTypes.START_LOADING_ACCOUNT_STATE },
- { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE },
- { type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, data: expectedData },
- ]
- const store = mockStore({ news: initialState })
- return store
- .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client))
- .then(() => {
- expect(store.getActions()).toEqual(expectedActions)
- })
- })
-
- it('should dispatch correct actions on server error', () => {
- client.setReturnError()
- const expectedActions = [
- { type: actionTypes.START_LOADING_ACCOUNT_STATE },
- { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE },
- {
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- status: SERVER_ERROR,
- error: 'get_account_state_failed',
- },
- ]
- const store = mockStore({ news: initialState })
- return store
- .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client))
- .then(() => {
- expect(store.getActions()).toEqual(expectedActions)
- })
- })
-
- it('should dispatch correct actions on ripple address not found', () => {
- client.addResponse('account_info', { result: actNotFound })
- const expectedActions = [
- { type: actionTypes.START_LOADING_ACCOUNT_STATE },
- { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE },
- {
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- status: NOT_FOUND,
- error: '',
- },
- ]
- const store = mockStore({ news: initialState })
- return store
- .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client))
- .then(() => {
- expect(store.getActions()).toEqual(expectedActions)
- })
- })
-
- it('should dispatch correct actions on invalid ripple address', () => {
- const expectedActions = [
- {
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- status: BAD_REQUEST,
- error: '',
- },
- ]
- const store = mockStore({ news: initialState })
- store.dispatch(actions.loadTokenState('ZZZ', null, client)).then(() => {
- expect(store.getActions()).toEqual(expectedActions)
- })
- })
-})
diff --git a/src/containers/Token/TokenHeader/test/reducer.test.js b/src/containers/Token/TokenHeader/test/reducer.test.js
deleted file mode 100644
index ceecc491f..000000000
--- a/src/containers/Token/TokenHeader/test/reducer.test.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import * as actionTypes from '../actionTypes'
-import reducer, { initialState } from '../reducer'
-
-describe('AccountHeader reducers', () => {
- it('should return the initial state', () => {
- expect(reducer(undefined, {})).toEqual(initialState)
- })
-
- it('should handle START_LOADING_ACCOUNT_STATE', () => {
- const nextState = { ...initialState, loading: true }
- expect(
- reducer(initialState, { type: actionTypes.START_LOADING_ACCOUNT_STATE }),
- ).toEqual(nextState)
- })
-
- it('should handle FINISHED_LOADING_ACCOUNT_STATE', () => {
- const nextState = { ...initialState, loading: false }
- expect(
- reducer(initialState, {
- type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE,
- }),
- ).toEqual(nextState)
- })
-
- it('should handle ACCOUNT_STATE_LOAD_SUCCESS', () => {
- const data = [['XRP', 123.456]]
- const nextState = { ...initialState, data }
- expect(
- reducer(initialState, {
- data,
- type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS,
- }),
- ).toEqual(nextState)
- })
-
- it('should handle ACCOUNT_STATE_LOAD_FAIL', () => {
- const status = 500
- const error = 'error'
- const nextState = { ...initialState, status, error }
- expect(
- reducer(initialState, {
- status,
- error,
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- }),
- ).toEqual(nextState)
- })
-
- it('will not clear previous data on ACCOUNT_STATE_LOAD_FAIL', () => {
- const data = [['XRP', 123.456]]
- const error = 'error'
- const status = 500
- const stateWithData = { ...initialState, data }
- const nextState = { ...stateWithData, error, status }
- expect(
- reducer(stateWithData, {
- status,
- error,
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- }),
- ).toEqual(nextState)
- })
-
- it('should clear data on rehydration', () => {
- const error = 'error'
- const status = 500
- const nextState = { ...initialState, error, status }
- expect(
- reducer(initialState, {
- type: actionTypes.ACCOUNT_STATE_LOAD_FAIL,
- error,
- status,
- }),
- ).toEqual(nextState)
- expect(reducer(nextState, { type: 'persist/REHYDRATE' })).toEqual(
- initialState,
- )
- })
-})
diff --git a/src/containers/Token/index.tsx b/src/containers/Token/index.tsx
index 09310ac75..84f7e87f1 100644
--- a/src/containers/Token/index.tsx
+++ b/src/containers/Token/index.tsx
@@ -1,9 +1,9 @@
-import { FC, PropsWithChildren, useEffect } from 'react'
+import { FC, PropsWithChildren, useContext, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
-import { connect } from 'react-redux'
import { Helmet } from 'react-helmet-async'
-import TokenHeader from './TokenHeader'
+import { useQuery } from 'react-query'
+import { TokenHeader } from './TokenHeader'
import { TokenTransactionTable } from './TokenTransactionTable'
import { DEXPairs } from './DEXPairs'
import NoMatch from '../NoMatch'
@@ -14,6 +14,9 @@ import { useAnalytics } from '../shared/analytics'
import { ErrorMessages } from '../shared/Interfaces'
import { TOKEN_ROUTE } from '../App/routes'
import { useRouteParams } from '../shared/routing'
+import { getToken } from '../../rippled'
+import SocketContext from '../shared/SocketContext'
+import { Loader } from '../shared/components/Loader'
const IS_MAINNET = process.env.VITE_ENVIRONMENT === 'mainnet'
@@ -45,11 +48,20 @@ const Page: FC
> = ({
)
-const Token: FC<{ error: string }> = ({ error }) => {
+export const Token: FC<{ error: string }> = () => {
+ const rippledSocket = useContext(SocketContext)
const { trackScreenLoaded } = useAnalytics()
const { token = '' } = useRouteParams(TOKEN_ROUTE)
const [currency, accountId] = token.split('.')
const { t } = useTranslation()
+ const {
+ data: tokenData,
+ error: tokenDataError,
+ isLoading: isTokenDataLoading,
+ } = useQuery({
+ queryKey: ['token', currency, accountId],
+ queryFn: () => getToken(currency, accountId, rippledSocket),
+ })
useEffect(() => {
trackScreenLoaded({
@@ -63,21 +75,29 @@ const Token: FC<{ error: string }> = ({ error }) => {
}, [accountId, currency, trackScreenLoaded])
const renderError = () => {
- const message = getErrorMessage(error)
+ const message = getErrorMessage(tokenDataError)
return
- {accountId && }
- {accountId && IS_MAINNET && (
+ {isTokenDataLoading ? (
+
+ ) : (
+
+ )}
+ {accountId && tokenData && IS_MAINNET && (
)}
- {accountId && (
+ {accountId && tokenData && (
{t('token_transactions')}
@@ -91,7 +111,3 @@ const Token: FC<{ error: string }> = ({ error }) => {
)
}
-
-export default connect((state: any) => ({
- error: state.accountHeader.status,
-}))(Token)
diff --git a/src/rippled/token.js b/src/rippled/token.ts
similarity index 74%
rename from src/rippled/token.js
rename to src/rippled/token.ts
index aedc188c2..9f6d8736d 100644
--- a/src/rippled/token.js
+++ b/src/rippled/token.ts
@@ -4,7 +4,26 @@ import { getBalances, getAccountInfo, getServerInfo } from './lib/rippled'
const log = logger({ name: 'iou' })
-const getToken = async (currencyCode, issuer, rippledSocket) => {
+export interface TokenData {
+ name: string
+ balance: string
+ reserve: number
+ sequence: number
+ gravatar: string
+ rate?: number
+ obligations?: string
+ domain?: string
+ emailHash?: string
+ previousLedger: number
+ previousTxn: string
+ flags: string[]
+}
+
+const getToken = async (
+ currencyCode,
+ issuer,
+ rippledSocket,
+): Promise => {
try {
log.info('fetching account info from rippled')
const accountInfo = await getAccountInfo(rippledSocket, issuer)
@@ -47,7 +66,9 @@ const getToken = async (currencyCode, issuer, rippledSocket) => {
previousLedger,
}
} catch (error) {
- log.error(error.toString())
+ if (error) {
+ log.error(error.toString())
+ }
throw error
}
}
diff --git a/src/rootReducer.js b/src/rootReducer.js
index 69ab09b9a..0ad9a2f70 100644
--- a/src/rootReducer.js
+++ b/src/rootReducer.js
@@ -2,18 +2,13 @@ import { combineReducers } from 'redux'
import accountHeaderReducer, {
initialState as accountHeaderState,
} from './containers/Accounts/AccountHeader/reducer'
-import tokenHeaderReducer, {
- initialState as tokenHeaderState,
-} from './containers/Token/TokenHeader/reducer'
export const initialState = {
accountHeader: accountHeaderState,
- tokenHeader: tokenHeaderState,
}
const rootReducer = combineReducers({
accountHeader: accountHeaderReducer,
- tokenHeader: tokenHeaderReducer,
})
export default rootReducer