Skip to content
This repository has been archived by the owner on Aug 9, 2022. It is now read-only.

chore(backport): fix(hotfix): v1.4.2 #973

Open
wants to merge 1 commit into
base: mainnet
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion package-lock.json

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

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"name": "rif-marketplace-ui",
<<<<<<< HEAD
"version": "1.3.5",
=======
"version": "1.4.2",
>>>>>>> db46ca1 (fix(hotfix): v1.4.2)
"description": "RIF Marketplace provides a digital catalogue with a wide range of decentralised services.",
"keywords": [
"RIF",
Expand Down Expand Up @@ -104,4 +108,4 @@
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.ts"
}
}
}
}
154 changes: 154 additions & 0 deletions src/components/organisms/notifier/buy/CheckoutPayment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import RoundBtn from 'components/atoms/RoundBtn'
import React, {
FC, useState, useEffect, useContext,
} from 'react'
import Typography from '@material-ui/core/Typography'
import GridRow from 'components/atoms/GridRow'
import Grid, { GridProps } from '@material-ui/core/Grid'
import { TokenXR } from 'models/Market'
import ExpirationDate from 'components/molecules/ExpirationDate'
import PriceSummary from 'components/molecules/PriceSummary'
import { makeStyles, Theme } from '@material-ui/core/styles'
import Box from '@material-ui/core/Box'
import RoundedCard from 'components/atoms/RoundedCard'
import Big from 'big.js'
import { Web3Store } from '@rsksmart/rif-ui'
import { getBalance } from 'contracts/utils/accountBalance'
import NotEnoughFunds from 'components/atoms/NotEnoughFunds'
import Web3 from 'web3'
import useErrorReporter from 'hooks/useErrorReporter'
import TermsAndConditions from 'components/organisms/TermsAndConditions'
import { TERMS_CONDITIONS_BUY } from 'constants/notifier/strings'

type Props = {
onBuy: () => void
fiatDisplayName: string
expirationDate: Date
tokenXR: TokenXR
cryptoPrice: Big
}

const useStyles = makeStyles((theme: Theme) => ({
priceSummaryCard: {
padding: theme.spacing(1.5, 3),
marginBottom: theme.spacing(1),
},
expirationDate: {
justifyContent: 'center',
},
}))

const CheckoutPayment: FC<Props> = ({
onBuy, fiatDisplayName, expirationDate, tokenXR, cryptoPrice,
}) => {
const classes = useStyles()
const reportError = useErrorReporter()

const { state: { web3, account } } = useContext(Web3Store)
const [hasEnoughFunds, setHasEnoughFunds] = useState(false)
const [isLoadingBalance, setIsLoadingBalance] = useState(false)
const [termsChecked, setTermsChecked] = useState(false)

const {
symbol: selectedTokenSymbol,
} = tokenXR

useEffect(() => {
const calculateBalance = async (): Promise<void> => {
try {
setIsLoadingBalance(true)
const balance = await getBalance(
web3 as Web3, account as string, selectedTokenSymbol,
)
setHasEnoughFunds(Big(balance).gte(cryptoPrice))
} catch (error) {
reportError({
error,
id: 'get-balance',
text: 'Could not read account balance',
})
} finally {
setIsLoadingBalance(false)
}
}
calculateBalance()
}, [account, web3, selectedTokenSymbol, cryptoPrice, reportError])

const handleTermsChange = (): void => setTermsChecked((prev) => !prev)

const colProps: GridProps = {
container: true,
item: true,
direction: 'column',
md: 6,
sm: 12,
alignItems: 'center',
justify: 'center',
}
const isBuyDisabled = !hasEnoughFunds || isLoadingBalance || !termsChecked

return (
<>
<Typography component="div" variant="caption" gutterBottom>
<Box>
{`To acquire this notification service you have to select
the currency to get the final price.`}
</Box>
<Box>
You can add more events to this contract before or after renew.
</Box>
</Typography>
<GridRow spacing={3} alignItems="center">
<Grid {...colProps}>
<RoundedCard className={classes.priceSummaryCard} color="primary">
<PriceSummary
cryptoPrice={cryptoPrice}
tokenXR={tokenXR}
fiatDisplayName={fiatDisplayName}
/>
</RoundedCard>
<GridRow justify="center">
<Typography color="secondary" align="center">Expiration date</Typography>
<ExpirationDate
className={classes.expirationDate}
type="normal"
date={expirationDate}
/>
</GridRow>
</Grid>
<Grid {...colProps}>
{
!isLoadingBalance && !hasEnoughFunds && (
<NotEnoughFunds token={tokenXR} />
)
}
<GridRow justify="center">
<TermsAndConditions
checked={termsChecked}
onChange={handleTermsChange}
terms={TERMS_CONDITIONS_BUY}
/>
</GridRow>
<GridRow justify="center">
<RoundBtn
disabled={isBuyDisabled}
onClick={onBuy}
>
Buy
</RoundBtn>
</GridRow>
<Typography
color="secondary"
variant="caption"
align="center"
>
{`Your wallet will open and you will be asked
to confirm the transaction for buying the notification plan.`}
</Typography>
</Grid>
</GridRow>
</>
)
}

export default CheckoutPayment
185 changes: 185 additions & 0 deletions src/components/pages/notifier/buy/NotifierOfferCheckoutPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import React, {
FC, useContext, useState,
} from 'react'
import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
import {
NotifierOffersContextProps as ContextProps,
NotifierOffersContext,
} from 'context/Services/notifier/offers'
import CenteredPageTemplate from 'components/templates/CenteredPageTemplate'
import NotifierPlanDescription from 'components/organisms/notifier/NotifierPlanDescription'
import MarketContext, { MarketContextProps } from 'context/Market'
import CheckoutStepper from 'components/organisms/notifier/buy/CheckoutStepper'
import { NotifierEventItem } from 'models/marketItems/NotifierEventItem'
import NotifierContract from 'contracts/notifier/Notifier'
import Web3 from 'web3'
import { Web3Store } from '@rsksmart/rif-ui'
import useErrorReporter from 'hooks/useErrorReporter'
import ProgressOverlay from 'components/templates/ProgressOverlay'
import RoundBtn from 'components/atoms/RoundBtn'
import ROUTES from 'routes'
import { useHistory } from 'react-router-dom'
import { ConfirmationsContext } from 'context/Confirmations'
import { convertToWeiString } from 'utils/parsers'
import WithLoginCard from 'components/hoc/WithLoginCard'
import { getOrCreateSubscription } from 'api/rif-notifier-service/subscriptionUtils'

const NotifierOfferCheckoutPage: FC = () => {
const {
state: { account, web3 },
} = useContext(Web3Store)
const {
state: {
exchangeRates: {
currentFiat: {
displayName: currentFiat,
},
crypto,
},
},
} = useContext<MarketContextProps>(MarketContext)
const { dispatch: confirmationsDispatch } = useContext(ConfirmationsContext)

const {
state: {
order,
},
} = useContext<ContextProps>(NotifierOffersContext)
const reportError = useErrorReporter()
const history = useHistory()

const [isProcessingTx, setIsProcessingTx] = useState(false)
const [txOperationDone, setTxOperationDone] = useState(false)
const [eventsAdded, setEventsAdded] = useState<NotifierEventItem[]>([])

if (!order?.item) {
history.push(ROUTES.NOTIFIER.BUY.BASE)
return null
}

const handleEventRemoved = (
{ id: notifierEventId }: NotifierEventItem,
): void => {
const filteredEvents = eventsAdded.filter(
({ id }) => id !== notifierEventId,
)
setEventsAdded(filteredEvents)
}

const handleEventItemAdded = (
eventItem: NotifierEventItem,
): void => {
setEventsAdded([...eventsAdded, eventItem])
}

const handleOnBuy = async (): Promise<void> => {
if (!account) return // wrapped with withLoginCard
try {
setIsProcessingTx(true)

const { item } = order
const {
provider: providerAddress,
value: amount,
token,
planId,
url,
} = item

const { symbol, tokenAddress } = token

const {
hash: subscriptionHash, signature,
} = await getOrCreateSubscription({
planId, symbol, url, value: amount,
}, eventsAdded, account, reportError)

if (!subscriptionHash) return

const purchaseReceipt = await NotifierContract.getInstance(web3 as Web3)
.createSubscription(
{
subscriptionHash,
providerAddress,
signature,
amount,
tokenAddress,
},
{
from: account,
value: convertToWeiString(amount),
},
)

if (purchaseReceipt) {
setTxOperationDone(true)
confirmationsDispatch({
type: 'NEW_REQUEST',
payload: {
contractAction: 'NOTIFIER_CREATE_SUBSCRIPTION',
txHash: purchaseReceipt.transactionHash,
},
})
}
} catch (error) {
const { customMessage } = error
reportError({
error,
id: 'contract-notifier',
text: customMessage || 'Could not complete the order',
})
} finally {
setIsProcessingTx(false)
}
}

return (
<CenteredPageTemplate>
<Grid item xs={11} md="auto">
<Typography gutterBottom variant="h6" color="primary">
Notification plan selected
</Typography>
</Grid>
<NotifierPlanDescription {...{ item: order.item, crypto, currentFiat }} />
<CheckoutStepper
onBuy={handleOnBuy}
onEventItemAdded={handleEventItemAdded}
onEventItemRemoved={handleEventRemoved}
order={order}
eventsAdded={eventsAdded}
/>
<ProgressOverlay
title="Buying your plan!"
doneMsg="Your notification plan has been bought!"
inProgress={isProcessingTx}
isDone={txOperationDone}
buttons={[
<RoundBtn
key="go_to_my_purchases"
onClick={
(): void => history.push(ROUTES.NOTIFIER.MYPURCHASES.BASE)
}
>
View my purchases
</RoundBtn>,
<RoundBtn
key="go_to_list"
onClick={
(): void => history.push(ROUTES.NOTIFIER.BUY.BASE)
}
>
View offers listing
</RoundBtn>,
]}

/>
</CenteredPageTemplate>
)
}

export default WithLoginCard({
WrappedComponent: NotifierOfferCheckoutPage,
title: 'Please, connect your wallet.',
contentText: 'Connect your wallet in order to proceed to the checkout.',
})
Loading