Skip to content

Commit

Permalink
Merge branch 'main' into tomm/act-1386
Browse files Browse the repository at this point in the history
  • Loading branch information
MuckT authored Oct 9, 2024
2 parents 71b13b9 + ff7976e commit a58d40f
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
"futoin-hkdf": "^1.5.3",
"fuzzysort": "^3.0.2",
"google-libphonenumber": "^3.2.38",
"i18next": "^23.15.1",
"i18next": "^23.15.2",
"ibantools": "^4.5.1",
"intl-pluralrules": "^2.0.1",
"io-ts": "2.2.21",
Expand Down
2 changes: 1 addition & 1 deletion src/positions/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const allowHooksPreviewSelector = () =>

const positionsSelector = (state: RootState) =>
showPositionsSelector() ? state.positions.positions : []
const earnPositionIdsSelector = (state: RootState) => state.positions.earnPositionIds
export const earnPositionIdsSelector = (state: RootState) => state.positions.earnPositionIds
export const positionsStatusSelector = (state: RootState) =>
showPositionsSelector() ? state.positions.status : 'idle'
export const positionsFetchedAtSelector = (state: RootState) => state.positions.positionsFetchedAt
Expand Down
1 change: 1 addition & 0 deletions src/positions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface PositionDisplayProps {
title: string
description: string
imageUrl: string
manageUrl?: string
}

type DataProps = EarnDataProps
Expand Down
46 changes: 44 additions & 2 deletions src/tokens/PositionItem.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { fireEvent, render } from '@testing-library/react-native'
import React from 'react'
import { Provider } from 'react-redux'
import { AssetsEvents } from 'src/analytics/Events'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { AssetsEvents } from 'src/analytics/Events'
import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { AppTokenPosition } from 'src/positions/types'
import { PositionItem } from 'src/tokens/PositionItem'
import { createMockStore } from 'test/utils'
import { mockPositions } from 'test/values'
import { mockEarnPositions, mockPositions } from 'test/values'

beforeEach(() => {
jest.clearAllMocks()
Expand Down Expand Up @@ -34,6 +36,46 @@ describe('PositionItem', () => {
})
})

it('navigates to internal browser manageUrl when tapped and manageUrl exists, not an earnPosition', () => {
const { getByText } = render(
<Provider store={createMockStore({})}>
<PositionItem position={mockPositions[0]} />
</Provider>
)

fireEvent.press(getByText('MOO / CELO'))
expect(navigate).toHaveBeenCalledWith(Screens.WebViewScreen, { uri: 'mock-position.com' })
})
it('does not call navigate when tapped and manageUrl does not, not an earnPosition', () => {
const { getByText } = render(
<Provider store={createMockStore({})}>
<PositionItem position={mockPositions[1]} />
</Provider>
)

fireEvent.press(getByText('G$ / cUSD'))
expect(navigate).not.toHaveBeenCalled()
})

it('navigates to EarnPoolInfoScreen when tapped if position is an earnPosition', () => {
const { getByText } = render(
<Provider
store={createMockStore({
positions: {
earnPositionIds: ['arbitrum-sepolia:0x460b97bd498e1157530aeb3086301d5225b91216'],
},
})}
>
<PositionItem position={mockEarnPositions[0]} />
</Provider>
)

fireEvent.press(getByText('USDC'))
expect(navigate).toHaveBeenCalledWith(Screens.EarnPoolInfoScreen, {
pool: mockEarnPositions[0],
})
})

it('shows the correct info for a position', () => {
const { getByText } = render(
<Provider store={createMockStore({})}>
Expand Down
103 changes: 59 additions & 44 deletions src/tokens/PositionItem.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import BigNumber from 'bignumber.js'
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { TouchableWithoutFeedback } from 'react-native-gesture-handler'
import { AssetsEvents } from 'src/analytics/Events'
import { Platform, StyleSheet, Text, View } from 'react-native'
import { useSelector } from 'react-redux'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { AssetsEvents } from 'src/analytics/Events'
import { openUrl } from 'src/app/actions'
import LegacyTokenDisplay from 'src/components/LegacyTokenDisplay'
import { Position } from 'src/positions/types'
import Touchable from 'src/components/Touchable'
import { navigate } from 'src/navigator/NavigationService'
import { Screens } from 'src/navigator/Screens'
import { earnPositionIdsSelector } from 'src/positions/selectors'
import { EarnPosition, Position } from 'src/positions/types'
import { useDispatch } from 'src/redux/hooks'
import Colors from 'src/styles/colors'
import { typeScale } from 'src/styles/fonts'
import { Spacing } from 'src/styles/styles'
import { Currency } from 'src/utils/currencies'
import { PositionIcon } from 'src/tokens/PositionIcon'
import { Currency } from 'src/utils/currencies'

export const PositionItem = ({
position,
Expand All @@ -19,12 +25,15 @@ export const PositionItem = ({
position: Position
hideBalances?: boolean
}) => {
const dispatch = useDispatch()

const balanceInDecimal =
position.type === 'contract-position' ? undefined : new BigNumber(position.balance)
const balanceUsd =
position.type === 'contract-position'
? new BigNumber(position.balanceUsd)
: new BigNumber(position.balance).multipliedBy(position.priceUsd)
const earnPositionIds = useSelector(earnPositionIdsSelector)

const onPress = () => {
AppAnalytics.track(AssetsEvents.tap_asset, {
Expand All @@ -36,50 +45,56 @@ export const PositionItem = ({
description: position.displayProps.description,
balanceUsd: balanceUsd.toNumber(),
})
const uri = position.displayProps.manageUrl
if (earnPositionIds.includes(position.positionId)) {
navigate(Screens.EarnPoolInfoScreen, { pool: position as EarnPosition })
} else if (uri) {
Platform.OS === 'android'
? navigate(Screens.WebViewScreen, { uri })
: dispatch(openUrl(uri, true))
}
}

return (
<TouchableWithoutFeedback
testID="PositionItem"
style={styles.positionsContainer}
onPress={onPress}
>
<View style={styles.row}>
<PositionIcon position={position} />
<Touchable testID="PositionItem" style={styles.positionsContainer} onPress={onPress}>
<>
<View style={styles.row}>
<PositionIcon position={position} />

<View style={styles.tokenLabels}>
<Text style={styles.tokenName} numberOfLines={1}>
{position.displayProps.title}
</Text>
<Text style={styles.subtext}>{position.displayProps.description}</Text>
</View>
</View>
{!hideBalances && (
<View style={styles.balances}>
{balanceUsd.gt(0) || balanceUsd.lt(0) ? (
<LegacyTokenDisplay
amount={balanceUsd}
currency={Currency.Dollar}
style={styles.tokenAmt}
/>
) : (
// If the balance is 0 / NaN, display a dash instead
// as it means we don't have a price for at least one of the underlying tokens
<Text style={styles.tokenAmt}>-</Text>
)}
{balanceInDecimal && (
<LegacyTokenDisplay
amount={balanceInDecimal}
// Hack to display the token balance without having said token in the base token list
currency={Currency.Celo}
style={styles.subtext}
showLocalAmount={false}
showSymbol={false}
/>
)}
<View style={styles.tokenLabels}>
<Text style={styles.tokenName} numberOfLines={1}>
{position.displayProps.title}
</Text>
<Text style={styles.subtext}>{position.displayProps.description}</Text>
</View>
</View>
)}
</TouchableWithoutFeedback>
{!hideBalances && (
<View style={styles.balances}>
{balanceUsd.gt(0) || balanceUsd.lt(0) ? (
<LegacyTokenDisplay
amount={balanceUsd}
currency={Currency.Dollar}
style={styles.tokenAmt}
/>
) : (
// If the balance is 0 / NaN, display a dash instead
// as it means we don't have a price for at least one of the underlying tokens
<Text style={styles.tokenAmt}>-</Text>
)}
{balanceInDecimal && (
<LegacyTokenDisplay
amount={balanceInDecimal}
// Hack to display the token balance without having said token in the base token list
currency={Currency.Celo}
style={styles.subtext}
showLocalAmount={false}
showSymbol={false}
/>
)}
</View>
)}
</>
</Touchable>
)
}

Expand Down
3 changes: 3 additions & 0 deletions test/RootStateSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3201,6 +3201,9 @@
"imageUrl": {
"type": "string"
},
"manageUrl": {
"type": "string"
},
"title": {
"type": "string"
}
Expand Down
1 change: 1 addition & 0 deletions test/values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,7 @@ export const mockPositions: Position[] = [
title: 'MOO / CELO',
description: 'Pool',
imageUrl: '',
manageUrl: 'mock-position.com',
},
tokens: [
{
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8708,10 +8708,10 @@ husky@^3.0.0:
run-node "^1.0.0"
slash "^3.0.0"

i18next@^23.15.1:
version "23.15.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.15.1.tgz#c50de337bf12ca5195e697cc0fbe5f32304871d9"
integrity sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==
i18next@^23.15.2:
version "23.15.2"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.15.2.tgz#8a54f877ccbbc46696eacb5bd5b31d84f9ade7cb"
integrity sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==
dependencies:
"@babel/runtime" "^7.23.2"

Expand Down

0 comments on commit a58d40f

Please sign in to comment.