feat: add wallet settings page
This commit is contained in:
parent
20674c4b12
commit
1f7ae74b42
31 changed files with 1793 additions and 258 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import { makeStyles } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import { ReactComponent as ErrorIcon } from 'src/styling/icons/warning-icon/tomato.svg'
|
||||
import { errorColor } from 'src/styling/variables'
|
||||
|
|
@ -20,8 +20,7 @@ const styles = {
|
|||
alignItems: 'center',
|
||||
color: errorColor,
|
||||
margin: 0,
|
||||
whiteSpace: 'break-spaces',
|
||||
width: 250
|
||||
whiteSpace: 'break-spaces'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
54
new-lamassu-admin/src/components/Modal.js
Normal file
54
new-lamassu-admin/src/components/Modal.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { makeStyles, Modal as MaterialModal, Paper } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||
|
||||
const styles = {
|
||||
modal: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
modalContentWrapper: {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
minHeight: 400,
|
||||
maxHeight: '90vh',
|
||||
overflowY: 'auto',
|
||||
borderRadius: 8,
|
||||
outline: 0,
|
||||
'& > div': {
|
||||
width: '100%'
|
||||
}
|
||||
},
|
||||
closeIcon: {
|
||||
position: 'absolute',
|
||||
width: 18,
|
||||
height: 18,
|
||||
padding: 0,
|
||||
top: 20,
|
||||
right: 20
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const Modal = ({ handleClose, children, className, ...props }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<MaterialModal onClose={handleClose} className={classes.modal} {...props}>
|
||||
<Paper className={classnames(classes.modalContentWrapper, className)}>
|
||||
<button
|
||||
className={classnames(classes.iconButton, classes.closeIcon)}
|
||||
onClick={() => handleClose()}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
{children}
|
||||
</Paper>
|
||||
</MaterialModal>
|
||||
)
|
||||
}
|
||||
|
||||
export default Modal
|
||||
112
new-lamassu-admin/src/components/Stage.js
Normal file
112
new-lamassu-admin/src/components/Stage.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo } from 'react'
|
||||
|
||||
import { ReactComponent as CompleteStageIconSpring } from 'src/styling/icons/stage/spring/complete.svg'
|
||||
import { ReactComponent as CurrentStageIconSpring } from 'src/styling/icons/stage/spring/current.svg'
|
||||
import { ReactComponent as EmptyStageIconSpring } from 'src/styling/icons/stage/spring/empty.svg'
|
||||
import { ReactComponent as CompleteStageIconZodiac } from 'src/styling/icons/stage/zodiac/complete.svg'
|
||||
import { ReactComponent as CurrentStageIconZodiac } from 'src/styling/icons/stage/zodiac/current.svg'
|
||||
import { ReactComponent as EmptyStageIconZodiac } from 'src/styling/icons/stage/zodiac/empty.svg'
|
||||
import {
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
offColor,
|
||||
disabledColor
|
||||
} from 'src/styling/variables'
|
||||
|
||||
const styles = {
|
||||
stages: {
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
},
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
margin: 0
|
||||
},
|
||||
stage: {
|
||||
display: 'flex',
|
||||
height: 28,
|
||||
width: 28,
|
||||
zIndex: 2,
|
||||
'& > svg': {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
overflow: 'visible'
|
||||
}
|
||||
},
|
||||
separator: {
|
||||
width: 28,
|
||||
height: 2,
|
||||
border: [[2, 'solid']],
|
||||
zIndex: 1
|
||||
},
|
||||
separatorSpring: {
|
||||
borderColor: secondaryColor
|
||||
},
|
||||
separatorZodiac: {
|
||||
borderColor: primaryColor
|
||||
},
|
||||
separatorSpringEmpty: {
|
||||
borderColor: disabledColor
|
||||
},
|
||||
separatorZodiacEmpty: {
|
||||
borderColor: offColor
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const Stage = memo(({ stages, currentStage, color = 'spring', className }) => {
|
||||
if (currentStage < 1 || currentStage > stages)
|
||||
throw Error('Value of currentStage is invalid')
|
||||
if (stages < 1) throw Error('Value of stages is invalid')
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
const separatorClasses = {
|
||||
[classes.separator]: true,
|
||||
[classes.separatorSpring]: color === 'spring',
|
||||
[classes.separatorZodiac]: color === 'zodiac'
|
||||
}
|
||||
|
||||
const separatorEmptyClasses = {
|
||||
[classes.separator]: true,
|
||||
[classes.separatorSpringEmpty]: color === 'spring',
|
||||
[classes.separatorZodiacEmpty]: color === 'zodiac'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classnames(className, classes.stages)}>
|
||||
{R.range(1, currentStage).map(idx => (
|
||||
<div key={idx} className={classes.wrapper}>
|
||||
{idx > 1 && <div className={classnames(separatorClasses)} />}
|
||||
<div className={classes.stage}>
|
||||
{color === 'spring' && <CompleteStageIconSpring />}
|
||||
{color === 'zodiac' && <CompleteStageIconZodiac />}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className={classes.wrapper}>
|
||||
{currentStage > 1 && <div className={classnames(separatorClasses)} />}
|
||||
<div className={classes.stage}>
|
||||
{color === 'spring' && <CurrentStageIconSpring />}
|
||||
{color === 'zodiac' && <CurrentStageIconZodiac />}
|
||||
</div>
|
||||
</div>
|
||||
{R.range(currentStage + 1, stages + 1).map(idx => (
|
||||
<div key={idx} className={classes.wrapper}>
|
||||
<div className={classnames(separatorEmptyClasses)} />
|
||||
<div className={classes.stage}>
|
||||
{color === 'spring' && <EmptyStageIconSpring />}
|
||||
{color === 'zodiac' && <EmptyStageIconZodiac />}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default Stage
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import Paper from '@material-ui/core/Paper'
|
||||
import Popper from '@material-ui/core/Popper'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Downshift from 'downshift'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo, useState } from 'react'
|
||||
|
||||
import {
|
||||
renderInput,
|
||||
renderSuggestion,
|
||||
filterSuggestions,
|
||||
styles
|
||||
} from './commons'
|
||||
|
||||
const Autocomplete = memo(
|
||||
({
|
||||
suggestions,
|
||||
classes,
|
||||
placeholder,
|
||||
label,
|
||||
itemToString,
|
||||
code = 'code',
|
||||
display = 'display',
|
||||
...props
|
||||
}) => {
|
||||
const { name, value, onBlur } = props.field
|
||||
const { touched, errors, setFieldValue } = props.form
|
||||
|
||||
const [popperNode, setPopperNode] = useState(null)
|
||||
|
||||
return (
|
||||
<Downshift
|
||||
id={name}
|
||||
itemToString={it => {
|
||||
if (itemToString) return itemToString(it)
|
||||
if (it) return it[display]
|
||||
return undefined
|
||||
}}
|
||||
onChange={it => setFieldValue(name, it)}
|
||||
defaultHighlightedIndex={0}
|
||||
selectedItem={value}>
|
||||
{({
|
||||
getInputProps,
|
||||
getItemProps,
|
||||
getMenuProps,
|
||||
isOpen,
|
||||
inputValue: inputValue2,
|
||||
selectedItem: selectedItem2,
|
||||
highlightedIndex,
|
||||
inputValue,
|
||||
toggleMenu,
|
||||
clearSelection
|
||||
}) => (
|
||||
<div className={classes.container}>
|
||||
{renderInput({
|
||||
name,
|
||||
fullWidth: true,
|
||||
error:
|
||||
(touched[`${name}-input`] || touched[name]) && errors[name],
|
||||
success:
|
||||
(touched[`${name}-input`] || touched[name] || value) &&
|
||||
!errors[name],
|
||||
InputProps: getInputProps({
|
||||
value: inputValue2 || '',
|
||||
placeholder,
|
||||
onBlur,
|
||||
onClick: event => {
|
||||
setPopperNode(event.currentTarget.parentElement)
|
||||
toggleMenu()
|
||||
},
|
||||
onChange: it => {
|
||||
if (it.target.value === '') {
|
||||
clearSelection()
|
||||
}
|
||||
inputValue = it.target.value
|
||||
}
|
||||
}),
|
||||
label
|
||||
})}
|
||||
<Popper
|
||||
open={isOpen}
|
||||
anchorEl={popperNode}
|
||||
modifiers={{ flip: { enabled: true } }}
|
||||
style={{ zIndex: 9999 }}>
|
||||
<div
|
||||
{...(isOpen
|
||||
? getMenuProps({}, { suppressRefError: true })
|
||||
: {})}>
|
||||
<Paper
|
||||
square
|
||||
style={{
|
||||
minWidth: popperNode ? popperNode.clientWidth + 2 : null
|
||||
}}>
|
||||
{filterSuggestions(
|
||||
suggestions,
|
||||
inputValue2,
|
||||
value ? R.of(value) : [],
|
||||
code,
|
||||
display
|
||||
).map((suggestion, index) =>
|
||||
renderSuggestion({
|
||||
suggestion,
|
||||
index,
|
||||
itemProps: getItemProps({ item: suggestion }),
|
||||
highlightedIndex,
|
||||
selectedItem: selectedItem2,
|
||||
code,
|
||||
display
|
||||
})
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
</Popper>
|
||||
</div>
|
||||
)}
|
||||
</Downshift>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default withStyles(styles)(Autocomplete)
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import Paper from '@material-ui/core/Paper'
|
||||
import Popper from '@material-ui/core/Popper'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import classnames from 'classnames'
|
||||
import Downshift from 'downshift'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo, useState } from 'react'
|
||||
|
||||
import {
|
||||
renderInput,
|
||||
renderSuggestion,
|
||||
filterSuggestions,
|
||||
styles
|
||||
} from './commons'
|
||||
|
||||
const AutocompleteSelect = memo(
|
||||
({
|
||||
suggestions,
|
||||
classes,
|
||||
placeholder,
|
||||
label,
|
||||
itemToString,
|
||||
code = 'code',
|
||||
display = 'display',
|
||||
name,
|
||||
value,
|
||||
touched,
|
||||
error,
|
||||
handleChange,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const [popperNode, setPopperNode] = useState(null)
|
||||
|
||||
return (
|
||||
<Downshift
|
||||
id={name}
|
||||
itemToString={it => {
|
||||
if (itemToString) return itemToString(it)
|
||||
if (it) return it[display]
|
||||
return undefined
|
||||
}}
|
||||
onChange={handleChange}
|
||||
defaultHighlightedIndex={0}
|
||||
selectedItem={value}>
|
||||
{({
|
||||
getInputProps,
|
||||
getItemProps,
|
||||
getMenuProps,
|
||||
isOpen,
|
||||
inputValue: inputValue2,
|
||||
selectedItem: selectedItem2,
|
||||
highlightedIndex,
|
||||
inputValue,
|
||||
toggleMenu,
|
||||
clearSelection
|
||||
}) => (
|
||||
<div className={classnames(classes.container, className)}>
|
||||
{renderInput({
|
||||
name,
|
||||
fullWidth: true,
|
||||
error: touched && error,
|
||||
success: touched && !error,
|
||||
InputProps: getInputProps({
|
||||
value: inputValue2 || '',
|
||||
placeholder,
|
||||
onClick: event => {
|
||||
setPopperNode(event.currentTarget.parentElement)
|
||||
toggleMenu()
|
||||
},
|
||||
onChange: it => {
|
||||
if (it.target.value === '') {
|
||||
clearSelection()
|
||||
}
|
||||
inputValue = it.target.value
|
||||
}
|
||||
}),
|
||||
label
|
||||
})}
|
||||
<Popper
|
||||
open={isOpen}
|
||||
anchorEl={popperNode}
|
||||
modifiers={{ flip: { enabled: true } }}
|
||||
style={{ zIndex: 9999 }}>
|
||||
<div
|
||||
{...(isOpen
|
||||
? getMenuProps({}, { suppressRefError: true })
|
||||
: {})}>
|
||||
<Paper
|
||||
square
|
||||
style={{
|
||||
minWidth: popperNode ? popperNode.clientWidth + 2 : null
|
||||
}}>
|
||||
{filterSuggestions(
|
||||
suggestions,
|
||||
inputValue2,
|
||||
value ? R.of(value) : [],
|
||||
code,
|
||||
display
|
||||
).map((suggestion, index) =>
|
||||
renderSuggestion({
|
||||
suggestion,
|
||||
index,
|
||||
itemProps: getItemProps({ item: suggestion }),
|
||||
highlightedIndex,
|
||||
selectedItem: selectedItem2,
|
||||
code,
|
||||
display
|
||||
})
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
</Popper>
|
||||
</div>
|
||||
)}
|
||||
</Downshift>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default withStyles(styles)(AutocompleteSelect)
|
||||
132
new-lamassu-admin/src/components/inputs/autocomplete/commons.js
Normal file
132
new-lamassu-admin/src/components/inputs/autocomplete/commons.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import MenuItem from '@material-ui/core/MenuItem'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Fuse from 'fuse.js'
|
||||
import React from 'react'
|
||||
import slugify from 'slugify'
|
||||
|
||||
import {
|
||||
fontColor,
|
||||
inputFontSize,
|
||||
inputFontWeight,
|
||||
zircon
|
||||
} from 'src/styling/variables'
|
||||
import S from 'src/utils/sanctuary'
|
||||
|
||||
import { TextInput } from '../base'
|
||||
|
||||
function renderInput({ InputProps, error, name, success, ...props }) {
|
||||
const { onChange, onBlur, value } = InputProps
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
error={!!error}
|
||||
InputProps={InputProps}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function renderSuggestion({
|
||||
suggestion,
|
||||
index,
|
||||
itemProps,
|
||||
highlightedIndex,
|
||||
selectedItem,
|
||||
code,
|
||||
display
|
||||
}) {
|
||||
const isHighlighted = highlightedIndex === index
|
||||
|
||||
const StyledMenuItem = withStyles(theme => ({
|
||||
root: {
|
||||
fontSize: 14,
|
||||
fontWeight: 400,
|
||||
color: fontColor
|
||||
},
|
||||
selected: {
|
||||
'&.Mui-selected, &.Mui-selected:hover': {
|
||||
fontWeight: 500,
|
||||
backgroundColor: zircon
|
||||
}
|
||||
}
|
||||
}))(MenuItem)
|
||||
|
||||
return (
|
||||
<StyledMenuItem
|
||||
{...itemProps}
|
||||
key={suggestion[code]}
|
||||
selected={isHighlighted}
|
||||
component="div">
|
||||
{suggestion[display]}
|
||||
</StyledMenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
function filterSuggestions(
|
||||
suggestions = [],
|
||||
value = '',
|
||||
currentValues = [],
|
||||
code,
|
||||
display
|
||||
) {
|
||||
const options = {
|
||||
shouldSort: true,
|
||||
threshold: 0.2,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
keys: [code, display]
|
||||
}
|
||||
|
||||
const fuse = new Fuse(suggestions, options)
|
||||
const result = value ? fuse.search(slugify(value, ' ')) : suggestions
|
||||
|
||||
const currentCodes = S.map(S.prop(code))(currentValues)
|
||||
const filtered = S.filter(it => !S.elem(it[code])(currentCodes))(result)
|
||||
|
||||
const amountToTake = S.min(filtered.length)(5)
|
||||
|
||||
return S.compose(S.fromMaybe([]))(S.take(amountToTake))(filtered)
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
height: 250
|
||||
},
|
||||
container: {
|
||||
flexGrow: 1,
|
||||
position: 'relative'
|
||||
},
|
||||
paper: {
|
||||
// position: 'absolute',
|
||||
zIndex: 1,
|
||||
marginTop: theme.spacing(1),
|
||||
left: 0,
|
||||
right: 0
|
||||
},
|
||||
inputRoot: {
|
||||
fontSize: inputFontSize,
|
||||
color: fontColor,
|
||||
fontWeight: inputFontWeight,
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
inputInput: {
|
||||
flex: 1
|
||||
},
|
||||
success: {
|
||||
'&:after': {
|
||||
transform: 'scaleX(1)'
|
||||
}
|
||||
},
|
||||
divider: {
|
||||
height: theme.spacing(2)
|
||||
}
|
||||
})
|
||||
|
||||
export { renderInput, renderSuggestion, filterSuggestions, styles }
|
||||
|
|
@ -15,6 +15,7 @@ const { p } = typographyStyles
|
|||
const GreenRadio = withStyles({
|
||||
root: {
|
||||
color: secondaryColor,
|
||||
padding: [[9, 8, 9, 9]],
|
||||
'&$checked': {
|
||||
color: secondaryColor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import React, { memo, useState } from 'react'
|
||||
import classnames from 'classnames'
|
||||
import { makeStyles } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import React, { memo, useState } from 'react'
|
||||
|
||||
import TextInputFormik from './TextInput'
|
||||
import { styles } from './TextInput.styles'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const SecretInputFormik = memo(({ ...props }) => {
|
||||
const SecretInputFormik = memo(({ className, ...props }) => {
|
||||
const { value } = props.field
|
||||
|
||||
const classes = useStyles()
|
||||
|
|
@ -37,7 +37,7 @@ const SecretInputFormik = memo(({ ...props }) => {
|
|||
<TextInputFormik
|
||||
{...props}
|
||||
onFocus={handleFocus}
|
||||
className={classnames(inputClass)}
|
||||
className={classnames(inputClass, className)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import AutocompleteSelect from './autocomplete/AutocompleteSelect'
|
||||
import Checkbox from './base/Checkbox'
|
||||
import Radio from './base/Radio'
|
||||
import RadioGroup from './base/RadioGroup'
|
||||
|
|
@ -5,4 +6,12 @@ import Select from './base/Select'
|
|||
import Switch from './base/Switch'
|
||||
import TextInput from './base/TextInput'
|
||||
|
||||
export { TextInput, Radio, Checkbox, Switch, Select, RadioGroup }
|
||||
export {
|
||||
AutocompleteSelect,
|
||||
TextInput,
|
||||
Radio,
|
||||
Checkbox,
|
||||
Switch,
|
||||
Select,
|
||||
RadioGroup
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,11 @@ export default {
|
|||
},
|
||||
titleAndButtonsContainer: {
|
||||
display: 'flex'
|
||||
},
|
||||
iconButton: {
|
||||
border: 'none',
|
||||
outline: 0,
|
||||
backgroundColor: 'transparent',
|
||||
cursor: 'pointer'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,10 +81,9 @@ const BitgoCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
||||
const getBitgoFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const token = getValue(schema.token.code)
|
||||
const btcWalletId = getValue(schema.btcWalletId.code)
|
||||
const btcWalletPassphrase = getValue(schema.btcWalletPassphrase.code)
|
||||
|
|
@ -98,7 +97,7 @@ const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
|||
const dashWalletPassphrase = getValue(schema.dashWalletPassphrase.code)
|
||||
const environment = getValue(schema.environment.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
token: token,
|
||||
BTCWalletId: btcWalletId,
|
||||
|
|
@ -157,82 +156,90 @@ const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
|||
return errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.btcWalletId.code,
|
||||
label: schema.btcWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.btcWalletPassphrase.code,
|
||||
label: schema.btcWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.ltcWalletId.code,
|
||||
label: schema.ltcWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.ltcWalletPassphrase.code,
|
||||
label: schema.ltcWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.zecWalletId.code,
|
||||
label: schema.zecWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.zecWalletPassphrase.code,
|
||||
label: schema.zecWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.bchWalletId.code,
|
||||
label: schema.bchWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.bchWalletPassphrase.code,
|
||||
label: schema.bchWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.dashWalletId.code,
|
||||
label: schema.dashWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.dashWalletPassphrase.code,
|
||||
label: schema.dashWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.environment.code,
|
||||
label: schema.environment.display,
|
||||
placeholder: 'prod or test',
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
const getBitgoFields = () => [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.btcWalletId.code,
|
||||
label: schema.btcWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.btcWalletPassphrase.code,
|
||||
label: schema.btcWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.ltcWalletId.code,
|
||||
label: schema.ltcWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.ltcWalletPassphrase.code,
|
||||
label: schema.ltcWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.zecWalletId.code,
|
||||
label: schema.zecWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.zecWalletPassphrase.code,
|
||||
label: schema.zecWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.bchWalletId.code,
|
||||
label: schema.bchWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.bchWalletPassphrase.code,
|
||||
label: schema.bchWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.dashWalletId.code,
|
||||
label: schema.dashWalletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.dashWalletPassphrase.code,
|
||||
label: schema.dashWalletPassphrase.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.environment.code,
|
||||
label: schema.environment.display,
|
||||
placeholder: 'prod or test',
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getBitgoFormik(account)
|
||||
|
||||
const fields = getBitgoFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -247,4 +254,4 @@ const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { BitgoForm, BitgoCard }
|
||||
export { BitgoForm, BitgoCard, getBitgoFormik, getBitgoFields }
|
||||
|
|
|
|||
|
|
@ -52,15 +52,14 @@ const BitstampCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const BitstampForm = ({ account, ...props }) => {
|
||||
const getBitstampFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const clientId = getValue(schema.clientId.code)
|
||||
const key = getValue(schema.key.code)
|
||||
const secret = getValue(schema.secret.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
clientId: clientId,
|
||||
key: key,
|
||||
|
|
@ -78,27 +77,35 @@ const BitstampForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.clientId.code,
|
||||
label: schema.clientId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.key.code,
|
||||
label: schema.key.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.secret.code,
|
||||
label: schema.secret.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
const getBitstampFields = () => [
|
||||
{
|
||||
name: schema.clientId.code,
|
||||
label: schema.clientId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.key.code,
|
||||
label: schema.key.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.secret.code,
|
||||
label: schema.secret.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const BitstampForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getBitstampFormik(account)
|
||||
|
||||
const fields = getBitstampFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -113,4 +120,4 @@ const BitstampForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { BitstampForm, BitstampCard }
|
||||
export { BitstampForm, BitstampCard, getBitstampFormik, getBitstampFields }
|
||||
|
|
|
|||
|
|
@ -47,14 +47,13 @@ const BlockcypherCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const BlockcypherForm = ({ account, ...props }) => {
|
||||
const getBlockcypherFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const token = getValue(schema.token.code)
|
||||
const confidenceFactor = getValue(schema.confidenceFactor.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
token: token,
|
||||
confidenceFactor: confidenceFactor
|
||||
|
|
@ -69,21 +68,29 @@ const BlockcypherForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.confidenceFactor.code,
|
||||
label: schema.confidenceFactor.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
const getBlockcypherFields = () => [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.confidenceFactor.code,
|
||||
label: schema.confidenceFactor.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const BlockcypherForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getBlockcypherFormik(account)
|
||||
|
||||
const fields = getBlockcypherFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -98,4 +105,9 @@ const BlockcypherForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { BlockcypherForm, BlockcypherCard }
|
||||
export {
|
||||
BlockcypherForm,
|
||||
BlockcypherCard,
|
||||
getBlockcypherFormik,
|
||||
getBlockcypherFields
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,15 +52,14 @@ const InfuraCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const InfuraForm = ({ account, ...props }) => {
|
||||
const getInfuraFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const apiKey = getValue(schema.apiKey.code)
|
||||
const apiSecret = getValue(schema.apiSecret.code)
|
||||
const endpoint = getValue(schema.endpoint.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
apiKey: apiKey,
|
||||
apiSecret: apiSecret,
|
||||
|
|
@ -79,8 +78,10 @@ const InfuraForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
const getInfuraFields = () => {
|
||||
return [
|
||||
{
|
||||
name: schema.apiKey.code,
|
||||
label: schema.apiKey.display,
|
||||
|
|
@ -100,6 +101,14 @@ const InfuraForm = ({ account, ...props }) => {
|
|||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const InfuraForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getInfuraFormik(account)
|
||||
|
||||
const fields = getInfuraFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -114,4 +123,4 @@ const InfuraForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { InfuraCard, InfuraForm }
|
||||
export { InfuraCard, InfuraForm, getInfuraFormik, getInfuraFields }
|
||||
|
|
|
|||
|
|
@ -51,16 +51,15 @@ const ItbitCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const ItbitForm = ({ account, ...props }) => {
|
||||
const getItbitFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const userId = getValue(schema.userId.code)
|
||||
const walletId = getValue(schema.walletId.code)
|
||||
const clientKey = getValue(schema.clientKey.code)
|
||||
const clientSecret = getValue(schema.clientSecret.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
userId: userId,
|
||||
walletId: walletId,
|
||||
|
|
@ -82,33 +81,41 @@ const ItbitForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.userId.code,
|
||||
label: schema.userId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.walletId.code,
|
||||
label: schema.walletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.clientKey.code,
|
||||
label: schema.clientKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.clientSecret.code,
|
||||
label: schema.clientSecret.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
const getItbitFields = () => [
|
||||
{
|
||||
name: schema.userId.code,
|
||||
label: schema.userId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.walletId.code,
|
||||
label: schema.walletId.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.clientKey.code,
|
||||
label: schema.clientKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.clientSecret.code,
|
||||
label: schema.clientSecret.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const ItbitForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getItbitFormik(account)
|
||||
|
||||
const fields = getItbitFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -123,4 +130,4 @@ const ItbitForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { ItbitCard, ItbitForm }
|
||||
export { ItbitCard, ItbitForm, getItbitFormik, getItbitFields }
|
||||
|
|
|
|||
|
|
@ -48,14 +48,13 @@ const KrakenCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const KrakenForm = ({ account, ...props }) => {
|
||||
const getKrakenFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const apiKey = getValue(schema.apiKey.code)
|
||||
const privateKey = getValue(schema.privateKey.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
apiKey: apiKey,
|
||||
privateKey: privateKey
|
||||
|
|
@ -69,21 +68,29 @@ const KrakenForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.apiKey.code,
|
||||
label: schema.apiKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.privateKey.code,
|
||||
label: schema.privateKey.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
const getKrakenFields = () => [
|
||||
{
|
||||
name: schema.apiKey.code,
|
||||
label: schema.apiKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.privateKey.code,
|
||||
label: schema.privateKey.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const KrakenForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getKrakenFormik(account)
|
||||
|
||||
const fields = getKrakenFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -98,4 +105,4 @@ const KrakenForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { KrakenCard, KrakenForm }
|
||||
export { KrakenCard, KrakenForm, getKrakenFormik, getKrakenFields }
|
||||
|
|
|
|||
|
|
@ -55,16 +55,15 @@ const MailgunCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const MailgunForm = ({ account, ...props }) => {
|
||||
const getMailgunFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const apiKey = getValue(schema.apiKey.code)
|
||||
const domain = getValue(schema.domain.code)
|
||||
const fromEmail = getValue(schema.fromEmail.code)
|
||||
const toEmail = getValue(schema.toEmail.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
apiKey: apiKey,
|
||||
domain: domain,
|
||||
|
|
@ -88,33 +87,41 @@ const MailgunForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.apiKey.code,
|
||||
label: schema.apiKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.domain.code,
|
||||
label: schema.domain.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.fromEmail.code,
|
||||
label: schema.fromEmail.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.toEmail.code,
|
||||
label: schema.toEmail.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
const getMailgunFields = () => [
|
||||
{
|
||||
name: schema.apiKey.code,
|
||||
label: schema.apiKey.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.domain.code,
|
||||
label: schema.domain.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.fromEmail.code,
|
||||
label: schema.fromEmail.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.toEmail.code,
|
||||
label: schema.toEmail.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const MailgunForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getMailgunFormik(account)
|
||||
|
||||
const fields = getMailgunFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -129,4 +136,4 @@ const MailgunForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { MailgunCard, MailgunForm }
|
||||
export { MailgunCard, MailgunForm, getMailgunFormik, getMailgunFields }
|
||||
|
|
|
|||
|
|
@ -37,13 +37,12 @@ const StrikeCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const StrikeForm = ({ account, ...props }) => {
|
||||
const getStrikeFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const code = 'strike'
|
||||
const token = getValue(schema.token.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
token: token
|
||||
},
|
||||
|
|
@ -53,15 +52,23 @@ const StrikeForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
const getStrikeFields = () => [
|
||||
{
|
||||
name: schema.token.code,
|
||||
label: schema.token.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const StrikeForm = ({ account, ...props }) => {
|
||||
const code = 'strike'
|
||||
|
||||
const formik = getStrikeFormik(account)
|
||||
|
||||
const fields = getStrikeFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -76,4 +83,4 @@ const StrikeForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { StrikeCard, StrikeForm }
|
||||
export { StrikeCard, StrikeForm, getStrikeFormik, getStrikeFields }
|
||||
|
|
|
|||
|
|
@ -56,16 +56,15 @@ const TwilioCard = memo(({ account, onEdit, ...props }) => {
|
|||
)
|
||||
})
|
||||
|
||||
const TwilioForm = ({ account, ...props }) => {
|
||||
const getTwilioFormik = account => {
|
||||
const getValue = getValueAux(account)
|
||||
|
||||
const { code } = account
|
||||
const accountSid = getValue(schema.accountSid.code)
|
||||
const authToken = getValue(schema.authToken.code)
|
||||
const fromNumber = getValue(schema.fromNumber.code)
|
||||
const toNumber = getValue(schema.toNumber.code)
|
||||
|
||||
const formik = {
|
||||
return {
|
||||
initialValues: {
|
||||
accountSid: accountSid,
|
||||
authToken: authToken,
|
||||
|
|
@ -87,33 +86,41 @@ const TwilioForm = ({ account, ...props }) => {
|
|||
.required('Required')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: schema.accountSid.code,
|
||||
label: schema.accountSid.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.authToken.code,
|
||||
label: schema.authToken.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.fromNumber.code,
|
||||
label: schema.fromNumber.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.toNumber.code,
|
||||
label: schema.toNumber.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
const getTwilioFields = () => [
|
||||
{
|
||||
name: schema.accountSid.code,
|
||||
label: schema.accountSid.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.authToken.code,
|
||||
label: schema.authToken.display,
|
||||
type: 'text',
|
||||
component: SecretInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.fromNumber.code,
|
||||
label: schema.fromNumber.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
},
|
||||
{
|
||||
name: schema.toNumber.code,
|
||||
label: schema.toNumber.display,
|
||||
type: 'text',
|
||||
component: TextInputFormik
|
||||
}
|
||||
]
|
||||
|
||||
const TwilioForm = ({ account, ...props }) => {
|
||||
const { code } = account
|
||||
|
||||
const formik = getTwilioFormik(account)
|
||||
|
||||
const fields = getTwilioFields()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -128,4 +135,4 @@ const TwilioForm = ({ account, ...props }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export { TwilioCard, TwilioForm }
|
||||
export { TwilioCard, TwilioForm, getTwilioFormik, getTwilioFields }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react'
|
||||
import * as R from 'ramda'
|
||||
import { makeStyles } from '@material-ui/core'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
|
||||
import SingleRowTable from 'src/components/single-row-table/SingleRowTable'
|
||||
|
||||
const getValue = R.curry((account, code) => account[code] ?? '')
|
||||
const getValue = R.curry((account, code) => (account ? account[code] : ''))
|
||||
|
||||
const formatLong = value => {
|
||||
if (!value) return ''
|
||||
|
|
|
|||
451
new-lamassu-admin/src/pages/Wallet/WalletSettings.js
Normal file
451
new-lamassu-admin/src/pages/Wallet/WalletSettings.js
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core'
|
||||
import { gql } from 'apollo-boost'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
import ErrorMessage from 'src/components/ErrorMessage'
|
||||
import Modal from 'src/components/Modal'
|
||||
import Title from 'src/components/Title'
|
||||
import {
|
||||
Table,
|
||||
THead,
|
||||
Th,
|
||||
TBody,
|
||||
Tr,
|
||||
Td
|
||||
} from 'src/components/fake-table/Table'
|
||||
import { Switch } from 'src/components/inputs'
|
||||
import { ReactComponent as DisabledEditIcon } from 'src/styling/icons/action/edit/disabled.svg'
|
||||
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
|
||||
import { zircon } from 'src/styling/variables'
|
||||
|
||||
import Wizard from './Wizard'
|
||||
import WizardSplash from './WizardSplash'
|
||||
import {
|
||||
CRYPTOCURRENCY_KEY,
|
||||
TICKER_KEY,
|
||||
WALLET_KEY,
|
||||
EXCHANGE_KEY,
|
||||
ZERO_CONF_KEY,
|
||||
EDIT_KEY,
|
||||
ENABLE_KEY,
|
||||
SIZE_KEY,
|
||||
TEXT_ALIGN_KEY
|
||||
} from './aux.js'
|
||||
|
||||
const styles = {
|
||||
disabledDrawing: {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
'& > div': {
|
||||
position: 'absolute',
|
||||
backgroundColor: zircon,
|
||||
height: 36,
|
||||
width: 678
|
||||
}
|
||||
},
|
||||
modal: {
|
||||
width: 544
|
||||
},
|
||||
switchErrorMessage: {
|
||||
margin: [['auto', 0, 'auto', 20]]
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const columns = {
|
||||
[CRYPTOCURRENCY_KEY]: {
|
||||
[SIZE_KEY]: 182,
|
||||
[TEXT_ALIGN_KEY]: 'left'
|
||||
},
|
||||
[TICKER_KEY]: {
|
||||
[SIZE_KEY]: 182,
|
||||
[TEXT_ALIGN_KEY]: 'left'
|
||||
},
|
||||
[WALLET_KEY]: {
|
||||
[SIZE_KEY]: 182,
|
||||
[TEXT_ALIGN_KEY]: 'left'
|
||||
},
|
||||
[EXCHANGE_KEY]: {
|
||||
[SIZE_KEY]: 182,
|
||||
[TEXT_ALIGN_KEY]: 'left'
|
||||
},
|
||||
[ZERO_CONF_KEY]: {
|
||||
[SIZE_KEY]: 229,
|
||||
[TEXT_ALIGN_KEY]: 'left'
|
||||
},
|
||||
[EDIT_KEY]: {
|
||||
[SIZE_KEY]: 134,
|
||||
[TEXT_ALIGN_KEY]: 'center'
|
||||
},
|
||||
[ENABLE_KEY]: {
|
||||
[SIZE_KEY]: 109,
|
||||
[TEXT_ALIGN_KEY]: 'center'
|
||||
}
|
||||
}
|
||||
|
||||
const GET_INFO = gql`
|
||||
{
|
||||
config
|
||||
accounts {
|
||||
code
|
||||
display
|
||||
class
|
||||
cryptos
|
||||
}
|
||||
cryptoCurrencies {
|
||||
code
|
||||
display
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const SAVE_CONFIG = gql`
|
||||
mutation Save($config: JSONObject) {
|
||||
saveConfig(config: $config)
|
||||
}
|
||||
`
|
||||
|
||||
const schema = {
|
||||
[TICKER_KEY]: '',
|
||||
[WALLET_KEY]: '',
|
||||
[EXCHANGE_KEY]: '',
|
||||
[ZERO_CONF_KEY]: '',
|
||||
[ENABLE_KEY]: false
|
||||
}
|
||||
|
||||
const WalletSettings = () => {
|
||||
const [cryptoCurrencies, setCryptoCurrencies] = useState(null)
|
||||
const [accounts, setAccounts] = useState(null)
|
||||
const [services, setServices] = useState(null)
|
||||
const [state, setState] = useState(null)
|
||||
const [modalContent, setModalContent] = useState(null)
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
const [error, setError] = useState(null)
|
||||
const [saveConfig] = useMutation(SAVE_CONFIG, {
|
||||
onCompleted: data => {
|
||||
setServices(data.saveConfig.accounts)
|
||||
setError(null)
|
||||
}
|
||||
})
|
||||
|
||||
useQuery(GET_INFO, {
|
||||
onCompleted: data => {
|
||||
const { cryptoCurrencies, config, accounts } = data
|
||||
|
||||
const wallet = config?.wallet ?? []
|
||||
const services = config?.accounts ?? {}
|
||||
|
||||
const newState = R.map(crypto => {
|
||||
const el = R.find(R.propEq(CRYPTOCURRENCY_KEY, crypto.code))(wallet)
|
||||
if (!el) return R.assoc(CRYPTOCURRENCY_KEY, crypto.code)(schema)
|
||||
return el
|
||||
})(cryptoCurrencies)
|
||||
|
||||
setState(newState)
|
||||
setCryptoCurrencies(cryptoCurrencies)
|
||||
setAccounts(accounts)
|
||||
setServices(services)
|
||||
},
|
||||
onError: error => console.error(error)
|
||||
})
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
const getSize = key => columns[key][SIZE_KEY]
|
||||
const getTextAlign = key => columns[key][TEXT_ALIGN_KEY]
|
||||
|
||||
const getDisplayName = list => code =>
|
||||
R.path(['display'], R.find(R.propEq('code', code), list))
|
||||
|
||||
const getCryptoDisplayName = row =>
|
||||
getDisplayName(cryptoCurrencies)(row[CRYPTOCURRENCY_KEY])
|
||||
|
||||
const getNoSetUpNeeded = accounts => {
|
||||
const needs = [
|
||||
'bitgo',
|
||||
'bitstamp',
|
||||
'blockcypher',
|
||||
'infura',
|
||||
'kraken',
|
||||
'strike'
|
||||
]
|
||||
return R.filter(account => !R.includes(account.code, needs), accounts)
|
||||
}
|
||||
const getAlreadySetUp = serviceClass => cryptocode => {
|
||||
const possible = R.filter(
|
||||
service => R.includes(cryptocode, service.cryptos),
|
||||
R.filter(R.propEq('class', serviceClass), accounts)
|
||||
)
|
||||
const isSetUp = service => R.includes(service.code, R.keys(services))
|
||||
const alreadySetUp = R.filter(isSetUp, possible)
|
||||
const join = [...alreadySetUp, ...getNoSetUpNeeded(possible)]
|
||||
return R.isEmpty(join) ? null : join
|
||||
}
|
||||
const getNotSetUp = serviceClass => cryptocode => {
|
||||
const possible = R.filter(
|
||||
service => R.includes(cryptocode, service.cryptos),
|
||||
R.filter(R.propEq('class', serviceClass), accounts)
|
||||
)
|
||||
const without = R.without(
|
||||
getAlreadySetUp(serviceClass)(cryptocode) ?? [],
|
||||
possible
|
||||
)
|
||||
return R.isEmpty(without) ? null : without
|
||||
}
|
||||
|
||||
const saveNewService = (code, it) => {
|
||||
const newAccounts = R.clone(services)
|
||||
newAccounts[code] = it
|
||||
return saveConfig({ variables: { config: { accounts: newAccounts } } })
|
||||
}
|
||||
const save = it => {
|
||||
const idx = R.findIndex(
|
||||
R.propEq(CRYPTOCURRENCY_KEY, it[CRYPTOCURRENCY_KEY]),
|
||||
state
|
||||
)
|
||||
const merged = R.mergeDeepRight(state[idx], it)
|
||||
const updated = R.update(idx, merged, state)
|
||||
return saveConfig({
|
||||
variables: { config: { wallet: updated } }
|
||||
})
|
||||
}
|
||||
|
||||
const isSet = crypto =>
|
||||
crypto[TICKER_KEY] &&
|
||||
crypto[WALLET_KEY] &&
|
||||
crypto[EXCHANGE_KEY] &&
|
||||
crypto[ZERO_CONF_KEY]
|
||||
|
||||
const handleEnable = row => event => {
|
||||
if (!isSet(row)) {
|
||||
setModalContent(
|
||||
<WizardSplash
|
||||
code={row[CRYPTOCURRENCY_KEY]}
|
||||
coinName={getCryptoDisplayName(row)}
|
||||
handleModalNavigation={handleModalNavigation(row)}
|
||||
/>
|
||||
)
|
||||
setModalOpen(true)
|
||||
setError(null)
|
||||
return
|
||||
}
|
||||
|
||||
save(R.assoc(ENABLE_KEY, event.target.checked, row)).catch(error =>
|
||||
setError(error)
|
||||
)
|
||||
}
|
||||
|
||||
const handleEditClick = row => {
|
||||
setModalOpen(true)
|
||||
handleModalNavigation(row)(1)
|
||||
}
|
||||
|
||||
const handleModalClose = () => {
|
||||
setModalOpen(false)
|
||||
setModalContent(null)
|
||||
}
|
||||
const handleModalNavigation = row => currentPage => {
|
||||
const cryptocode = row[CRYPTOCURRENCY_KEY]
|
||||
|
||||
switch (currentPage) {
|
||||
case 1:
|
||||
setModalContent(
|
||||
<Wizard
|
||||
crypto={row}
|
||||
coinName={getCryptoDisplayName(row)}
|
||||
handleModalNavigation={handleModalNavigation}
|
||||
pageName={TICKER_KEY}
|
||||
currentStage={1}
|
||||
alreadySetUp={R.filter(
|
||||
ticker => R.includes(cryptocode, ticker.cryptos),
|
||||
R.filter(R.propEq('class', 'ticker'), accounts)
|
||||
)}
|
||||
/>
|
||||
)
|
||||
break
|
||||
case 2:
|
||||
setModalContent(
|
||||
<Wizard
|
||||
crypto={row}
|
||||
coinName={getCryptoDisplayName(row)}
|
||||
handleModalNavigation={handleModalNavigation}
|
||||
pageName={WALLET_KEY}
|
||||
currentStage={2}
|
||||
alreadySetUp={getAlreadySetUp(WALLET_KEY)(cryptocode)}
|
||||
notSetUp={getNotSetUp(WALLET_KEY)(cryptocode)}
|
||||
saveNewService={saveNewService}
|
||||
/>
|
||||
)
|
||||
break
|
||||
case 3:
|
||||
setModalContent(
|
||||
<Wizard
|
||||
crypto={row}
|
||||
coinName={getCryptoDisplayName(row)}
|
||||
handleModalNavigation={handleModalNavigation}
|
||||
pageName={EXCHANGE_KEY}
|
||||
currentStage={3}
|
||||
alreadySetUp={getAlreadySetUp(EXCHANGE_KEY)(cryptocode)}
|
||||
notSetUp={getNotSetUp(EXCHANGE_KEY)(cryptocode)}
|
||||
saveNewService={saveNewService}
|
||||
/>
|
||||
)
|
||||
break
|
||||
case 4:
|
||||
setModalContent(
|
||||
<Wizard
|
||||
crypto={row}
|
||||
coinName={getCryptoDisplayName(row)}
|
||||
handleModalNavigation={handleModalNavigation}
|
||||
pageName={ZERO_CONF_KEY}
|
||||
currentStage={4}
|
||||
alreadySetUp={getAlreadySetUp(ZERO_CONF_KEY)(cryptocode)}
|
||||
notSetUp={getNotSetUp(ZERO_CONF_KEY)(cryptocode)}
|
||||
saveNewService={saveNewService}
|
||||
/>
|
||||
)
|
||||
break
|
||||
case 5:
|
||||
// Zero Conf
|
||||
return save(R.assoc(ENABLE_KEY, true, row)).then(m => {
|
||||
setModalOpen(false)
|
||||
setModalContent(null)
|
||||
})
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return new Promise(() => {})
|
||||
}
|
||||
|
||||
if (!state) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.titleWrapper}>
|
||||
<div className={classes.titleAndButtonsContainer}>
|
||||
<Title>Wallet Settings</Title>
|
||||
{error && !modalOpen && (
|
||||
<ErrorMessage className={classes.switchErrorMessage}>
|
||||
Failed to save
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.wrapper}>
|
||||
<Table>
|
||||
<THead>
|
||||
<Th
|
||||
size={getSize(CRYPTOCURRENCY_KEY)}
|
||||
textAlign={getTextAlign(CRYPTOCURRENCY_KEY)}>
|
||||
Cryptocurrency
|
||||
</Th>
|
||||
<Th size={getSize(TICKER_KEY)} textAlign={getTextAlign(TICKER_KEY)}>
|
||||
Ticker
|
||||
</Th>
|
||||
<Th size={getSize(WALLET_KEY)} textAlign={getTextAlign(WALLET_KEY)}>
|
||||
Wallet
|
||||
</Th>
|
||||
<Th
|
||||
size={getSize(EXCHANGE_KEY)}
|
||||
textAlign={getTextAlign(EXCHANGE_KEY)}>
|
||||
Exchange
|
||||
</Th>
|
||||
<Th
|
||||
size={getSize(ZERO_CONF_KEY)}
|
||||
textAlign={getTextAlign(ZERO_CONF_KEY)}>
|
||||
Zero Conf
|
||||
</Th>
|
||||
<Th size={getSize(EDIT_KEY)} textAlign={getTextAlign(EDIT_KEY)}>
|
||||
Edit
|
||||
</Th>
|
||||
<Th size={getSize(ENABLE_KEY)} textAlign={getTextAlign(ENABLE_KEY)}>
|
||||
Enable
|
||||
</Th>
|
||||
</THead>
|
||||
<TBody>
|
||||
{state.map((row, idx) => (
|
||||
<Tr key={idx}>
|
||||
<Td
|
||||
size={getSize(CRYPTOCURRENCY_KEY)}
|
||||
textAlign={getTextAlign(CRYPTOCURRENCY_KEY)}>
|
||||
{getCryptoDisplayName(row)}
|
||||
</Td>
|
||||
{!isSet(row) && (
|
||||
<Td
|
||||
size={
|
||||
getSize(TICKER_KEY) +
|
||||
getSize(WALLET_KEY) +
|
||||
getSize(EXCHANGE_KEY) +
|
||||
getSize(ZERO_CONF_KEY)
|
||||
}
|
||||
textAlign="center"
|
||||
className={classes.disabledDrawing}>
|
||||
<div />
|
||||
</Td>
|
||||
)}
|
||||
{isSet(row) && (
|
||||
<>
|
||||
<Td
|
||||
size={getSize(TICKER_KEY)}
|
||||
textAlign={getTextAlign(TICKER_KEY)}>
|
||||
{getDisplayName(accounts)(row[TICKER_KEY])}
|
||||
</Td>
|
||||
<Td
|
||||
size={getSize(WALLET_KEY)}
|
||||
textAlign={getTextAlign(WALLET_KEY)}>
|
||||
{getDisplayName(accounts)(row[WALLET_KEY])}
|
||||
</Td>
|
||||
<Td
|
||||
size={getSize(EXCHANGE_KEY)}
|
||||
textAlign={getTextAlign(EXCHANGE_KEY)}>
|
||||
{getDisplayName(accounts)(row[EXCHANGE_KEY])}
|
||||
</Td>
|
||||
<Td
|
||||
size={getSize(ZERO_CONF_KEY)}
|
||||
textAlign={getTextAlign(ZERO_CONF_KEY)}>
|
||||
{getDisplayName(accounts)(row[ZERO_CONF_KEY])}
|
||||
</Td>
|
||||
</>
|
||||
)}
|
||||
<Td size={getSize(EDIT_KEY)} textAlign={getTextAlign(EDIT_KEY)}>
|
||||
{!isSet(row) && <DisabledEditIcon />}
|
||||
{isSet(row) && (
|
||||
<button
|
||||
className={classes.iconButton}
|
||||
onClick={() => handleEditClick(row)}>
|
||||
<EditIcon />
|
||||
</button>
|
||||
)}
|
||||
</Td>
|
||||
<Td
|
||||
size={getSize(ENABLE_KEY)}
|
||||
textAlign={getTextAlign(ENABLE_KEY)}>
|
||||
<Switch
|
||||
checked={row[ENABLE_KEY]}
|
||||
onChange={handleEnable(row)}
|
||||
value={row[CRYPTOCURRENCY_KEY]}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</TBody>
|
||||
</Table>
|
||||
</div>
|
||||
<Modal
|
||||
aria-labelledby="simple-modal-title"
|
||||
aria-describedby="simple-modal-description"
|
||||
open={modalOpen}
|
||||
handleClose={handleModalClose}
|
||||
className={classes.modal}>
|
||||
{modalContent}
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default WalletSettings
|
||||
307
new-lamassu-admin/src/pages/Wallet/Wizard.js
Normal file
307
new-lamassu-admin/src/pages/Wallet/Wizard.js
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import { Formik, Field as FormikField } from 'formik'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
import ErrorMessage from 'src/components/ErrorMessage'
|
||||
import Stage from 'src/components/Stage'
|
||||
import { Button } from 'src/components/buttons'
|
||||
import { RadioGroup, AutocompleteSelect } from 'src/components/inputs'
|
||||
import { H1, Info2, H4 } from 'src/components/typography'
|
||||
import { startCase } from 'src/utils/string'
|
||||
|
||||
import { getBitgoFields, getBitgoFormik } from '../Services/Bitgo'
|
||||
import { getBitstampFields, getBitstampFormik } from '../Services/Bitstamp'
|
||||
import {
|
||||
getBlockcypherFields,
|
||||
getBlockcypherFormik
|
||||
} from '../Services/Blockcypher'
|
||||
import { getInfuraFields, getInfuraFormik } from '../Services/Infura'
|
||||
import { getKrakenFields, getKrakenFormik } from '../Services/Kraken'
|
||||
import { getStrikeFields, getStrikeFormik } from '../Services/Strike'
|
||||
|
||||
const styles = {
|
||||
modalContent: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: [[24, 32, 0]],
|
||||
'& > h1': {
|
||||
margin: [[0, 0, 10]]
|
||||
},
|
||||
'& > h4': {
|
||||
margin: [[32, 0, 32 - 9, 0]]
|
||||
},
|
||||
'& > p': {
|
||||
margin: 0
|
||||
}
|
||||
},
|
||||
submitButtonWrapper: {
|
||||
display: 'flex',
|
||||
alignSelf: 'flex-end',
|
||||
margin: [['auto', 0, 0]]
|
||||
},
|
||||
submitButton: {
|
||||
width: 67,
|
||||
padding: [[0, 0]],
|
||||
margin: [['auto', 0, 24, 20]],
|
||||
'&:active': {
|
||||
margin: [['auto', 0, 24, 20]]
|
||||
}
|
||||
},
|
||||
stages: {
|
||||
marginTop: 10
|
||||
},
|
||||
radios: {
|
||||
display: 'flex'
|
||||
},
|
||||
radiosAsColumn: {
|
||||
flexDirection: 'column'
|
||||
},
|
||||
radiosAsRow: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
alreadySetupRadioButtons: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
selectNewWrapper: {
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
},
|
||||
selectNew: {
|
||||
width: 204,
|
||||
flexGrow: 0,
|
||||
bottom: 7
|
||||
},
|
||||
newServiceForm: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
},
|
||||
newServiceFormFields: {
|
||||
marginTop: 20,
|
||||
marginBottom: 48
|
||||
},
|
||||
field: {
|
||||
'&:not(:last-child)': {
|
||||
marginBottom: 20
|
||||
}
|
||||
},
|
||||
formInput: {
|
||||
'& .MuiInputBase-input': {
|
||||
width: 426
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getNewServiceForm = serviceName => {
|
||||
switch (serviceName) {
|
||||
case 'bitgo':
|
||||
return { fields: getBitgoFields(), formik: getBitgoFormik() }
|
||||
case 'bitstamp':
|
||||
return { fields: getBitstampFields(), formik: getBitstampFormik() }
|
||||
case 'blockcypher':
|
||||
return { fields: getBlockcypherFields(), formik: getBlockcypherFormik() }
|
||||
case 'infura':
|
||||
return { fields: getInfuraFields(), formik: getInfuraFormik() }
|
||||
case 'kraken':
|
||||
return { fields: getKrakenFields(), formik: getKrakenFormik() }
|
||||
case 'strike':
|
||||
return { fields: getStrikeFields(), formik: getStrikeFormik() }
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const SubmitButton = ({ error, ...props }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<div className={classes.submitButtonWrapper}>
|
||||
{error && <ErrorMessage>Failed to save</ErrorMessage>}
|
||||
<Button {...props}>Next</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Wizard = ({
|
||||
crypto,
|
||||
coinName,
|
||||
pageName,
|
||||
currentStage,
|
||||
alreadySetUp,
|
||||
notSetUp,
|
||||
handleModalNavigation,
|
||||
saveNewService
|
||||
}) => {
|
||||
const [selectedRadio, setSelectedRadio] = useState(
|
||||
crypto[pageName] !== '' ? crypto[pageName] : null
|
||||
)
|
||||
useEffect(() => {
|
||||
setFormContent(null)
|
||||
setSelectedFromDropdown(null)
|
||||
setSetUpNew('')
|
||||
setSelectedRadio(crypto[pageName] !== '' ? crypto[pageName] : null)
|
||||
}, [crypto, pageName])
|
||||
const [setUpNew, setSetUpNew] = useState(null)
|
||||
const [selectedFromDropdown, setSelectedFromDropdown] = useState(null)
|
||||
const [formContent, setFormContent] = useState(null)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
const radiosClassNames = {
|
||||
[classes.radios]: true,
|
||||
[classes.radiosAsColumn]: !selectedFromDropdown,
|
||||
[classes.radiosAsRow]: selectedFromDropdown
|
||||
}
|
||||
|
||||
const radioButtonOptions =
|
||||
alreadySetUp &&
|
||||
R.map(el => {
|
||||
return { label: el.display, value: el.code }
|
||||
})(alreadySetUp)
|
||||
|
||||
const handleRadioButtons = event => {
|
||||
R.o(setSelectedRadio, R.path(['target', 'value']))(event)
|
||||
setSetUpNew('')
|
||||
setFormContent(null)
|
||||
setSelectedFromDropdown(null)
|
||||
setError(null)
|
||||
}
|
||||
|
||||
const handleSetUpNew = event => {
|
||||
R.o(setSetUpNew, R.path(['target', 'value']))(event)
|
||||
setSelectedRadio('')
|
||||
setFormContent(null)
|
||||
setSelectedFromDropdown(null)
|
||||
setError(null)
|
||||
}
|
||||
|
||||
const handleNext = value => event => {
|
||||
const nav = handleModalNavigation(
|
||||
R.mergeDeepRight(crypto, { [pageName]: value })
|
||||
)(currentStage + 1)
|
||||
|
||||
nav.catch(error => setError(error))
|
||||
}
|
||||
|
||||
const handleSelectFromDropdown = it => {
|
||||
setSelectedFromDropdown(it)
|
||||
setFormContent(getNewServiceForm(it?.code))
|
||||
setError(null)
|
||||
}
|
||||
|
||||
const isSubmittable = () => {
|
||||
if (selectedRadio) return true
|
||||
if (!selectedRadio && selectedFromDropdown && !formContent) return true
|
||||
return false
|
||||
}
|
||||
|
||||
console.log(formContent)
|
||||
|
||||
return (
|
||||
<div className={classes.modalContent}>
|
||||
<H1>Enable {coinName}</H1>
|
||||
<Info2>{startCase(pageName)}</Info2>
|
||||
<Stage
|
||||
stages={4}
|
||||
currentStage={currentStage}
|
||||
color="spring"
|
||||
className={classes.stages}
|
||||
/>
|
||||
<H4>{`Select a ${pageName} or set up a new one`}</H4>
|
||||
<div className={classnames(radiosClassNames)}>
|
||||
{alreadySetUp && (
|
||||
<RadioGroup
|
||||
name="already-setup-select"
|
||||
value={selectedRadio || radioButtonOptions[0]}
|
||||
options={radioButtonOptions}
|
||||
ariaLabel="already-setup-select"
|
||||
onChange={handleRadioButtons}
|
||||
className={classes.alreadySetupRadioButtons}
|
||||
/>
|
||||
)}
|
||||
{notSetUp && (
|
||||
<div className={classes.selectNewWrapper}>
|
||||
<RadioGroup
|
||||
name="setup-new-select"
|
||||
value={setUpNew || ''}
|
||||
options={[{ label: 'Set up new', value: 'new' }]}
|
||||
ariaLabel="setup-new-select"
|
||||
onChange={handleSetUpNew}
|
||||
className={classes.alreadySetupRadioButtons}
|
||||
/>
|
||||
{setUpNew && (
|
||||
<AutocompleteSelect
|
||||
id="chooseNew"
|
||||
name="chooseNew"
|
||||
label={`Select ${pageName}`}
|
||||
suggestions={notSetUp}
|
||||
value={selectedFromDropdown}
|
||||
handleChange={handleSelectFromDropdown}
|
||||
className={classes.selectNew}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{formContent && (
|
||||
<Formik
|
||||
initialValues={formContent.formik.initialValues}
|
||||
validationSchema={formContent.formik.validationSchema}
|
||||
onSubmit={values =>
|
||||
saveNewService(selectedFromDropdown.code, values)
|
||||
.then(m => {
|
||||
handleNext(selectedFromDropdown.code)()
|
||||
})
|
||||
.catch(error => setError(error))
|
||||
}>
|
||||
{props => (
|
||||
<form
|
||||
onReset={props.handleReset}
|
||||
onSubmit={props.handleSubmit}
|
||||
className={classes.newServiceForm}
|
||||
{...props}>
|
||||
<div className={classes.newServiceFormFields}>
|
||||
{formContent.fields.map((field, idx) => (
|
||||
<div key={idx} className={classes.field}>
|
||||
<FormikField
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
component={field.component}
|
||||
placeholder={field.placeholder}
|
||||
type={field.type}
|
||||
label={field.label}
|
||||
className={classes.formInput}
|
||||
onFocus={() => {
|
||||
setError(null)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<SubmitButton
|
||||
disabled={R.isEmpty(props.touched) || !props.isValid}
|
||||
className={classes.submitButton}
|
||||
type="submit"
|
||||
error={error}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
</Formik>
|
||||
)}
|
||||
{!formContent && (
|
||||
<SubmitButton
|
||||
className={classes.submitButton}
|
||||
disabled={!isSubmittable()}
|
||||
onClick={handleNext(selectedRadio || selectedFromDropdown?.code)}
|
||||
error={error}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Wizard
|
||||
85
new-lamassu-admin/src/pages/Wallet/WizardSplash.js
Normal file
85
new-lamassu-admin/src/pages/Wallet/WizardSplash.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
import React from 'react'
|
||||
|
||||
import { Button } from 'src/components/buttons'
|
||||
import { H1, P } from 'src/components/typography'
|
||||
import { ReactComponent as BitcoinLogo } from 'src/styling/logos/icon-bitcoin-colour.svg'
|
||||
import { ReactComponent as BitcoinCashLogo } from 'src/styling/logos/icon-bitcoincash-colour.svg'
|
||||
import { ReactComponent as DashLogo } from 'src/styling/logos/icon-dash-colour.svg'
|
||||
import { ReactComponent as EthereumLogo } from 'src/styling/logos/icon-ethereum-colour.svg'
|
||||
import { ReactComponent as LitecoinLogo } from 'src/styling/logos/icon-litecoin-colour.svg'
|
||||
import { ReactComponent as ZCashLogo } from 'src/styling/logos/icon-zcash-colour.svg'
|
||||
|
||||
const styles = {
|
||||
logoWrapper: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 80,
|
||||
margin: [[40, 0, 24]],
|
||||
'& > svg': {
|
||||
maxHeight: '100%',
|
||||
width: '100%'
|
||||
}
|
||||
},
|
||||
modalContent: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: [[0, 66]],
|
||||
'& > h1': {
|
||||
margin: [[0, 0, 32]]
|
||||
},
|
||||
'& > p': {
|
||||
margin: 0
|
||||
},
|
||||
'& > button': {
|
||||
margin: [['auto', 0, 56]],
|
||||
'&:active': {
|
||||
margin: [['auto', 0, 56]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const renderLogo = code => {
|
||||
switch (code) {
|
||||
case 'BTC':
|
||||
return <BitcoinLogo />
|
||||
case 'BCH':
|
||||
return <BitcoinCashLogo />
|
||||
case 'DASH':
|
||||
return <DashLogo />
|
||||
case 'ETH':
|
||||
return <EthereumLogo />
|
||||
case 'LTC':
|
||||
return <LitecoinLogo />
|
||||
case 'ZEC':
|
||||
return <ZCashLogo />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const WizardSplash = ({ code, coinName, handleModalNavigation }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<div className={classes.modalContent}>
|
||||
<div className={classes.logoWrapper}>{renderLogo(code)}</div>
|
||||
<H1>Enable {coinName}</H1>
|
||||
<P>
|
||||
You are about to enable {coinName} on your system. This will allow you
|
||||
to use this cryptocurrency on your machines. To able to do that, you’ll
|
||||
have to setup all the necessary 3rd party services.
|
||||
</P>
|
||||
<Button onClick={() => handleModalNavigation(1)}>
|
||||
Start configuration
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default WizardSplash
|
||||
21
new-lamassu-admin/src/pages/Wallet/aux.js
Normal file
21
new-lamassu-admin/src/pages/Wallet/aux.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const CRYPTOCURRENCY_KEY = 'cryptocurrency'
|
||||
const TICKER_KEY = 'ticker'
|
||||
const WALLET_KEY = 'wallet'
|
||||
const EXCHANGE_KEY = 'exchange'
|
||||
const ZERO_CONF_KEY = 'zeroConf'
|
||||
const EDIT_KEY = 'edit'
|
||||
const ENABLE_KEY = 'enabled'
|
||||
const SIZE_KEY = 'size'
|
||||
const TEXT_ALIGN_KEY = 'textAlign'
|
||||
|
||||
export {
|
||||
CRYPTOCURRENCY_KEY,
|
||||
TICKER_KEY,
|
||||
WALLET_KEY,
|
||||
EXCHANGE_KEY,
|
||||
ZERO_CONF_KEY,
|
||||
EDIT_KEY,
|
||||
ENABLE_KEY,
|
||||
SIZE_KEY,
|
||||
TEXT_ALIGN_KEY
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import OperatorInfo from 'src/pages/OperatorInfo/OperatorInfo'
|
|||
import ServerLogs from 'src/pages/ServerLogs'
|
||||
import Services from 'src/pages/Services/Services'
|
||||
import Transactions from 'src/pages/Transactions/Transactions'
|
||||
import WalletSettings from 'src/pages/Wallet/WalletSettings'
|
||||
import MachineStatus from 'src/pages/maintenance/MachineStatus'
|
||||
|
||||
const tree = [
|
||||
|
|
@ -93,6 +94,12 @@ const tree = [
|
|||
label: 'Operator Info',
|
||||
route: '/settings/operator-info',
|
||||
component: OperatorInfo
|
||||
},
|
||||
{
|
||||
key: 'wallet',
|
||||
label: 'Wallet',
|
||||
route: '/settings/wallet',
|
||||
component: WalletSettings
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="104" height="64" version="1.1">
|
||||
<circle fill="#F7931A" cx="52" cy="32" r="32"/>
|
||||
<path fill="#FFF" d="m66.103,27.444c0.637-4.258-2.605-6.547-7.038-8.074l1.438-5.768-3.511-0.875-1.4,5.616c-0.923-0.23-1.871-0.447-2.813-0.662l1.41-5.653-3.509-0.875-1.439,5.766c-0.764-0.174-1.514-0.346-2.242-0.527l0.004-0.018-4.842-1.209-0.934,3.75s2.605,0.597,2.55,0.634c1.422,0.355,1.679,1.296,1.636,2.042l-1.638,6.571c0.098,0.025,0.225,0.061,0.365,0.117-0.117-0.029-0.242-0.061-0.371-0.092l-2.296,9.205c-0.174,0.432-0.615,1.08-1.609,0.834,0.035,0.051-2.552-0.637-2.552-0.637l-1.743,4.019,4.569,1.139c0.85,0.213,1.683,0.436,2.503,0.646l-1.453,5.834,3.507,0.875,1.439-5.772c0.958,0.26,1.888,0.5,2.798,0.726l-1.434,5.745,3.511,0.875,1.453-5.823c5.987,1.133,10.489,0.676,12.384-4.739,1.527-4.36-0.076-6.875-3.226-8.515,2.294-0.529,4.022-2.038,4.483-5.155zm-8.022,11.249c-1.085,4.36-8.426,2.003-10.806,1.412l1.928-7.729c2.38,0.594,10.012,1.77,8.878,6.317zm1.086-11.312c-0.99,3.966-7.1,1.951-9.082,1.457l1.748-7.01c1.982,0.494,8.365,1.416,7.334,5.553z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="104" height="64" version="1.1">
|
||||
<path fill="#F7931A" d="m0,0l29.7,0a39,39,0,0,0,0,64l-29.7,0zm52,0a32,32,0,0,0,0,64a32,32,0,0,0,0,-64m52,0l-29.7,0a39,39,0,0,1,0,64l29.7,0z"/>
|
||||
<path fill="#FFF" transform="rotate(-28 52 32)" d="m66.103,27.444c0.637-4.258-2.605-6.547-7.038-8.074l1.438-5.768-3.511-0.875-1.4,5.616c-0.923-0.23-1.871-0.447-2.813-0.662l1.41-5.653-3.509-0.875-1.439,5.766c-0.764-0.174-1.514-0.346-2.242-0.527l0.004-0.018-4.842-1.209-0.934,3.75s2.605,0.597,2.55,0.634c1.422,0.355,1.679,1.296,1.636,2.042l-1.638,6.571c0.098,0.025,0.225,0.061,0.365,0.117-0.117-0.029-0.242-0.061-0.371-0.092l-2.296,9.205c-0.174,0.432-0.615,1.08-1.609,0.834,0.035,0.051-2.552-0.637-2.552-0.637l-1.743,4.019,4.569,1.139c0.85,0.213,1.683,0.436,2.503,0.646l-1.453,5.834,3.507,0.875,1.439-5.772c0.958,0.26,1.888,0.5,2.798,0.726l-1.434,5.745,3.511,0.875,1.453-5.823c5.987,1.133,10.489,0.676,12.384-4.739,1.527-4.36-0.076-6.875-3.226-8.515,2.294-0.529,4.022-2.038,4.483-5.155zm-8.022,11.249c-1.085,4.36-8.426,2.003-10.806,1.412l1.928-7.729c2.38,0.594,10.012,1.77,8.878,6.317zm1.086-11.312c-0.99,3.966-7.1,1.951-9.082,1.457l1.748-7.01c1.982,0.494,8.365,1.416,7.334,5.553z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
new-lamassu-admin/src/styling/logos/icon-dash-colour.svg
Normal file
1
new-lamassu-admin/src/styling/logos/icon-dash-colour.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000" width="2500" height="2500"><circle cx="1000" cy="1000" r="1000" fill="#2573c2"/><g fill="#fff"><path d="M1652.6 736.8a143.65 143.65 0 0 0-19.2-63.6c-10-20-27.8-35.6-48.6-43.6a143.51 143.51 0 0 0-68.4-15H628.8l-63.6 190.6h804.2l-127 389.6h-804l-63.6 190.6h891.8a246.33 246.33 0 0 0 77.8-15c25-14.2 53.6-28.6 77.8-48.6a382.69 382.69 0 0 0 63.6-63.6 432.2 432.2 0 0 0 39.2-73.4l117.8-370.4a137.38 137.38 0 0 0 9.8-77.6z"/><path d="M882.2 911.6H409l-63.6 176.2h478z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 538 B |
11
new-lamassu-admin/src/styling/logos/icon-ethereum-colour.svg
Normal file
11
new-lamassu-admin/src/styling/logos/icon-ethereum-colour.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="417px" viewBox="0 0 256 417" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<polygon fill="#343434" points="127.9611 0 125.1661 9.5 125.1661 285.168 127.9611 287.958 255.9231 212.32"></polygon>
|
||||
<polygon fill="#8C8C8C" points="127.962 0 0 212.32 127.962 287.959 127.962 154.158"></polygon>
|
||||
<polygon fill="#3C3C3B" points="127.9611 312.1866 126.3861 314.1066 126.3861 412.3056 127.9611 416.9066 255.9991 236.5866"></polygon>
|
||||
<polygon fill="#8C8C8C" points="127.962 416.9052 127.962 312.1852 0 236.5852"></polygon>
|
||||
<polygon fill="#141414" points="127.9611 287.9577 255.9211 212.3207 127.9611 154.1587"></polygon>
|
||||
<polygon fill="#393939" points="0.0009 212.3208 127.9609 287.9578 127.9609 154.1588"></polygon>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 895 B |
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="104" height="64" version="1.1">
|
||||
<circle fill="#989898" cx="52" cy="32" r="32"/>
|
||||
<path fill="#FFF" d="m46.92598,12.31703l-4.97801,18.8088l-3.42705,1.32711l-1.64691,6.17189l3.42705,-1.29514l-2.8461,10.76083l30.60893,0l2.09993,-7.98401l-18.42505,0l2.09993,-7.82412l3.3631,-1.26316l1.6469,-6.17188l-3.36309,1.29513l3.6509,-13.83611l-12.21053,0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
15
new-lamassu-admin/src/styling/logos/icon-zcash-colour.svg
Normal file
15
new-lamassu-admin/src/styling/logos/icon-zcash-colour.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 493.3 490.2" style="enable-background:new 0 0 493.3 490.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#231F20;}
|
||||
.st1{fill:#F4B728;}
|
||||
</style>
|
||||
<title>headerArtboard 7</title>
|
||||
<path class="st0" d="M245.4,20C121.1,20,20,121.1,20,245.4s101.1,225.4,225.4,225.4s225.4-101.1,225.4-225.4S369.7,20,245.4,20z
|
||||
M245.4,433.6c-103.8,0-188.2-84.4-188.2-188.2S141.6,57.2,245.4,57.2s188.2,84.4,188.2,188.2S349.2,433.6,245.4,433.6z"/>
|
||||
<circle class="st1" cx="245.4" cy="245.4" r="177.6"/>
|
||||
<polygon class="st0" points="165,315.5 165,349.9 226.5,349.9 226.5,387.6 264.3,387.6 264.3,349.9 325.8,349.9 325.8,304.4
|
||||
230.4,304.4 325.8,175 325.8,140.6 264.3,140.6 264.3,103 226.5,103 226.5,140.6 165,140.6 165,186.2 260.4,186.2 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1,007 B |
Loading…
Add table
Add a link
Reference in a new issue