Commit 34431bcb authored by Jack Short's avatar Jack Short Committed by GitHub

feat: porting over transaction screens (#4720)

* feat: porting over transaction screens

* cannot trigger unless flag enabled

* inital comment addressings

* adjusting zIndex

* changing zIndex when modal is open
parent 0041b787
...@@ -2,6 +2,7 @@ import { useWeb3React } from '@web3-react/core' ...@@ -2,6 +2,7 @@ import { useWeb3React } from '@web3-react/core'
import AddressClaimModal from 'components/claim/AddressClaimModal' import AddressClaimModal from 'components/claim/AddressClaimModal'
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked' import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
import TokensBanner from 'components/Tokens/TokensBanner' import TokensBanner from 'components/Tokens/TokensBanner'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens' import { TokensVariant, useTokensFlag } from 'featureFlags/flags/tokens'
import useAccountRiskCheck from 'hooks/useAccountRiskCheck' import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
import { lazy } from 'react' import { lazy } from 'react'
...@@ -11,6 +12,7 @@ import { ApplicationModal } from 'state/application/reducer' ...@@ -11,6 +12,7 @@ import { ApplicationModal } from 'state/application/reducer'
const Cart = lazy(() => import('nft/components/sell/modal/ListingTag')) const Cart = lazy(() => import('nft/components/sell/modal/ListingTag'))
const Bag = lazy(() => import('nft/components/bag/Bag')) const Bag = lazy(() => import('nft/components/bag/Bag'))
const TransactionCompleteModal = lazy(() => import('nft/components/collection/TransactionCompleteModal'))
export default function TopLevelModals() { export default function TopLevelModals() {
const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM) const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM)
...@@ -30,6 +32,7 @@ export default function TopLevelModals() { ...@@ -30,6 +32,7 @@ export default function TopLevelModals() {
(location.pathname.includes('/pool') || location.pathname.includes('/swap')) && <TokensBanner />} (location.pathname.includes('/pool') || location.pathname.includes('/swap')) && <TokensBanner />}
<Cart /> <Cart />
<Bag /> <Bag />
{useNftFlag() === NftVariant.Enabled && <TransactionCompleteModal />}
</> </>
) )
} }
...@@ -13,7 +13,6 @@ export const bagContainer = style([ ...@@ -13,7 +13,6 @@ export const bagContainer = style([
color: 'textPrimary', color: 'textPrimary',
paddingTop: '20', paddingTop: '20',
paddingBottom: '24', paddingBottom: '24',
zIndex: { sm: 'offcanvas', md: '3' },
}), }),
{ {
'@media': { '@media': {
......
...@@ -314,7 +314,7 @@ const Bag = () => { ...@@ -314,7 +314,7 @@ const Bag = () => {
<> <>
{bagExpanded && shouldShowBag ? ( {bagExpanded && shouldShowBag ? (
<Portal> <Portal>
<Column className={styles.bagContainer}> <Column zIndex={isMobile || isOpen ? 'modal' : '3'} className={styles.bagContainer}>
<BagHeader numberOfAssets={itemsInBag.length} toggleBag={toggleBag} resetFlow={reset} /> <BagHeader numberOfAssets={itemsInBag.length} toggleBag={toggleBag} resetFlow={reset} />
{itemsInBag.length === 0 && bagStatus === BagStatus.ADDING_TO_BAG && <EmptyState />} {itemsInBag.length === 0 && bagStatus === BagStatus.ADDING_TO_BAG && <EmptyState />}
<ScrollingIndicator top show={userCanScroll && scrollProgress > 0} /> <ScrollingIndicator top show={userCanScroll && scrollProgress > 0} />
......
import { globalStyle, style } from '@vanilla-extract/css'
import { center } from 'nft/css/common.css'
import { sprinkles, themeVars, vars } from 'nft/css/sprinkles.css'
globalStyle('a', {
color: vars.color.genieBlue,
fontWeight: 'bold',
textDecoration: 'none',
})
export const modalContainer = style([
sprinkles({
display: 'flex',
position: 'fixed',
flexWrap: 'wrap',
height: 'full',
width: { sm: 'full', md: 'min' },
left: { sm: '0', md: '1/2' },
top: '0',
zIndex: 'modal',
}),
{
alignContent: 'center',
'@media': {
'screen and (min-width: 656px)': {
marginLeft: '-320px',
},
},
},
])
export const successModal = style([
sprinkles({
background: 'backgroundSurface',
borderRadius: '20',
display: 'flex',
flexWrap: 'wrap',
height: 'min',
position: 'relative',
width: { sm: 'full', md: 'min' },
paddingTop: { sm: '28', md: '28' },
paddingBottom: { sm: '28', md: '28' },
}),
{
boxShadow: vars.color.dropShadow,
boxSizing: 'border-box',
'@media': {
'screen and (min-width: 656px)': {
minWidth: '640px',
},
},
},
])
export const uniLogo = style([
sprinkles({
position: 'absolute',
left: '32',
right: '40',
}),
])
export const title = style([
sprinkles({
fontWeight: 'bold',
color: 'textPrimary',
fontSize: '20',
marginLeft: 'auto',
marginRight: 'auto',
marginTop: '0',
marginBottom: { sm: '8', md: '4' },
}),
{
lineHeight: '25px',
},
])
export const walletAddress = style([
sprinkles({
color: 'textSecondary',
fontSize: '10',
display: 'flex',
alignItems: 'center',
height: 'min',
right: '16',
}),
{
bottom: '42px',
marginTop: '-2px',
lineHeight: '13px',
letterSpacing: '0.04em',
textTransform: 'uppercase',
},
])
export const addressHash = style([
sprinkles({
color: 'textSecondary',
fontSize: '10',
fontWeight: 'normal',
marginTop: '4',
}),
{
lineHeight: '13px',
letterSpacing: '0.04em',
},
])
export const subHeading = style([
sprinkles({
color: 'textPrimary',
fontSize: '14',
width: 'full',
textAlign: 'center',
marginLeft: 'auto',
marginRight: 'auto',
marginTop: '0',
marginBottom: '20',
}),
{
lineHeight: '18px',
},
])
export const successAssetsContainer = style([
sprinkles({
display: 'flex',
flexWrap: 'wrap',
width: 'full',
overflow: 'scroll',
justifyContent: 'center',
}),
{
height: 'min',
scrollbarWidth: 'none',
selectors: {
'&::-webkit-scrollbar': {
display: 'none',
},
},
},
])
export const successAssetImage = style([
sprinkles({
borderRadius: '20',
flexShrink: '0',
}),
{
height: 'auto',
width: 'auto',
boxSizing: 'border-box',
objectFit: 'contain',
},
])
export const successAssetImageGrid = style([
sprinkles({
marginRight: { sm: '4', md: '8' },
marginBottom: { sm: '4', md: '8' },
}),
])
export const overflowFade = style({
backgroundImage: `linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, ${themeVars.colors.backgroundSurface} 100%)`,
width: '576px',
height: '20px',
marginLeft: '32px',
marginTop: '-20px',
})
export const successfulNftCount = style([
sprinkles({
fontWeight: 'normal',
fontSize: '14',
color: 'textPrimary',
marginTop: '0',
marginRight: '16',
marginBottom: '0',
}),
{
lineHeight: '20px',
// TODO: find a way to download the success modal with webkit text gradients
// background: 'magicGradient',
// backgroundClip: 'text',
// color: 'transparent',
},
])
export const totalEthCost = style([
sprinkles({
fontSize: '14',
color: 'textPrimary',
marginTop: '1',
marginBottom: '0',
}),
{
lineHeight: '18px',
},
])
export const bottomBar = style([
sprinkles({
color: 'textPrimary',
fontSize: '14',
}),
])
export const refundTextEthIcon = style([
sprinkles({
height: '16',
width: '16',
fill: 'textSecondary',
}),
{
marginLeft: '-2px',
marginBottom: '-3px',
marginRight: '-3px',
},
])
export const button = style([
sprinkles({
height: '40',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '14',
color: 'textPrimary',
display: 'flex',
alignItems: 'center',
marginBottom: 'auto',
marginRight: 'auto',
bottom: { sm: '20', md: 'auto' },
}),
{
left: 'calc(50% - 107px)',
width: '214px',
lineHeight: '18px',
borderRadius: '100px',
marginTop: '15px',
},
])
export const backArrow = style([
sprinkles({
fill: 'genieBlue',
marginLeft: '6',
marginRight: '1',
}),
])
export const circleButton = style([
center,
sprinkles({
marginRight: '8',
marginTop: '16',
marginBottom: 'auto',
borderRadius: 'round',
cursor: 'pointer',
backgroundColor: 'white',
border: 'none',
}),
{
height: '44px',
width: '44px',
},
])
export const mixedRefundModal = style([
sprinkles({
background: 'backgroundSurface',
borderRadius: '20',
display: 'flex',
flexWrap: 'wrap',
paddingTop: { sm: '24', md: '32' },
paddingRight: { sm: '16', md: '24' },
paddingLeft: { sm: '24', md: '32' },
height: 'min',
width: { sm: 'full', md: 'min' },
position: 'relative',
marginTop: '8',
}),
{
boxShadow: vars.color.dropShadow,
paddingBottom: '68px',
'@media': {
'screen and (min-width: 656px)': {
minWidth: '640px',
paddingBottom: '32px',
},
},
},
])
export const subtitle = style([
sprinkles({
color: 'textPrimary',
fontWeight: 'bold',
fontSize: '16',
marginLeft: '4',
marginRight: 'auto',
marginBottom: { sm: '0', md: 'auto' },
}),
{
lineHeight: '20px',
marginTop: '2px',
},
])
export const interStd = style([
sprinkles({
color: 'textPrimary',
fontSize: '14',
marginLeft: 'auto',
marginRight: 'auto',
marginTop: '10',
marginBottom: '16',
width: 'full',
}),
{
lineHeight: '18px',
},
])
export const totalUsdRefund = style([
sprinkles({
color: 'textSecondary',
fontSize: '12',
marginLeft: '4',
}),
{
lineHeight: '15px',
marginTop: '3px',
marginBottom: '2px',
},
])
export const refundAssetsContainer = style([
sprinkles({
height: { sm: 'min', md: 'full' },
width: { sm: 'full', md: 'half' },
flexWrap: 'wrap',
overflow: 'scroll',
flexDirection: 'row',
display: 'inline-flex',
paddingLeft: { md: '16' },
}),
{
maxHeight: '152px',
scrollbarWidth: 'none',
selectors: {
'&::-webkit-scrollbar': {
display: 'none',
},
},
},
])
export const refundAssetImage = style([
sprinkles({
height: '52',
width: '52',
borderRadius: '8',
marginRight: '4',
marginBottom: '1',
}),
{
boxSizing: 'border-box',
border: `2px solid ${themeVars.colors.backgroundSurface}`,
filter: 'grayscale(100%)',
},
])
export const refundEthCost = style([
sprinkles({
fontSize: '12',
color: 'textPrimary',
marginTop: '0',
marginLeft: 'auto',
marginRight: '0',
textAlign: 'right',
overflow: 'hidden',
whiteSpace: 'nowrap',
width: '36',
}),
{
lineHeight: '15px',
marginBottom: '9px',
textOverflow: 'ellipsis ".."',
},
])
export const refundEthIcon = style({
height: '14px',
width: '14px',
marginTop: '0px',
marginLeft: '-2px',
marginRight: '2px',
})
export const refundOverflowFade = style([
sprinkles({
width: { sm: 'full', md: 'half' },
marginLeft: 'auto',
zIndex: '1',
}),
{
backgroundImage: `linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, ${themeVars.colors.backgroundSurface} 100%)`,
height: '30px',
marginRight: '18px',
marginTop: '-20px',
},
])
export const fullRefundModal = style([
sprinkles({
background: 'backgroundSurface',
borderRadius: '20',
display: 'flex',
flexWrap: 'wrap',
marginRight: 'auto',
textAlign: 'center',
marginLeft: { sm: 'auto', md: '100' },
padding: '32',
height: 'min',
}),
{
boxShadow: vars.color.dropShadow,
width: '344px',
},
])
export const returnButton = style([
sprinkles({
height: '40',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '14',
color: 'explicitWhite',
backgroundColor: 'genieBlue',
display: 'flex',
alignItems: 'center',
marginLeft: 'auto',
marginRight: 'auto',
marginTop: '10',
}),
{
width: '276px',
lineHeight: '18px',
borderRadius: '100px',
},
])
export const fullRefundBackArrow = style([
sprinkles({
fill: 'explicitWhite',
marginLeft: '12',
marginRight: '28',
}),
])
export const bodySmall = style([
sprinkles({
color: 'textPrimary',
fontSize: '14',
marginLeft: 'auto',
marginRight: 'auto',
marginTop: '4',
}),
{
marginBottom: '22px',
lineHeight: '18px',
},
])
export const allUnavailableAssets = style([
sprinkles({
height: 'full',
width: 'full',
}),
{
overflow: 'auto',
maxHeight: '210px',
minHeight: '58px',
},
])
export const fullRefundOverflowFade = style({
backgroundImage: `linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, ${themeVars.colors.backgroundSurface} 100%)`,
width: '266px',
height: '20px',
marginTop: '-20px',
marginBottom: '20px',
position: 'relative',
})
export const toggleUnavailable = style([
sprinkles({
backgroundColor: 'backgroundSurface',
borderRadius: '8',
display: 'flex',
flexWrap: 'wrap',
marginTop: '1',
marginBottom: '1',
height: '52',
cursor: 'pointer',
}),
])
export const unavailableAssetPreview = style([
sprinkles({
borderRadius: '4',
height: '36',
width: '36',
position: 'relative',
}),
{
boxSizing: 'border-box',
border: `2px solid ${themeVars.colors.backgroundSurface}`,
marginLeft: '-16px',
filter: 'grayscale(100%)',
},
])
export const unavailableText = style([
sprinkles({
color: 'textSecondary',
fontWeight: 'normal',
fontSize: '14',
paddingTop: '8',
paddingBottom: '8',
paddingLeft: '12',
}),
{
fontStyle: 'normal',
lineHeight: '18px',
},
])
export const unavailableItems = style([
sprinkles({
fontWeight: 'normal',
fontSize: '12',
display: 'flex',
}),
{
fontStyle: 'normal',
lineHeight: '15px',
},
])
export const assetContainer = style({
height: '48px',
width: '48px',
flexShrink: '0',
marginRight: '4px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
})
export const fullRefundImage = style([
sprinkles({
borderRadius: '4',
height: 'auto',
maxHeight: '36',
width: 'auto',
maxWidth: '36',
objectFit: 'contain',
}),
{
boxSizing: 'border-box',
filter: 'grayscale(100%)',
},
])
export const chevron = style([
sprinkles({
marginBottom: 'auto',
marginLeft: '0',
marginRight: 'auto',
height: '20',
width: '20',
}),
{
marginTop: '7px',
},
])
export const chevronDown = style({
transform: 'rotate(180deg)',
})
import clsx from 'clsx'
import { Box } from 'nft/components/Box'
import { Portal } from 'nft/components/common/Portal'
import { Row } from 'nft/components/Flex'
import { BackArrowIcon, ChevronUpIcon, LightningBoltIcon, UniIcon } from 'nft/components/icons'
import { Overlay, stopPropagation } from 'nft/components/modals/Overlay'
import { vars } from 'nft/css/sprinkles.css'
import { useIsMobile, useSendTransaction, useTransactionResponse } from 'nft/hooks'
import { TxResponse, TxStateType } from 'nft/types'
import {
fetchPrice,
formatEthPrice,
formatUsdPrice,
formatUSDPriceWithCommas,
getSuccessfulImageSize,
parseTransactionResponse,
shortenTxHash,
} from 'nft/utils'
import { useEffect, useMemo, useRef, useState } from 'react'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import * as styles from './TransactionCompleteModal.css'
const TxCompleteModal = () => {
const [ethPrice, setEthPrice] = useState(3000)
const [showUnavailable, setShowUnavailable] = useState(false)
const txHash = useSendTransaction((state) => state.txHash)
const setTxState = useSendTransaction((state) => state.setState)
const txState = useSendTransaction((state) => state.state)
const transactionStateRef = useRef(txState)
const transactionResponse = useTransactionResponse((state) => state.transactionResponse)
const setTransactionResponse = useTransactionResponse((state) => state.setTransactionResponse)
const isMobile = useIsMobile()
const txHashUrl = getExplorerLink(1, txHash, ExplorerDataType.TRANSACTION)
const shouldShowModal = (txState === TxStateType.Success || txState === TxStateType.Failed) && txState
const {
nftsPurchased,
nftsNotPurchased,
showPurchasedModal,
showRefundModal,
totalPurchaseValue,
totalRefundValue,
totalUSDRefund,
txFeeFiat,
} = useMemo(() => {
return parseTransactionResponse(transactionResponse, ethPrice)
}, [transactionResponse, ethPrice])
const toggleShowUnavailable = () => {
setShowUnavailable(!showUnavailable)
}
function closeTxCompleteScreen() {
setTransactionResponse({} as TxResponse)
setTxState(TxStateType.New)
}
useEffect(() => {
fetchPrice().then((price) => {
setEthPrice(price ?? 0)
})
}, [])
useEffect(() => {
useSendTransaction.subscribe((state) => (transactionStateRef.current = state.state))
}, [])
return (
<>
{shouldShowModal && (
<Portal>
<Overlay onClick={closeTxCompleteScreen} />
<Box className={styles.modalContainer} onClick={closeTxCompleteScreen}>
{/* Successfully purchased NFTs */}
{showPurchasedModal && (
<Box className={styles.successModal} onClick={stopPropagation}>
<UniIcon color={vars.color.pink400} width="36" height="36" className={styles.uniLogo} />
<Box display="flex" flexWrap="wrap" width="full" height="min">
<h1 className={styles.title}>Complete!</h1>
<p className={styles.subHeading}>Uniswap has granted your wish!</p>
</Box>
<Box
className={styles.successAssetsContainer}
style={{
maxHeight: nftsPurchased.length > 32 ? (isMobile ? '172px' : '292px') : 'min-content',
}}
>
{[...nftsPurchased].map((nft, index) => (
<img
className={clsx(
styles.successAssetImage,
nftsPurchased.length > 1 && styles.successAssetImageGrid
)}
style={{
maxHeight: `${getSuccessfulImageSize(nftsPurchased.length, isMobile)}px`,
maxWidth: `${getSuccessfulImageSize(nftsPurchased.length, isMobile)}px`,
}}
src={nft.imageUrl}
alt={nft.name}
key={index}
/>
))}
</Box>
{nftsPurchased.length > 32 && <Box className={styles.overflowFade} />}
<Box
display="flex"
width="full"
height="min"
flexDirection="row"
marginTop={{ sm: '20', md: '20' }}
flexWrap={{ sm: 'wrap', md: 'nowrap' }}
alignItems="center"
paddingRight={'40'}
paddingLeft={'40'}
className={styles.bottomBar}
justifyContent="space-between"
>
<Row>
<Box marginRight="16">
{nftsPurchased.length} NFT{nftsPurchased.length === 1 ? '' : 's'}
</Box>
<Box>{formatEthPrice(totalPurchaseValue.toString())} ETH</Box>
</Row>
<a href={txHashUrl} target="_blank" rel="noreferrer">
<Box color="textPrimary" fontWeight="normal">
{shortenTxHash(txHash, 2, 2)}
</Box>
</a>
</Box>
</Box>
)}
{/* NFTs that were not purchased ie Refunds */}
{showRefundModal &&
/* Showing both purchases & refunds */
(showPurchasedModal ? (
<Box className={styles.mixedRefundModal} onClick={stopPropagation}>
<Box
height="full"
display="inline-flex"
flexWrap="wrap"
width={{ sm: 'full', md: 'half' }}
paddingRight={{ sm: '0', md: '32' }}
>
<LightningBoltIcon color="pink" />
<p className={styles.subtitle}>Instant Refund</p>
<p className={styles.interStd}>
Uniswap returned{' '}
<span style={{ fontWeight: '700' }}>{formatEthPrice(totalRefundValue.toString())} ETH</span> back
to your wallet for unavailable items.
</p>
<Box
display="flex"
flexWrap="wrap"
bottom="24"
width="full"
alignSelf="flex-end"
position={{ sm: 'absolute', md: 'static' }}
>
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
{formatEthPrice(totalRefundValue.toString())} ETH
</p>
<p className={styles.totalUsdRefund}>{formatUSDPriceWithCommas(totalUSDRefund)}</p>
<p className={styles.totalEthCost} style={{ width: '100%' }}>
for {nftsNotPurchased.length} unavailable item
{nftsNotPurchased.length === 1 ? '' : 's'}.
</p>
<Box
position={{ sm: 'absolute', md: 'relative' }}
right={{ sm: '0', md: 'auto' }}
bottom={{ sm: '0', md: 'auto' }}
justifyContent={{ sm: 'flex-end', md: 'flex-start' }}
textAlign={{ sm: 'right', md: 'left' }}
flexShrink="0"
marginRight={{ sm: '40', md: '24' }}
width={{ sm: 'half', md: 'auto' }}
>
<a href={txHashUrl} target="_blank" rel="noreferrer">
<Box fontWeight="normal" marginTop="16" className={styles.totalEthCost}>
{shortenTxHash(txHash, 2, 2)}
</Box>
</a>
</Box>
</Box>
</Box>
<Box className={styles.refundAssetsContainer}>
{nftsNotPurchased.map((nft, index) => (
<Box display="flex" flexWrap="wrap" height="min" width="52" key={index}>
<img className={styles.refundAssetImage} src={nft.imageUrl} alt={nft.name} key={index} />
</Box>
))}
</Box>
<Box className={styles.refundOverflowFade} />
</Box>
) : (
// Only showing when all assets are unavailable
<Box className={styles.fullRefundModal} onClick={stopPropagation}>
<Box marginLeft="auto" marginRight="auto" display="flex">
{txState === TxStateType.Success ? (
<>
<LightningBoltIcon />
<h1 className={styles.title}>Instant Refund</h1>
</>
) : (
<h1 className={styles.title}>Failed Transaction</h1>
)}
</Box>
<p className={styles.bodySmall}>
{txState === TxStateType.Success &&
`Selected item${
nftsPurchased.length === 1 ? ' is' : 's are'
} no longer available. Uniswap instantly refunded you for this incomplete transaction. `}
{formatUsdPrice(txFeeFiat)} was used for gas in attempt to complete this transaction. For support,
please visit our <a href="https://discord.gg/FCfyBSbCU5">Discord</a>
</p>
<Box className={styles.allUnavailableAssets}>
{nftsNotPurchased.length >= 3 && (
<Box className={styles.toggleUnavailable} onClick={() => toggleShowUnavailable()}>
{!showUnavailable && (
<Box paddingLeft="20" paddingTop="8" paddingBottom="8">
{nftsNotPurchased.slice(0, 3).map((asset, index) => (
<img
style={{ zIndex: 2 - index }}
className={styles.unavailableAssetPreview}
src={asset.imageUrl}
alt={asset.name}
key={index}
/>
))}
</Box>
)}
<Box
color={showUnavailable ? 'textPrimary' : 'textSecondary'}
className={styles.unavailableText}
>
Unavailable
<Box className={styles.unavailableItems}>
{nftsNotPurchased.length} item{nftsNotPurchased.length === 1 ? '' : 's'}
</Box>
</Box>
<ChevronUpIcon className={`${!showUnavailable && styles.chevronDown} ${styles.chevron}`} />
</Box>
)}
{(showUnavailable || nftsNotPurchased.length < 3) &&
nftsNotPurchased.map((asset, index) => (
<Box
backgroundColor="backgroundSurface"
display="flex"
padding="4"
marginBottom="1"
borderRadius="8"
key={index}
>
<Box className={styles.assetContainer}>
<img className={styles.fullRefundImage} src={asset.imageUrl} alt={asset.name} />
</Box>
<Box flexWrap="wrap" marginTop="4">
<Box marginLeft="4" width="full" display="flex">
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
{formatEthPrice(
asset.updatedPriceInfo ? asset.updatedPriceInfo.ETHPrice : asset.priceInfo.ETHPrice
)}{' '}
ETH
</p>
</Box>
<Box color="textPrimary" className={styles.totalUsdRefund}>
{txState === TxStateType.Success ? 'Refunded' : asset.name}
</Box>
</Box>
</Box>
))}
</Box>
{showUnavailable && <Box className={styles.fullRefundOverflowFade} />}
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
{formatEthPrice(totalRefundValue.toString())} ETH
</p>
<p className={styles.totalUsdRefund}>{formatUSDPriceWithCommas(totalUSDRefund)}</p>
<Box className={styles.walletAddress} marginLeft="auto" marginRight="0">
<a href={txHashUrl} target="_blank" rel="noreferrer">
<Box className={styles.addressHash}>{shortenTxHash(txHash, 2, 2)}</Box>
</a>
</Box>
<p className={styles.totalEthCost}>
for {nftsNotPurchased.length} unavailable item
{nftsNotPurchased.length === 1 ? '' : 's'}.
</p>
<Box
as="button"
border="none"
backgroundColor="genieBlue"
cursor="pointer"
className={styles.returnButton}
type="button"
onClick={() => closeTxCompleteScreen()}
>
<BackArrowIcon className={styles.fullRefundBackArrow} />
Return to Marketplace
</Box>
</Box>
))}
</Box>
</Portal>
)}
</>
)
}
export default TxCompleteModal
...@@ -11,7 +11,7 @@ export const overlay = style([ ...@@ -11,7 +11,7 @@ export const overlay = style([
position: 'fixed', position: 'fixed',
display: 'block', display: 'block',
background: 'black', background: 'black',
zIndex: '2', zIndex: 'modalBackdrop',
}), }),
{ {
opacity: 0.72, opacity: 0.72,
......
...@@ -12,14 +12,6 @@ import CryptoPunksMarket from '../abis/CryptoPunksMarket.json' ...@@ -12,14 +12,6 @@ import CryptoPunksMarket from '../abis/CryptoPunksMarket.json'
import { GenieAsset, RouteResponse, RoutingItem, TxResponse, TxStateType, UpdatedGenieAsset } from '../types' import { GenieAsset, RouteResponse, RoutingItem, TxResponse, TxStateType, UpdatedGenieAsset } from '../types'
import { combineBuyItemsWithTxRoute } from '../utils/txRoute/combineItemsWithTxRoute' import { combineBuyItemsWithTxRoute } from '../utils/txRoute/combineItemsWithTxRoute'
// Shortens a given txHash. With standard charsToShorten var of 4, a hash will become 0x1234...1234
export const shortenTxHash = (txHash: string, charsToShorten = 4, addCharsToBack = 0): string => {
return `${txHash.substring(0, charsToShorten + 2)}...${txHash.substring(
txHash.length - charsToShorten,
txHash.length - (charsToShorten + addCharsToBack)
)}`
}
interface TxState { interface TxState {
state: TxStateType state: TxStateType
setState: (state: TxStateType) => void setState: (state: TxStateType) => void
......
import { TxResponse } from 'nft/types'
import create from 'zustand' import create from 'zustand'
import { devtools } from 'zustand/middleware' import { devtools } from 'zustand/middleware'
import { TxResponse } from '../types'
type TransactionResponseValue = TxResponse | undefined type TransactionResponseValue = TxResponse | undefined
type TransactionResponseState = { type TransactionResponseState = {
......
...@@ -2,8 +2,11 @@ export * from './buildActivityAsset' ...@@ -2,8 +2,11 @@ export * from './buildActivityAsset'
export * from './buildSellObject' export * from './buildSellObject'
export * from './calcPoolPrice' export * from './calcPoolPrice'
export * from './currency' export * from './currency'
export * from './fetchPrice'
export * from './isAudio' export * from './isAudio'
export * from './isVideo' export * from './isVideo'
export * from './listNfts' export * from './listNfts'
export * from './putCommas' export * from './putCommas'
export * from './rarity' export * from './rarity'
export * from './transactionResponse'
export * from './updatedAssets'
import { BigNumber } from '@ethersproject/bignumber'
import { formatEther } from '@ethersproject/units'
import { TxResponse, UpdatedGenieAsset } from 'nft/types'
import { getTotalNftValue } from 'nft/utils'
// Shortens a given txHash. With standard charsToShorten var of 4, a hash will become 0x1234...1234
export const shortenTxHash = (txHash: string, charsToShorten = 4, addCharsToBack = 0): string => {
return `${txHash.substring(0, charsToShorten + 2)}...${txHash.substring(
txHash.length - charsToShorten,
txHash.length - (charsToShorten + addCharsToBack)
)}`
}
export const parseTransactionResponse = (transactionResponse: TxResponse | undefined, ethPrice: number) => {
let nftsPurchased: UpdatedGenieAsset[] = []
let nftsNotPurchased: UpdatedGenieAsset[] = []
let showPurchasedModal = false
let showRefundModal = false
let totalPurchaseValue = BigNumber.from(0)
let totalRefundValue = BigNumber.from(0)
let totalUSDRefund = 0
let txFeeFiat = 0
if (transactionResponse !== undefined) {
const { nftsPurchased: purchasedNfts, nftsNotPurchased: notPurchasedNfts, txReceipt } = transactionResponse
if (nftsPurchased && nftsNotPurchased && txReceipt) {
nftsPurchased = purchasedNfts
nftsNotPurchased = notPurchasedNfts
showPurchasedModal = nftsPurchased.length >= 1
showRefundModal = nftsNotPurchased.length >= 1
totalPurchaseValue = getTotalNftValue(nftsPurchased)
totalRefundValue = getTotalNftValue(nftsNotPurchased)
totalUSDRefund = totalRefundValue && parseFloat(formatEther(totalRefundValue)) * ethPrice
const txFee = BigNumber.from(txReceipt ? txReceipt.gasUsed : 0).mul(
BigNumber.from(txReceipt ? txReceipt.effectiveGasPrice : 0)
)
txFeeFiat = parseFloat(formatEther(txFee)) * ethPrice
}
}
return {
nftsPurchased,
nftsNotPurchased,
showPurchasedModal,
showRefundModal,
totalPurchaseValue,
totalRefundValue,
totalUSDRefund,
txFeeFiat,
}
}
// Given the length of the array of successfully purchased NFTs, returns the maxHeight and maxWidth of each asset preview
export const getSuccessfulImageSize = (numSuccessful: number, isMobile: boolean) => {
const sizeModifier = isMobile ? 2 : 1
if (numSuccessful === 1) {
return 574 / sizeModifier
} else if (numSuccessful === 2) {
return 280 / sizeModifier
} else if (numSuccessful === 3 || (numSuccessful >= 5 && numSuccessful < 7)) {
return 184 / sizeModifier
} else if (numSuccessful === 4 || (numSuccessful >= 7 && numSuccessful < 13)) {
return 136 / sizeModifier
} else if (numSuccessful >= 13 && numSuccessful < 21) {
return 108 / sizeModifier
} else return isMobile ? 39 : 64
}
...@@ -9,3 +9,14 @@ export const updatedAssetPriceDifference = (asset: UpdatedGenieAsset) => { ...@@ -9,3 +9,14 @@ export const updatedAssetPriceDifference = (asset: UpdatedGenieAsset) => {
export const sortUpdatedAssets = (x: UpdatedGenieAsset, y: UpdatedGenieAsset) => { export const sortUpdatedAssets = (x: UpdatedGenieAsset, y: UpdatedGenieAsset) => {
return updatedAssetPriceDifference(x).gt(updatedAssetPriceDifference(y)) ? -1 : 1 return updatedAssetPriceDifference(x).gt(updatedAssetPriceDifference(y)) ? -1 : 1
} }
export const getTotalNftValue = (nfts: UpdatedGenieAsset[]): BigNumber => {
return (
nfts &&
nfts.reduce(
(ethTotal, nft) =>
ethTotal.add(BigNumber.from(nft.updatedPriceInfo ? nft.updatedPriceInfo.ETHPrice : nft.priceInfo.ETHPrice)),
BigNumber.from(0)
)
)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment