mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
lots of pricve refactor, build out advanced UI
This commit is contained in:
parent
576b9f4c2e
commit
cbee8a714d
@ -37,7 +37,6 @@
|
||||
{
|
||||
"name": "price",
|
||||
"label": "Price",
|
||||
"help": "Set your price for accessing this data set in Ocean Tokens.",
|
||||
"type": "price",
|
||||
"required": true
|
||||
},
|
||||
|
@ -1,9 +1,23 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import styles from './Help.module.css'
|
||||
import Markdown from '../Markdown'
|
||||
import classNames from 'classnames/bind'
|
||||
|
||||
const FormHelp = ({ children }: { children: string }): ReactElement => (
|
||||
<Markdown className={styles.help} text={children} />
|
||||
)
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const FormHelp = ({
|
||||
children,
|
||||
className
|
||||
}: {
|
||||
children: string
|
||||
className?: string
|
||||
}): ReactElement => {
|
||||
const styleClasses = cx({
|
||||
help: true,
|
||||
[className]: className
|
||||
})
|
||||
|
||||
return <Markdown className={styleClasses} text={children} />
|
||||
}
|
||||
|
||||
export default FormHelp
|
||||
|
@ -33,7 +33,8 @@
|
||||
|
||||
.input[readonly],
|
||||
.input[disabled] {
|
||||
background-color: var(--brand-grey-lighter);
|
||||
background-color: var(--brand-grey-dimmed);
|
||||
color: var(--brand-grey-light);
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -84,6 +85,56 @@
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.prefixGroup,
|
||||
.postfixGroup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.prefixGroup input,
|
||||
.postfixGroup input {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.prefixGroup input {
|
||||
border-left: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.postfixGroup input {
|
||||
border-right: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.prefix,
|
||||
.postfix {
|
||||
border: 1px solid var(--brand-grey-lighter);
|
||||
min-height: 43px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: calc(var(--spacer) / 2);
|
||||
padding-right: calc(var(--spacer) / 2);
|
||||
color: var(--color-secondary);
|
||||
font-size: var(--font-size-small);
|
||||
transition: border 0.2s ease-out;
|
||||
}
|
||||
|
||||
.prefix {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.postfix {
|
||||
border-top-right-radius: var(--border-radius);
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.input:focus + .postfix {
|
||||
border-color: var(--brand-grey);
|
||||
}
|
||||
|
||||
/* Size modifiers */
|
||||
|
||||
.small {
|
||||
|
@ -7,7 +7,7 @@ import Terms from '../../molecules/FormFields/Terms'
|
||||
import Price from '../../molecules/FormFields/Price'
|
||||
|
||||
export default function InputElement(props: InputProps): ReactElement {
|
||||
const { type, options, rows, name, value } = props
|
||||
const { type, options, rows, name, prefix, postfix } = props
|
||||
|
||||
switch (type) {
|
||||
case 'select':
|
||||
@ -62,7 +62,19 @@ export default function InputElement(props: InputProps): ReactElement {
|
||||
case 'terms':
|
||||
return <Terms name={name} {...props} />
|
||||
default:
|
||||
return (
|
||||
return prefix || postfix ? (
|
||||
<div className={`${prefix ? styles.prefixGroup : styles.postfixGroup}`}>
|
||||
{prefix && <div className={styles.prefix}>{prefix}</div>}
|
||||
<input
|
||||
id={name}
|
||||
className={styles.input}
|
||||
name={name}
|
||||
{...props}
|
||||
type={type || 'text'}
|
||||
/>
|
||||
{postfix && <div className={styles.postfix}>{postfix}</div>}
|
||||
</div>
|
||||
) : (
|
||||
<input
|
||||
id={name}
|
||||
className={styles.input}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { FormEvent, ChangeEvent, ReactElement } from 'react'
|
||||
import React, { FormEvent, ChangeEvent, ReactElement, ReactNode } from 'react'
|
||||
import InputElement from './InputElement'
|
||||
import Help from './Help'
|
||||
import Label from './Label'
|
||||
@ -31,8 +31,12 @@ export interface InputProps {
|
||||
pattern?: string
|
||||
min?: string
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
field?: any
|
||||
form?: any
|
||||
prefix?: string
|
||||
postfix?: string
|
||||
step?: string
|
||||
}
|
||||
|
||||
export default function Input(props: Partial<InputProps>): ReactElement {
|
||||
|
@ -2,19 +2,29 @@ import React, { useEffect, useState, ReactElement } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { fetchData, isBrowser } from '../../../utils'
|
||||
import styles from './Conversion.module.css'
|
||||
import classNames from 'classnames/bind'
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const currencies = 'EUR' // comma-separated list
|
||||
const url = `https://api.coingecko.com/api/v3/simple/price?ids=ocean-protocol&vs_currencies=${currencies}&include_24hr_change=true`
|
||||
|
||||
export default function Conversion({
|
||||
price,
|
||||
update = true
|
||||
update = true,
|
||||
className
|
||||
}: {
|
||||
price: string // expects price in OCEAN, not wei
|
||||
update?: boolean
|
||||
className?: string
|
||||
}): ReactElement {
|
||||
const [priceEur, setPriceEur] = useState('0.00')
|
||||
|
||||
const styleClasses = cx({
|
||||
conversion: true,
|
||||
[className]: className
|
||||
})
|
||||
|
||||
const onSuccess = async (data: { 'ocean-protocol': { eur: number } }) => {
|
||||
if (!data) return
|
||||
if (!price || price === '' || price === '0') {
|
||||
@ -45,5 +55,5 @@ export default function Conversion({
|
||||
})
|
||||
}
|
||||
|
||||
return <span className={styles.conversion}>≈ EUR {priceEur}</span>
|
||||
return <span className={styleClasses}>≈ EUR {priceEur}</span>
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
.advancedInput {
|
||||
display: flex;
|
||||
gap: calc(var(--spacer) / 2);
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
.advanced {
|
||||
}
|
||||
|
||||
.advancedInput label {
|
||||
.advanced > div:last-child {
|
||||
display: grid;
|
||||
gap: calc(var(--spacer) / 2);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import React, { ReactElement, useState, ChangeEvent } from 'react'
|
||||
import { InputProps } from '../../../atoms/Input'
|
||||
import InputElement from '../../../atoms/Input/InputElement'
|
||||
import stylesIndex from './index.module.css'
|
||||
@ -6,21 +6,62 @@ import styles from './Advanced.module.css'
|
||||
import Label from '../../../atoms/Input/Label'
|
||||
import { MetadataPublishForm } from '../../../../@types/MetaData'
|
||||
import Cost from './Cost'
|
||||
import Conversion from '../../../atoms/Price/Conversion'
|
||||
import FormHelp from '../../../atoms/Input/Help'
|
||||
|
||||
export default function Advanced(props: InputProps): ReactElement {
|
||||
const { price } = props.form.values as MetadataPublishForm
|
||||
const [weight, setWeight] = useState('10')
|
||||
|
||||
const liquidity = (price.cost * Number(weight)).toString()
|
||||
|
||||
function handleWeightChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setWeight(event.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${stylesIndex.content} ${styles.advancedInput}`}>
|
||||
<Cost {...props} />
|
||||
<div>
|
||||
<Label htmlFor="price.tokensToMint">Tokens to Mint</Label>
|
||||
<InputElement
|
||||
{...props.field}
|
||||
value={(price && price.tokensToMint) || 1}
|
||||
name="price.tokensToMint"
|
||||
type="number"
|
||||
/>
|
||||
<div className={stylesIndex.content}>
|
||||
<div className={styles.advanced}>
|
||||
<FormHelp className={stylesIndex.help}>
|
||||
Set your price for accessing this data set. A Data Token for this data
|
||||
set worth the entered amount of OCEAN, and a Data Token/OCEAN
|
||||
liquidity pool will be created with Balancer.
|
||||
</FormHelp>
|
||||
|
||||
<div>
|
||||
<Cost {...props} />
|
||||
<div>
|
||||
<Label htmlFor="weight">Weight on Data Token</Label>
|
||||
<InputElement
|
||||
value={weight}
|
||||
name="weight"
|
||||
type="number"
|
||||
onChange={handleWeightChange}
|
||||
step="10"
|
||||
postfix="%"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.liquidity}>
|
||||
<Label htmlFor="liquidity">Liquidity</Label>
|
||||
<InputElement
|
||||
value={liquidity}
|
||||
name="liquidity"
|
||||
readOnly
|
||||
prefix="OCEAN"
|
||||
/>
|
||||
<Conversion price={liquidity} className={stylesIndex.conversion} />
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="price.tokensToMint">Tokens to Mint</Label>
|
||||
<InputElement
|
||||
{...props.field}
|
||||
value={(price && price.tokensToMint) || 1}
|
||||
name="price.tokensToMint"
|
||||
type="number"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,28 +0,0 @@
|
||||
.cost {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cost label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cost input {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.prefix {
|
||||
border: 1px solid var(--brand-grey-lighter);
|
||||
min-height: 43px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: calc(var(--spacer) / 2);
|
||||
padding-right: calc(var(--spacer) / 2);
|
||||
color: var(--color-secondary);
|
||||
font-size: var(--font-size-small);
|
||||
margin-right: -2px;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
}
|
@ -1,26 +1,30 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import InputElement from '../../../atoms/Input/InputElement'
|
||||
import styles from './Cost.module.css'
|
||||
import { MetadataPublishForm } from '../../../../@types/MetaData'
|
||||
import Conversion from '../../../atoms/Price/Conversion'
|
||||
import { InputProps } from '../../../atoms/Input'
|
||||
import Label from '../../../atoms/Input/Label'
|
||||
import stylesIndex from './index.module.css'
|
||||
|
||||
export default function Cost(props: InputProps): ReactElement {
|
||||
const { price } = props.form.values as MetadataPublishForm
|
||||
|
||||
return (
|
||||
<div className={styles.cost}>
|
||||
<div>
|
||||
<Label htmlFor="price.cost">Cost</Label>
|
||||
|
||||
<div className={styles.prefix}>OCEAN</div>
|
||||
<InputElement
|
||||
{...props.field}
|
||||
value={(price && price.cost) || 0}
|
||||
name="price.cost"
|
||||
type="number"
|
||||
prefix="OCEAN"
|
||||
/>
|
||||
|
||||
<Conversion
|
||||
price={price.cost.toString()}
|
||||
className={stylesIndex.conversion}
|
||||
/>
|
||||
<Conversion price={price.cost.toString()} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
.simple {
|
||||
margin-bottom: calc(var(--spacer) / 2);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.simple > div {
|
||||
justify-content: center;
|
||||
.simple > div:last-child {
|
||||
max-width: 13.25rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.simple label {
|
||||
|
@ -9,9 +9,12 @@ export default function Simple(props: InputProps): ReactElement {
|
||||
return (
|
||||
<div className={stylesIndex.content}>
|
||||
<div className={styles.simple}>
|
||||
<FormHelp className={stylesIndex.help}>
|
||||
Set your price for accessing this data set. A Data Token for this data
|
||||
set worth the entered amount of OCEAN will be created.
|
||||
</FormHelp>
|
||||
<Cost {...props} />
|
||||
</div>
|
||||
{props.help && <FormHelp>{props.help}</FormHelp>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -20,3 +20,14 @@
|
||||
.content p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.conversion {
|
||||
display: block;
|
||||
padding-left: 5rem;
|
||||
margin-top: calc(var(--spacer) / 6);
|
||||
}
|
||||
|
||||
.help {
|
||||
text-align: center;
|
||||
margin-bottom: calc(var(--spacer) / 2);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user