Skip to content

Commit 9e3459d

Browse files
authored
CP-9945: Add Trending Tokens (#2325)
1 parent a3bf28e commit 9e3459d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1263
-562
lines changed

packages/core-mobile/app/components/Avatar.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TokenSymbol } from 'store/network'
66
import { SvgUri } from 'react-native-svg'
77
import { formatUriImageToPng, isContentfulImageUri } from 'utils/Contentful'
88
import { Image } from 'expo-image'
9-
import { Text, useTheme, View } from '@avalabs/k2-mobile'
9+
import { Text, useTheme, View, alpha } from '@avalabs/k2-mobile'
1010
import { useGetInitials } from 'hooks/useGetInitials'
1111
import { SuggestedSiteName } from 'store/browser/const'
1212
import { isBase64Png, isSugguestedSiteName } from 'screens/browser/utils'
@@ -143,6 +143,7 @@ interface TokenAvatarProps {
143143
}
144144

145145
const TokenAvatar: FC<TokenAvatarProps> = props => {
146+
const { theme } = useTheme()
146147
return (
147148
<AvatarBase
148149
{...props}
@@ -151,6 +152,7 @@ const TokenAvatar: FC<TokenAvatarProps> = props => {
151152
testID={props.symbol}
152153
backgroundColor={props.backgroundColor}
153154
showBorder={props.showBorder}
155+
fallbackBackgroundColor={alpha(theme.colors.$neutral700, 0.5)}
154156
/>
155157
)
156158
}
@@ -208,8 +210,8 @@ function FallbackAvatar({
208210
variant="body1"
209211
sx={{
210212
color: '$neutral50',
211-
fontSize: size * 0.5,
212-
lineHeight: size * 0.75
213+
fontSize: size * 0.4,
214+
lineHeight: size * 0.65
213215
}}>
214216
{initials}
215217
</Text>

packages/core-mobile/app/components/PortfolioListItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ const PortfolioListItem: FC<Props> = ({
5858
/>
5959
)
6060

61-
const { getMarketToken } = useWatchlist()
62-
const marketToken = getMarketToken(symbol)
61+
const { getMarketTokenBySymbol } = useWatchlist()
62+
const marketToken = getMarketTokenBySymbol(symbol)
6363
const percentChange = marketToken?.priceChangePercentage24h ?? undefined
6464
const priceChange = percentChange
6565
? (tokenPriceInCurrency * percentChange) / 100

packages/core-mobile/app/components/ZeroState.tsx

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface BaseProps {
1919
const ZeroStateBase: FC<BaseProps> = ({ image, title, message, button }) => {
2020
const { theme } = useApplicationContext()
2121

22-
function renderImage() {
22+
function renderImage(): JSX.Element | null {
2323
if (!image) {
2424
return null
2525
}
@@ -41,7 +41,7 @@ const ZeroStateBase: FC<BaseProps> = ({ image, title, message, button }) => {
4141
)
4242
}
4343

44-
function renderTitle() {
44+
function renderTitle(): JSX.Element {
4545
if (typeof title === 'string') {
4646
return (
4747
<AvaText.Heading2 textStyle={{ marginTop: 16 }}>
@@ -52,7 +52,7 @@ const ZeroStateBase: FC<BaseProps> = ({ image, title, message, button }) => {
5252
return <View style={{ marginTop: 16 }}>{title}</View>
5353
}
5454

55-
function renderMessage() {
55+
function renderMessage(): JSX.Element {
5656
if (typeof message === 'string') {
5757
return (
5858
<AvaText.Body2
@@ -64,7 +64,7 @@ const ZeroStateBase: FC<BaseProps> = ({ image, title, message, button }) => {
6464
return <View>{message}</View>
6565
}
6666

67-
function renderButton() {
67+
function renderButton(): JSX.Element | null {
6868
if (!button) return null
6969

7070
return (
@@ -93,7 +93,11 @@ const ZeroStateBase: FC<BaseProps> = ({ image, title, message, button }) => {
9393
)
9494
}
9595

96-
function ZeroStateNetworkTokens({ goToReceive }: { goToReceive: () => void }) {
96+
function ZeroStateNetworkTokens({
97+
goToReceive
98+
}: {
99+
goToReceive: () => void
100+
}): JSX.Element {
97101
const title = 'No assets'
98102
const message = 'Add assets by clicking the button below.'
99103

@@ -109,14 +113,14 @@ function ZeroStateNetworkTokens({ goToReceive }: { goToReceive: () => void }) {
109113
return <ZeroStateBase title={title} message={message} button={button} />
110114
}
111115

112-
function ZeroStateCollectibles() {
116+
function ZeroStateCollectibles(): JSX.Element {
113117
const title = 'No Collectibles'
114118
const message = 'You don’t have any collectibles yet.'
115119

116120
return <ZeroStateBase title={title} message={message} />
117121
}
118122

119-
function ZeroStateNoRecentAccounts() {
123+
function ZeroStateNoRecentAccounts(): JSX.Element {
120124
const title = 'No recent recipients'
121125
const message = 'Enter the address in the field above.'
122126

@@ -127,7 +131,7 @@ function ZeroStateEmptyAddressBook({
127131
onGoToAddressBook
128132
}: {
129133
onGoToAddressBook: () => void
130-
}) {
134+
}): JSX.Element {
131135
const title = 'No addresses'
132136
const message = 'You can add addresses in Address Book'
133137

@@ -146,17 +150,21 @@ function ZeroStateEmptyAddressBook({
146150

147151
type NoResultsProps = Pick<BaseProps, 'message'>
148152

149-
// removed "man with lantern" as per ux request
150-
function ZeroStateNoResults({ message }: NoResultsProps) {
153+
function ZeroStateNoResults({ message }: NoResultsProps): JSX.Element {
151154
const title = 'No results found'
152155
return <ZeroStateBase title={title} message={message} />
153156
}
154157

155-
function ZeroStateComingSoon() {
158+
function ZeroStateSomethingWentWrong(): JSX.Element {
159+
const title = 'Oops! Something went wrong'
160+
return <ZeroStateBase title={title} message={'Please try again later'} />
161+
}
162+
163+
function ZeroStateComingSoon(): JSX.Element {
156164
return <ZeroStateBase title={'Coming soon!'} />
157165
}
158166

159-
function ZeroStateNoTransactions() {
167+
function ZeroStateNoTransactions(): JSX.Element {
160168
const title = 'No recent activity'
161169
const message = 'New transactions will show here'
162170

@@ -167,7 +175,7 @@ function ZeroStateNoWatchlistFavorites({
167175
exploreAllTokens
168176
}: {
169177
exploreAllTokens?: () => void
170-
}) {
178+
}): JSX.Element {
171179
const title = 'No Favorites'
172180
const message = 'Click the star icon on any token to mark it as a favorite.'
173181

@@ -185,7 +193,11 @@ function ZeroStateNoWatchlistFavorites({
185193
)
186194
}
187195

188-
function ZeroStateNoContacts({ addContact }: { addContact: () => void }) {
196+
function ZeroStateNoContacts({
197+
addContact
198+
}: {
199+
addContact: () => void
200+
}): JSX.Element {
189201
const title = 'No Addresses Saved'
190202
const message = 'Tap the button below to add an address.'
191203
const button = (
@@ -210,7 +222,7 @@ function ZeroStateSites({
210222
onAddNewConnection
211223
}: {
212224
onAddNewConnection: () => void
213-
}) {
225+
}): JSX.Element {
214226
const title = 'No Connected Sites'
215227
const message = 'Tap the button below to scan QR code and connect.'
216228

@@ -243,7 +255,8 @@ const ZeroState = {
243255
NoWatchlistFavorites: ZeroStateNoWatchlistFavorites,
244256
EmptyAddressBook: ZeroStateEmptyAddressBook, // used in Send screens
245257
NoContacts: ZeroStateNoContacts, // used in Contacts screen
246-
Sites: ZeroStateSites
258+
Sites: ZeroStateSites,
259+
SomethingWentWrong: ZeroStateSomethingWentWrong
247260
}
248261

249262
export default ZeroState

packages/core-mobile/app/consts/reactQueryKeys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export enum ReactQueryKeys {
1313
NETWORKS = 'networks',
1414
NETWORK_CONTRACT_TOKENS = 'networkContractTokens',
1515
WATCHLIST_TOKENS_AND_CHARTS = 'watchlistTokensAndCharts',
16+
WATCHLIST_TRENDING_TOKENS_AND_CHARTS = 'watchlistTrendingTokensAndCharts',
1617
WATCHLIST_PRICES = 'watchlistPrices',
1718
WATCHLIST_TOKEN_SEARCH = 'watchlistTokenSearch'
1819
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React, {
2+
createContext,
3+
ReactNode,
4+
useContext,
5+
useMemo,
6+
useState,
7+
Dispatch
8+
} from 'react'
9+
10+
interface WatchlistContextState {
11+
searchText: string
12+
setSearchText: Dispatch<string>
13+
}
14+
15+
export const WatchlistContext = createContext<WatchlistContextState>(
16+
{} as WatchlistContextState
17+
)
18+
19+
export const WatchlistContextProvider = ({
20+
children
21+
}: {
22+
children: ReactNode
23+
}): JSX.Element => {
24+
const [searchText, setSearchText] = useState('')
25+
26+
const state: WatchlistContextState = useMemo(
27+
() => ({
28+
searchText,
29+
setSearchText
30+
}),
31+
[searchText, setSearchText]
32+
)
33+
34+
return (
35+
<WatchlistContext.Provider value={state}>
36+
{children}
37+
</WatchlistContext.Provider>
38+
)
39+
}
40+
41+
export function useWatchlistContext(): WatchlistContextState {
42+
return useContext(WatchlistContext)
43+
}

packages/core-mobile/app/hooks/balance/useTokenPortfolioPriceChange.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { LocalTokenWithBalance } from 'store/balance/types'
2-
import { MarketToken } from 'store/watchlist'
2+
import { MarketToken } from 'store/watchlist/types'
33
import { useWatchlist } from '../watchlist/useWatchlist'
44

55
export const useTokenPortfolioPriceChange = (
66
tokens: LocalTokenWithBalance[]
77
): { tokenPortfolioPriceChange: number } => {
8-
const { getMarketToken } = useWatchlist()
8+
const { getMarketTokenBySymbol } = useWatchlist()
99

1010
const tokensWithPrices = tokens
1111
.map(token => {
12-
const tokenInWatchlist = getMarketToken(token.symbol)
12+
const tokenInWatchlist = getMarketTokenBySymbol(token.symbol)
1313

1414
if (tokenInWatchlist) {
1515
return { ...token, ...tokenInWatchlist }
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { UseQueryResult, useQuery } from '@tanstack/react-query'
2+
import { ReactQueryKeys } from 'consts/reactQueryKeys'
3+
import { TrendingToken } from 'services/token/types'
4+
import WatchlistService from 'services/watchlist/WatchlistService'
5+
6+
export const useGetTrendingTokens = <TData = TrendingToken[]>(
7+
select?: (data: TrendingToken[]) => TData
8+
): UseQueryResult<TData, Error> => {
9+
return useQuery({
10+
queryKey: [ReactQueryKeys.WATCHLIST_TRENDING_TOKENS_AND_CHARTS],
11+
queryFn: async () => WatchlistService.getTrendingTokens(),
12+
refetchInterval: 120000, // 2 mins
13+
select
14+
})
15+
}
16+
17+
export const useGetTrendingToken = (
18+
address: string
19+
): UseQueryResult<TrendingToken | undefined, Error> =>
20+
useGetTrendingTokens(data => data.find(token => token.address === address))

0 commit comments

Comments
 (0)