Skip to content

Commit

Permalink
feat(nfts): show user offers
Browse files Browse the repository at this point in the history
  • Loading branch information
plondon committed Nov 24, 2021
1 parent f9ddd10 commit 82601be
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ export default ({ api }) => {
return function* nftSaga() {
yield takeLatest(actions.cancelListing, nftsSagas.cancelListing)
yield takeLatest(actions.clearAndRefetchAssets, nftsSagas.clearAndRefetchAssets)
yield takeLatest(actions.clearAndRefetchOffersMade, nftsSagas.clearAndRefetchOffersMade)
yield takeLatest(actions.clearAndRefetchOrders, nftsSagas.clearAndRefetchOrders)
yield takeLatest(actions.createOffer, nftsSagas.createOffer)
yield takeLatest(actions.createOrder, nftsSagas.createOrder)
yield takeLatest(actions.createSellOrder, nftsSagas.createSellOrder)
yield takeLatest(actions.fetchFees, nftsSagas.fetchFees)
yield takeLatest(actions.fetchNftAssets, nftsSagas.fetchNftAssets)
yield takeLatest(actions.fetchNftCollections, nftsSagas.fetchNftCollections)
yield takeLatest(actions.fetchNftOffersMade, nftsSagas.fetchNftOffersMade)
yield takeLatest(actions.fetchNftOrders, nftsSagas.fetchNftOrders)
yield takeLatest(actions.nftOrderFlowClose, nftsSagas.nftOrderFlowClose)
yield takeLatest(actions.nftOrderFlowOpen, nftsSagas.nftOrderFlowOpen)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ export const logLocation = 'components/nfts/sagas'
const taskToPromise = (t) => new Promise((resolve, reject) => t.fork(reject, resolve))

export default ({ api }: { api: APIType }) => {
const clearAndRefetchAssets = function* () {
yield put(A.resetNftAssets())
yield put(A.fetchNftAssets())
}

const clearAndRefetchOrders = function* () {
yield put(A.resetNftOrders())
yield put(A.fetchNftOrders())
}

const clearAndRefetchOffersMade = function* () {
yield put(A.resetNftOffersMade())
yield put(A.fetchNftOffersMade())
}

const fetchNftAssets = function* () {
try {
const assets = S.getNftAssets(yield select())
Expand All @@ -63,16 +78,6 @@ export default ({ api }: { api: APIType }) => {
}
}

const clearAndRefetchAssets = function* () {
yield put(A.resetNftAssets())
yield put(A.fetchNftAssets())
}

const clearAndRefetchOrders = function* () {
yield put(A.resetNftOrders())
yield put(A.fetchNftOrders())
}

const fetchNftCollections = function* (action: ReturnType<typeof A.fetchNftCollections>) {
try {
const collections = S.getNftCollections(yield select())
Expand Down Expand Up @@ -100,6 +105,32 @@ export default ({ api }: { api: APIType }) => {
}
}

const fetchNftOffersMade = function* () {
try {
const offers = S.getOffersMade(yield select())
if (offers.atBound) return
yield put(A.fetchNftOffersMadeLoading())
const ethAddrR = selectors.core.kvStore.eth.getDefaultAddress(yield select())
const ethAddr = ethAddrR.getOrFail('No ETH address.')
const { asset_events }: ReturnType<typeof api.getOffersMade> = yield call(
api.getOffersMade,
ethAddr,
offers.page
)

if (asset_events.length < NFT_ORDER_PAGE_LIMIT) {
yield put(A.setOffersMadeBounds({ atBound: true }))
} else {
yield put(A.setOffersMadeData({ page: offers.page + 1 }))
}

yield put(A.fetchNftOffersMadeSuccess(asset_events))
} catch (e) {
const error = errorHandler(e)
yield put(A.fetchNftOffersMadeFailure(error))
}
}

const fetchNftOrders = function* () {
try {
const marketplace = S.getMarketplace(yield select())
Expand Down Expand Up @@ -452,13 +483,15 @@ export default ({ api }: { api: APIType }) => {
return {
cancelListing,
clearAndRefetchAssets,
clearAndRefetchOffersMade,
clearAndRefetchOrders,
createOffer,
createOrder,
createSellOrder,
fetchFees,
fetchNftAssets,
fetchNftCollections,
fetchNftOffersMade,
fetchNftOrders,
formChanged,
formInitialized,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RootState } from 'data/rootReducer'
export const getNftAssets = (state: RootState) => state.components.nfts.assets
export const getNftCollections = (state: RootState) => state.components.nfts.collections
export const getMarketplace = (state: RootState) => state.components.nfts.marketplace
export const getOffersMade = (state: RootState) => state.components.nfts.offersMade
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { init } from 'ramda'

import { Remote } from '@core'
import {
AssetEventsType,
CollectionData,
ExplorerGatewayNftCollectionType,
GasCalculationOperations,
GasDataI,
NftAsset,
NftAssetsType,
NftOrdersType,
OfferEventsType,
Order,
SellOrder
} from '@core/network/api/nfts/types'
Expand Down Expand Up @@ -38,6 +40,13 @@ const initialState: NftsStateType = {
page: 0,
token_ids_queried: []
},
offersMade: {
atBound: false,
isFailure: false,
isLoading: true,
list: [],
page: 0
},
orderFlow: {
activeOrder: null,
asset: Remote.NotAsked,
Expand Down Expand Up @@ -66,6 +75,7 @@ const nftsSlice = createSlice({
state.cancelListing = Remote.Success(true)
},
clearAndRefetchAssets: (state) => {},
clearAndRefetchOffersMade: (state) => {},
clearAndRefetchOrders: (state) => {},
createOffer: (
state,
Expand Down Expand Up @@ -182,6 +192,18 @@ const nftsSlice = createSlice({
) => {
state.collections = Remote.Success(action.payload)
},
fetchNftOffersMade: () => {},
fetchNftOffersMadeFailure: (state, action: PayloadAction<string>) => {
state.offersMade.isFailure = true
},
fetchNftOffersMadeLoading: (state) => {
state.offersMade.isLoading = true
},
fetchNftOffersMadeSuccess: (state, action: PayloadAction<OfferEventsType['asset_events']>) => {
state.offersMade.isFailure = false
state.offersMade.isLoading = false
state.offersMade.list = [...state.offersMade.list, ...action.payload]
},
fetchNftOrderAsset: () => {},
fetchNftOrderAssetFailure: (state, action: PayloadAction<string>) => {
state.orderFlow.asset = Remote.Failure(action.payload)
Expand Down Expand Up @@ -232,6 +254,13 @@ const nftsSlice = createSlice({
state.assets.isLoading = false
state.assets.list = []
},
resetNftOffersMade: (state) => {
state.offersMade.atBound = false
state.offersMade.page = 0
state.offersMade.isFailure = false
state.offersMade.isLoading = true
state.offersMade.list = []
},
resetNftOrders: (state) => {
state.marketplace.atBound = false
state.marketplace.page = 0
Expand Down Expand Up @@ -274,6 +303,12 @@ const nftsSlice = createSlice({
if (action.payload.token_ids_queried)
state.marketplace.token_ids_queried = action.payload.token_ids_queried
},
setOffersMadeBounds: (state, action: PayloadAction<{ atBound: boolean }>) => {
state.offersMade.atBound = action.payload.atBound
},
setOffersMadeData: (state, action: PayloadAction<{ page?: number }>) => {
state.assets.page = action.payload.page || 0
},
setOrderFlowStep: (state, action: PayloadAction<{ step: NftOrderStepEnum }>) => {
state.orderFlow.step = action.payload.step
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
AssetEventsType,
CollectionData,
ExplorerGatewayNftCollectionType,
NftAsset,
NftAssetsType,
NftOrdersType,
OfferEventsType,
Order
} from '@core/network/api/nfts/types'
import { calculateGasFees } from '@core/redux/payment/nfts'
Expand Down Expand Up @@ -36,6 +38,13 @@ export type NftsStateType = {
page: number
token_ids_queried: string[]
}
offersMade: {
atBound?: boolean
isFailure: boolean
isLoading: boolean
list: OfferEventsType['asset_events']
page: number
}
orderFlow: {
activeOrder: NftOrdersType['orders'][0] | null
asset: RemoteDataType<string, NftAsset>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const NftHeader: React.FC<InjectedFormProps<{}, Props> & Props> = ({
>
My Collection
</TabMenuItem>
<TabMenuItem onClick={() => setActiveTab('offers')} selected={activeTab === 'offers'}>
Offers
</TabMenuItem>
</TabMenu>
</TabsContainer>
<StyledForm onSubmit={handleSubmit}>
Expand Down Expand Up @@ -89,8 +92,8 @@ const NftHeader: React.FC<InjectedFormProps<{}, Props> & Props> = ({
}

type Props = OwnProps & {
activeTab: 'explore' | 'my-collection'
setActiveTab: React.Dispatch<React.SetStateAction<'explore' | 'my-collection'>>
activeTab: 'explore' | 'my-collection' | 'offers'
setActiveTab: React.Dispatch<React.SetStateAction<'explore' | 'my-collection' | 'offers'>>
}

export default reduxForm<{}, Props>({ form: 'nftSearch' })(NftHeader)
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useEffect } from 'react'
import styled from 'styled-components'

import { displayCoinToCoin } from '@core/exchange'
import { Button, Text } from 'blockchain-info-components'
import LazyLoadWrapper from 'components/LazyLoadContainer'

import { Props as OwnProps } from '..'

const Row = styled(Text)`
width: 100%;
display: flex;
font-size: 14px;
font-weight: 600;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid ${(props) => props.theme.grey000};
`

const Col = styled.div`
display: flex;
align-items: center;
> div {
margin-right: 8px;
}
`

const Offers: React.FC<Props> = (props) => {
useEffect(() => {
props.nftsActions.fetchNftOffersMade()
}, [])

return (
<LazyLoadWrapper onLazyLoad={() => props.nftsActions.fetchNftOffersMade()}>
{props.offersMade.list.map((offer, i) => {
return (
<Row key={i}>
<Col>
<img
style={{ height: '32px', marginRight: '8px' }}
alt=''
src={offer.asset.image_thumbnail_url}
/>
<div>{offer.asset.collection.name}</div>
<div>-</div>
<div>({offer.asset.name})</div>
</Col>
<Col>
<div>
{displayCoinToCoin({ coin: offer.payment_token.symbol, value: offer.bid_amount })}
</div>
<div>
<Button width='72px' height='32px' data-e2e='cancelOffer' nature='empty-blue'>
Cancel
</Button>
</div>
</Col>
</Row>
)
})}
</LazyLoadWrapper>
)
}

type Props = OwnProps

export default Offers
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const YourCollection: React.FC<Props> = (props) => {
}

export type Props = OwnProps & {
setActiveTab: React.Dispatch<React.SetStateAction<'explore' | 'my-collection'>>
setActiveTab: React.Dispatch<React.SetStateAction<'explore' | 'my-collection' | 'offers'>>
}

export default YourCollection
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { RootState } from 'data/rootReducer'

import NftHeader from './Header'
import Marketplace from './Marketplace'
import Offers from './Offers'
import YourCollection from './YourCollection'

const NftPage = styled.div`
width: 100%;
`

const Nfts: React.FC<Props> = (props) => {
const [activeTab, setActiveTab] = useState<'explore' | 'my-collection'>('explore')
const [activeTab, setActiveTab] = useState<'explore' | 'my-collection' | 'offers'>('explore')

useEffect(() => {
props.nftsActions.fetchNftCollections({})
Expand All @@ -28,6 +29,7 @@ const Nfts: React.FC<Props> = (props) => {
{activeTab === 'my-collection' ? (
<YourCollection {...props} setActiveTab={setActiveTab} />
) : null}
{activeTab === 'offers' ? <Offers {...props} /> : null}
</NftPage>
)
}
Expand All @@ -37,7 +39,8 @@ const mapStateToProps = (state: RootState) => ({
collections: selectors.components.nfts.getNftCollections(state),
defaultEthAddr: selectors.core.kvStore.eth.getDefaultAddress(state).getOrElse(''),
formValues: selectors.form.getFormValues('nftMarketplace')(state),
marketplace: selectors.components.nfts.getMarketplace(state)
marketplace: selectors.components.nfts.getMarketplace(state),
offersMade: selectors.components.nfts.getOffersMade(state)
})

const mapDispatchToProps = (dispatch) => ({
Expand Down

0 comments on commit 82601be

Please sign in to comment.