Skip to content

Commit

Permalink
feat(nfts): start on transfer work
Browse files Browse the repository at this point in the history
  • Loading branch information
plondon committed Dec 6, 2021
1 parent 78b3cff commit f7834c2
Show file tree
Hide file tree
Showing 12 changed files with 304 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const TabMenuItem = (props) => {
const isSelectedOrActive = selected || className === 'active'

return (
<BaseTabMenuItem selected={isSelectedOrActive} {...rest}>
<BaseTabMenuItem role='button' selected={isSelectedOrActive} {...rest}>
{children}
</BaseTabMenuItem>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,18 @@ export default ({ api }: { api: APIType }) => {
order
)
yield put(A.fetchFeesSuccess(fees))
} else if (action.payload.operation === GasCalculationOperations.Transfer) {
fees = yield call(
calculateGasFees,
GasCalculationOperations.Transfer,
signer,
undefined,
undefined,
undefined,
action.payload.asset,
action.payload.to
)
yield put(A.fetchFeesSuccess(fees))
}
} catch (e) {
// eslint-disable-next-line no-console
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export const getOffersMade = (state: RootState) => state.components.nfts.offersM
export const getOrderFlow = (state: RootState) => state.components.nfts.orderFlow
export const getCancelListing = (state: RootState) => state.components.nfts.cancelListing
export const getSellOrder = (state: RootState) => state.components.nfts.sellOrder
export const getTransfer = (state: RootState) => state.components.nfts.transfer
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ const initialState: NftsStateType = {
order: Remote.NotAsked,
step: NftOrderStepEnum.SHOW_ASSET
},
sellOrder: Remote.NotAsked
sellOrder: Remote.NotAsked,
transfer: Remote.NotAsked
}

const nftsSlice = createSlice({
Expand Down Expand Up @@ -129,6 +130,23 @@ const nftsSlice = createSlice({
createSellOrderSuccess: (state, action: PayloadAction<Order>) => {
state.sellOrder = Remote.Success(action.payload)
},
createTransfer: (
state,
action: PayloadAction<{
asset: NftAssetsType['assets'][0]
gasData: GasDataI
to: string
}>
) => {},
createTransferFailure: (state, action: PayloadAction<string>) => {
state.transfer = Remote.Failure(action.payload)
},
createTransferLoading: (state) => {
state.transfer = Remote.Loading
},
createTransferSuccess: (state, action: PayloadAction<boolean>) => {
state.transfer = Remote.Success(action.payload)
},
fetchFees: (
state,
action: PayloadAction<
Expand All @@ -143,6 +161,11 @@ const nftsSlice = createSlice({
operation: GasCalculationOperations.Sell
startPrice: number
}
| {
asset: NftAsset
operation: GasCalculationOperations.Transfer
to: string
}
| {
operation: GasCalculationOperations.Cancel
order: SellOrder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export enum NftOrderStepEnum {
CONFIRM_BUY = 'CONFIRM_BUY',
MAKE_OFFER = 'MAKE_OFFER',
MARK_FOR_SALE = 'MARK_FOR_SALE',
SHOW_ASSET = 'SHOW_ASSET'
SHOW_ASSET = 'SHOW_ASSET',
TRANSFER = 'TRANSFER'
}

export type NftsStateType = {
Expand Down Expand Up @@ -53,4 +54,5 @@ export type NftsStateType = {
step: NftOrderStepEnum
}
sellOrder: RemoteDataType<string, boolean>
transfer: RemoteDataType<string, boolean>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react'
import { FormattedMessage } from 'react-intl'

import { Link, Text } from 'blockchain-info-components'
import { NftOrderStepEnum } from 'data/components/nfts/types'

import { Props as OwnProps } from '../..'

const CTA: React.FC<Props> = (props) => {
const { nftActions } = props

return (
<>
<Text size='12px' weight={500} style={{ margin: '8px 0', textAlign: 'center' }}>
Or
</Text>
<Link
weight={600}
size='14px'
onClick={() => nftActions.setOrderFlowStep({ step: NftOrderStepEnum.TRANSFER })}
style={{ display: 'block', textAlign: 'center', width: '100%' }}
>
<FormattedMessage id='copy.transfer' defaultMessage='Transfer' />
</Link>
</>
)
}

type Props = OwnProps

export default CTA
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { useEffect } from 'react'
import { FormattedMessage } from 'react-intl'
import BigNumber from 'bignumber.js'

import { GasCalculationOperations, NftAsset } from '@core/network/api/nfts/types'
import { NULL_ADDRESS } from '@core/redux/payment/nfts/utils'
import { SpinningLoader } from 'blockchain-info-components'
import CoinDisplay from 'components/Display/CoinDisplay'
import FiatDisplay from 'components/Display/FiatDisplay'
import { Title, Value } from 'components/Flyout/model'

import { CTARow } from '../../../components'
import { Props as OwnProps } from '../..'

const Fees: React.FC<Props> = (props) => {
const { nftActions, orderFlow } = props

useEffect(() => {
if (props.asset) {
nftActions.fetchFees({
asset: props.asset,
operation: GasCalculationOperations.Transfer,
to: NULL_ADDRESS
})
}
}, [])

return (
<>
{orderFlow.fees.cata({
Failure: () => null,
Loading: () => (
<CTARow>
<div style={{ marginBottom: '22px' }}>
<SpinningLoader width='14px' height='14px' borderWidth='3px' />
</div>
</CTARow>
),
NotAsked: () => null,
Success: (val) => {
return (
<>
<CTARow>
<Title>
<FormattedMessage id='copy.fees' defaultMessage='Fees' />
</Title>
<Value>
<div style={{ display: 'flex' }}>
<CoinDisplay size='14px' color='black' weight={600} coin='ETH'>
{new BigNumber(val.totalFees).multipliedBy(val.gasPrice).toString()}
</CoinDisplay>
&nbsp;-&nbsp;
<FiatDisplay size='12px' color='grey600' weight={600} coin='ETH'>
{new BigNumber(val.totalFees).multipliedBy(val.gasPrice).toString()}
</FiatDisplay>
</div>
</Value>
</CTARow>
</>
)
}
})}
</>
)
}

type Props = OwnProps & { asset: NftAsset }

export default Fees
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import BuyFees from './BuyNow/fees'
import CancelListingCTA from './CancelListing/cta'
import CancelListingFees from './CancelListing/fees'
import SellCTA from './Sell/cta'
import TransferCTA from './Transfer/cta'

const ShowAsset: React.FC<Props> = (props) => {
const { close, orderFlow } = props
Expand Down Expand Up @@ -130,7 +131,10 @@ const ShowAsset: React.FC<Props> = (props) => {
</>
) : /* No sell_orders, can mark for sale */
!val.sell_orders?.length ? (
<SellCTA {...props} />
<>
<SellCTA {...props} />
<TransferCTA {...props} />
</>
) : null}
</StickyCTA>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import React from 'react'
import { FormattedMessage } from 'react-intl'
import { connect, ConnectedProps } from 'react-redux'
import { compose } from 'redux'
import { Field, reduxForm } from 'redux-form'

import { Remote } from '@core'
import { convertCoinToCoin } from '@core/exchange'
import { GasCalculationOperations } from '@core/network/api/nfts/types'
import { Button, Icon, SpinningLoader, Text } from 'blockchain-info-components'
import { ErrorCartridge } from 'components/Cartridge'
import FiatDisplay from 'components/Display/FiatDisplay'
import { Row, Title, Value } from 'components/Flyout/model'
import { Form, NumberBox, TextBox } from 'components/Form'
import TabMenuNftSaleType from 'components/Form/TabMenuNftSaleType'
import { selectors } from 'data'
import { NftOrderStepEnum } from 'data/components/nfts/types'
import { required, validEthAddress } from 'services/forms'

import { AssetDesc, FullAssetImage, StickyCTA } from '../../components'
import { Props as OwnProps } from '..'
import TransferFees from '../ShowAsset/Transfer/fees'

const Transfer: React.FC<Props> = (props) => {
const { close, formValues, nftActions, orderFlow } = props
const coin = 'ETH'

const disabled = formValues ? !formValues.to || Remote.Loading.is(props.sellOrder) : true

return (
<>
{orderFlow.asset.cata({
Failure: (e) => <Text>{e}</Text>,
Loading: () => (
<AssetDesc>
<SpinningLoader width='14px' height='14px' borderWidth='3px' />
</AssetDesc>
),
NotAsked: () => null,
Success: (val) => (
<>
<div style={{ position: 'relative' }}>
<Icon
onClick={() => nftActions.setOrderFlowStep({ step: NftOrderStepEnum.SHOW_ASSET })}
name='arrow-left'
cursor
role='button'
style={{ left: '40px', position: 'absolute', top: '40px' }}
/>
<Icon
onClick={() => close()}
name='close'
cursor
role='button'
style={{ position: 'absolute', right: '40px', top: '40px' }}
/>
<FullAssetImage cropped backgroundImage={val?.image_url.replace(/=s\d*/, '')} />
</div>
<AssetDesc>
<Text size='16px' color='grey900' weight={600}>
{val?.collection?.name}
</Text>
<Text style={{ marginTop: '4px' }} size='20px' color='grey900' weight={600}>
{val?.name}
</Text>
</AssetDesc>
<Row>
<Title>
<FormattedMessage id='copy.description' defaultMessage='Description' />
</Title>
<Value>
{val?.description || (
<FormattedMessage id='copy.none_found' defaultMessage='None found.' />
)}
</Value>
</Row>
<Form>
<Row>
<Title>
<b>
<FormattedMessage id='copy.to' defaultMessage='To' />
</b>
</Title>
<Value>
<Field name='to' component={TextBox} validate={[required, validEthAddress]} />
</Value>
</Row>
</Form>
<StickyCTA>
<TransferFees {...props} asset={val} />
{props.orderFlow.fees.cata({
Failure: () => (
<Button jumbo nature='sent' fullwidth data-e2e='sellNft' disabled>
<FormattedMessage id='copy.transfer' defaultMessage='Transfer' />
</Button>
),
Loading: () => (
<Button jumbo nature='primary' fullwidth data-e2e='sellNft' disabled>
<FormattedMessage id='copy.transfer' defaultMessage='Transfer' />
</Button>
),
NotAsked: () => null,
Success: (fees) => (
<Button
jumbo
nature='primary'
fullwidth
data-e2e='transferNft'
disabled={disabled}
onClick={() =>
nftActions.createTransfer({
asset: val,
gasData: fees,
to: formValues.to
})
}
>
<FormattedMessage id='copy.transfer' defaultMessage='Transfer' />
</Button>
)
})}
</StickyCTA>
</>
)
})}
</>
)
}

const mapStateToProps = (state) => ({
formValues: selectors.form.getFormValues('nftTransfer')(state) as { to: string }
})

const connector = connect(mapStateToProps)

const enhance = compose(
reduxForm<{}, OwnProps>({
form: 'nftTransfer'
}),
connector
)

type Props = OwnProps & ConnectedProps<typeof connector>

export default enhance(Transfer) as React.FC<OwnProps>

0 comments on commit f7834c2

Please sign in to comment.