Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.

Commit fac84a7

Browse files
authored
Merge pull request #6354 from blockchain/feat/GROWUX-3484-fin-prom-message
feat(finproms): added info for investment risk
2 parents 78840e8 + 494740d commit fac84a7

9 files changed

Lines changed: 1104 additions & 5 deletions

File tree

lang/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
"buttons.manage": "Manage",
3636
"buttons.next": "Next",
3737
"buttons.ok": "OK",
38+
"buttons.read_more": "Read more",
39+
"buttons.read_less": "Read less",
3840
"buttons.preview_swap": "Preview Swap",
3941
"buttons.receive": "Receive",
4042
"buttons.remove": "Remove",
@@ -1532,6 +1534,7 @@
15321534
"scenes.borrow.warning.safe": "Your collateralization ratio is <span class=\"green600\">{currentRatio}</span>, no action needed at this time.",
15331535
"scenes.borrow.warning.unsafe": "Your collateralization ratio is below {unsafeRatio}. Your loan is in danger of being liquidated.",
15341536
"scenes.buysell.exchangecheckout.rate": "The rate offered by your region's exchange partner. May include fees.",
1537+
"scenes.coin.investement_risk.title": "Investment risk",
15351538
"scenes.exchange.blockchain": "Exchange",
15361539
"scenes.exchange.changeinput": "Change Input",
15371540
"scenes.exchange.confirm.oopsheader": "Oops! Something went wrong.",

packages/blockchain-wallet-v4-frontend/src/scenes/CoinPage/components/CoinPage/CoinPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const CoinPage: CoinPageComponent = ({
3636

3737
<ChartWrapper>{chart}</ChartWrapper>
3838
</Flex>
39-
4039
{about}
4140
{activity}
4241
</Flex>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import styled from 'styled-components'
2+
3+
export const ListContainer = styled.div<{
4+
$isCollapsed: boolean
5+
}>`
6+
overflow: hidden;
7+
transition: max-height 0.3s ease;
8+
9+
max-height: ${(props) => (props.$isCollapsed ? '40px' : '200px')};
10+
`
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { useState } from 'react'
2+
import { FormattedMessage } from 'react-intl'
3+
import { Button as ConstellationButton } from '@blockchain-com/constellation'
4+
5+
import { Text } from 'blockchain-info-components'
6+
7+
import { ListContainer } from './Lines.styles'
8+
9+
type Props = {
10+
lines: string[]
11+
}
12+
13+
export const Lines = ({ lines }: Props) => {
14+
const [isCollapsed, setIsCollapsed] = useState(true)
15+
16+
const toggleCollapse = () => {
17+
setIsCollapsed(!isCollapsed)
18+
}
19+
20+
return (
21+
<div>
22+
<ListContainer $isCollapsed={isCollapsed}>
23+
<ul>
24+
{lines.map((line) => (
25+
<li key={line}>
26+
<Text size='14px' weight={500} color='grey900' lineHeight='150%'>
27+
{line}
28+
</Text>
29+
</li>
30+
))}
31+
</ul>
32+
</ListContainer>
33+
<ConstellationButton
34+
type='button'
35+
variant='minimal'
36+
onClick={toggleCollapse}
37+
data-e2e='toggle-button'
38+
size='small'
39+
text={
40+
isCollapsed ? (
41+
<FormattedMessage defaultMessage='Read more' id='buttons.read_more' />
42+
) : (
43+
<FormattedMessage defaultMessage='Read less' id='buttons.read_less' />
44+
)
45+
}
46+
/>
47+
</div>
48+
)
49+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import styled from 'styled-components'
2+
3+
export const MainWrapper = styled.div<{
4+
expanded: boolean
5+
}>`
6+
margin: 20px 0 30px 0;
7+
display: flex;
8+
flex-direction: column;
9+
border: 1px solid ${(props) => props.theme.grey100};
10+
border-radius: 16px;
11+
12+
overflow: hidden;
13+
transition: max-height 0.3s ease;
14+
max-height: ${({ expanded }) => (expanded ? '800px' : '50px')};
15+
`
16+
17+
export const ContentWrapper = styled.div`
18+
display: flex;
19+
padding: 16px;
20+
flex-direction: column;
21+
gap: 8px;
22+
border-bottom: 1px solid ${(props) => props.theme.grey100};
23+
24+
&:last-child {
25+
border-bottom: none;
26+
}
27+
`
28+
29+
export const Title = styled.div`
30+
padding: 16px;
31+
display: flex;
32+
justify-content: space-between;
33+
border-bottom: 1px solid ${(props) => props.theme.grey100};
34+
`
35+
36+
export const Arrow = styled.div`
37+
cursor: pointer;
38+
transition: transform 0.3s ease;
39+
`

packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/RiskInvestment/data.json

Lines changed: 931 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React, { useState } from 'react'
2+
import { FormattedMessage } from 'react-intl'
3+
import { IconChevronDownV2, IconChevronUpV2 } from '@blockchain-com/constellation'
4+
5+
import { AllCoinsType, Text } from 'blockchain-info-components'
6+
7+
import data from './data.json'
8+
import { Lines } from './Lines'
9+
import { Arrow, ContentWrapper, MainWrapper, Title } from './RiskInvestment.styles'
10+
11+
type Props = {
12+
coin: AllCoinsType
13+
}
14+
15+
export const RiskInvestment = ({ coin }: Props) => {
16+
const [isExpanded, setIsExpanded] = useState(false)
17+
18+
const toggleExpanded = () => {
19+
setIsExpanded((prevExpanded) => !prevExpanded)
20+
}
21+
22+
const coinData = data.find((d) => d.coin === coin)
23+
24+
if (!coinData) {
25+
return null
26+
}
27+
28+
return (
29+
<MainWrapper expanded={isExpanded}>
30+
<Title>
31+
<Text size='16px' weight={600} color='grey900'>
32+
<FormattedMessage
33+
defaultMessage='Investment risk'
34+
id='scenes.coin.investement_risk.title'
35+
/>
36+
</Text>
37+
<Arrow onClick={toggleExpanded}>
38+
{isExpanded ? (
39+
<IconChevronUpV2 label='up' size='small' />
40+
) : (
41+
<IconChevronDownV2 label='down' size='small' />
42+
)}
43+
</Arrow>
44+
</Title>
45+
{coinData.sections.map((section) => (
46+
<ContentWrapper key={coin + section.title}>
47+
<Text size='14px' weight={600} color='grey900'>
48+
{section.title}
49+
</Text>
50+
<Text size='14px' weight={500} color='grey900'>
51+
{section.description}
52+
</Text>
53+
<Lines lines={section.lines} />
54+
</ContentWrapper>
55+
))}
56+
</MainWrapper>
57+
)
58+
}

packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { media } from 'services/styles'
2828
import CoinIntroduction from './CoinIntroduction'
2929
import CoinPerformance from './CoinPerformance'
3030
import RecurringBuys from './RecurringBuys'
31+
import { RiskInvestment } from './RiskInvestment'
3132
import { getData } from './selectors'
3233
import TransactionFilters from './TransactionFilters'
3334
import TransactionList from './TransactionList'
@@ -152,6 +153,7 @@ class TransactionsContainer extends React.PureComponent<Props> {
152153
isSearchEntered,
153154
loadMoreTxs,
154155
pages,
156+
showRiskInvestments,
155157
sourceType,
156158
stakingEligible
157159
} = this.props
@@ -319,6 +321,7 @@ class TransactionsContainer extends React.PureComponent<Props> {
319321
sourceType={sourceType}
320322
/>
321323
))}
324+
{showRiskInvestments && <RiskInvestment coin={coin} />}
322325
</LazyLoadContainer>
323326
</SceneWrapper>
324327
)
@@ -338,6 +341,8 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => {
338341
miscActions: bindActionCreators(actions.core.data.misc, dispatch),
339342
recurringBuyActions: bindActionCreators(actions.components.recurringBuy, dispatch)
340343
}
344+
const isCustodialCoin = selectors.core.data.coins.getCustodialCoins().includes(coin)
345+
341346
if (selectors.core.data.coins.getErc20Coins().includes(coin)) {
342347
return {
343348
...baseActions,
@@ -346,10 +351,7 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => {
346351
loadMoreTxs: () => dispatch(actions.components.ethTransactions.loadMoreErc20(coin))
347352
}
348353
}
349-
if (
350-
selectors.core.data.coins.getCustodialCoins().includes(coin) ||
351-
selectors.core.data.coins.getDynamicSelfCustodyCoins().includes(coin)
352-
) {
354+
if (isCustodialCoin || selectors.core.data.coins.getDynamicSelfCustodyCoins().includes(coin)) {
353355
return {
354356
...baseActions,
355357
fetchData: () => {},

packages/blockchain-wallet-v4-frontend/src/scenes/Transactions/selectors.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ export const getData = (state: RootState, ownProps: OwnProps) => {
114114
const userData = selectors.modules.profile.getUserData(state)
115115
const current = userData?.data?.tiers?.current || 0
116116
const isGoldTier = current >= 2
117+
const signupCountry = selectors.signup.getSignupCountry(state)
118+
const loginMetadata = selectors.auth.getProductAuthMetadata(state)
117119

118120
return createSelector(
119121
[
@@ -136,6 +138,11 @@ export const getData = (state: RootState, ownProps: OwnProps) => {
136138
)
137139
: []
138140

141+
const ipCountry = loginMetadata?.ipCountry
142+
const country = userData.data?.address?.country
143+
const userCountry = country !== undefined ? country : ipCountry
144+
const showRiskInvestments = userCountry === 'GB' || signupCountry === 'GB'
145+
139146
return {
140147
coin,
141148
currency: currencyR.getOrElse(''),
@@ -148,6 +155,7 @@ export const getData = (state: RootState, ownProps: OwnProps) => {
148155
// @ts-ignore
149156
isSearchEntered: search.length > 0 || status !== '',
150157
pages: filteredPages,
158+
showRiskInvestments,
151159
sourceType,
152160
stakingEligible: stakingEligibleR.getOrElse({})
153161
}

0 commit comments

Comments
 (0)