fix: get triggers up to spec
This commit is contained in:
parent
b07c0e180a
commit
0b28e7f98a
22 changed files with 347 additions and 95 deletions
|
|
@ -9,13 +9,14 @@ import React, { useEffect, useState, memo } from 'react'
|
||||||
|
|
||||||
import { Button, IconButton } from 'src/components/buttons'
|
import { Button, IconButton } from 'src/components/buttons'
|
||||||
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||||
|
import { fontSize3 } from 'src/styling/variables'
|
||||||
|
|
||||||
import { TextInput } from './inputs'
|
import { TextInput } from './inputs'
|
||||||
import { H4, P } from './typography'
|
import { H4, P } from './typography'
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
label: {
|
label: {
|
||||||
fontSize: 16
|
fontSize: fontSize3
|
||||||
},
|
},
|
||||||
spacing: {
|
spacing: {
|
||||||
padding: 32
|
padding: 32
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,25 @@ const styles = {
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
outline: 0
|
outline: 0
|
||||||
}),
|
}),
|
||||||
|
infoPanelWrapper: ({ width, infoPanelHeight }) => ({
|
||||||
|
width,
|
||||||
|
height: infoPanelHeight,
|
||||||
|
marginTop: 16,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
minHeight: infoPanelHeight ?? 200,
|
||||||
|
maxHeight: '90vh',
|
||||||
|
overflowY: 'auto',
|
||||||
|
borderRadius: 8,
|
||||||
|
outline: 0
|
||||||
|
}),
|
||||||
|
panelContent: {
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flex: 1,
|
||||||
|
padding: [[0, 24]]
|
||||||
|
},
|
||||||
content: ({ small }) => ({
|
content: ({ small }) => ({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -48,17 +67,24 @@ const useStyles = makeStyles(styles)
|
||||||
const Modal = ({
|
const Modal = ({
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
infoPanelHeight,
|
||||||
title,
|
title,
|
||||||
small,
|
small,
|
||||||
infoPanel,
|
infoPanel,
|
||||||
handleClose,
|
handleClose,
|
||||||
children,
|
children,
|
||||||
|
secondaryModal,
|
||||||
className,
|
className,
|
||||||
closeOnEscape,
|
closeOnEscape,
|
||||||
closeOnBackdropClick,
|
closeOnBackdropClick,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles({ width, height, small })
|
const classes = useStyles({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
small,
|
||||||
|
infoPanelHeight
|
||||||
|
})
|
||||||
const TitleCase = small ? H4 : H1
|
const TitleCase = small ? H4 : H1
|
||||||
const closeSize = small ? 16 : 20
|
const closeSize = small ? 16 : 20
|
||||||
|
|
||||||
|
|
@ -84,8 +110,8 @@ const Modal = ({
|
||||||
<div className={classes.content}>{children}</div>
|
<div className={classes.content}>{children}</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
{infoPanel && (
|
{infoPanel && (
|
||||||
<Paper className={classnames(classes.wrapper, className)}>
|
<Paper className={classnames(classes.infoPanelWrapper, className)}>
|
||||||
{infoPanel}
|
<div className={classes.panelContent}>{infoPanel}</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { makeStyles } from '@material-ui/core'
|
import { makeStyles } from '@material-ui/core'
|
||||||
|
import classnames from 'classnames'
|
||||||
import { Field, useFormikContext } from 'formik'
|
import { Field, useFormikContext } from 'formik'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
|
|
@ -158,7 +159,7 @@ const groupStriped = elements => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ERow = ({ editing, disabled }) => {
|
const ERow = ({ editing, disabled, lastOfGroup }) => {
|
||||||
const { errors } = useFormikContext()
|
const { errors } = useFormikContext()
|
||||||
const {
|
const {
|
||||||
elements,
|
elements,
|
||||||
|
|
@ -169,6 +170,8 @@ const ERow = ({ editing, disabled }) => {
|
||||||
stripeWhen
|
stripeWhen
|
||||||
} = useContext(TableCtx)
|
} = useContext(TableCtx)
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
const { values } = useFormikContext()
|
const { values } = useFormikContext()
|
||||||
const shouldStripe = stripeWhen && stripeWhen(values) && !editing
|
const shouldStripe = stripeWhen && stripeWhen(values) && !editing
|
||||||
|
|
||||||
|
|
@ -187,8 +190,13 @@ const ERow = ({ editing, disabled }) => {
|
||||||
it => it.editable === undefined || it.editable
|
it => it.editable === undefined || it.editable
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const classNames = {
|
||||||
|
[classes.lastOfGroup]: lastOfGroup
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr
|
<Tr
|
||||||
|
className={classnames(classNames)}
|
||||||
size={rowSize}
|
size={rowSize}
|
||||||
error={errors && errors.length}
|
error={errors && errors.length}
|
||||||
errorMessage={errors && errors.toString()}>
|
errorMessage={errors && errors.toString()}>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ export default {
|
||||||
cancelButton: {
|
cancelButton: {
|
||||||
marginRight: 20
|
marginRight: 20
|
||||||
},
|
},
|
||||||
|
lastOfGroup: {
|
||||||
|
marginBottom: 24
|
||||||
|
},
|
||||||
extraPaddingLeft: {
|
extraPaddingLeft: {
|
||||||
paddingLeft: 35
|
paddingLeft: 35
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ const ETable = ({
|
||||||
setEditing,
|
setEditing,
|
||||||
stripeWhen,
|
stripeWhen,
|
||||||
disableRowEdit,
|
disableRowEdit,
|
||||||
|
groupBy,
|
||||||
|
sortBy,
|
||||||
createText = 'Add override'
|
createText = 'Add override'
|
||||||
}) => {
|
}) => {
|
||||||
const [editingId, setEditingId] = useState(null)
|
const [editingId, setEditingId] = useState(null)
|
||||||
|
|
@ -102,6 +104,8 @@ const ETable = ({
|
||||||
const canAdd = !forceDisable && !editingId && !disableAdd && !adding
|
const canAdd = !forceDisable && !editingId && !disableAdd && !adding
|
||||||
const showTable = adding || data.length !== 0
|
const showTable = adding || data.length !== 0
|
||||||
|
|
||||||
|
const innerData = sortBy ? R.sortWith(sortBy)(data) : data
|
||||||
|
|
||||||
const ctxValue = {
|
const ctxValue = {
|
||||||
elements,
|
elements,
|
||||||
enableEdit,
|
enableEdit,
|
||||||
|
|
@ -159,24 +163,33 @@ const ETable = ({
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
{data.map((it, idx) => (
|
{innerData.map((it, idx) => {
|
||||||
<Formik
|
const nextElement = innerData[idx + 1]
|
||||||
key={it.id ?? idx}
|
const isLastOfGroup =
|
||||||
enableReinitialize
|
groupBy &&
|
||||||
initialValues={it}
|
nextElement &&
|
||||||
onReset={onReset}
|
nextElement[groupBy] !== it[groupBy]
|
||||||
validationSchema={validationSchema}
|
|
||||||
onSubmit={innerSave}>
|
return (
|
||||||
<Form>
|
<Formik
|
||||||
<ERow
|
key={it.id ?? idx}
|
||||||
editing={editingId === it.id}
|
enableReinitialize
|
||||||
disabled={
|
initialValues={it}
|
||||||
forceDisable || (editingId && editingId !== it.id)
|
onReset={onReset}
|
||||||
}
|
validationSchema={validationSchema}
|
||||||
/>
|
onSubmit={innerSave}>
|
||||||
</Form>
|
<Form>
|
||||||
</Formik>
|
<ERow
|
||||||
))}
|
lastOfGroup={isLastOfGroup}
|
||||||
|
editing={editingId === it.id}
|
||||||
|
disabled={
|
||||||
|
forceDisable || (editingId && editingId !== it.id)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</TBody>
|
</TBody>
|
||||||
</Table>
|
</Table>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import CheckBoxIcon from '@material-ui/icons/CheckBox'
|
||||||
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'
|
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { secondaryColor } from '../../../styling/variables'
|
import { fontSize2, fontSize3, secondaryColor } from 'src/styling/variables'
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
root: {
|
root: {
|
||||||
|
|
@ -30,9 +30,11 @@ const CheckboxInput = ({ name, onChange, value, label, ...props }) => {
|
||||||
value={value}
|
value={value}
|
||||||
checked={value}
|
checked={value}
|
||||||
icon={
|
icon={
|
||||||
<CheckBoxOutlineBlankIcon style={{ marginLeft: 2, fontSize: 16 }} />
|
<CheckBoxOutlineBlankIcon
|
||||||
|
style={{ marginLeft: 2, fontSize: fontSize3 }}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
checkedIcon={<CheckBoxIcon style={{ fontSize: 20 }} />}
|
checkedIcon={<CheckBoxIcon style={{ fontSize: fontSize2 }} />}
|
||||||
disableRipple
|
disableRipple
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { secondaryColor } from 'src/styling/variables'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
size: ({ size }) => ({
|
size: ({ size }) => ({
|
||||||
marginTop: size === 'lg' ? -2 : 0,
|
marginTop: size === 'lg' ? 0 : 2,
|
||||||
...bySize(size)
|
...bySize(size)
|
||||||
}),
|
}),
|
||||||
bold,
|
bold,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const Row = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.rowWrapper}>
|
<div className={classes.rowWrapper}>
|
||||||
<div className={classnames({ [classes.before]: expanded })}>
|
<div className={classnames({ [classes.before]: expanded && id !== 0 })}>
|
||||||
<Tr
|
<Tr
|
||||||
className={classnames(trClasses)}
|
className={classnames(trClasses)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export default {
|
||||||
padding: 1
|
padding: 1
|
||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
|
border: [[2, 'solid', 'transparent']],
|
||||||
borderRadius: 0
|
borderRadius: 0
|
||||||
},
|
},
|
||||||
expanded: {
|
expanded: {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,21 @@ function H4({ children, noMargin, className, ...props }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function H5({ children, noMargin, className, ...props }) {
|
||||||
|
const classes = useStyles()
|
||||||
|
const classNames = {
|
||||||
|
[classes.h5]: true,
|
||||||
|
[classes.noMargin]: noMargin,
|
||||||
|
[className]: !!className
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<h5 className={classnames(classNames)} {...props}>
|
||||||
|
{children}
|
||||||
|
</h5>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const P = pBuilder('p')
|
const P = pBuilder('p')
|
||||||
const Info1 = pBuilder('info1')
|
const Info1 = pBuilder('info1')
|
||||||
const Info2 = pBuilder('info2')
|
const Info2 = pBuilder('info2')
|
||||||
|
|
@ -99,6 +114,7 @@ export {
|
||||||
H2,
|
H2,
|
||||||
H3,
|
H3,
|
||||||
H4,
|
H4,
|
||||||
|
H5,
|
||||||
TL1,
|
TL1,
|
||||||
TL2,
|
TL2,
|
||||||
P,
|
P,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from 'src/styling/variables'
|
} from 'src/styling/variables'
|
||||||
|
|
||||||
const base = {
|
const base = {
|
||||||
lineHeight: '110%',
|
lineHeight: '120%',
|
||||||
color: fontColor
|
color: fontColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,6 +40,12 @@ export default {
|
||||||
fontFamily: fontPrimary,
|
fontFamily: fontPrimary,
|
||||||
fontWeight: 700
|
fontWeight: 700
|
||||||
},
|
},
|
||||||
|
h5: {
|
||||||
|
extend: base,
|
||||||
|
fontSize: fontSize3,
|
||||||
|
fontFamily: fontPrimary,
|
||||||
|
fontWeight: 700
|
||||||
|
},
|
||||||
p: {
|
p: {
|
||||||
extend: base,
|
extend: base,
|
||||||
fontSize: fontSize4,
|
fontSize: fontSize4,
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ const getOverridesFields = (getData, currency) => {
|
||||||
{
|
{
|
||||||
name: 'fixedFee',
|
name: 'fixedFee',
|
||||||
display: 'Fixed fee',
|
display: 'Fixed fee',
|
||||||
width: 140,
|
width: 144,
|
||||||
input: NumberInput,
|
input: NumberInput,
|
||||||
doubleHeader: 'Cash-in only',
|
doubleHeader: 'Cash-in only',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
|
|
@ -87,7 +87,7 @@ const getOverridesFields = (getData, currency) => {
|
||||||
{
|
{
|
||||||
name: 'minimumTx',
|
name: 'minimumTx',
|
||||||
display: 'Minimun Tx',
|
display: 'Minimun Tx',
|
||||||
width: 140,
|
width: 144,
|
||||||
input: NumberInput,
|
input: NumberInput,
|
||||||
doubleHeader: 'Cash-in only',
|
doubleHeader: 'Cash-in only',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import typographyStyles from 'src/components/typography/styles'
|
import typographyStyles from 'src/components/typography/styles'
|
||||||
import baseStyles from 'src/pages/Logs.styles'
|
import baseStyles from 'src/pages/Logs.styles'
|
||||||
import { zircon, primaryColor } from 'src/styling/variables'
|
import { zircon, primaryColor, fontSize4 } from 'src/styling/variables'
|
||||||
|
|
||||||
const { label1 } = typographyStyles
|
const { label1 } = typographyStyles
|
||||||
const { titleWrapper, titleAndButtonsContainer } = baseStyles
|
const { titleWrapper, titleAndButtonsContainer } = baseStyles
|
||||||
|
|
@ -30,7 +30,7 @@ export default {
|
||||||
},
|
},
|
||||||
p: {
|
p: {
|
||||||
fontFamily: 'MuseoSans',
|
fontFamily: 'MuseoSans',
|
||||||
fontSize: 14,
|
fontSize: fontSize4,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontStretch: 'normal',
|
fontStretch: 'normal',
|
||||||
fontStyle: 'normal',
|
fontStyle: 'normal',
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ import {
|
||||||
tomato,
|
tomato,
|
||||||
spring3,
|
spring3,
|
||||||
spring4,
|
spring4,
|
||||||
comet
|
comet,
|
||||||
|
fontSize5
|
||||||
} from 'src/styling/variables'
|
} from 'src/styling/variables'
|
||||||
|
|
||||||
const propertyCardStyles = {
|
const propertyCardStyles = {
|
||||||
|
|
@ -25,7 +26,7 @@ const propertyCardStyles = {
|
||||||
},
|
},
|
||||||
label1: {
|
label1: {
|
||||||
fontFamily: 'MuseoSans',
|
fontFamily: 'MuseoSans',
|
||||||
fontSize: 12,
|
fontSize: fontSize5,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontStretch: 'normal',
|
fontStretch: 'normal',
|
||||||
fontStyle: 'normal',
|
fontStyle: 'normal',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { fontSize5 } from 'src/styling/variables'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
titleWrapper: {
|
titleWrapper: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -41,7 +43,7 @@ export default {
|
||||||
margin: 8,
|
margin: 8,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
fontSize: 12,
|
fontSize: fontSize5,
|
||||||
padding: [[0, 12]]
|
padding: [[0, 12]]
|
||||||
},
|
},
|
||||||
shareIcon: {
|
shareIcon: {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { fade } from '@material-ui/core/styles/colorManipulator'
|
import { fade } from '@material-ui/core/styles/colorManipulator'
|
||||||
|
|
||||||
import { offColor, comet } from 'src/styling/variables'
|
import { fontSize4, offColor, comet } from 'src/styling/variables'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
wrapper: {
|
wrapper: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
marginBottom: 32,
|
marginBottom: 32,
|
||||||
fontSize: 14
|
fontSize: fontSize4
|
||||||
},
|
},
|
||||||
column1: {
|
column1: {
|
||||||
width: 600
|
width: 600
|
||||||
|
|
|
||||||
|
|
@ -118,17 +118,17 @@ const Transactions = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Date (UTC)',
|
header: 'Date (UTC)',
|
||||||
view: it => moment.utc(it.created).format('YYYY-MM-D'),
|
view: it => moment.utc(it.created).format('YYYY-MM-DD'),
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 124
|
width: 144
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Time (UTC)',
|
header: 'Time (UTC)',
|
||||||
view: it => moment.utc(it.created).format('HH:mm:ss'),
|
view: it => moment.utc(it.created).format('HH:mm:ss'),
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 124
|
width: 144
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@ import { v4 } from 'uuid'
|
||||||
import Title from 'src/components/Title'
|
import Title from 'src/components/Title'
|
||||||
import { Link } from 'src/components/buttons'
|
import { Link } from 'src/components/buttons'
|
||||||
import { Table as EditableTable } from 'src/components/editableTable'
|
import { Table as EditableTable } from 'src/components/editableTable'
|
||||||
|
import { fromNamespace, namespaces } from 'src/utils/config'
|
||||||
|
|
||||||
import { mainStyles } from './Triggers.styles'
|
import { mainStyles } from './Triggers.styles'
|
||||||
import Wizard from './Wizard'
|
import Wizard from './Wizard'
|
||||||
import { Schema, elements } from './helper'
|
import { Schema, elements, sortBy } from './helper'
|
||||||
|
|
||||||
const useStyles = makeStyles(mainStyles)
|
const useStyles = makeStyles(mainStyles)
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ const GET_INFO = gql`
|
||||||
`
|
`
|
||||||
|
|
||||||
const Triggers = () => {
|
const Triggers = () => {
|
||||||
|
const classes = useStyles()
|
||||||
const [wizard, setWizard] = useState(false)
|
const [wizard, setWizard] = useState(false)
|
||||||
const [error, setError] = useState(false)
|
const [error, setError] = useState(false)
|
||||||
|
|
||||||
|
|
@ -51,7 +53,9 @@ const Triggers = () => {
|
||||||
return saveConfig({ variables: { config } })
|
return saveConfig({ variables: { config } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = useStyles()
|
const currency = R.path(['fiatCurrency'])(
|
||||||
|
fromNamespace(namespaces.LOCALE)(data?.config)
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -69,13 +73,20 @@ const Triggers = () => {
|
||||||
data={triggers}
|
data={triggers}
|
||||||
name="triggers"
|
name="triggers"
|
||||||
enableEdit
|
enableEdit
|
||||||
|
sortBy={sortBy}
|
||||||
|
groupBy="triggerType"
|
||||||
enableDelete
|
enableDelete
|
||||||
save={save}
|
save={save}
|
||||||
validationSchema={Schema}
|
validationSchema={Schema}
|
||||||
elements={elements}
|
elements={elements}
|
||||||
/>
|
/>
|
||||||
{wizard && (
|
{wizard && (
|
||||||
<Wizard error={error} save={add} onClose={() => setWizard(null)} />
|
<Wizard
|
||||||
|
currency={currency}
|
||||||
|
error={error}
|
||||||
|
save={add}
|
||||||
|
onClose={() => setWizard(null)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import { makeStyles } from '@material-ui/core'
|
import { makeStyles } from '@material-ui/core'
|
||||||
import { Form, Formik } from 'formik'
|
import { Form, Formik, useFormikContext } from 'formik'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useState, Fragment } from 'react'
|
import React, { useState, Fragment, useEffect } from 'react'
|
||||||
|
|
||||||
import ErrorMessage from 'src/components/ErrorMessage'
|
import ErrorMessage from 'src/components/ErrorMessage'
|
||||||
import Modal from 'src/components/Modal'
|
import Modal from 'src/components/Modal'
|
||||||
import Stepper from 'src/components/Stepper'
|
import Stepper from 'src/components/Stepper'
|
||||||
import { Button } from 'src/components/buttons'
|
import { Button } from 'src/components/buttons'
|
||||||
|
import { H5, Info3 } from 'src/components/typography'
|
||||||
|
import { comet } from 'src/styling/variables'
|
||||||
|
|
||||||
import { direction, type, requirements } from './helper'
|
import { direction, type, requirements } from './helper'
|
||||||
|
|
||||||
|
|
@ -28,6 +30,12 @@ const styles = {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column'
|
flexDirection: 'column'
|
||||||
|
},
|
||||||
|
infoTitle: {
|
||||||
|
margin: [[18, 0, 20, 0]]
|
||||||
|
},
|
||||||
|
infoCurrentText: {
|
||||||
|
color: comet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,9 +54,118 @@ const getStep = step => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wizard = ({ machine, onClose, save, error }) => {
|
const getText = (step, config, currency) => {
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
return `In ${getDirectionText(config)} transactions`
|
||||||
|
case 2:
|
||||||
|
return `if the user ${getTypeText(config, currency)}`
|
||||||
|
case 3:
|
||||||
|
return `the user will be ${getRequirementText(config)}.`
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const orUnderline = value => {
|
||||||
|
return R.isEmpty(value) || R.isNil(value) ? '⎼⎼⎼⎼⎼ ' : value
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDirectionText = config => {
|
||||||
|
switch (config.cashDirection) {
|
||||||
|
case 'both':
|
||||||
|
return 'both cash-in and cash-out'
|
||||||
|
case 'cashIn':
|
||||||
|
return 'cash-in'
|
||||||
|
case 'cashOut':
|
||||||
|
return 'cash-out'
|
||||||
|
default:
|
||||||
|
return orUnderline(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypeText = (config, currency) => {
|
||||||
|
switch (config.triggerType) {
|
||||||
|
case 'txAmount':
|
||||||
|
return `makes a single transaction over ${orUnderline(
|
||||||
|
config.threshold
|
||||||
|
)} ${currency}`
|
||||||
|
case 'txVolume':
|
||||||
|
return `makes transactions over ${orUnderline(
|
||||||
|
config.threshold
|
||||||
|
)} ${currency} in ${orUnderline(config.days)} days`
|
||||||
|
case 'txVelocity':
|
||||||
|
return `makes ${orUnderline(
|
||||||
|
config.threshold
|
||||||
|
)} transactions in ${orUnderline(config.days)} days`
|
||||||
|
case 'consecutiveDays':
|
||||||
|
return `at least one transaction every day for ${orUnderline(
|
||||||
|
config.days
|
||||||
|
)} days`
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRequirementText = config => {
|
||||||
|
switch (config.requirement) {
|
||||||
|
case 'sms':
|
||||||
|
return 'asked to enter code provided through SMS verification'
|
||||||
|
case 'idPhoto':
|
||||||
|
return 'asked to scan a ID with photo'
|
||||||
|
case 'idData':
|
||||||
|
return 'asked to scan a ID'
|
||||||
|
case 'facephoto':
|
||||||
|
return 'asked to have a photo taken'
|
||||||
|
case 'sanctions':
|
||||||
|
return 'matched against the OFAC sanctions list'
|
||||||
|
case 'superuser':
|
||||||
|
return ''
|
||||||
|
case 'suspend':
|
||||||
|
return 'suspended'
|
||||||
|
case 'block':
|
||||||
|
return 'blocked'
|
||||||
|
default:
|
||||||
|
return orUnderline(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfoPanel = ({ step, config = {}, liveValues = {}, currency }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const oldText = R.range(1, step)
|
||||||
|
.map(it => getText(it, config, currency))
|
||||||
|
.join(', ')
|
||||||
|
const newText = getText(step, liveValues, currency)
|
||||||
|
const isLastStep = step === LAST_STEP
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<H5 className={classes.infoTitle}>Trigger overview so far</H5>
|
||||||
|
<Info3 noMargin>
|
||||||
|
{oldText}
|
||||||
|
{step !== 1 && ', '}
|
||||||
|
<span className={classes.infoCurrentText}>{newText}</span>
|
||||||
|
{!isLastStep && '...'}
|
||||||
|
</Info3>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetValues = ({ setValues }) => {
|
||||||
|
const { values } = useFormikContext()
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('triggered')
|
||||||
|
setValues && values && setValues(values)
|
||||||
|
}, [setValues, values])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wizard = ({ onClose, save, error, currency }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const [liveValues, setLiveValues] = useState({})
|
||||||
const [{ step, config }, setState] = useState({
|
const [{ step, config }, setState] = useState({
|
||||||
step: 1
|
step: 1
|
||||||
})
|
})
|
||||||
|
|
@ -70,33 +187,45 @@ const Wizard = ({ machine, onClose, save, error }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<>
|
||||||
title="New compliance trigger"
|
<Modal
|
||||||
handleClose={onClose}
|
title="New compliance trigger"
|
||||||
width={520}
|
handleClose={onClose}
|
||||||
height={480}
|
width={520}
|
||||||
open={true}>
|
height={480}
|
||||||
<Stepper
|
infoPanel={
|
||||||
className={classes.stepper}
|
<InfoPanel
|
||||||
steps={LAST_STEP}
|
currency={currency}
|
||||||
currentStep={step}
|
step={step}
|
||||||
/>
|
config={config}
|
||||||
<Formik
|
liveValues={liveValues}
|
||||||
enableReinitialize
|
/>
|
||||||
onSubmit={onContinue}
|
}
|
||||||
initialValues={stepOptions.initialValues}
|
infoPanelHeight={172}
|
||||||
validationSchema={stepOptions.schema}>
|
open={true}>
|
||||||
<Form className={classes.form}>
|
<Stepper
|
||||||
<stepOptions.Component />
|
className={classes.stepper}
|
||||||
<div className={classes.submit}>
|
steps={LAST_STEP}
|
||||||
{error && <ErrorMessage>Failed to save</ErrorMessage>}
|
currentStep={step}
|
||||||
<Button className={classes.button} type="submit">
|
/>
|
||||||
{isLastStep ? 'Finish' : 'Next'}
|
<Formik
|
||||||
</Button>
|
enableReinitialize
|
||||||
</div>
|
onSubmit={onContinue}
|
||||||
</Form>
|
initialValues={stepOptions.initialValues}
|
||||||
</Formik>
|
validationSchema={stepOptions.schema}>
|
||||||
</Modal>
|
<Form onChange={console.log} className={classes.form}>
|
||||||
|
<GetValues setValues={setLiveValues} />
|
||||||
|
<stepOptions.Component />
|
||||||
|
<div className={classes.submit}>
|
||||||
|
{error && <ErrorMessage>Failed to save</ErrorMessage>}
|
||||||
|
<Button className={classes.button} type="submit">
|
||||||
|
{isLastStep ? 'Finish' : 'Next'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import * as Yup from 'yup'
|
||||||
import { TextInput, RadioGroup } from 'src/components/inputs/formik'
|
import { TextInput, RadioGroup } from 'src/components/inputs/formik'
|
||||||
import Autocomplete from 'src/components/inputs/formik/Autocomplete'
|
import Autocomplete from 'src/components/inputs/formik/Autocomplete'
|
||||||
import { H4 } from 'src/components/typography'
|
import { H4 } from 'src/components/typography'
|
||||||
|
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||||
|
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||||
import { errorColor } from 'src/styling/variables'
|
import { errorColor } from 'src/styling/variables'
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
|
|
@ -32,6 +34,12 @@ const useStyles = makeStyles({
|
||||||
specialGrid: {
|
specialGrid: {
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
gridTemplateColumns: [[182, 162, 141]]
|
gridTemplateColumns: [[182, 162, 141]]
|
||||||
|
},
|
||||||
|
directionIcon: {
|
||||||
|
marginRight: 2
|
||||||
|
},
|
||||||
|
directionName: {
|
||||||
|
marginLeft: 6
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -98,8 +106,8 @@ const typeSchema = Yup.object().shape({
|
||||||
|
|
||||||
const typeOptions = [
|
const typeOptions = [
|
||||||
{ display: 'Transaction amount', code: 'txAmount' },
|
{ display: 'Transaction amount', code: 'txAmount' },
|
||||||
{ display: 'Transaction velocity', code: 'txVelocity' },
|
|
||||||
{ display: 'Transaction volume', code: 'txVolume' },
|
{ display: 'Transaction volume', code: 'txVolume' },
|
||||||
|
{ display: 'Transaction velocity', code: 'txVelocity' },
|
||||||
{ display: 'Consecutive days', code: 'consecutiveDays' }
|
{ display: 'Consecutive days', code: 'consecutiveDays' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -131,9 +139,6 @@ const Type = () => {
|
||||||
size="lg"
|
size="lg"
|
||||||
name="threshold"
|
name="threshold"
|
||||||
options={typeOptions}
|
options={typeOptions}
|
||||||
labelClassName={classes.radioLabel}
|
|
||||||
radioClassName={classes.radio}
|
|
||||||
className={classes.radioGroup}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
@ -199,12 +204,29 @@ const getView = (data, code, compare) => it => {
|
||||||
return R.compose(R.prop(code), R.find(R.propEq(compare ?? 'code', it)))(data)
|
return R.compose(R.prop(code), R.find(R.propEq(compare ?? 'code', it)))(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DirectionDisplay = ({ code }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
const displayName = getView(directionOptions, 'display')(code)
|
||||||
|
const showCashIn = code === 'cashIn' || code === 'both'
|
||||||
|
const showCashOut = code === 'cashOut' || code === 'both'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{showCashOut && <TxOutIcon className={classes.directionIcon} />}
|
||||||
|
{showCashIn && <TxInIcon className={classes.directionIcon} />}
|
||||||
|
<span className={classes.directionName}>{displayName}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
{
|
{
|
||||||
name: 'triggerType',
|
name: 'triggerType',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 271,
|
width: 230,
|
||||||
input: Autocomplete,
|
input: ({ field: { value: name } }) => (
|
||||||
|
<>{getView(typeOptions, 'display')(name)}</>
|
||||||
|
),
|
||||||
view: getView(typeOptions, 'display'),
|
view: getView(typeOptions, 'display'),
|
||||||
inputProps: {
|
inputProps: {
|
||||||
options: typeOptions,
|
options: typeOptions,
|
||||||
|
|
@ -216,8 +238,10 @@ const elements = [
|
||||||
{
|
{
|
||||||
name: 'requirement',
|
name: 'requirement',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 271,
|
width: 230,
|
||||||
input: Autocomplete,
|
input: ({ field: { value: name } }) => (
|
||||||
|
<>{getView(requirementOptions, 'display')(name)}</>
|
||||||
|
),
|
||||||
view: getView(requirementOptions, 'display'),
|
view: getView(requirementOptions, 'display'),
|
||||||
inputProps: {
|
inputProps: {
|
||||||
options: requirementOptions,
|
options: requirementOptions,
|
||||||
|
|
@ -229,14 +253,15 @@ const elements = [
|
||||||
{
|
{
|
||||||
name: 'threshold',
|
name: 'threshold',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 271,
|
width: 260,
|
||||||
|
textAlign: 'right',
|
||||||
input: TextInput
|
input: TextInput
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'cashDirection',
|
name: 'cashDirection',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
width: 200,
|
width: 282,
|
||||||
view: getView(directionOptions, 'display'),
|
view: it => <DirectionDisplay code={it} />,
|
||||||
input: Autocomplete,
|
input: Autocomplete,
|
||||||
inputProps: {
|
inputProps: {
|
||||||
options: directionOptions,
|
options: directionOptions,
|
||||||
|
|
@ -247,4 +272,12 @@ const elements = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export { Schema, elements, direction, type, requirements }
|
const triggerOrder = R.map(R.prop('code'))(typeOptions)
|
||||||
|
const sortBy = [
|
||||||
|
R.comparator(
|
||||||
|
(a, b) =>
|
||||||
|
triggerOrder.indexOf(a.triggerType) < triggerOrder.indexOf(b.triggerType)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
export { Schema, elements, direction, type, requirements, sortBy }
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,11 @@ const fontPrimary = 'Mont'
|
||||||
const fontSecondary = 'MuseoSans'
|
const fontSecondary = 'MuseoSans'
|
||||||
const fontMonospaced = 'BPmono'
|
const fontMonospaced = 'BPmono'
|
||||||
|
|
||||||
let fontSize1 = 24
|
let fontSize1 = 25
|
||||||
let fontSize2 = 20
|
let fontSize2 = 21
|
||||||
let fontSize3 = 16
|
let fontSize3 = 17
|
||||||
let fontSize4 = 14
|
let fontSize4 = 15
|
||||||
let fontSize5 = 12
|
let fontSize5 = 13
|
||||||
|
|
||||||
if (version === 8) {
|
if (version === 8) {
|
||||||
fontSize1 = 32
|
fontSize1 = 32
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ Overall:
|
||||||
- validation is bad rn, negatives being allowed
|
- validation is bad rn, negatives being allowed
|
||||||
- locale based mil separators 1.000 1,000
|
- locale based mil separators 1.000 1,000
|
||||||
- Table should be loaded on slow internet (we want to load the table with no data)
|
- Table should be loaded on slow internet (we want to load the table with no data)
|
||||||
- font sizes could be better
|
|
||||||
- tooltip like components should close on esc
|
- tooltip like components should close on esc
|
||||||
- saving should be a one time thing. disable buttons so user doesnt spam it
|
- saving should be a one time thing. disable buttons so user doesnt spam it
|
||||||
- disable edit on non-everrides => overrides
|
- disable edit on non-everrides => overrides
|
||||||
|
|
@ -21,9 +20,6 @@ Locale:
|
||||||
Notifications:
|
Notifications:
|
||||||
- one of the crypto balance alerts has to be optional because of migration
|
- one of the crypto balance alerts has to be optional because of migration
|
||||||
|
|
||||||
Machine status:
|
|
||||||
- font-size of the 'write to confirm'
|
|
||||||
|
|
||||||
Server:
|
Server:
|
||||||
- Takes too long to load. Investigate
|
- Takes too long to load. Investigate
|
||||||
|
|
||||||
|
|
@ -47,3 +43,7 @@ Compliance:
|
||||||
Ideas
|
Ideas
|
||||||
- Transactions could have a link to the customer
|
- Transactions could have a link to the customer
|
||||||
- Transactions table on customer should have a link to "transactions"
|
- Transactions table on customer should have a link to "transactions"
|
||||||
|
|
||||||
|
|
||||||
|
Feedback needed
|
||||||
|
- font sizes could be better (I've bumped all font sizes by 1px, looks pretty good as fonts do a good vertical bump in size. Maybe some of the fonts don't like even values)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue