Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.
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
4 changes: 4 additions & 0 deletions package-lock.json

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

4 changes: 4 additions & 0 deletions 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.1",
>>>>>>> c95a872 (chore(vBump): hotfix v1.4.1)
"description": "RIF Marketplace provides a digital catalogue with a wide range of decentralised services.",
"keywords": [
"RIF",
Expand Down
65 changes: 65 additions & 0 deletions src/components/molecules/ExpirationDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Typography, { TypographyProps } from '@material-ui/core/Typography'
import React, { FC } from 'react'
import { getShortDateString } from 'utils/dateUtils'
import {
makeStyles, Theme,
} from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import WatchLaterIcon from '@material-ui/icons/WatchLater'

const useStyles = makeStyles(({ palette }: Theme) => ({
normal: {
color: palette.text.secondary,
},
warning: {
color: palette.warning.main,
},
blocked: {
color: palette.error.main,
},
disabled: {
color: palette.text.disabled,
},
}))

export const EXPIRATION_TYPES = {
normal: 'normal',
warning: 'warning',
blocked: 'blocked',
disabled: 'disabled',
} as const

export type SubscriptionExpirationType = keyof typeof EXPIRATION_TYPES

type Props = {
className?: string
date: Date
type: SubscriptionExpirationType
} & TypographyProps

const ExpirationDate: FC<Props> = ({
className = '', date, type, ...typoProps
}) => {
const classes = useStyles()

return (
<Grid
container
wrap="nowrap"
alignItems="center"
spacing={1}
className={`${classes[type]} ${className}`}
>
<Grid item>
<Typography variant="body2" {...typoProps}>
{getShortDateString(date)}
</Typography>
</Grid>
<Grid item>
{type === 'warning' && <WatchLaterIcon />}
</Grid>
</Grid>
)
}

export default ExpirationDate
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: any) {
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
95 changes: 95 additions & 0 deletions src/components/organisms/notifier/buy/CheckoutStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { FC, useContext, useState } from 'react'
import Stepper from '@material-ui/core/Stepper'
import Step from '@material-ui/core/Step'
import StepLabel from '@material-ui/core/StepLabel'
import StepContent from '@material-ui/core/StepContent'
import { Button } from '@rsksmart/rif-ui'
import MarketContext from 'context/Market'
import { OffersOrder } from 'context/Services/notifier/offers/interfaces'
import { NotifierEventItem } from 'models/marketItems/NotifierEventItem'
import CheckoutPayment from './CheckoutPayment'
import EventsRegistrar from './EventsRegistrar'

type Props = {
order: OffersOrder
onEventItemAdded: (eventitem: NotifierEventItem) => void
onEventItemRemoved: (eventitem: NotifierEventItem) => void
onBuy: () => void
eventsAdded: NotifierEventItem[]
}

const getExpirationDate = (daysLeft: number): Date => {
const expirationDate = new Date()
expirationDate.setUTCHours(0, 0, 0, 0)
expirationDate.setUTCDate(expirationDate.getDate() + daysLeft)
return new Date(expirationDate)
}

const CheckoutStepper: FC<Props> = (
{
onBuy, order, onEventItemAdded, onEventItemRemoved, eventsAdded,
},
) => {
const [activeStep, setActiveStep] = useState(0)
const {
state: {
exchangeRates: {
crypto: cryptoXRs,
currentFiat: { displayName: fiatDisplayName },
},
},
} = useContext(MarketContext)

const {
item: {
token: { symbol: tokenSymbol },
value: tokenValue,
daysLeft,
},
} = order

const handleNext = (): void => setActiveStep(1)
const handleBack = (): void => setActiveStep(0)

const expirationDate = getExpirationDate(daysLeft)
const tokenXR = cryptoXRs[tokenSymbol]

return (
<Stepper activeStep={activeStep} orientation="vertical">
<Step>
<StepLabel>Notification events</StepLabel>
<StepContent>
<EventsRegistrar
onNext={handleNext}
order={order}
onEventAdded={onEventItemAdded}
onEventRemoved={onEventItemRemoved}
eventsAdded={eventsAdded}
/>
</StepContent>
</Step>
<Step>
<StepLabel>Payment</StepLabel>
<StepContent>
<CheckoutPayment
onBuy={onBuy}
fiatDisplayName={fiatDisplayName}
expirationDate={expirationDate}
cryptoPrice={tokenValue}
tokenXR={tokenXR}
/>
<Button
onClick={handleBack}
variant="outlined"
color="secondary"
rounded
>
Back
</Button>
</StepContent>
</Step>
</Stepper>
)
}

export default CheckoutStepper
Loading