Skip to content

Commit

Permalink
Merge pull request #65 from pnetwork-association/feat/redirect-banner
Browse files Browse the repository at this point in the history
Feat/redirect banner
  • Loading branch information
envin3 authored Feb 15, 2024
2 parents 12ffbd8 + a9cb7df commit f76e6e6
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 38 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "plain-dapp-update",
"private": true,
"version": "1.19.0",
"version": "1.20.0",
"type": "module",
"scripts": {
"dev": "npm run create-version-file && vite",
Expand Down
27 changes: 17 additions & 10 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import React, { useEffect } from 'react'
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { Route, Switch, Redirect, useRouteMatch } from 'react-router-dom'
import queryString from 'query-string'
import { connect } from 'react-redux'

import SwapController from './components/pages/swap/SwapController'
import { sendPageView, setPageLocation } from './ga4'
import SwapOldPntController from './components/pages/swapOldPnt/SwapOldPntController'
import { loadSwapData } from './store/swap/swap.actions'
import { loadMigrationData } from './store/migration/migration.actions'
import { loadSwapOldPntData } from './store/swap-old-pnt/swap-old-pnt.actions'
import { selectPage, setTheme } from './store/pages/pages.actions'
import { Route, Switch, Redirect, useRouteMatch } from 'react-router-dom'
import history from './utils/history'
import queryString from 'query-string'
import { connect } from 'react-redux'
import MigrationController from './components/pages/migration/MigrationController'
import MigrationHomeController from './components/pages/migrationHome/MigrationHomeController'
import SwapController from './components/pages/swap/SwapController'
import SwapOldPntController from './components/pages/swapOldPnt/SwapOldPntController'
import HeaderController from './components/organisms/header/HeaderController'
import MainWrapper from './components/atoms/mainWrapper/MainWrapper'
import Notifications from './components/molecules/notifications/Notifications'
import NftsController from './components/pages/nfts/NftsController'
import Risks from './components/pages/risks/Risks'
import MainWrapper from './components/atoms/mainWrapper/MainWrapper'
import Notifications from './components/molecules/notifications/Notifications'
import Popup from './components/molecules/popup/Popup'
import RedirectBanner from './components/molecules/popup/RedirectBanner'
import WarningPopup from './components/molecules/popup/Warning'
import SocialLinks from './components/molecules/socials/Socials'
import Version from './components/molecules/version/Version'
import { sendPageView, setPageLocation } from './ga4'
import HeaderController from './components/organisms/header/HeaderController'

history.listen((location) => {
setPageLocation(location.pathname)
Expand Down Expand Up @@ -66,6 +69,8 @@ const RisksPage = () => {
}

const App = ({ loading, setTheme, loadSwapData, loadSwapOldPntData, loadMigrationData, selectPage }) => {
const [showWarningPopup, setShowWarningPopup] = useState(true)

useEffect(() => {
/* window.location.search -> window.location.hash
* window.location.search not available in HashRouter
Expand Down Expand Up @@ -107,6 +112,8 @@ const App = ({ loading, setTheme, loadSwapData, loadSwapOldPntData, loadMigratio
<MainWrapper>
<Notifications />
<HeaderController />
<RedirectBanner/>
<WarningPopup show={showWarningPopup} onClose={() => setShowWarningPopup(false)} />
<Switch>
<Route exact path={'/swap'} render={() => <SwapController />} />
<Route
Expand Down
67 changes: 67 additions & 0 deletions src/components/molecules/popup/RedirectBanner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Alert, Row } from 'react-bootstrap'
import styled from 'styled-components'

import Icon from '../../atoms/icon/Icon'
import { OuterContainerSwap } from '../../pages/swap/Swap'

const DISMISSED_DOMAIN = 'ptokens.io'

const StyledAlert = styled(Alert)`
// background: ${({ theme }) => theme.bg1};
font-size: 16px;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 0.5rem;
`

const WarningIcon = styled(Icon)`
height: 20px;
width: 20px;
margin: 5px;
vertical-align: top;
color: #475965;
`

const Paragraph = styled.div`
text-align: center;
margin: 0rem;
margin-left: 2px;
`

const getDomain = () => {
try {
const currentUrl = new URL(window.location.href)
return currentUrl.hostname
} catch (_err) {
// Handle error in case of use with ipns/ipfs enabled browsers
console.error('Error while retreiving url', _err.message)
return null
}
}

const RedirectBanner = () => {
const domain = getDomain()
return (
<>
{domain && domain.includes(DISMISSED_DOMAIN) ? (
<Row>
<OuterContainerSwap className="mx-auto">
<StyledAlert variant="info">
<Paragraph>
<WarningIcon icon="info" />
<br />
You are using an old domain that will be dismissed in the future.
<br />
Please use <a href="https://dapp.pnetworkprotocol.eth.limo">pnetworkprotocol.eth</a>
</Paragraph>
</StyledAlert>
</OuterContainerSwap>
</Row>
) : null}
</>
)
}

export default RedirectBanner
37 changes: 24 additions & 13 deletions src/components/molecules/popup/Warning.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import React from 'react'
import { Alert, Row } from 'react-bootstrap'
import styled from 'styled-components'
import { Alert } from 'react-bootstrap'

import Icon from '../../atoms/icon/Icon'
import { OuterContainerSwap } from '../../pages/swap/Swap'

const StyledAlert = styled(Alert)`
// background: ${({ theme }) => theme.bg1};
Expand All @@ -13,27 +15,36 @@ const StyledAlert = styled(Alert)`
`

const WarningIcon = styled(Icon)`
padding-left: 0px;
padding-bottom: 2px;
padding-right: 5px;
height: 20px;
width: 20px;
margin: 5px;
vertical-align: top;
color: #475965;
`

const Paragraph = styled.div`
text-align: center;
margin: 0rem;
margin-left: 2px;
margin-left: 25px;
`

const WarningPopup = ({ show, onClose }) => {
return (
<StyledAlert show={show} onClose={onClose} variant="warning" dismissible>
<Paragraph>
<WarningIcon icon="warning" />
pNetwork is a new technology, and security audits don't eliminate risks completely. Please don't provide assets
you can't afford to lose.
</Paragraph>
</StyledAlert>
<Row>
<OuterContainerSwap className="mx-auto">
<StyledAlert show={show} onClose={onClose} variant="warning" dismissible>
<Paragraph>
<WarningIcon icon="warning" />
<br />
pNetwork is a new technology, and security audits don't
<br />
eliminate risks completely. Please don't provide assets you
<br />
can't afford to lose.
</Paragraph>
</StyledAlert>
</OuterContainerSwap>
</Row>
)
}

Expand Down
39 changes: 39 additions & 0 deletions src/components/molecules/popup/__test__/RedirectBanner.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint-disable import/first */
import { render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import RedirectBanner from '../RedirectBanner'

const expectedText = 'You are using an old domain that will be dismissed in the future.'

describe('RedirectBanner', async () => {
test.each([
['http://ptokens.io'],
['http://dapp.ptokens.io'],
['https://dapp.ptokens.io/#/swap?asset=btc&from=btc&to=eth'],
])('Should show the url popup only on specific url', async (url) => {
Object.defineProperty(window, 'location', {
value: {
href: url,
},
})
render(<RedirectBanner />)
const textElement = screen.getByText((content) => content.includes(expectedText))
expect(textElement).toBeInTheDocument()
})

test.each([
['http://p.network/'],
['http://pnetworkprotocol.eth'],
['https://dapp.pnetworkprotocol.eth.limo/'],
['ipns://dapp.pnetworkprotocol.eth']['https://dapp.pnetworkprotocol.eth/#/swap?asset=btc&from=btc&to=eth'],
])('Should show the url popup only on specific url', async (url) => {
Object.defineProperty(window, 'location', {
value: {
href: url,
},
})
const { container } = render(<RedirectBanner />)
expect(container.firstChild).toBeNull()
})
})
3 changes: 0 additions & 3 deletions src/components/pages/swap/Swap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import Button from '../../atoms/button/Button'
import Icon from '../../atoms/icon/Icon'
import Switch from '../../atoms/switch/Switch'
import AddressWarning from '../../molecules/popup/AddressWarning'
import WarningPopup from '../../molecules/popup/Warning'
import Progress from '../../molecules/progress/Progress'
import AssetListModal from '../../organisms/assetListModal/AssetListModal'
import DepositAddressModal from '../../organisms/depositAddressModal/DepositAddressModal'
Expand Down Expand Up @@ -196,7 +195,6 @@ const Swap = ({
const [notifyMigration, setNotifyMigration] = useState()
const [TosShow, setTosShow] = useState(false)
const [AddressWarningShow, setAddressWarningShow] = useState(false)
const [showWarningPopup, setShowWarningPopup] = useState(true)

const {
from,
Expand Down Expand Up @@ -281,7 +279,6 @@ const Swap = ({
return (
<React.Fragment>
<Container>
<WarningPopup show={showWarningPopup} onClose={() => setShowWarningPopup(false)} />
<Row>
<Col className="d-flex justify-content-center">
{assets.find(({ id }) => id === 'OLD_PBTC_ON_BSC_MAINNET') &&
Expand Down
63 changes: 54 additions & 9 deletions src/components/pages/swap/__test__/Swap.test.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/* eslint-disable import/first */
import UserEvent from '@testing-library/user-event'
import { describe, expect, it, vi } from 'vitest'
import { waitFor, render, screen, getByText } from '@testing-library/react'
import UserEvent from '@testing-library/user-event'
import BigNumber from 'bignumber.js'
import { useCallback, useState } from 'react'
import { ThemeContext } from 'styled-components'
import * as SwapInfo from '../../../organisms/swapInfo/SwapInfo'
import * as AssetListModal from '../../../organisms/assetListModal/AssetListModal'
import * as feeUtils from '../../../../utils/fee'
import Swap from '../Swap'
import { describe, expect, it, vi } from 'vitest'

import { PBTC_ON_ETH_MAINNET, PNT_ON_BSC_MAINNET, PNT_ON_ETH_MAINNET } from '../../../../constants'
import swapAssets from '../../../../settings/swap-assets'
import { getDefaultSelection } from '../../../../store/swap/utils/default-selection'
import { useCallback, useState } from 'react'
import * as feeUtils from '../../../../utils/fee'
import * as AssetListModal from '../../../organisms/assetListModal/AssetListModal'
import * as SwapInfo from '../../../organisms/swapInfo/SwapInfo'
import Swap from '../Swap'

const Wrapper = ({ asset, originBlockchain, destBlockchain }) => {
const ThemeContextMock = {}
Expand Down Expand Up @@ -60,6 +63,48 @@ describe('Swap', async () => {
expect(computeSwap).toBeCalledTimes(2)
})

it('Should prevent swap if balance is 0', async () => {
vi.spyOn(SwapInfo, 'default').mockImplementation(() => <div data-testid="swap-info" />)
vi.spyOn(feeUtils, 'getSwapFees').mockResolvedValue({ basisPoints: 15, networkFee: 1e18, minProtocolFee: 2e18 })
swapAssets.find((_el) => _el.id === PNT_ON_ETH_MAINNET).balance = BigNumber(0)
swapAssets.find((_el) => _el.id === PNT_ON_BSC_MAINNET).balance = BigNumber(0)
render(<Wrapper asset="pnt" originBlockchain="eth" destBlockchain="bsc" />)
await waitFor(() => expect(screen.getByText(/balance is 0/)).toBeInTheDocument())
const [, , swapButton] = screen.getAllByRole('button')
const [fromInput, toInput, addressInput] = screen.getAllByRole('textbox')
await UserEvent.type(fromInput, '1')
expect(fromInput).toHaveAttribute('value', '1')
expect(toInput).toHaveAttribute('value', '-2')
expect(swapButton).toHaveTextContent(
`${swapAssets.find((_el) => _el.id === PNT_ON_ETH_MAINNET).symbol} balance is 0`
)
expect(swapButton).toBeDisabled()
})

it('Should continue with balance null', async () => {
vi.spyOn(SwapInfo, 'default').mockImplementation(() => <div data-testid="swap-info" />)
vi.spyOn(feeUtils, 'getSwapFees').mockResolvedValue({ basisPoints: 15, networkFee: 1e18, minProtocolFee: 2e18 })
swapAssets.find((_el) => _el.id === 'BTC').balance = null
swapAssets.find((_el) => _el.id === PBTC_ON_ETH_MAINNET).balance = BigNumber(0)
render(<Wrapper asset="btc" originBlockchain="btc" destBlockchain="eth" />)
await waitFor(() => expect(screen.getByText(/Enter an address/)).toBeInTheDocument())
const [, swapButton] = screen.getAllByRole('button')
const [fromInput, toInput, addressInput] = screen.getAllByRole('textbox')
await UserEvent.type(fromInput, '1')
expect(fromInput).toHaveAttribute('value', '1')
expect(toInput).toHaveAttribute('value', '-2')
expect(swapButton).toHaveTextContent('Amount too low')
await UserEvent.type(fromInput, '0')
expect(fromInput).toHaveAttribute('value', '10')
expect(toInput).toHaveAttribute('value', '7')
expect(swapButton).toHaveTextContent('Enter an address')
await UserEvent.type(addressInput, 'tttt')
expect(swapButton).toHaveTextContent('Invalid Address')
await UserEvent.clear(addressInput)
await UserEvent.type(addressInput, '0xA8Ae3c4cF1c92ADFf13e33b35280fc59b6600cA3')
expect(swapButton).toHaveTextContent('Get Deposit Address')
})

it('Should update "to" amount correctly', async () => {
vi.spyOn(SwapInfo, 'default').mockImplementation(() => <div data-testid="swap-info" />)
vi.spyOn(feeUtils, 'getSwapFees').mockResolvedValue({ basisPoints: 15, networkFee: 1e18, minProtocolFee: 2e18 })
Expand Down Expand Up @@ -88,13 +133,13 @@ describe('Swap', async () => {
render(<Wrapper />)
await waitFor(() => expect(screen.getByText(/Enter an address/)).toBeInTheDocument())
let img1, img2, img3
;[, img1, , img2, img3] = screen.getAllByRole('img')
;[img1, , img2, img3] = screen.getAllByRole('img')
expect(img1).toHaveAttribute('src', './assets/svg/BTC.svg')
expect(img2).toHaveAttribute('src', './assets/svg/pBTC.svg')
expect(img3).toHaveAttribute('src', './assets/svg/ETH.svg')
const changeOrderButton = screen.getByTestId('icon-sort')
await UserEvent.click(changeOrderButton)
;[, img1, img2, , , img3] = screen.getAllByRole('img')
;[img1, img2, , , img3] = screen.getAllByRole('img')
expect(img1).toHaveAttribute('src', './assets/svg/pBTC.svg')
expect(img2).toHaveAttribute('src', './assets/svg/ETH.svg')
expect(img3).toHaveAttribute('src', './assets/svg/BTC.svg')
Expand Down
5 changes: 5 additions & 0 deletions src/hooks/use-swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ const useSwap = ({
return
}

if (BigNumber.isBigNumber(from.balance) && from.balance.isZero()) {
updateSwapButton(`${from.symbol} balance is 0`, true)
return
}

if (BigNumber(toAmount).isLessThan(0)) {
updateSwapButton('Amount too low', true)
return
Expand Down

1 comment on commit f76e6e6

@4everland
Copy link

@4everland 4everland bot commented on f76e6e6 Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following parameters

parameters Value
IPFS CID bafybeibltedlk2sp5z5buhgkva35e5vymlyciqc2bfheaw4apmufr5ceza
Assigned domain https://ptokens-dapp-zwtezo40-pnetwork-association.4everland.app
https://ptokens-dapp.4everland.app
Custom domain

Please sign in to comment.