mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge pull request #69 from oceanprotocol/feature/user-preferences
User preferences
This commit is contained in:
commit
87b0e65b98
@ -4,5 +4,8 @@ module.exports = {
|
||||
marketFeeAddress:
|
||||
process.env.GATSBY_MARKET_FEE_ADDRESS ||
|
||||
'0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7',
|
||||
marketFeeAmount: process.env.GATSBY_MARKET_FEE_AMOUNT || '0.1' // in %
|
||||
marketFeeAmount: process.env.GATSBY_MARKET_FEE_AMOUNT || '0.1', // in %
|
||||
// Used for conversion display, can be whatever coingecko API supports
|
||||
// see: https://api.coingecko.com/api/v3/simple/supported_vs_currencies
|
||||
currencies: ['EUR', 'USD', 'ETH', 'BTC']
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { FormikProps, connect } from 'formik'
|
||||
import debounce from 'lodash.debounce'
|
||||
import omit from 'lodash.omit'
|
||||
import isEqual from 'react-fast-compare'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
|
||||
export interface PersistProps {
|
||||
name: string
|
||||
@ -21,7 +22,7 @@ class PersistImpl extends React.Component<
|
||||
|
||||
saveForm = debounce((data: FormikProps<any>) => {
|
||||
const dataToSave = this.omitIgnoredFields(data)
|
||||
console.log('data tosave', dataToSave)
|
||||
Logger.log('data to save', dataToSave)
|
||||
if (this.props.isSessionStorage) {
|
||||
window.sessionStorage.setItem(this.props.name, JSON.stringify(dataToSave))
|
||||
} else {
|
||||
@ -31,10 +32,10 @@ class PersistImpl extends React.Component<
|
||||
|
||||
omitIgnoredFields = (data: FormikProps<any>) => {
|
||||
const { ignoreFields } = this.props
|
||||
console.log('omit fiel', ignoreFields)
|
||||
Logger.log('omitted fields', ignoreFields)
|
||||
const { values, touched, errors } = data
|
||||
|
||||
console.log('vale', values, omit(values, ignoreFields))
|
||||
Logger.log('values', values, omit(values, ignoreFields))
|
||||
return ignoreFields
|
||||
? omit(
|
||||
{
|
||||
|
@ -135,9 +135,8 @@
|
||||
/* Size modifiers */
|
||||
|
||||
.small {
|
||||
composes: input;
|
||||
font-size: var(--font-size-small);
|
||||
min-height: 32px;
|
||||
min-height: 34px;
|
||||
padding: calc(var(--spacer) / 4);
|
||||
}
|
||||
|
||||
@ -146,8 +145,8 @@
|
||||
}
|
||||
|
||||
.selectSmall {
|
||||
composes: select;
|
||||
height: 32px;
|
||||
composes: small;
|
||||
height: 34px;
|
||||
padding-right: 2rem;
|
||||
|
||||
/* custom arrow */
|
||||
|
@ -10,14 +10,27 @@ const DefaultInput = (props: InputProps) => (
|
||||
<input className={styles.input} id={props.name} {...props} />
|
||||
)
|
||||
|
||||
export default function InputElement(props: InputProps): ReactElement {
|
||||
const { type, options, name, prefix, postfix } = props
|
||||
|
||||
export default function InputElement({
|
||||
type,
|
||||
options,
|
||||
name,
|
||||
prefix,
|
||||
postfix,
|
||||
small,
|
||||
field,
|
||||
...props
|
||||
}: InputProps): ReactElement {
|
||||
switch (type) {
|
||||
case 'select':
|
||||
return (
|
||||
<select id={name} className={styles.select} {...props}>
|
||||
<option value="">---</option>
|
||||
<select
|
||||
id={name}
|
||||
className={`${styles.select} ${small && styles.selectSmall}`}
|
||||
{...props}
|
||||
>
|
||||
{field !== undefined && field.value === '' && (
|
||||
<option value="">---</option>
|
||||
)}
|
||||
{options &&
|
||||
options
|
||||
.sort((a: string, b: string) => a.localeCompare(b))
|
||||
@ -29,7 +42,9 @@ export default function InputElement(props: InputProps): ReactElement {
|
||||
</select>
|
||||
)
|
||||
case 'textarea':
|
||||
return <textarea id={name} className={styles.input} {...props} />
|
||||
return (
|
||||
<textarea name={name} id={name} className={styles.input} {...props} />
|
||||
)
|
||||
case 'radio':
|
||||
case 'checkbox':
|
||||
return (
|
||||
@ -41,6 +56,7 @@ export default function InputElement(props: InputProps): ReactElement {
|
||||
className={styles.radio}
|
||||
id={slugify(option)}
|
||||
type={type}
|
||||
name={name}
|
||||
{...props}
|
||||
/>
|
||||
<label className={styles.radioLabel} htmlFor={slugify(option)}>
|
||||
@ -51,20 +67,20 @@ export default function InputElement(props: InputProps): ReactElement {
|
||||
</div>
|
||||
)
|
||||
case 'files':
|
||||
return <FilesInput {...props} />
|
||||
return <FilesInput name={name} {...field} {...props} />
|
||||
case 'price':
|
||||
return <Price {...props} />
|
||||
return <Price name={name} {...field} {...props} />
|
||||
case 'terms':
|
||||
return <Terms {...props} />
|
||||
return <Terms name={name} options={options} {...field} {...props} />
|
||||
default:
|
||||
return prefix || postfix ? (
|
||||
<div className={`${prefix ? styles.prefixGroup : styles.postfixGroup}`}>
|
||||
{prefix && <div className={styles.prefix}>{prefix}</div>}
|
||||
<DefaultInput type={type || 'text'} {...props} />
|
||||
<DefaultInput name={name} type={type || 'text'} {...props} />
|
||||
{postfix && <div className={styles.postfix}>{postfix}</div>}
|
||||
</div>
|
||||
) : (
|
||||
<DefaultInput type={type || 'text'} {...props} />
|
||||
<DefaultInput name={name} type={type || 'text'} {...props} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -37,10 +37,20 @@ export interface InputProps {
|
||||
prefix?: string
|
||||
postfix?: string
|
||||
step?: string
|
||||
defaultChecked?: boolean
|
||||
small?: boolean
|
||||
}
|
||||
|
||||
export default function Input(props: Partial<InputProps>): ReactElement {
|
||||
const { required, name, label, help, additionalComponent, field } = props
|
||||
const {
|
||||
required,
|
||||
name,
|
||||
label,
|
||||
help,
|
||||
additionalComponent,
|
||||
small,
|
||||
field
|
||||
} = props
|
||||
|
||||
const hasError =
|
||||
props.form &&
|
||||
@ -60,7 +70,7 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
||||
<Label htmlFor={name} required={required}>
|
||||
{label}
|
||||
</Label>
|
||||
<InputElement {...field} {...props} />
|
||||
<InputElement small={small} {...field} {...props} />
|
||||
|
||||
{field && (
|
||||
<div className={styles.error}>
|
||||
|
@ -4,12 +4,11 @@ import { fetchData, isBrowser } from '../../../utils'
|
||||
import styles from './Conversion.module.css'
|
||||
import classNames from 'classnames/bind'
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
|
||||
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,
|
||||
@ -19,23 +18,30 @@ export default function Conversion({
|
||||
update?: boolean
|
||||
className?: string
|
||||
}): ReactElement {
|
||||
const [priceEur, setPriceEur] = useState('0.00')
|
||||
const { appConfig } = useSiteMetadata()
|
||||
const tokenId = 'ocean-protocol'
|
||||
const currencies = appConfig.currencies.join(',') // comma-separated list
|
||||
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=${currencies}&include_24hr_change=true`
|
||||
const { currency } = useUserPreferences()
|
||||
|
||||
const [priceConverted, setPriceConverted] = useState('0.00')
|
||||
|
||||
const styleClasses = cx({
|
||||
conversion: true,
|
||||
[className]: className
|
||||
})
|
||||
|
||||
const onSuccess = async (data: { 'ocean-protocol': { eur: number } }) => {
|
||||
const onSuccess = async (data: { [tokenId]: { [key: string]: number } }) => {
|
||||
if (!data) return
|
||||
if (!price || price === '' || price === '0') {
|
||||
setPriceEur('0.00')
|
||||
setPriceConverted('0.00')
|
||||
return
|
||||
}
|
||||
|
||||
const { eur } = data['ocean-protocol']
|
||||
const converted = eur * Number(price)
|
||||
setPriceEur(`${formatCurrency(converted, 'EUR', undefined, true)}`)
|
||||
const values = data[tokenId]
|
||||
const fiatValue = values[currency.toLowerCase()]
|
||||
const converted = fiatValue * Number(price)
|
||||
setPriceConverted(`${formatCurrency(converted, currency, undefined, true)}`)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -46,7 +52,7 @@ export default function Conversion({
|
||||
if (isBrowser && price !== '0') {
|
||||
getData()
|
||||
}
|
||||
}, [price])
|
||||
}, [price, currency])
|
||||
|
||||
if (update) {
|
||||
// Fetch new prices periodically with swr
|
||||
@ -61,7 +67,7 @@ export default function Conversion({
|
||||
className={styleClasses}
|
||||
title="Approximation based on current spot price on Coingecko"
|
||||
>
|
||||
≈ {priceEur} EUR
|
||||
≈ {priceConverted} {currency}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
import React, { ReactElement, ReactNode } from 'react'
|
||||
import classNames from 'classnames/bind'
|
||||
import loadable from '@loadable/component'
|
||||
import { useSpring, animated } from 'react-spring'
|
||||
import styles from './Tooltip.module.css'
|
||||
import { ReactComponent as Info } from '../../images/info.svg'
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const Tippy = loadable(() => import('@tippyjs/react/headless'))
|
||||
|
||||
const animation = {
|
||||
@ -22,12 +25,14 @@ export default function Tooltip({
|
||||
content,
|
||||
children,
|
||||
trigger,
|
||||
disabled
|
||||
disabled,
|
||||
className
|
||||
}: {
|
||||
content: ReactNode
|
||||
children?: ReactNode
|
||||
trigger?: string
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}): ReactElement {
|
||||
const [props, setSpring] = useSpring(() => animation.from)
|
||||
|
||||
@ -47,6 +52,11 @@ export default function Tooltip({
|
||||
})
|
||||
}
|
||||
|
||||
const styleClasses = cx({
|
||||
tooltip: true,
|
||||
[className]: className
|
||||
})
|
||||
|
||||
return (
|
||||
<Tippy
|
||||
interactive
|
||||
@ -69,10 +79,10 @@ export default function Tooltip({
|
||||
onMount={onMount}
|
||||
onHide={onHide}
|
||||
fallback={
|
||||
<div className={styles.tooltip}>{children || <DefaultTrigger />}</div>
|
||||
<div className={styleClasses}>{children || <DefaultTrigger />}</div>
|
||||
}
|
||||
>
|
||||
<div className={styles.tooltip}>{children || <DefaultTrigger />}</div>
|
||||
<div className={styleClasses}>{children || <DefaultTrigger />}</div>
|
||||
</Tippy>
|
||||
)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import Tabs from '../../../atoms/Tabs'
|
||||
import Fixed from './Fixed'
|
||||
import Dynamic from './Dynamic'
|
||||
import { useField } from 'formik'
|
||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||
|
||||
const query = graphql`
|
||||
query PriceFieldQuery {
|
||||
@ -35,6 +36,7 @@ const query = graphql`
|
||||
`
|
||||
|
||||
export default function Price(props: InputProps): ReactElement {
|
||||
const { debug } = useUserPreferences()
|
||||
const data = useStaticQuery(query)
|
||||
const content = data.content.edges[0].node.childPagesJson.price
|
||||
|
||||
@ -89,9 +91,11 @@ export default function Price(props: InputProps): ReactElement {
|
||||
return (
|
||||
<div className={styles.price}>
|
||||
<Tabs items={tabs} handleTabChange={handleTabChange} />
|
||||
<pre>
|
||||
<code>{JSON.stringify(field.value)}</code>
|
||||
</pre>
|
||||
{debug === true && (
|
||||
<pre>
|
||||
<code>{JSON.stringify(field.value)}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
.navigation li {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.navigation button,
|
||||
|
@ -6,6 +6,7 @@ import styles from './Menu.module.css'
|
||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||
import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg'
|
||||
import Container from '../atoms/Container'
|
||||
import UserPreferences from './UserPreferences'
|
||||
|
||||
const Wallet = loadable(() => import('./Wallet'))
|
||||
|
||||
@ -49,6 +50,9 @@ export default function Menu(): ReactElement {
|
||||
<MenuLink item={item} />
|
||||
</li>
|
||||
))}
|
||||
<li>
|
||||
<UserPreferences />
|
||||
</li>
|
||||
</ul>
|
||||
</Container>
|
||||
</nav>
|
||||
|
26
src/components/molecules/UserPreferences/Currency.tsx
Normal file
26
src/components/molecules/UserPreferences/Currency.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React, { ReactElement, ChangeEvent } from 'react'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import Input from '../../atoms/Input'
|
||||
|
||||
export default function Currency(): ReactElement {
|
||||
const { currency, setCurrency } = useUserPreferences()
|
||||
const { appConfig } = useSiteMetadata()
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Input
|
||||
name="currency"
|
||||
label="Currency"
|
||||
help="Select your preferred currency."
|
||||
type="select"
|
||||
options={appConfig.currencies}
|
||||
value={currency}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
setCurrency(e.target.value)
|
||||
}
|
||||
small
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
}
|
21
src/components/molecules/UserPreferences/Debug.tsx
Normal file
21
src/components/molecules/UserPreferences/Debug.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import FormHelp from '../../atoms/Input/Help'
|
||||
import InputElement from '../../atoms/Input/InputElement'
|
||||
|
||||
export default function Debug(): ReactElement {
|
||||
const { debug, setDebug } = useUserPreferences()
|
||||
|
||||
return (
|
||||
<li>
|
||||
<InputElement
|
||||
name="debug"
|
||||
type="checkbox"
|
||||
options={['Debug Mode']}
|
||||
defaultChecked={debug === true}
|
||||
onChange={() => setDebug(!debug)}
|
||||
/>
|
||||
<FormHelp>Show geeky information in some places.</FormHelp>
|
||||
</li>
|
||||
)
|
||||
}
|
36
src/components/molecules/UserPreferences/index.module.css
Normal file
36
src/components/molecules/UserPreferences/index.module.css
Normal file
@ -0,0 +1,36 @@
|
||||
.preferences {
|
||||
padding: calc(var(--spacer) / 2);
|
||||
margin-left: var(--spacer);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: var(--brand-grey-light);
|
||||
transition: fill 0.2s ease-out;
|
||||
}
|
||||
|
||||
.preferences:hover .icon,
|
||||
.preferences:focus .icon,
|
||||
.preferences:active .icon,
|
||||
.preferences[aria-expanded='true'] .icon {
|
||||
fill: var(--brand-grey);
|
||||
}
|
||||
|
||||
.preferencesDetails {
|
||||
padding: calc(var(--spacer) / 2);
|
||||
}
|
||||
|
||||
.preferencesDetails li > div {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.preferencesDetails li {
|
||||
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||
margin-bottom: calc(var(--spacer) / 2);
|
||||
}
|
||||
|
||||
.preferencesDetails li:last-child,
|
||||
.preferencesDetails li:last-child p {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
23
src/components/molecules/UserPreferences/index.tsx
Normal file
23
src/components/molecules/UserPreferences/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import Tooltip from '../../atoms/Tooltip'
|
||||
import { ReactComponent as Cog } from '../../../images/cog.svg'
|
||||
import styles from './index.module.css'
|
||||
import Currency from './Currency'
|
||||
import Debug from './Debug'
|
||||
|
||||
export default function UserPreferences(): ReactElement {
|
||||
return (
|
||||
<Tooltip
|
||||
content={
|
||||
<ul className={styles.preferencesDetails}>
|
||||
<Currency />
|
||||
<Debug />
|
||||
</ul>
|
||||
}
|
||||
trigger="click focus"
|
||||
className={styles.preferences}
|
||||
>
|
||||
<Cog aria-label="Preferences" className={styles.icon} />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
@ -8,6 +8,7 @@ import Token from './Token'
|
||||
import { Balance } from './'
|
||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||
import Actions from './Actions'
|
||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||
|
||||
// TODO: handle and display all fees somehow
|
||||
|
||||
@ -22,6 +23,7 @@ export default function Add({
|
||||
totalPoolTokens: string
|
||||
totalBalance: Balance
|
||||
}): ReactElement {
|
||||
const { debug } = useUserPreferences()
|
||||
const { ocean, accountId, balance } = useOcean()
|
||||
const [amount, setAmount] = useState('')
|
||||
const [swapFee, setSwapFee] = useState<string>()
|
||||
@ -89,7 +91,7 @@ export default function Add({
|
||||
<div className={styles.output}>
|
||||
<div>
|
||||
<p>You will receive</p>
|
||||
<Token symbol="BPT" balance={newPoolTokens} />
|
||||
{debug === true && <Token symbol="BPT" balance={newPoolTokens} />}
|
||||
<Token symbol="% of pool" balance={newPoolShare} />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -12,6 +12,7 @@ import Remove from './Remove'
|
||||
import Tooltip from '../../../atoms/Tooltip'
|
||||
import Conversion from '../../../atoms/Price/Conversion'
|
||||
import EtherscanLink from '../../../atoms/EtherscanLink'
|
||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||
|
||||
export interface Balance {
|
||||
ocean: string
|
||||
@ -23,6 +24,7 @@ export interface Balance {
|
||||
*/
|
||||
|
||||
export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
||||
const { debug } = useUserPreferences()
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { price, poolAddress } = useMetadata(ddo)
|
||||
|
||||
@ -149,7 +151,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
||||
</h3>
|
||||
<Token symbol="OCEAN" balance={userBalance.ocean} />
|
||||
<Token symbol={dtSymbol} balance={userBalance.dt} />
|
||||
<Token symbol="BPT" balance={poolTokens} />
|
||||
{debug === true && <Token symbol="BPT" balance={poolTokens} />}
|
||||
<Token symbol="% of pool" balance={poolShare} />
|
||||
</div>
|
||||
|
||||
@ -157,7 +159,9 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
||||
<h3 className={styles.title}>Pool Statistics</h3>
|
||||
<Token symbol="OCEAN" balance={totalBalance.ocean} />
|
||||
<Token symbol={dtSymbol} balance={totalBalance.dt} />
|
||||
<Token symbol="BPT" balance={totalPoolTokens} />
|
||||
{debug === true && (
|
||||
<Token symbol="BPT" balance={totalPoolTokens} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -8,6 +8,7 @@ import MetaSecondary from './MetaSecondary'
|
||||
import styles from './index.module.css'
|
||||
import AssetActions from '../AssetActions'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
|
||||
export interface AssetContentProps {
|
||||
metadata: MetadataMarket
|
||||
@ -21,6 +22,7 @@ export default function AssetContent({
|
||||
}: AssetContentProps): ReactElement {
|
||||
const { datePublished } = metadata.main
|
||||
const { description, categories } = metadata.additionalInformation
|
||||
const { debug } = useUserPreferences()
|
||||
|
||||
return (
|
||||
<article className={styles.grid}>
|
||||
@ -52,9 +54,11 @@ export default function AssetContent({
|
||||
{/* <DeleteAction ddo={ddo} /> */}
|
||||
</div>
|
||||
|
||||
<pre>
|
||||
<code>{JSON.stringify(ddo, null, 2)}</code>
|
||||
</pre>
|
||||
{debug === true && (
|
||||
<pre>
|
||||
<code>{JSON.stringify(ddo, null, 2)}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div className={styles.sticky}>
|
||||
|
@ -12,6 +12,7 @@ import { transformPublishFormToMetadata } from './utils'
|
||||
import Preview from './Preview'
|
||||
import { MetadataPublishForm } from '../../../@types/MetaData'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
|
||||
export default function PublishPage({
|
||||
content
|
||||
@ -19,6 +20,7 @@ export default function PublishPage({
|
||||
content: { form: FormContent }
|
||||
}): ReactElement {
|
||||
const { marketFeeAddress, marketFeeAmount } = useSiteMetadata()
|
||||
const { debug } = useUserPreferences()
|
||||
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||
const navigate = useNavigate()
|
||||
|
||||
@ -85,25 +87,29 @@ export default function PublishPage({
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div>
|
||||
<h5>Collected Form Values</h5>
|
||||
<pre>
|
||||
<code>{JSON.stringify(values, null, 2)}</code>
|
||||
</pre>
|
||||
</div>
|
||||
{debug === true && (
|
||||
<>
|
||||
<div>
|
||||
<h5>Collected Form Values</h5>
|
||||
<pre>
|
||||
<code>{JSON.stringify(values, null, 2)}</code>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h5>Transformed Values</h5>
|
||||
<pre>
|
||||
<code>
|
||||
{JSON.stringify(
|
||||
transformPublishFormToMetadata(values),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Transformed Values</h5>
|
||||
<pre>
|
||||
<code>
|
||||
{JSON.stringify(
|
||||
transformPublishFormToMetadata(values),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Formik>
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
ConfigHelperNetworkName,
|
||||
ConfigHelperNetworkId
|
||||
} from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { UserPreferencesProvider } from '../providers/UserPreferences'
|
||||
|
||||
export function getOceanConfig(
|
||||
network: ConfigHelperNetworkName | ConfigHelperNetworkId
|
||||
@ -30,8 +31,10 @@ export default function wrapRootElement({
|
||||
initialConfig={oceanInitialConfig}
|
||||
web3ModalOpts={web3ModalOpts}
|
||||
>
|
||||
<NetworkMonitor />
|
||||
{element}
|
||||
<UserPreferencesProvider>
|
||||
<NetworkMonitor />
|
||||
{element}
|
||||
</UserPreferencesProvider>
|
||||
</OceanProvider>
|
||||
)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ const query = graphql`
|
||||
network
|
||||
marketFeeAddress
|
||||
marketFeeAmount
|
||||
currencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
src/images/cog.svg
Normal file
3
src/images/cog.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.1593 10.98C17.1993 10.66 17.2293 10.34 17.2293 10C17.2293 9.66 17.1993 9.34 17.1593 9.02L19.2693 7.37C19.4593 7.22 19.5093 6.95 19.3893 6.73L17.3893 3.27C17.2693 3.05 16.9993 2.97 16.7793 3.05L14.2893 4.05C13.7693 3.65 13.2093 3.32 12.5993 3.07L12.2193 0.42C12.1893 0.18 11.9793 0 11.7293 0H7.72933C7.47933 0 7.26933 0.18 7.23933 0.42L6.85933 3.07C6.24933 3.32 5.68933 3.66 5.16933 4.05L2.67933 3.05C2.44933 2.96 2.18933 3.05 2.06933 3.27L0.0693316 6.73C-0.0606684 6.95 -0.000668302 7.22 0.189332 7.37L2.29933 9.02C2.25933 9.34 2.22933 9.67 2.22933 10C2.22933 10.33 2.25933 10.66 2.29933 10.98L0.189332 12.63C-0.000668302 12.78 -0.0506684 13.05 0.0693316 13.27L2.06933 16.73C2.18933 16.95 2.45933 17.03 2.67933 16.95L5.16933 15.95C5.68933 16.35 6.24933 16.68 6.85933 16.93L7.23933 19.58C7.26933 19.82 7.47933 20 7.72933 20H11.7293C11.9793 20 12.1893 19.82 12.2193 19.58L12.5993 16.93C13.2093 16.68 13.7693 16.34 14.2893 15.95L16.7793 16.95C17.0093 17.04 17.2693 16.95 17.3893 16.73L19.3893 13.27C19.5093 13.05 19.4593 12.78 19.2693 12.63L17.1593 10.98V10.98ZM9.72933 13.5C7.79933 13.5 6.22933 11.93 6.22933 10C6.22933 8.07 7.79933 6.5 9.72933 6.5C11.6593 6.5 13.2293 8.07 13.2293 10C13.2293 11.93 11.6593 13.5 9.72933 13.5Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
77
src/providers/UserPreferences.tsx
Normal file
77
src/providers/UserPreferences.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
useState,
|
||||
useEffect
|
||||
} from 'react'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { LogLevel } from '@oceanprotocol/lib/dist/node/utils/Logger'
|
||||
|
||||
interface UserPreferencesValue {
|
||||
debug: boolean
|
||||
currency: string
|
||||
setDebug?: (value: boolean) => void
|
||||
setCurrency?: (value: string) => void
|
||||
}
|
||||
|
||||
const UserPreferencesContext = createContext(null)
|
||||
|
||||
const localStorageKey = 'ocean-user-preferences'
|
||||
|
||||
function getLocalStorage() {
|
||||
const storageParsed =
|
||||
typeof window !== 'undefined' &&
|
||||
JSON.parse(window.localStorage.getItem(localStorageKey))
|
||||
return storageParsed
|
||||
}
|
||||
|
||||
function setLocalStorage(values: UserPreferencesValue) {
|
||||
return (
|
||||
typeof window !== 'undefined' &&
|
||||
window.localStorage.setItem(localStorageKey, JSON.stringify(values))
|
||||
)
|
||||
}
|
||||
|
||||
function UserPreferencesProvider({
|
||||
children
|
||||
}: {
|
||||
children: ReactNode
|
||||
}): ReactElement {
|
||||
const localStorage = getLocalStorage()
|
||||
|
||||
// Set default values from localStorage
|
||||
const [debug, setDebug] = useState<boolean>(
|
||||
(localStorage && localStorage.debug) || false
|
||||
)
|
||||
const [currency, setCurrency] = useState<string>(
|
||||
(localStorage && localStorage.currency) || 'EUR'
|
||||
)
|
||||
|
||||
// Write values to localStorage on change
|
||||
useEffect(() => {
|
||||
setLocalStorage({ debug, currency })
|
||||
}, [debug, currency])
|
||||
|
||||
// Set ocen-lib-js log levels, default: Error
|
||||
useEffect(() => {
|
||||
debug === true
|
||||
? Logger.setLevel(LogLevel.Verbose)
|
||||
: Logger.setLevel(LogLevel.Error)
|
||||
}, [debug])
|
||||
|
||||
return (
|
||||
<UserPreferencesContext.Provider
|
||||
value={{ debug, currency, setDebug, setCurrency } as UserPreferencesValue}
|
||||
>
|
||||
{children}
|
||||
</UserPreferencesContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
// Helper hook to access the provider values
|
||||
const useUserPreferences = (): UserPreferencesValue =>
|
||||
useContext(UserPreferencesContext)
|
||||
|
||||
export { UserPreferencesProvider, useUserPreferences, UserPreferencesValue }
|
Loading…
Reference in New Issue
Block a user