diff --git a/apps/wallet-mobile/src/features/Portfolio/common/PortfolioProvider.tsx b/apps/wallet-mobile/src/features/Portfolio/common/PortfolioProvider.tsx index 0a1b1662ae..fd267fdcab 100644 --- a/apps/wallet-mobile/src/features/Portfolio/common/PortfolioProvider.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/common/PortfolioProvider.tsx @@ -1,6 +1,10 @@ -import {invalid} from '@yoroi/common' +import {invalid, isRight} from '@yoroi/common' +import {Portfolio} from '@yoroi/types' import {produce} from 'immer' import * as React from 'react' +import {useQuery} from 'react-query' + +import {useSelectedNetwork} from '../../WalletManager/common/hooks/useSelectedNetwork' export const PortfolioDetailsTab = { Performance: 'Performance', @@ -32,6 +36,7 @@ const defaultActions: PortfolioActions = { } as const const defaultState: PortfolioState = { + isTokenHistoryApiAvailable: false, isPrimaryTokenActive: false, detailsTab: PortfolioDetailsTab.Overview, listTab: PortfolioListTab.Wallet, @@ -39,6 +44,7 @@ const defaultState: PortfolioState = { } as const type PortfolioState = { + isTokenHistoryApiAvailable: boolean isPrimaryTokenActive: boolean detailsTab: PortfolioDetailsTab listTab: PortfolioListTab @@ -57,6 +63,22 @@ export const PortfolioProvider = ({ children: React.ReactNode initialState?: Partial }) => { + const { + networkManager: {tokenManager}, + } = useSelectedNetwork() + const {data} = useQuery({ + queryKey: ['isTokenHistoryApiAvailable'], + initialData: () => false, + queryFn: async () => { + const response = await tokenManager.api.tokenHistory( + '279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f.534e454b', + Portfolio.Token.HistoryPeriod.OneDay, + ) + if (isRight(response)) return true + return false + }, + }) + const isTokenHistoryApiAvailable = data ?? false const [portfolioState, dispatch] = React.useReducer(portfolioReducer, {...defaultState, ...initialState}) const actions = React.useRef({ @@ -76,8 +98,8 @@ export const PortfolioProvider = ({ }).current const context = React.useMemo( - () => ({...portfolioState, ...actions}), - [actions, portfolioState], + () => ({...portfolioState, ...actions, isTokenHistoryApiAvailable}), + [actions, portfolioState, isTokenHistoryApiAvailable], ) return {children} diff --git a/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts b/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts index af3b08f03e..640fed7085 100644 --- a/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts +++ b/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts @@ -4,10 +4,10 @@ import {Chain, Portfolio} from '@yoroi/types' import {useQuery, UseQueryOptions} from 'react-query' import {supportedCurrencies, time} from '../../../../kernel/constants' -import {features} from '../../../../kernel/features' import {useLanguage} from '../../../../kernel/i18n' import {logger} from '../../../../kernel/logger/logger' import {fetchPtPriceActivity} from '../../../../yoroi-wallets/cardano/usePrimaryTokenActivity' +import {delay} from '../../../../yoroi-wallets/utils/timeUtils' import {useCurrencyPairing} from '../../../Settings/Currency/CurrencyContext' import {useSelectedNetwork} from '../../../WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' @@ -15,7 +15,7 @@ import {networkConfigs} from '../../../WalletManager/network-manager/network-man import {priceChange} from '../helpers/priceChange' import {usePortfolioTokenDetailParams} from './useNavigateTo' -export const TOKEN_CHART_INTERVAL = { +export const TokenChartInterval = { DAY: '24 H', WEEK: '1 W', MONTH: '1 M', @@ -24,7 +24,7 @@ export const TOKEN_CHART_INTERVAL = { ALL: 'ALL', } as const -export type TokenChartInterval = (typeof TOKEN_CHART_INTERVAL)[keyof typeof TOKEN_CHART_INTERVAL] +export type TokenChartInterval = (typeof TokenChartInterval)[keyof typeof TokenChartInterval] type TokenChartData = { label: string @@ -36,13 +36,13 @@ type TokenChartData = { const getTimestamps = (timeInterval: TokenChartInterval) => { const now = Date.now() const [from, resolution] = { - [TOKEN_CHART_INTERVAL.DAY]: [now - time.oneDay, 96], - [TOKEN_CHART_INTERVAL.WEEK]: [now - time.oneWeek, 168], - [TOKEN_CHART_INTERVAL.MONTH]: [now - time.oneMonth, 180], - [TOKEN_CHART_INTERVAL.SIX_MONTHS]: [now - time.sixMonths, 180], - [TOKEN_CHART_INTERVAL.YEAR]: [now - time.oneYear, 365], - [TOKEN_CHART_INTERVAL.ALL]: [new Date('2018').getTime(), 256], - }[timeInterval] + [TokenChartInterval.DAY]: [now - time.oneDay, 96], + [TokenChartInterval.WEEK]: [now - time.oneWeek, 168], + [TokenChartInterval.MONTH]: [now - time.oneMonth, 180], + [TokenChartInterval.SIX_MONTHS]: [now - time.sixMonths, 180], + [TokenChartInterval.YEAR]: [now - time.oneYear, 365], + [TokenChartInterval.ALL]: [new Date('2018').getTime(), 256], + }[timeInterval ?? TokenChartInterval.DAY] const step = (now - from) / resolution return Array.from({length: resolution}, (_, i) => from + Math.round(step * i)) @@ -50,8 +50,19 @@ const getTimestamps = (timeInterval: TokenChartInterval) => { const ptTicker = networkConfigs[Chain.Network.Mainnet].primaryTokenInfo.ticker +export const ptPriceQueryFn = async ({queryKey}: {queryKey: ['ptPriceHistory', TokenChartInterval]}) => { + const response = await fetchPtPriceActivity(getTimestamps(queryKey[1])) + if (isRight(response) && !response.value.data.error) { + const tickers = response.value.data.tickers + if (tickers.length === 0) return null + return tickers + } + logger.error('Failed to fetch token chart data for PT') + return null +} + export const useGetPortfolioTokenChart = ( - timeInterval = TOKEN_CHART_INTERVAL.DAY as TokenChartInterval, + timeInterval = TokenChartInterval.DAY as TokenChartInterval, options: UseQueryOptions< TokenChartData[] | null, Error, @@ -70,45 +81,50 @@ export const useGetPortfolioTokenChart = ( const {currency} = useCurrencyPairing() const {languageCode} = useLanguage() - const ptQuery = useQuery({ + const ptPriceQuery = useQuery< + Awaited>, + Error, + Awaited>, + ['ptPriceHistory', TokenChartInterval] + >({ + enabled: tokenInfo && isPrimaryToken(tokenInfo.info), staleTime: time.halfHour, cacheTime: time.oneHour, retryDelay: time.oneSecond, - optimisticResults: true, refetchInterval: time.halfHour, - useErrorBoundary: true, - refetchOnMount: false, + queryKey: ['ptPriceHistory', timeInterval], + queryFn: ptPriceQueryFn, + }) + + const ptQuery = useQuery({ enabled: tokenInfo && isPrimaryToken(tokenInfo.info), + staleTime: time.oneMinute, ...options, - queryKey: ['useGetPortfolioTokenChart', tokenInfo?.info.id ?? '', timeInterval, currency], + queryKey: ['useGetPortfolioTokenChart', '.', timeInterval, currency], queryFn: async () => { - const response = await fetchPtPriceActivity(getTimestamps(timeInterval)) - if (isRight(response)) { - if (response.value.data.error) throw new Error(response.value.data.error) - - const tickers = response.value.data.tickers - if (tickers.length === 0) return null - - const validCurrency = currency === ptTicker ? supportedCurrencies.USD : currency ?? supportedCurrencies.USD - - const initialPrice = tickers[0].prices[validCurrency] - const records = tickers - .map((ticker) => { - const value = ticker.prices[validCurrency] - if (value === undefined) return undefined - const {changePercent, changeValue} = priceChange(initialPrice, value) - const label = new Date(ticker.timestamp).toLocaleString(languageCode, { - dateStyle: 'short', - timeStyle: 'short', - }) - return {label, value, changePercent, changeValue} + // force queryFn to be async, otherwise it takes longer and doesn't show isFetching + await delay(0) + + const tickers = ptPriceQuery.data ?? [] + if (tickers.length === 0) return null + + const validCurrency = currency === ptTicker ? supportedCurrencies.USD : currency ?? supportedCurrencies.USD + + const initialPrice = tickers[0].prices[validCurrency] + const records = tickers + .map((ticker) => { + const value = ticker.prices[validCurrency] + if (value === undefined) return undefined + const {changePercent, changeValue} = priceChange(initialPrice, value) + const label = new Date(ticker.timestamp).toLocaleString(languageCode, { + dateStyle: 'short', + timeStyle: 'short', }) - .filter(Boolean) as TokenChartData[] + return {label, value, changePercent, changeValue} + }) + .filter(Boolean) as TokenChartData[] - return records - } - logger.error('Failed to fetch token chart data for PT') - return null + return records }, }) @@ -119,8 +135,6 @@ export const useGetPortfolioTokenChart = ( ...options, queryKey: ['useGetPortfolioTokenChart', tokenInfo?.info.id ?? '', timeInterval], queryFn: async () => { - if (!features.portfolioSecondaryCharts) return null - const response = await tokenManager.api.tokenHistory(tokenId, chartIntervalToHistoryPeriod(timeInterval)) if (isRight(response)) { const prices = response.value.data.prices @@ -153,10 +167,10 @@ export const useGetPortfolioTokenChart = ( const chartIntervalToHistoryPeriod = (i: TokenChartInterval): Portfolio.Token.HistoryPeriod => ({ - [TOKEN_CHART_INTERVAL.DAY]: Portfolio.Token.HistoryPeriod.OneDay, - [TOKEN_CHART_INTERVAL.WEEK]: Portfolio.Token.HistoryPeriod.OneWeek, - [TOKEN_CHART_INTERVAL.MONTH]: Portfolio.Token.HistoryPeriod.OneMonth, - [TOKEN_CHART_INTERVAL.SIX_MONTHS]: Portfolio.Token.HistoryPeriod.SixMonth, - [TOKEN_CHART_INTERVAL.YEAR]: Portfolio.Token.HistoryPeriod.OneYear, - [TOKEN_CHART_INTERVAL.ALL]: Portfolio.Token.HistoryPeriod.All, + [TokenChartInterval.DAY]: Portfolio.Token.HistoryPeriod.OneDay, + [TokenChartInterval.WEEK]: Portfolio.Token.HistoryPeriod.OneWeek, + [TokenChartInterval.MONTH]: Portfolio.Token.HistoryPeriod.OneMonth, + [TokenChartInterval.SIX_MONTHS]: Portfolio.Token.HistoryPeriod.SixMonth, + [TokenChartInterval.YEAR]: Portfolio.Token.HistoryPeriod.OneYear, + [TokenChartInterval.ALL]: Portfolio.Token.HistoryPeriod.All, }[i] ?? Portfolio.Token.HistoryPeriod.OneDay) diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx index 3bb1067dfb..a46c16d8b1 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx @@ -2,11 +2,7 @@ import {useTheme} from '@yoroi/theme' import React, {useCallback, useState} from 'react' import {StyleSheet, View} from 'react-native' -import { - type TokenChartInterval, - TOKEN_CHART_INTERVAL, - useGetPortfolioTokenChart, -} from '../../../common/hooks/useGetPortfolioTokenChart' +import {TokenChartInterval, useGetPortfolioTokenChart} from '../../../common/hooks/useGetPortfolioTokenChart' import {ChartPlaceholder} from './ChartPlaceholder' import {PortfolioTokenChartSkeleton} from './PortfolioTokenChartSkeleton' import {TokenChart} from './TokenChart' @@ -18,7 +14,7 @@ export const PortfolioTokenChart = () => { const [selectedIndex, setSelectedIndex] = useState(0) - const [timeInterval, setTimeInterval] = useState(TOKEN_CHART_INTERVAL.DAY) + const [timeInterval, setTimeInterval] = useState(TokenChartInterval.DAY) const {data, isFetching} = useGetPortfolioTokenChart(timeInterval) diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenChartToolBar.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenChartToolBar.tsx index 651112ea13..92b4092aa0 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenChartToolBar.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenChartToolBar.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {Text} from '../../../../../components/Text' -import {type TokenChartInterval, TOKEN_CHART_INTERVAL} from '../../../common/hooks/useGetPortfolioTokenChart' +import {TokenChartInterval} from '../../../common/hooks/useGetPortfolioTokenChart' interface Props { timeInterval: TokenChartInterval @@ -21,7 +21,7 @@ export const TokenChartToolbar = ({timeInterval, disabled, onChange}: Props) => return ( - {Object.values(TOKEN_CHART_INTERVAL).map((itv) => ( + {Object.values(TokenChartInterval).map((itv) => ( handleChange(itv)} style={[itv === timeInterval ? styles.chartToolbarItemActive : {}, styles.chartToolbarItem]} diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx index b14eaef25b..b62322cf7c 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx @@ -7,7 +7,7 @@ import {Text} from '../../../../../components/Text' import {Tooltip} from '../../../../../components/Tooltip/Tooltip' import {useCurrencyPairing} from '../../../../Settings/Currency/CurrencyContext' import {formatPriceChange} from '../../../common/helpers/priceChange' -import {TOKEN_CHART_INTERVAL, TokenChartInterval} from '../../../common/hooks/useGetPortfolioTokenChart' +import {TokenChartInterval} from '../../../common/hooks/useGetPortfolioTokenChart' import {useStrings} from '../../../common/hooks/useStrings' import {PnlTag} from '../../../common/PnlTag/PnlTag' @@ -35,17 +35,17 @@ export const TokenPerformance = ({tokenPerformance, timeInterval}: Props) => { const intervalLabel = React.useMemo(() => { switch (timeInterval) { - case TOKEN_CHART_INTERVAL.DAY: + case TokenChartInterval.DAY: return strings._24_hours - case TOKEN_CHART_INTERVAL.WEEK: + case TokenChartInterval.WEEK: return strings._1_week - case TOKEN_CHART_INTERVAL.MONTH: + case TokenChartInterval.MONTH: return strings._1_month - case TOKEN_CHART_INTERVAL.SIX_MONTHS: + case TokenChartInterval.SIX_MONTHS: return strings._6_months - case TOKEN_CHART_INTERVAL.YEAR: + case TokenChartInterval.YEAR: return strings._1_year - case TOKEN_CHART_INTERVAL.ALL: + case TokenChartInterval.ALL: return strings.all_time default: return strings._24_hours diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx index 28bd845fe8..2de5c45759 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx @@ -1,3 +1,4 @@ +import {isPrimaryTokenInfo} from '@yoroi/portfolio' import {useTheme} from '@yoroi/theme' import {App} from '@yoroi/types' import * as React from 'react' @@ -21,16 +22,16 @@ import {PortfolioTokenBalance} from './PortfolioTokenBalance/PortfolioTokenBalan import {PortfolioTokenChart} from './PortfolioTokenChart/PortfolioTokenChart' import {PortfolioTokenInfo} from './PortfolioTokenInfo/PortfolioTokenInfo' -const HEADER_HEIGHT = 304 - export const PortfolioTokenDetailsScreen = () => { const strings = useStrings() - const {detailsTab, setDetailsTab} = usePortfolio() + const {detailsTab, setDetailsTab, isTokenHistoryApiAvailable} = usePortfolio() const {track} = useMetrics() const [isStickyTab, setIsStickyTab] = React.useState(false) const {id: tokenId} = usePortfolioTokenDetailParams() const {wallet} = useSelectedWallet() const tokenInfo = wallet.balances.records.get(tokenId)?.info + const isPrimaryToken = isPrimaryTokenInfo(tokenInfo) + const HEADER_HEIGHT = isPrimaryToken || isTokenHistoryApiAvailable ? 304 : 85 const {styles} = useStyles(HEADER_HEIGHT) if (!tokenInfo) throwLoggedError(new App.Errors.InvalidState('Token info not found, invalid state')) @@ -91,9 +92,13 @@ export const PortfolioTokenDetailsScreen = () => { - + {(isPrimaryToken || isTokenHistoryApiAvailable) && ( + <> + - + + + )} {renderTabs} diff --git a/apps/wallet-mobile/src/kernel/features.ts b/apps/wallet-mobile/src/kernel/features.ts index 51aa85a456..76e3908c0b 100644 --- a/apps/wallet-mobile/src/kernel/features.ts +++ b/apps/wallet-mobile/src/kernel/features.ts @@ -6,7 +6,6 @@ export const features = { showProdPoolsInDev: isDev, moderatingNftsEnabled: false, poolTransition: true, - portfolioSecondaryCharts: isDev, portfolioPerformance: false, portfolioNews: false, portfolioExport: false, diff --git a/apps/wallet-mobile/src/kernel/query-client.ts b/apps/wallet-mobile/src/kernel/query-client.ts index 3e1d1442ed..bc08f553b6 100644 --- a/apps/wallet-mobile/src/kernel/query-client.ts +++ b/apps/wallet-mobile/src/kernel/query-client.ts @@ -1,7 +1,19 @@ import {freeze} from 'immer' import {QueryClient} from 'react-query' +import {ptPriceQueryFn, TokenChartInterval} from '../features/Portfolio/common/hooks/useGetPortfolioTokenChart' + const queryClient = new QueryClient() + +Object.values(TokenChartInterval).forEach((TokenChartInterval) => { + queryClient.prefetchQuery< + Awaited>, + Error, + Awaited>, + ['ptPriceHistory', TokenChartInterval] + >({queryKey: ['ptPriceHistory', TokenChartInterval], queryFn: ptPriceQueryFn}) +}) + const keyToPersist = 'persist' /* const queryPersistorStorageKey = 'react-query-persistor' diff --git a/apps/wallet-mobile/translations/messages/src/WalletNavigator.json b/apps/wallet-mobile/translations/messages/src/WalletNavigator.json index 0618bc2879..b8cde09ac5 100644 --- a/apps/wallet-mobile/translations/messages/src/WalletNavigator.json +++ b/apps/wallet-mobile/translations/messages/src/WalletNavigator.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Transactions", "file": "src/WalletNavigator.tsx", "start": { - "line": 301, + "line": 305, "column": 22, - "index": 10506 + "index": 10584 }, "end": { - "line": 304, + "line": 308, "column": 3, - "index": 10609 + "index": 10687 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Send", "file": "src/WalletNavigator.tsx", "start": { - "line": 305, + "line": 309, "column": 14, - "index": 10625 + "index": 10703 }, "end": { - "line": 308, + "line": 312, "column": 3, - "index": 10724 + "index": 10802 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Receive", "file": "src/WalletNavigator.tsx", "start": { - "line": 309, + "line": 313, "column": 17, - "index": 10743 + "index": 10821 }, "end": { - "line": 312, + "line": 316, "column": 3, - "index": 10848 + "index": 10926 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Dashboard", "file": "src/WalletNavigator.tsx", "start": { - "line": 313, + "line": 317, "column": 19, - "index": 10869 + "index": 10947 }, "end": { - "line": 316, + "line": 320, "column": 3, - "index": 10966 + "index": 11044 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!Delegate", "file": "src/WalletNavigator.tsx", "start": { - "line": 317, + "line": 321, "column": 18, - "index": 10986 + "index": 11064 }, "end": { - "line": 320, + "line": 324, "column": 3, - "index": 11081 + "index": 11159 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Wallet", "file": "src/WalletNavigator.tsx", "start": { - "line": 321, + "line": 325, "column": 16, - "index": 11099 + "index": 11177 }, "end": { - "line": 324, + "line": 328, "column": 3, - "index": 11197 + "index": 11275 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Staking", "file": "src/WalletNavigator.tsx", "start": { - "line": 325, + "line": 329, "column": 17, - "index": 11216 + "index": 11294 }, "end": { - "line": 328, + "line": 332, "column": 3, - "index": 11281 + "index": 11359 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!NFT Gallery", "file": "src/WalletNavigator.tsx", "start": { - "line": 329, + "line": 333, "column": 14, - "index": 11297 + "index": 11375 }, "end": { - "line": 332, + "line": 336, "column": 3, - "index": 11391 + "index": 11469 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Menu", "file": "src/WalletNavigator.tsx", "start": { - "line": 333, + "line": 337, "column": 14, - "index": 11407 + "index": 11485 }, "end": { - "line": 336, + "line": 340, "column": 3, - "index": 11459 + "index": 11537 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!Discover", "file": "src/WalletNavigator.tsx", "start": { - "line": 337, + "line": 341, "column": 18, - "index": 11479 + "index": 11557 }, "end": { - "line": 340, + "line": 344, "column": 3, - "index": 11568 + "index": 11646 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!My wallets", "file": "src/WalletNavigator.tsx", "start": { - "line": 341, + "line": 345, "column": 31, - "index": 11601 + "index": 11679 }, "end": { - "line": 344, + "line": 348, "column": 3, - "index": 11710 + "index": 11788 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!Portfolio", "file": "src/WalletNavigator.tsx", "start": { - "line": 345, + "line": 349, "column": 19, - "index": 11731 + "index": 11809 }, "end": { - "line": 348, + "line": 352, "column": 3, - "index": 11800 + "index": 11878 } } ] \ No newline at end of file