chore: prettier config

husky needs to be delegated to v11 since it breaks with node 14 + 22
combo
This commit is contained in:
Rafael 2024-12-03 09:33:06 +00:00
parent dbca0c8a8c
commit d3c3de66fe
65 changed files with 1542 additions and 22553 deletions

View file

@ -0,0 +1,8 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"arrowParens": "avoid",
"bracketSameLine": true
}

View file

@ -2,6 +2,7 @@ import globals from 'globals'
import pluginJs from '@eslint/js'
import pluginReact from 'eslint-plugin-react'
import reactCompiler from 'eslint-plugin-react-compiler'
import eslintConfigPrettier from 'eslint-config-prettier'
/** @type {import('eslint').Linter.Config[]} */
export default [
@ -17,7 +18,7 @@ export default [
settings: {
react: {
version: '16'
},
}
},
plugins: {
'react-compiler': reactCompiler
@ -31,7 +32,8 @@ export default [
'react/prop-types': 'off',
'react/display-name': 'off',
'react/no-unescaped-entities': 'off',
'react-compiler/react-compiler': 'warn',
'react-compiler/react-compiler': 'warn'
}
}
]
},
eslintConfigPrettier
]

File diff suppressed because it is too large Load diff

View file

@ -56,26 +56,19 @@
"@vitejs/plugin-react-swc": "^3.7.2",
"esbuild-plugin-react-virtualized": "^1.0.4",
"eslint": "^9.16.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-compiler": "^19.0.0-beta-df7b47d-20241124",
"globals": "^15.13.0",
"husky": "^3.1.0",
"lint-staged": "^9.5.0",
"react-scripts": "4.0.0",
"lint-staged": "^15.2.10",
"prettier": "3.4.1",
"vite": "^6.0.1",
"vite-plugin-svgr": "^4.3.0"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
"eslint --fix",
"git add"
]
},
"scripts": {
"start": "vite",
"build": "vite build",
"preview": "vite preview",
"fix": "eslint --fix --ext .js,.md,.json src/"
"preview": "vite preview"
},
"browserslist": {
"production": [
@ -88,5 +81,9 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"lint-staged": {
"*.{js,jsx,md,json}": "eslint --cache --fix",
"*.{js,jsx,css,md,json}": "prettier --write"
}
}

View file

@ -115,15 +115,10 @@ const Main = () => {
)}
<main className={classes.wrapper}>
{sidebar && !is404 && wizardTested && (
<Slide
direction="left"
in={true}
mountOnEnter
unmountOnExit
>
<div>
<TitleSection title={parent.title}></TitleSection>
</div>
<Slide direction="left" in={true} mountOnEnter unmountOnExit>
<div>
<TitleSection title={parent.title}></TitleSection>
</div>
</Slide>
)}

View file

@ -1,98 +1,98 @@
import {
Dialog,
DialogActions,
DialogContent,
makeStyles
} from '@material-ui/core'
import React from 'react'
import { H4, P } from 'src/components/typography'
import CloseIcon from 'src/styling/icons/action/close/zodiac.svg?react'
import { Button, IconButton } from 'src/components/buttons'
import { spacer } from 'src/styling/variables'
import ErrorMessage from './ErrorMessage'
const useStyles = makeStyles({
content: {
width: 434,
padding: spacer * 2,
paddingRight: spacer * 3.5
},
titleSection: {
padding: spacer * 2,
paddingRight: spacer * 1.5,
display: 'flex',
justifyContent: 'space-between',
margin: 0
},
actions: {
padding: spacer * 4,
paddingTop: spacer * 2
},
title: {
margin: 0
},
closeButton: {
padding: 0,
marginTop: -(spacer / 2)
}
})
export const DialogTitle = ({ children, close }) => {
const classes = useStyles()
return (
<div className={classes.titleSection}>
{children}
{close && (
<IconButton
size={16}
aria-label="close"
onClick={close}
className={classes.closeButton}>
<CloseIcon />
</IconButton>
)}
</div>
)
}
export const DeleteDialog = ({
title = 'Confirm Delete',
open = false,
onConfirmed,
onDismissed,
item = 'item',
confirmationMessage = `Are you sure you want to delete this ${item}?`,
extraMessage,
errorMessage = ''
}) => {
const classes = useStyles()
return (
<Dialog open={open} aria-labelledby="form-dialog-title">
<DialogTitle close={() => onDismissed()}>
<H4 className={classes.title}>{title}</H4>
</DialogTitle>
{errorMessage && (
<DialogTitle>
<ErrorMessage>
{errorMessage.split(':').map(error => (
<>
{error}
<br />
</>
))}
</ErrorMessage>
</DialogTitle>
)}
<DialogContent className={classes.content}>
{confirmationMessage && <P>{confirmationMessage}</P>}
{extraMessage}
</DialogContent>
<DialogActions className={classes.actions}>
<Button onClick={onConfirmed}>Confirm</Button>
</DialogActions>
</Dialog>
)
}
import {
Dialog,
DialogActions,
DialogContent,
makeStyles
} from '@material-ui/core'
import React from 'react'
import { H4, P } from 'src/components/typography'
import CloseIcon from 'src/styling/icons/action/close/zodiac.svg?react'
import { Button, IconButton } from 'src/components/buttons'
import { spacer } from 'src/styling/variables'
import ErrorMessage from './ErrorMessage'
const useStyles = makeStyles({
content: {
width: 434,
padding: spacer * 2,
paddingRight: spacer * 3.5
},
titleSection: {
padding: spacer * 2,
paddingRight: spacer * 1.5,
display: 'flex',
justifyContent: 'space-between',
margin: 0
},
actions: {
padding: spacer * 4,
paddingTop: spacer * 2
},
title: {
margin: 0
},
closeButton: {
padding: 0,
marginTop: -(spacer / 2)
}
})
export const DialogTitle = ({ children, close }) => {
const classes = useStyles()
return (
<div className={classes.titleSection}>
{children}
{close && (
<IconButton
size={16}
aria-label="close"
onClick={close}
className={classes.closeButton}>
<CloseIcon />
</IconButton>
)}
</div>
)
}
export const DeleteDialog = ({
title = 'Confirm Delete',
open = false,
onConfirmed,
onDismissed,
item = 'item',
confirmationMessage = `Are you sure you want to delete this ${item}?`,
extraMessage,
errorMessage = ''
}) => {
const classes = useStyles()
return (
<Dialog open={open} aria-labelledby="form-dialog-title">
<DialogTitle close={() => onDismissed()}>
<H4 className={classes.title}>{title}</H4>
</DialogTitle>
{errorMessage && (
<DialogTitle>
<ErrorMessage>
{errorMessage.split(':').map(error => (
<>
{error}
<br />
</>
))}
</ErrorMessage>
</DialogTitle>
)}
<DialogContent className={classes.content}>
{confirmationMessage && <P>{confirmationMessage}</P>}
{extraMessage}
</DialogContent>
<DialogActions className={classes.actions}>
<Button onClick={onConfirmed}>Confirm</Button>
</DialogActions>
</Dialog>
)
}

View file

@ -55,8 +55,8 @@ const styles = {
margin: xl
? [[0, 0, 'auto', 'auto']]
: small
? [[12, 12, 'auto', 'auto']]
: [[16, 16, 'auto', 'auto']]
? [[12, 12, 'auto', 'auto']]
: [[16, 16, 'auto', 'auto']]
}),
header: {
display: 'flex'

View file

@ -60,8 +60,8 @@ const NotificationRow = ({
typeDisplay && deviceName
? `${typeDisplay} - ${deviceName}`
: !typeDisplay && deviceName
? `${deviceName}`
: `${typeDisplay}`
? `${deviceName}`
: `${typeDisplay}`
const iconClass = {
[classes.readIcon]: read,

View file

@ -1,299 +1,299 @@
import { makeStyles } from '@material-ui/core'
import classnames from 'classnames'
import { Field, useFormikContext } from 'formik'
import * as R from 'ramda'
import React, { useContext, useState } from 'react'
import { DeleteDialog } from 'src/components/DeleteDialog'
import { Td, Tr } from 'src/components/fake-table/Table'
import { Label2 } from 'src/components/typography'
import DisabledDeleteIcon from 'src/styling/icons/action/delete/disabled.svg?react'
import DeleteIcon from 'src/styling/icons/action/delete/enabled.svg?react'
import DisabledEditIcon from 'src/styling/icons/action/edit/disabled.svg?react'
import EditIcon from 'src/styling/icons/action/edit/enabled.svg?react'
import StripesSvg from 'src/styling/icons/stripes.svg?react'
import { Link, IconButton } from 'src/components/buttons'
import { Switch } from 'src/components/inputs'
import TableCtx from './Context'
import styles from './Row.styles'
const useStyles = makeStyles(styles)
const ActionCol = ({ disabled, editing }) => {
const classes = useStyles()
const { values, submitForm, resetForm } = useFormikContext()
const {
editWidth,
onEdit,
enableEdit,
enableDelete,
disableRowEdit,
onDelete,
deleteWidth,
enableToggle,
onToggle,
toggleWidth,
forceAdd,
clearError,
actionColSize,
error
} = useContext(TableCtx)
const disableEdit = disabled || (disableRowEdit && disableRowEdit(values))
const cancel = () => {
clearError()
resetForm()
}
const [deleteDialog, setDeleteDialog] = useState(false)
const onConfirmed = () => {
onDelete(values.id).then(res => {
if (!R.isNil(res)) setDeleteDialog(false)
})
}
return (
<>
{editing && (
<Td textAlign="center" width={actionColSize}>
<Link
className={classes.saveButton}
type="submit"
color="primary"
onClick={submitForm}>
Save
</Link>
{!forceAdd && (
<Link color="secondary" onClick={cancel}>
Cancel
</Link>
)}
</Td>
)}
{!editing && enableEdit && (
<Td textAlign="center" width={editWidth}>
<IconButton
disabled={disableEdit}
className={classes.editButton}
onClick={() => onEdit && onEdit(values.id)}>
{disableEdit ? <DisabledEditIcon /> : <EditIcon />}
</IconButton>
</Td>
)}
{!editing && enableDelete && (
<Td textAlign="center" width={deleteWidth}>
<IconButton
disabled={disabled}
onClick={() => {
setDeleteDialog(true)
}}>
{disabled ? <DisabledDeleteIcon /> : <DeleteIcon />}
</IconButton>
<DeleteDialog
open={deleteDialog}
setDeleteDialog={setDeleteDialog}
onConfirmed={onConfirmed}
onDismissed={() => {
setDeleteDialog(false)
clearError()
}}
errorMessage={error}
/>
</Td>
)}
{!editing && enableToggle && (
<Td textAlign="center" width={toggleWidth}>
<Switch
checked={!!values.active}
value={!!values.active}
disabled={disabled}
onChange={() => onToggle(values.id)}
/>
</Td>
)}
</>
)
}
const ECol = ({ editing, focus, config, extraPaddingRight, extraPadding }) => {
const {
name,
names,
bypassField,
input,
editable = true,
size,
bold,
width,
textAlign,
editingAlign = textAlign,
prefix,
PrefixComponent = Label2,
suffix,
SuffixComponent = Label2,
textStyle = it => {},
isHidden = it => false,
view = it => it?.toString(),
inputProps = {}
} = config
const fields = names ?? [name]
const { values } = useFormikContext()
const isEditable = editable => {
if (typeof editable === 'function') return editable(values)
return editable
}
const isEditing = editing && isEditable(editable)
const isField = !bypassField
const classes = useStyles({
textAlign: isEditing ? editingAlign : textAlign,
size
})
const innerProps = {
fullWidth: true,
autoFocus: focus,
size,
bold,
textAlign: isEditing ? editingAlign : textAlign,
...inputProps
}
return (
<div className={classes.fields}>
{fields.map((f, idx) => (
<Td
key={idx}
className={{
[classes.extraPaddingRight]: extraPaddingRight,
[classes.extraPadding]: extraPadding,
[classes.withSuffix]: suffix,
[classes.withPrefix]: prefix
}}
width={width}
size={size}
bold={bold}
textAlign={textAlign}>
{prefix && !isHidden(values) && (
<PrefixComponent
className={classes.prefix}
style={isEditing ? {} : textStyle(values, isEditing)}>
{typeof prefix === 'function' ? prefix(f) : prefix}
</PrefixComponent>
)}
{isEditing && isField && !isHidden(values) && (
<Field name={f} component={input} {...innerProps} />
)}
{isEditing && !isField && !isHidden(values) && (
<config.input name={f} />
)}
{!isEditing && values && !isHidden(values) && (
<div style={textStyle(values, isEditing)}>
{view(values[f], values)}
</div>
)}
{suffix && !isHidden(values) && (
<SuffixComponent
className={classes.suffix}
style={isEditing ? {} : textStyle(values, isEditing)}>
{suffix}
</SuffixComponent>
)}
{isHidden(values) && <StripesSvg />}
</Td>
))}
</div>
)
}
const groupStriped = elements => {
const [toStripe, noStripe] = R.partition(R.propEq('stripe', true))(elements)
if (!toStripe.length) {
return elements
}
const index = R.indexOf(toStripe[0], elements)
const width = R.compose(R.sum, R.map(R.path(['width'])))(toStripe)
return R.insert(
index,
{ width, editable: false, view: () => <StripesSvg /> },
noStripe
)
}
const ERow = ({ editing, disabled, lastOfGroup, newRow }) => {
const { touched, errors, values } = useFormikContext()
const {
elements,
enableEdit,
enableDelete,
error,
enableToggle,
rowSize,
stripeWhen
} = useContext(TableCtx)
const classes = useStyles()
const shouldStripe = !editing && stripeWhen && stripeWhen(values)
const innerElements = shouldStripe ? groupStriped(elements) : elements
const [toSHeader] = R.partition(R.has('doubleHeader'))(elements)
const extraPaddingIndex = toSHeader?.length
? R.indexOf(toSHeader[0], elements)
: -1
const extraPaddingRightIndex = toSHeader?.length
? R.indexOf(toSHeader[toSHeader.length - 1], elements)
: -1
const elementToFocusIndex = innerElements.findIndex(
it => it.editable === undefined || it.editable
)
const classNames = {
[classes.lastOfGroup]: lastOfGroup
}
const touchedErrors = R.pick(R.keys(touched), errors)
const hasTouchedErrors = touchedErrors && R.keys(touchedErrors).length > 0
const hasErrors = hasTouchedErrors || !!error
const errorMessage =
error || (touchedErrors && R.values(touchedErrors).join(', '))
return (
<Tr
className={classnames(classNames)}
size={rowSize}
error={editing && hasErrors}
newRow={newRow && !hasErrors}
shouldShowError
errorMessage={errorMessage}>
{innerElements.map((it, idx) => {
return (
<ECol
key={idx}
config={it}
editing={editing}
focus={idx === elementToFocusIndex && editing}
extraPaddingRight={extraPaddingRightIndex === idx}
extraPadding={extraPaddingIndex === idx}
/>
)
})}
{(enableEdit || enableDelete || enableToggle) && (
<ActionCol disabled={disabled} editing={editing} />
)}
</Tr>
)
}
export default ERow
import { makeStyles } from '@material-ui/core'
import classnames from 'classnames'
import { Field, useFormikContext } from 'formik'
import * as R from 'ramda'
import React, { useContext, useState } from 'react'
import { DeleteDialog } from 'src/components/DeleteDialog'
import { Td, Tr } from 'src/components/fake-table/Table'
import { Label2 } from 'src/components/typography'
import DisabledDeleteIcon from 'src/styling/icons/action/delete/disabled.svg?react'
import DeleteIcon from 'src/styling/icons/action/delete/enabled.svg?react'
import DisabledEditIcon from 'src/styling/icons/action/edit/disabled.svg?react'
import EditIcon from 'src/styling/icons/action/edit/enabled.svg?react'
import StripesSvg from 'src/styling/icons/stripes.svg?react'
import { Link, IconButton } from 'src/components/buttons'
import { Switch } from 'src/components/inputs'
import TableCtx from './Context'
import styles from './Row.styles'
const useStyles = makeStyles(styles)
const ActionCol = ({ disabled, editing }) => {
const classes = useStyles()
const { values, submitForm, resetForm } = useFormikContext()
const {
editWidth,
onEdit,
enableEdit,
enableDelete,
disableRowEdit,
onDelete,
deleteWidth,
enableToggle,
onToggle,
toggleWidth,
forceAdd,
clearError,
actionColSize,
error
} = useContext(TableCtx)
const disableEdit = disabled || (disableRowEdit && disableRowEdit(values))
const cancel = () => {
clearError()
resetForm()
}
const [deleteDialog, setDeleteDialog] = useState(false)
const onConfirmed = () => {
onDelete(values.id).then(res => {
if (!R.isNil(res)) setDeleteDialog(false)
})
}
return (
<>
{editing && (
<Td textAlign="center" width={actionColSize}>
<Link
className={classes.saveButton}
type="submit"
color="primary"
onClick={submitForm}>
Save
</Link>
{!forceAdd && (
<Link color="secondary" onClick={cancel}>
Cancel
</Link>
)}
</Td>
)}
{!editing && enableEdit && (
<Td textAlign="center" width={editWidth}>
<IconButton
disabled={disableEdit}
className={classes.editButton}
onClick={() => onEdit && onEdit(values.id)}>
{disableEdit ? <DisabledEditIcon /> : <EditIcon />}
</IconButton>
</Td>
)}
{!editing && enableDelete && (
<Td textAlign="center" width={deleteWidth}>
<IconButton
disabled={disabled}
onClick={() => {
setDeleteDialog(true)
}}>
{disabled ? <DisabledDeleteIcon /> : <DeleteIcon />}
</IconButton>
<DeleteDialog
open={deleteDialog}
setDeleteDialog={setDeleteDialog}
onConfirmed={onConfirmed}
onDismissed={() => {
setDeleteDialog(false)
clearError()
}}
errorMessage={error}
/>
</Td>
)}
{!editing && enableToggle && (
<Td textAlign="center" width={toggleWidth}>
<Switch
checked={!!values.active}
value={!!values.active}
disabled={disabled}
onChange={() => onToggle(values.id)}
/>
</Td>
)}
</>
)
}
const ECol = ({ editing, focus, config, extraPaddingRight, extraPadding }) => {
const {
name,
names,
bypassField,
input,
editable = true,
size,
bold,
width,
textAlign,
editingAlign = textAlign,
prefix,
PrefixComponent = Label2,
suffix,
SuffixComponent = Label2,
textStyle = it => {},
isHidden = it => false,
view = it => it?.toString(),
inputProps = {}
} = config
const fields = names ?? [name]
const { values } = useFormikContext()
const isEditable = editable => {
if (typeof editable === 'function') return editable(values)
return editable
}
const isEditing = editing && isEditable(editable)
const isField = !bypassField
const classes = useStyles({
textAlign: isEditing ? editingAlign : textAlign,
size
})
const innerProps = {
fullWidth: true,
autoFocus: focus,
size,
bold,
textAlign: isEditing ? editingAlign : textAlign,
...inputProps
}
return (
<div className={classes.fields}>
{fields.map((f, idx) => (
<Td
key={idx}
className={{
[classes.extraPaddingRight]: extraPaddingRight,
[classes.extraPadding]: extraPadding,
[classes.withSuffix]: suffix,
[classes.withPrefix]: prefix
}}
width={width}
size={size}
bold={bold}
textAlign={textAlign}>
{prefix && !isHidden(values) && (
<PrefixComponent
className={classes.prefix}
style={isEditing ? {} : textStyle(values, isEditing)}>
{typeof prefix === 'function' ? prefix(f) : prefix}
</PrefixComponent>
)}
{isEditing && isField && !isHidden(values) && (
<Field name={f} component={input} {...innerProps} />
)}
{isEditing && !isField && !isHidden(values) && (
<config.input name={f} />
)}
{!isEditing && values && !isHidden(values) && (
<div style={textStyle(values, isEditing)}>
{view(values[f], values)}
</div>
)}
{suffix && !isHidden(values) && (
<SuffixComponent
className={classes.suffix}
style={isEditing ? {} : textStyle(values, isEditing)}>
{suffix}
</SuffixComponent>
)}
{isHidden(values) && <StripesSvg />}
</Td>
))}
</div>
)
}
const groupStriped = elements => {
const [toStripe, noStripe] = R.partition(R.propEq('stripe', true))(elements)
if (!toStripe.length) {
return elements
}
const index = R.indexOf(toStripe[0], elements)
const width = R.compose(R.sum, R.map(R.path(['width'])))(toStripe)
return R.insert(
index,
{ width, editable: false, view: () => <StripesSvg /> },
noStripe
)
}
const ERow = ({ editing, disabled, lastOfGroup, newRow }) => {
const { touched, errors, values } = useFormikContext()
const {
elements,
enableEdit,
enableDelete,
error,
enableToggle,
rowSize,
stripeWhen
} = useContext(TableCtx)
const classes = useStyles()
const shouldStripe = !editing && stripeWhen && stripeWhen(values)
const innerElements = shouldStripe ? groupStriped(elements) : elements
const [toSHeader] = R.partition(R.has('doubleHeader'))(elements)
const extraPaddingIndex = toSHeader?.length
? R.indexOf(toSHeader[0], elements)
: -1
const extraPaddingRightIndex = toSHeader?.length
? R.indexOf(toSHeader[toSHeader.length - 1], elements)
: -1
const elementToFocusIndex = innerElements.findIndex(
it => it.editable === undefined || it.editable
)
const classNames = {
[classes.lastOfGroup]: lastOfGroup
}
const touchedErrors = R.pick(R.keys(touched), errors)
const hasTouchedErrors = touchedErrors && R.keys(touchedErrors).length > 0
const hasErrors = hasTouchedErrors || !!error
const errorMessage =
error || (touchedErrors && R.values(touchedErrors).join(', '))
return (
<Tr
className={classnames(classNames)}
size={rowSize}
error={editing && hasErrors}
newRow={newRow && !hasErrors}
shouldShowError
errorMessage={errorMessage}>
{innerElements.map((it, idx) => {
return (
<ECol
key={idx}
config={it}
editing={editing}
focus={idx === elementToFocusIndex && editing}
extraPaddingRight={extraPaddingRightIndex === idx}
extraPadding={extraPaddingIndex === idx}
/>
)
})}
{(enableEdit || enableDelete || enableToggle) && (
<ActionCol disabled={disabled} editing={editing} />
)}
</Tr>
)
}
export default ERow

View file

@ -75,7 +75,7 @@ const ETable = ({
setSaving(true)
const it = validationSchema.cast(value, { assert: 'ignore-optionality'})
const it = validationSchema.cast(value, { assert: 'ignore-optionality' })
const index = R.findIndex(R.propEq('id', it.id))(data)
const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data)

View file

@ -6,7 +6,8 @@ import { styles } from './TextInput.styles'
const useStyles = makeStyles(styles)
const mask = /(\+)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,2}){0,1}$/
const mask =
/(\+)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,2}){0,1}$/
const maskValue = value =>
value ? value.replace(mask, '$1 $2 $3 $4 $5 $6') : ''

View file

@ -1,24 +1,24 @@
import React, { memo } from 'react'
import { SecretInput } from '../base'
const SecretInputFormik = memo(({ isPasswordFilled, ...props }) => {
const { name, onChange, onBlur, value } = props.field
const { touched, errors } = props.form
const error = !isPasswordFilled && !!(touched[name] && errors[name])
return (
<SecretInput
name={name}
isPasswordFilled={isPasswordFilled}
onChange={onChange}
onBlur={onBlur}
value={value}
error={error}
{...props}
/>
)
})
export default SecretInputFormik
import React, { memo } from 'react'
import { SecretInput } from '../base'
const SecretInputFormik = memo(({ isPasswordFilled, ...props }) => {
const { name, onChange, onBlur, value } = props.field
const { touched, errors } = props.form
const error = !isPasswordFilled && !!(touched[name] && errors[name])
return (
<SecretInput
name={name}
isPasswordFilled={isPasswordFilled}
onChange={onChange}
onBlur={onBlur}
value={value}
error={error}
{...props}
/>
)
})
export default SecretInputFormik

View file

@ -141,7 +141,9 @@ const Header = memo(({ tree, user }) => {
className={classnames(classes.link, classes.whiteLink)}
activeClassName={classes.activeLink}>
<li className={classes.li}>
<span className={classes.forceSize} data-forcesize={it.label}>
<span
className={classes.forceSize}
data-forcesize={it.label}>
{it.label}
</span>
</li>

View file

@ -26,7 +26,10 @@ const Sidebar = ({
{loading && <P>Loading...</P>}
{!loading &&
data?.map((it, idx) => (
<div key={idx} className={classes.linkWrapper} onClick={() => onClick(it)}>
<div
key={idx}
className={classes.linkWrapper}
onClick={() => onClick(it)}>
<div
key={idx}
className={classnames({

View file

@ -50,7 +50,6 @@ const Graph = ({
const step = R.clone(start)
while (step <= end) {
ticks.push(R.clone(step))
step.setUTCHours(step.getUTCHours() + interval)
@ -105,19 +104,25 @@ const Graph = ({
])
.rangeRound([GRAPH_MARGIN.left, GRAPH_WIDTH - GRAPH_MARGIN.right])
const groupedByDateInterval = R.map(it => {
const lowerBound = R.clone(it)
it.setUTCHours(it.getUTCHours() + 2)
const upperBound = R.clone(it)
return [lowerBound, filterByHourInterval(lowerBound, upperBound)]
}, R.init(getTickIntervals(x.domain(), 2)))
const groupedByDateInterval = R.map(
it => {
const lowerBound = R.clone(it)
it.setUTCHours(it.getUTCHours() + 2)
const upperBound = R.clone(it)
return [lowerBound, filterByHourInterval(lowerBound, upperBound)]
},
R.init(getTickIntervals(x.domain(), 2))
)
const groupedByTxClass = R.map(it => {
const lowerBound = R.clone(it)
it.setUTCHours(it.getUTCHours() + 2)
const upperBound = R.clone(it)
return [lowerBound, txClassByHourInterval(lowerBound, upperBound)]
}, R.init(getTickIntervals(x.domain(), 2)))
const groupedByTxClass = R.map(
it => {
const lowerBound = R.clone(it)
it.setUTCHours(it.getUTCHours() + 2)
const upperBound = R.clone(it)
return [lowerBound, txClassByHourInterval(lowerBound, upperBound)]
},
R.init(getTickIntervals(x.domain(), 2))
)
const y = d3
.scaleLinear()
@ -416,9 +421,7 @@ const Graph = ({
])
useEffect(() => {
d3.select(ref.current)
.selectAll('*')
.remove()
d3.select(ref.current).selectAll('*').remove()
drawChart()
}, [drawChart])

View file

@ -404,10 +404,7 @@ const Graph = ({
)
// Left side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -428,10 +425,7 @@ const Graph = ({
})
// Right side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -560,9 +554,7 @@ const Graph = ({
])
useEffect(() => {
d3.select(ref.current)
.selectAll('*')
.remove()
d3.select(ref.current).selectAll('*').remove()
drawChart()
}, [drawChart])

View file

@ -455,10 +455,7 @@ const Graph = ({
)
// Left side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -479,10 +476,7 @@ const Graph = ({
})
// Right side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -636,9 +630,7 @@ const Graph = ({
])
useEffect(() => {
d3.select(ref.current)
.selectAll('*')
.remove()
d3.select(ref.current).selectAll('*').remove()
drawChart()
}, [drawChart])

View file

@ -36,10 +36,13 @@ const Graph = ({ data, machines, currency, selectedMachine }) => {
const filledMachines =
R.length(machines) >= AMOUNT_OF_MACHINES
? machinesClone
: R.map(it => {
if (!R.isNil(machinesClone[it])) return machinesClone[it]
return { code: `ghostMachine${it}`, display: `` }
}, R.times(R.identity, AMOUNT_OF_MACHINES))
: R.map(
it => {
if (!R.isNil(machinesClone[it])) return machinesClone[it]
return { code: `ghostMachine${it}`, display: `` }
},
R.times(R.identity, AMOUNT_OF_MACHINES)
)
const txByDevice = R.reduce(
(acc, value) => {
@ -108,8 +111,9 @@ const Graph = ({ data, machines, currency, selectedMachine }) => {
.axisBottom(x)
.tickFormat(
d =>
`${R.find(it => it.code === d[0], filledMachines).display ??
''}`
`${
R.find(it => it.code === d[0], filledMachines).display ?? ''
}`
)
.tickSize(0)
.tickPadding(10)
@ -140,14 +144,14 @@ const Graph = ({ data, machines, currency, selectedMachine }) => {
)
const positionXAxisLabels = useCallback(() => {
d3.selectAll('.x-axis-1 .tick text').attr('transform', function(d) {
d3.selectAll('.x-axis-1 .tick text').attr('transform', function (d) {
const widthPerEntry = (x.range()[1] - x.range()[0]) / AMOUNT_OF_MACHINES
return `translate(${-widthPerEntry / 2.25 + this.getBBox().width / 2}, 0)`
})
}, [x])
const positionXAxis2Labels = useCallback(() => {
d3.selectAll('.x-axis-2 .tick text').attr('transform', function(d) {
d3.selectAll('.x-axis-2 .tick text').attr('transform', function (d) {
const widthPerEntry = (x.range()[1] - x.range()[0]) / AMOUNT_OF_MACHINES
return `translate(${widthPerEntry / 2.25 - this.getBBox().width / 2}, 0)`
})
@ -295,9 +299,7 @@ const Graph = ({ data, machines, currency, selectedMachine }) => {
])
useEffect(() => {
d3.select(ref.current)
.selectAll('*')
.remove()
d3.select(ref.current).selectAll('*').remove()
drawChart()
}, [drawChart])

View file

@ -48,10 +48,7 @@ const GET_USER_DATA = gql`
`
const validationSchema = Yup.object().shape({
email: Yup.string()
.label('Email')
.required()
.email(),
email: Yup.string().label('Email').required().email(),
password: Yup.string().required('Password field is required'),
rememberMe: Yup.boolean()
})

View file

@ -109,9 +109,7 @@ const BlacklistAdvanced = ({
const validationSchema = Yup.object().shape({
label: Yup.string().required('A label is required!'),
content: Yup.string()
.required('The message content is required!')
.trim()
content: Yup.string().required('The message content is required!').trim()
})
return (

View file

@ -36,9 +36,7 @@ const BlackListModal = ({ onClose, addToBlacklist, errorMsg }) => {
address: ''
}}
validationSchema={Yup.object({
address: Yup.string()
.trim()
.required('An address is required')
address: Yup.string().trim().required('An address is required')
})}
onSubmit={({ address }) => {
handleAddToBlacklist(address.trim())

View file

@ -83,63 +83,43 @@ const Wizard = ({ machine, locale, onClose, save, error }) => {
cassette1:
machine.numberOfCassettes >= 1 && step >= 1
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
cassette2:
machine.numberOfCassettes >= 2 && step >= 2
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
cassette3:
machine.numberOfCassettes >= 3 && step >= 3
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
cassette4:
machine.numberOfCassettes >= 4 && step >= 4
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler1:
machine.numberOfRecyclers >= 1 && step >= machine.numberOfCassettes + 1
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler2:
machine.numberOfRecyclers >= 2 && step >= machine.numberOfCassettes + 2
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler3:
machine.numberOfRecyclers >= 3 && step >= machine.numberOfCassettes + 3
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler4:
machine.numberOfRecyclers >= 4 && step >= machine.numberOfCassettes + 4
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler5:
machine.numberOfRecyclers >= 5 && step >= machine.numberOfCassettes + 5
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable(),
: Yup.number().transform(transformNumber).nullable(),
recycler6:
machine.numberOfRecyclers >= 6 && step >= machine.numberOfCassettes + 6
? Yup.number().required()
: Yup.number()
.transform(transformNumber)
.nullable()
: Yup.number().transform(transformNumber).nullable()
})
return (

View file

@ -325,10 +325,7 @@ const getOverridesSchema = (values, rawData, locale) => {
const highestBill = R.isEmpty(bills) ? CURRENCY_MAX : Math.max(...bills)
return Yup.object().shape({
machine: Yup.string()
.nullable()
.label('Machine')
.required(),
machine: Yup.string().nullable().label('Machine').required(),
cryptoCurrencies: Yup.array()
.test({
test() {
@ -474,13 +471,8 @@ const getListCommissionsSchema = locale => {
const highestBill = R.isEmpty(bills) ? CURRENCY_MAX : Math.max(...bills)
return Yup.object().shape({
machine: Yup.string()
.label('Machine')
.required(),
cryptoCurrencies: Yup.array()
.label('Crypto currency')
.required()
.min(1),
machine: Yup.string().label('Machine').required(),
cryptoCurrencies: Yup.array().label('Crypto currency').required().min(1),
cashIn: Yup.number()
.label('Cash-in')
.min(percentMin)

View file

@ -89,8 +89,8 @@ const CustomerData = ({
const sanctionsDisplay = !sanctionsAt
? 'Not checked yet'
: sanctions
? 'Passed'
: 'Failed'
? 'Passed'
: 'Failed'
const sortByName = R.sortBy(
R.compose(R.toLower, R.path(['customInfoRequest', 'customRequest', 'name']))
@ -263,9 +263,7 @@ const CustomerData = ({
src={
!R.isNil(previewPhoto)
? URL.createObjectURL(previewPhoto)
: `/front-camera-photo/${R.path(['frontCameraPath'])(
customer
)}`
: `/front-camera-photo/${R.path(['frontCameraPath'])(customer)}`
}
/>
) : null
@ -304,9 +302,7 @@ const CustomerData = ({
src={
!R.isNil(previewCard)
? URL.createObjectURL(previewCard)
: `/id-card-photo/${R.path(['idCardPhotoPath'])(
customer
)}`
: `/id-card-photo/${R.path(['idCardPhotoPath'])(customer)}`
}
/>
) : null
@ -386,44 +382,50 @@ const CustomerData = ({
})
}, customInfoRequests)
R.forEach(it => {
customFields.push({
fields: [
{
name: it.label,
label: it.label,
value: it.value ?? '',
component: TextInput,
editable: true
R.forEach(
it => {
customFields.push({
fields: [
{
name: it.label,
label: it.label,
value: it.value ?? '',
component: TextInput,
editable: true
}
],
title: it.label,
titleIcon: <EditIcon className={classes.editIcon} />,
save: values => {
updateCustomEntry({
fieldId: it.id,
value: values[it.label]
})
},
deleteEditedData: () => {},
validationSchema: Yup.object().shape({
[it.label]: Yup.string()
}),
initialValues: {
[it.label]: it.value ?? ''
}
],
title: it.label,
titleIcon: <EditIcon className={classes.editIcon} />,
save: values => {
updateCustomEntry({
fieldId: it.id,
value: values[it.label]
})
},
deleteEditedData: () => {},
validationSchema: Yup.object().shape({
[it.label]: Yup.string()
}),
initialValues: {
[it.label]: it.value ?? ''
}
})
}, R.path(['customFields'])(customer) ?? [])
})
},
R.path(['customFields'])(customer) ?? []
)
R.forEach(it => {
initialValues.smsData[it] = smsData[it]
smsDataElements.push({
name: it,
label: onlyFirstToUpper(it),
component: TextInput,
editable: false
})
}, R.keys(smsData) ?? [])
R.forEach(
it => {
initialValues.smsData[it] = smsData[it]
smsDataElements.push({
name: it,
label: onlyFirstToUpper(it),
component: TextInput,
editable: false
})
},
R.keys(smsData) ?? []
)
const externalCompliance = R.map(it => ({
fields: [
@ -492,7 +494,9 @@ const CustomerData = ({
deleteEditedData={deleteEditedData}
retrieveAdditionalData={retrieveAdditionalData}
checkAgainstSanctions={checkAgainstSanctions}
editable={editable}>{children}</EditableCard>
editable={editable}>
{children}
</EditableCard>
)
}
@ -509,7 +513,9 @@ const CustomerData = ({
titleIcon={titleIcon}
editable={false}
hasImage={hasImage}
fields={fields}>{children}</EditableCard>
fields={fields}>
{children}
</EditableCard>
)
}
@ -519,24 +525,25 @@ const CustomerData = ({
<div>
<div className={classes.header}>
<H3 className={classes.title}>{'Customer data'}</H3>
{// TODO: Remove false condition for next release
// false && (
// <>
// <FeatureButton
// active={!listView}
// className={classes.viewIcons}
// Icon={OverviewIcon}
// InverseIcon={OverviewReversedIcon}
// onClick={() => setListView(false)}
// />
// <FeatureButton
// active={listView}
// className={classes.viewIcons}
// Icon={CustomerListViewIcon}
// InverseIcon={CustomerListViewReversedIcon}
// onClick={() => setListView(true)}></FeatureButton>
// </>
// )
{
// TODO: Remove false condition for next release
// false && (
// <>
// <FeatureButton
// active={!listView}
// className={classes.viewIcons}
// Icon={OverviewIcon}
// InverseIcon={OverviewReversedIcon}
// onClick={() => setListView(false)}
// />
// <FeatureButton
// active={listView}
// className={classes.viewIcons}
// Icon={CustomerListViewIcon}
// InverseIcon={CustomerListViewReversedIcon}
// onClick={() => setListView(true)}></FeatureButton>
// </>
// )
}
</div>
<div>

View file

@ -59,15 +59,14 @@ const CustomerNotes = ({
<div className={classes.notesChipList}>
<NewNoteCard setOpenModal={setOpenModal} />
{customerNotes.map((it, idx) => (
<NoteCard
key={idx}
note={it}
deleteNote={deleteNote}
handleClick={setEditing}
timezone={timezone}
/>
)
)}
<NoteCard
key={idx}
note={it}
deleteNote={deleteNote}
handleClick={setEditing}
timezone={timezone}
/>
))}
</div>
)}
{!R.isNil(editing) && (

View file

@ -552,8 +552,8 @@ const CustomerProfile = memo(() => {
{name.length
? name
: email?.length
? email
: getFormattedPhone(phone, locale.country)}
? email
: getFormattedPhone(phone, locale.country)}
</Label2>
</Breadcrumbs>
<div className={classes.panels}>

View file

@ -120,9 +120,8 @@ const Customers = () => {
onCompleted: data => setFilteredCustomers(R.path(['customers'])(data))
})
const { data: filtersResponse, loading: loadingFilters } = useQuery(
GET_CUSTOMER_FILTERS
)
const { data: filtersResponse, loading: loadingFilters } =
useQuery(GET_CUSTOMER_FILTERS)
const [createNewCustomer] = useMutation(CREATE_CUSTOMER, {
onCompleted: () => setShowCreationModal(false),

View file

@ -134,8 +134,8 @@ const CustomInfoRequestsData = ({ data }) => {
it.approved === null
? { label: 'Pending', type: 'neutral' }
: it.approved === false
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
return (
<>

View file

@ -59,8 +59,8 @@ const CustomerDetails = memo(({ customer, photosData, locale, timezone }) => {
{name.length
? name
: email?.length
? email
: getFormattedPhone(phone, locale.country)}
? email
: getFormattedPhone(phone, locale.country)}
</H2>
</div>
<Box display="flex" mt="auto">

View file

@ -170,8 +170,8 @@ const EditableCard = ({
state === OVERRIDE_PENDING
? { label: 'Pending', type: 'neutral' }
: state === OVERRIDE_REJECTED
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
return (
<div>

View file

@ -38,9 +38,7 @@ const IdCardPhotoCard = memo(({ customerData, updateCustomer }) => {
{customerData.idCardPhotoPath ? (
<img
className={classes.idCardPhoto}
src={`/id-card-photo/${R.path(['idCardPhotoPath'])(
customerData
)}`}
src={`/id-card-photo/${R.path(['idCardPhotoPath'])(customerData)}`}
alt=""
/>
) : (

View file

@ -18,10 +18,7 @@ const initialValues = {
}
const validationSchema = Yup.object().shape({
title: Yup.string()
.required()
.trim()
.max(25),
title: Yup.string().required().trim().max(25),
content: Yup.string().required()
})

View file

@ -93,8 +93,8 @@ const PropertyCard = memo(
state === OVERRIDE_PENDING
? { label: 'Pending', type: 'neutral' }
: state === OVERRIDE_REJECTED
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
? { label: 'Rejected', type: 'error' }
: { label: 'Accepted', type: 'success' }
return (
<Paper

View file

@ -143,9 +143,9 @@ const getFormattedPhone = (phone, country) => {
const getName = it => {
const idData = R.path(['idCardData'])(it)
return `${R.path(['firstName'])(idData) ?? ''} ${R.path(['lastName'])(
idData
) ?? ''}`.trim()
return `${R.path(['firstName'])(idData) ?? ''} ${
R.path(['lastName'])(idData) ?? ''
}`.trim()
}
// Manual Entry Wizard

View file

@ -126,10 +126,10 @@ const RefLineChart = ({
])
.enter()
.append('stop')
.attr('offset', function(d) {
.attr('offset', function (d) {
return d.offset
})
.attr('stop-color', function(d) {
.attr('stop-color', function (d) {
return d.color
})
@ -152,20 +152,20 @@ const RefLineChart = ({
const line = d3
.line()
.x(function(d) {
.x(function (d) {
return x(new Date(d.created))
})
.y(function(d) {
.y(function (d) {
return y(d.profit)
})
const area = d3
.area()
.x(function(d) {
.x(function (d) {
return x(new Date(d.created))
})
.y0(height)
.y1(function(d) {
.y1(function (d) {
return y(d.profit)
})
@ -186,9 +186,7 @@ const RefLineChart = ({
useEffect(() => {
// first we clear old chart DOM elements on component update
d3.select(svgRef.current)
.selectAll('*')
.remove()
d3.select(svgRef.current).selectAll('*').remove()
drawGraph()
}, [drawGraph, realData])

View file

@ -211,12 +211,7 @@ const Graph = ({ data, timeFrame, timezone }) => {
g
.append('g')
.selectAll('line')
.data(
d3
.axisLeft(y)
.scale()
.ticks(5)
)
.data(d3.axisLeft(y).scale().ticks(5))
.join('line')
.attr('y1', d => 0.5 + y(d))
.attr('y2', d => 0.5 + y(d))
@ -240,10 +235,7 @@ const Graph = ({ data, timeFrame, timezone }) => {
)
// Left side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -261,10 +253,7 @@ const Graph = ({ data, timeFrame, timezone }) => {
})
// Right side breakpoint label
.call(g => {
const separator = d3
?.select('.dateSeparator')
?.node()
?.getBBox()
const separator = d3?.select('.dateSeparator')?.node()?.getBBox()
if (!separator) return
@ -355,9 +344,7 @@ const Graph = ({ data, timeFrame, timezone }) => {
])
useEffect(() => {
d3.select(ref.current)
.selectAll('*')
.remove()
d3.select(ref.current).selectAll('*').remove()
drawChart()
}, [drawChart])

View file

@ -108,14 +108,13 @@ const MachinesTable = ({ machines = [], numToRender }) => {
</div>
</HeaderCell> */}
{R.times(R.identity, maxNumberOfCassettes).map((it, idx) => (
<HeaderCell key={idx}>
<div className={classes.header}>
<TxOutIcon />
<Label2 className={classes.label}> {it + 1}</Label2>
</div>
</HeaderCell>
)
)}
<HeaderCell key={idx}>
<div className={classes.header}>
<TxOutIcon />
<Label2 className={classes.label}> {it + 1}</Label2>
</div>
</HeaderCell>
))}
</TableRow>
</TableHead>
<TableBody>
@ -142,18 +141,18 @@ const MachinesTable = ({ machines = [], numToRender }) => {
<Status status={machine.statuses[0]} />
</StyledCell>
{R.range(1, maxNumberOfCassettes + 1).map((it, idx) =>
machine.numberOfCassettes >= it ? (
<StyledCell key={idx} align="left">
{makePercentageText(
it,
machine.cashUnits[`cassette${it}`]
)}
</StyledCell>
) : (
<StyledCell key={idx} align="left">
<TL2>{`— %`}</TL2>
</StyledCell>
)
machine.numberOfCassettes >= it ? (
<StyledCell key={idx} align="left">
{makePercentageText(
it,
machine.cashUnits[`cassette${it}`]
)}
</StyledCell>
) : (
<StyledCell key={idx} align="left">
<TL2>{`— %`}</TL2>
</StyledCell>
)
)}
</TableRow>
)

View file

@ -153,42 +153,18 @@ const overrides = (auxData, auxElements, configureCoin) => {
}
const LocaleSchema = Yup.object().shape({
country: Yup.string()
.label('Country')
.required(),
fiatCurrency: Yup.string()
.label('Fiat currency')
.required(),
languages: Yup.array()
.label('Languages')
.required()
.min(1)
.max(4),
cryptoCurrencies: Yup.array()
.label('Crypto currencies')
.required()
.min(1),
timezone: Yup.string()
.label('Timezone')
.required()
country: Yup.string().label('Country').required(),
fiatCurrency: Yup.string().label('Fiat currency').required(),
languages: Yup.array().label('Languages').required().min(1).max(4),
cryptoCurrencies: Yup.array().label('Crypto currencies').required().min(1),
timezone: Yup.string().label('Timezone').required()
})
const OverridesSchema = Yup.object().shape({
machine: Yup.string()
.label('Machine')
.required(),
country: Yup.string()
.label('Country')
.required(),
languages: Yup.array()
.label('Languages')
.required()
.min(1)
.max(4),
cryptoCurrencies: Yup.array()
.label('Crypto currencies')
.required()
.min(1)
machine: Yup.string().label('Machine').required(),
country: Yup.string().label('Country').required(),
languages: Yup.array().label('Languages').required().min(1).max(4),
cryptoCurrencies: Yup.array().label('Crypto currencies').required().min(1)
})
const localeDefaults = {

View file

@ -65,9 +65,8 @@ const IndividualDiscounts = () => {
const { data: discountResponse, loading: discountLoading } = useQuery(
GET_INDIVIDUAL_DISCOUNTS
)
const { data: customerData, loading: customerLoading } = useQuery(
GET_CUSTOMERS
)
const { data: customerData, loading: customerLoading } =
useQuery(GET_CUSTOMERS)
const [createDiscount, { error: creationError }] = useMutation(
CREATE_DISCOUNT,

View file

@ -21,14 +21,8 @@ const initialValues = {
}
const validationSchema = Yup.object().shape({
code: Yup.string()
.required()
.trim()
.max(25),
discount: Yup.number()
.required()
.min(0)
.max(100)
code: Yup.string().required().trim().max(25),
discount: Yup.number().required().min(0).max(100)
})
const PromoCodesModal = ({ showModal, onClose, errorMsg, addCode }) => {

View file

@ -81,9 +81,8 @@ const Logs = () => {
const deviceId = selected?.deviceId
const { data: machineResponse, loading: machinesLoading } = useQuery(
GET_MACHINES
)
const { data: machineResponse, loading: machinesLoading } =
useQuery(GET_MACHINES)
const { data: configResponse, loading: configLoading } = useQuery(GET_DATA)
const timezone = R.path(['config', 'locale_timezone'], configResponse)

View file

@ -106,7 +106,7 @@ const CashUnitDetails = ({
<div className={classes.billList}>
<Label1>Cash box</Label1>
{R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>}
{(R.keys(billCount)).map((it, idx) => (
{R.keys(billCount).map((it, idx) => (
<span key={idx}>
<TL2 noMargin>{billCount[it]}</TL2>
<Chip label={`${it} ${currency}`} />
@ -149,7 +149,7 @@ const CashUnitDetails = ({
noMargin
className={classes.label}>{`Loading boxes`}</Label1>
<div className={classes.loadingBoxes}>
{(R.range(1, machine.numberOfCassettes + 1)).map((it, idx) => (
{R.range(1, machine.numberOfCassettes + 1).map((it, idx) => (
<CashOut
key={idx}
width={60}

View file

@ -182,10 +182,8 @@ const WizardStep = ({
const numberOfCassettes = machine.numberOfCassettes
const numberOfRecyclers = machine.numberOfRecyclers
const {
name: cashUnitField,
category: cashUnitCategory
} = getCashUnitFieldName(step, numberOfCassettes, numberOfRecyclers)
const { name: cashUnitField, category: cashUnitCategory } =
getCashUnitFieldName(step, numberOfCassettes, numberOfRecyclers)
const originalCashUnitCount = machine?.cashUnits?.[cashUnitField]
const cashUnitDenomination = cashoutSettings?.[cashUnitField]
@ -317,8 +315,8 @@ const WizardStep = ({
{cashUnitCategory === 'cassette'
? `dispenser`
: cashUnitCategory === 'recycler'
? `recycler`
: ``}
? `recycler`
: ``}
)
</H4>
</div>

View file

@ -57,7 +57,7 @@ const getElements = (
return (
<div className={classes.unitsRow}>
<div className={classes.units}>
{(R.range(1, m.numberOfCassettes + 1)).map((it, idx) => (
{R.range(1, m.numberOfCassettes + 1).map((it, idx) => (
<CashOutLite
key={idx}
width={'100%'}

View file

@ -33,14 +33,8 @@ const SingleFieldEditableNumber = ({
setSaving(false)
}
const {
save,
data,
currency,
isEditing,
isDisabled,
setEditing
} = useContext(NotificationsCtx)
const { save, data, currency, isEditing, isDisabled, setEditing } =
useContext(NotificationsCtx)
const schema = Yup.object().shape({
[name]: Yup.number()

View file

@ -14,14 +14,8 @@ const useStyles = makeStyles(styles)
const CryptoBalanceAlerts = ({ section, fieldWidth }) => {
const classes = useStyles()
const {
data,
save,
currency,
setEditing,
isEditing,
isDisabled
} = useContext(NotificationsCtx)
const { data, save, currency, setEditing, isEditing, isDisabled } =
useContext(NotificationsCtx)
return (
<div className={classes.cryptoBalanceAlerts}>

View file

@ -79,9 +79,7 @@ const FiatBalanceOverrides = ({ config, section }) => {
const percentMax = 100
const validationSchema = Yup.object()
.shape({
[MACHINE_KEY]: Yup.string()
.label('Machine')
.required(),
[MACHINE_KEY]: Yup.string().label('Machine').required(),
[CASHBOX_KEY]: Yup.number()
.label('Cash box')
.transform(transformNumber)

View file

@ -1,84 +1,87 @@
import * as R from 'ramda'
import React, { useContext } from 'react'
import Autocomplete from 'src/components/inputs/formik/Autocomplete'
import * as Yup from 'yup'
import { Table as EditableTable } from 'src/components/editableTable'
import { toNamespace, fromNamespace } from 'src/utils/config'
import NotificationsCtx from '../NotificationsContext'
const filterClass = type => R.filter(it => it.class === type)
const ThirdPartyProvider = () => {
const { save, data: _data, error, accountsConfig } = useContext(
NotificationsCtx
)
const data = fromNamespace('thirdParty')(_data)
const filterOptions = type => filterClass(type)(accountsConfig || [])
const getDisplayName = type => it =>
R.compose(
R.prop('display'),
R.find(R.propEq('code', it))
)(filterOptions(type))
const innerSave = async value => {
const config = toNamespace('thirdParty')(value?.thirdParty[0])
await save('thirdParty', config)
}
const ThirdPartySchema = Yup.object().shape({
sms: Yup.string('SMS must be a string').required('SMS is required'),
email: Yup.string('Email must be a string').required('Email is required')
})
const elements = [
{
name: 'sms',
size: 'sm',
view: getDisplayName('sms'),
width: 175,
input: Autocomplete,
inputProps: {
options: filterOptions('sms'),
valueProp: 'code',
labelProp: 'display'
}
},
{
name: 'email',
size: 'sm',
view: getDisplayName('email'),
width: 175,
input: Autocomplete,
inputProps: {
options: filterOptions('email'),
valueProp: 'code',
labelProp: 'display'
}
}
]
const values = {
sms: data.sms ?? 'twilio',
email: data.email ?? 'mailgun'
}
return (
<EditableTable
name="thirdParty"
initialValues={values}
data={R.of(values)}
error={error?.message}
enableEdit
editWidth={174}
save={innerSave}
validationSchema={ThirdPartySchema}
elements={elements}
/>
)
}
export default ThirdPartyProvider
import * as R from 'ramda'
import React, { useContext } from 'react'
import Autocomplete from 'src/components/inputs/formik/Autocomplete'
import * as Yup from 'yup'
import { Table as EditableTable } from 'src/components/editableTable'
import { toNamespace, fromNamespace } from 'src/utils/config'
import NotificationsCtx from '../NotificationsContext'
const filterClass = type => R.filter(it => it.class === type)
const ThirdPartyProvider = () => {
const {
save,
data: _data,
error,
accountsConfig
} = useContext(NotificationsCtx)
const data = fromNamespace('thirdParty')(_data)
const filterOptions = type => filterClass(type)(accountsConfig || [])
const getDisplayName = type => it =>
R.compose(
R.prop('display'),
R.find(R.propEq('code', it))
)(filterOptions(type))
const innerSave = async value => {
const config = toNamespace('thirdParty')(value?.thirdParty[0])
await save('thirdParty', config)
}
const ThirdPartySchema = Yup.object().shape({
sms: Yup.string('SMS must be a string').required('SMS is required'),
email: Yup.string('Email must be a string').required('Email is required')
})
const elements = [
{
name: 'sms',
size: 'sm',
view: getDisplayName('sms'),
width: 175,
input: Autocomplete,
inputProps: {
options: filterOptions('sms'),
valueProp: 'code',
labelProp: 'display'
}
},
{
name: 'email',
size: 'sm',
view: getDisplayName('email'),
width: 175,
input: Autocomplete,
inputProps: {
options: filterOptions('email'),
valueProp: 'code',
labelProp: 'display'
}
}
]
const values = {
sms: data.sms ?? 'twilio',
email: data.email ?? 'mailgun'
}
return (
<EditableTable
name="thirdParty"
initialValues={values}
data={R.of(values)}
error={error?.message}
enableEdit
editWidth={174}
save={innerSave}
validationSchema={ThirdPartySchema}
elements={elements}
/>
)
}
export default ThirdPartyProvider

View file

@ -61,7 +61,7 @@ const DISABLE_SMS_NOTICE = gql`
const multiReplace = (str, obj) => {
var re = new RegExp(Object.keys(obj).join('|'), 'gi')
return str.replace(re, function(matched) {
return str.replace(re, function (matched) {
return obj[matched.toLowerCase()]
})
}
@ -82,7 +82,8 @@ const formatContent = content => {
const TOOLTIPS = {
smsCode: ``,
cashOutDispenseReady: ``,
smsReceipt: formatContent(`The contents of this notice will be appended to the end of the SMS receipt sent, and not replace it.\n
smsReceipt:
formatContent(`The contents of this notice will be appended to the end of the SMS receipt sent, and not replace it.\n
To edit the contents of the SMS receipt, please go to the 'Receipt' tab`)
}
@ -124,9 +125,8 @@ const SMSNotices = () => {
const [previewCoords, setPreviewCoords] = useState({ x: 0, y: 0 })
const [errorMsg, setErrorMsg] = useState('')
const { data: messagesData, loading: messagesLoading } = useQuery(
GET_SMS_NOTICES
)
const { data: messagesData, loading: messagesLoading } =
useQuery(GET_SMS_NOTICES)
const timezone = R.path(['config', 'locale_timezone'])(messagesData)

View file

@ -44,9 +44,7 @@ const PREFILL = {
})
},
cashOutDispenseReady: {
validator: Yup.string()
.required('The message content is required!')
.trim()
validator: Yup.string().required('The message content is required!').trim()
},
smsReceipt: {
validator: Yup.string().trim()
@ -89,9 +87,7 @@ const SMSNoticesModal = ({
event: Yup.string().required('An event is required!'),
message:
PREFILL[sms?.event]?.validator ??
Yup.string()
.required('The message content is required!')
.trim()
Yup.string().required('The message content is required!').trim()
})
const handleSubmit = values => {
@ -155,33 +151,29 @@ const SMSNoticesModal = ({
<Info2 noMargin>Values to attach</Info2>
)}
<div className={classes.chipButtons}>
{R.splitEvery(3, CHIPS[sms?.event]).map(
(it, idx) => (
<div key={idx}>
{it.map(
(ite, idx2) => (
<Chip
key={idx2}
label={ite.display}
size="small"
style={{ backgroundColor: zircon }}
disabled={R.includes(ite.code, values.message)}
className={classes.chip}
onClick={() => {
setFieldValue(
'message',
values.message.concat(
R.last(values.message) === ' ' ? '' : ' ',
ite.code
)
)
}}
/>
)
)}
</div>
),
)}
{R.splitEvery(3, CHIPS[sms?.event]).map((it, idx) => (
<div key={idx}>
{it.map((ite, idx2) => (
<Chip
key={idx2}
label={ite.display}
size="small"
style={{ backgroundColor: zircon }}
disabled={R.includes(ite.code, values.message)}
className={classes.chip}
onClick={() => {
setFieldValue(
'message',
values.message.concat(
R.last(values.message) === ' ' ? '' : ' ',
ite.code
)
)
}}
/>
))}
</div>
))}
</div>
<div className={classes.footer}>
{getErrorMsg(errors, touched, creationError) && (

View file

@ -1,67 +1,64 @@
import { ALL_CRYPTOS } from '@lamassu/coins/config/consts'
import { getEquivalentCode } from '@lamassu/coins/lightUtils'
import * as R from 'ramda'
const WARNING_LEVELS = {
CLEAN: 'clean',
PARTIAL: 'partial',
IMPORTANT: 'important'
}
const secretTest = (secret, message) => ({
name: 'secret-test',
message: message ? `The ${message} is invalid` : 'Invalid field',
test(val) {
if (R.isNil(secret) && R.isNil(val)) {
return this.createError()
}
return true
}
})
const leadingZerosTest = (value, context) => {
if (
R.startsWith('0', context.originalValue) &&
R.length(context.originalValue) > 1
) {
return context.createError()
}
return true
}
const buildCurrencyOptions = markets => {
const prunedCoins = R.compose(
R.uniq,
R.map(getEquivalentCode)
)(ALL_CRYPTOS)
return R.map(it => {
const unavailableCryptos = R.difference(prunedCoins, markets[it])
const unavailableCryptosFiltered = R.difference(unavailableCryptos, [it]) // As the markets can have stablecoins to trade against other crypto, filter them out, as there can't be pairs such as USDT/USDT
const unavailableMarketsStr =
R.length(unavailableCryptosFiltered) > 1
? `${R.join(
', ',
R.slice(0, -1, unavailableCryptosFiltered)
)} and ${R.last(unavailableCryptosFiltered)}`
: unavailableCryptosFiltered[0]
const warningLevel = R.isEmpty(unavailableCryptosFiltered)
? WARNING_LEVELS.CLEAN
: !R.isEmpty(unavailableCryptosFiltered) &&
R.length(unavailableCryptosFiltered) < R.length(prunedCoins)
? WARNING_LEVELS.PARTIAL
: WARNING_LEVELS.IMPORTANT
return {
code: R.toUpper(it),
display: R.toUpper(it),
warning: warningLevel,
warningMessage: !R.isEmpty(unavailableCryptosFiltered)
? `No market pairs available for ${unavailableMarketsStr}`
: `All market pairs are available`
}
}, R.keys(markets))
}
export { secretTest, leadingZerosTest, buildCurrencyOptions }
import { ALL_CRYPTOS } from '@lamassu/coins/config/consts'
import { getEquivalentCode } from '@lamassu/coins/lightUtils'
import * as R from 'ramda'
const WARNING_LEVELS = {
CLEAN: 'clean',
PARTIAL: 'partial',
IMPORTANT: 'important'
}
const secretTest = (secret, message) => ({
name: 'secret-test',
message: message ? `The ${message} is invalid` : 'Invalid field',
test(val) {
if (R.isNil(secret) && R.isNil(val)) {
return this.createError()
}
return true
}
})
const leadingZerosTest = (value, context) => {
if (
R.startsWith('0', context.originalValue) &&
R.length(context.originalValue) > 1
) {
return context.createError()
}
return true
}
const buildCurrencyOptions = markets => {
const prunedCoins = R.compose(R.uniq, R.map(getEquivalentCode))(ALL_CRYPTOS)
return R.map(it => {
const unavailableCryptos = R.difference(prunedCoins, markets[it])
const unavailableCryptosFiltered = R.difference(unavailableCryptos, [it]) // As the markets can have stablecoins to trade against other crypto, filter them out, as there can't be pairs such as USDT/USDT
const unavailableMarketsStr =
R.length(unavailableCryptosFiltered) > 1
? `${R.join(
', ',
R.slice(0, -1, unavailableCryptosFiltered)
)} and ${R.last(unavailableCryptosFiltered)}`
: unavailableCryptosFiltered[0]
const warningLevel = R.isEmpty(unavailableCryptosFiltered)
? WARNING_LEVELS.CLEAN
: !R.isEmpty(unavailableCryptosFiltered) &&
R.length(unavailableCryptosFiltered) < R.length(prunedCoins)
? WARNING_LEVELS.PARTIAL
: WARNING_LEVELS.IMPORTANT
return {
code: R.toUpper(it),
display: R.toUpper(it),
warning: warningLevel,
warningMessage: !R.isEmpty(unavailableCryptosFiltered)
? `No market pairs available for ${unavailableMarketsStr}`
: `All market pairs are available`
}
}, R.keys(markets))
}
export { secretTest, leadingZerosTest, buildCurrencyOptions }

View file

@ -132,14 +132,10 @@ const DetailsRow = ({ it: tx, timezone }) => {
Number.parseFloat(tx.commissionPercentage, 2) * 100
).toFixed(2, 1) // ROUND_DOWN
const fixedFee = Number.parseFloat(tx.fixedFee) || 0
const fiat = BigNumber(tx.fiat)
.minus(fixedFee)
.toFixed(2, 1) // ROUND_DOWN
const fiat = BigNumber(tx.fiat).minus(fixedFee).toFixed(2, 1) // ROUND_DOWN
const crypto = getCryptoAmount(tx)
const cryptoFee = tx.fee ? `${getCryptoFeeAmount(tx)} ${tx.fiatCode}` : 'N/A'
const exchangeRate = BigNumber(fiat)
.div(crypto)
.toFixed(2, 1) // ROUND_DOWN
const exchangeRate = BigNumber(fiat).div(crypto).toFixed(2, 1) // ROUND_DOWN
const displayExRate = `1 ${tx.cryptoCode} = ${exchangeRate} ${tx.fiatCode}`
const discount = tx.discount ? `-${tx.discount}%` : null
@ -203,23 +199,22 @@ const DetailsRow = ({ it: tx, timezone }) => {
<div className={classes.walletScore}>
<svg width={103} height={10}>
{R.range(0, 10).map((it, idx) => (
<circle
key={idx}
cx={it * 10 + 6}
cy={4}
r={3.5}
fill={
it < tx.walletScore
? !hasChainAnalysisError(tx)
? primaryColor
: errorColor
: !hasChainAnalysisError(tx)
<circle
key={idx}
cx={it * 10 + 6}
cy={4}
r={3.5}
fill={
it < tx.walletScore
? !hasChainAnalysisError(tx)
? primaryColor
: errorColor
: !hasChainAnalysisError(tx)
? subheaderColor
: offErrorColor
}
/>
)
)}
}
/>
))}
</svg>
<P
noMargin

View file

@ -65,9 +65,7 @@ const ChooseType = () => {
}
const validationSchema = Yup.object().shape({
inputType: Yup.string()
.label('Input type')
.required()
inputType: Yup.string().label('Input type').required()
})
const defaultValues = {

View file

@ -31,12 +31,8 @@ const Screen1Information = () => {
}
const validationSchema = Yup.object().shape({
screen1Title: Yup.string()
.label('Screen title')
.required(),
screen1Text: Yup.string()
.label('Screen text')
.required()
screen1Title: Yup.string().label('Screen title').required(),
screen1Text: Yup.string().label('Screen text').required()
})
const defaultValues = {

View file

@ -29,12 +29,8 @@ const ScreenInformation = () => {
}
const validationSchema = Yup.object().shape({
screen2Title: Yup.string()
.label('Screen title')
.required(),
screen2Text: Yup.string()
.label('Screen text')
.required()
screen2Title: Yup.string().label('Screen title').required(),
screen2Text: Yup.string().label('Screen text').required()
})
const defaultValues = {

View file

@ -40,38 +40,27 @@ const validationSchema = Yup.lazy(values => {
switch (values.inputType) {
case 'numerical':
return Yup.object({
constraintType: Yup.string()
.label('Constraint type')
.required(),
constraintType: Yup.string().label('Constraint type').required(),
inputLength: Yup.number().when('constraintType', {
is: 'length',
then: schema => schema
.min(0)
.required('The number of digits is required'),
then: schema =>
schema.min(0).required('The number of digits is required'),
otherwise: schema => schema.mixed().notRequired()
})
})
case 'text':
return Yup.object({
constraintType: Yup.string()
.label('Constraint type')
.required(),
inputLabel1: Yup.string()
.label('Text entry label')
.required(),
constraintType: Yup.string().label('Constraint type').required(),
inputLabel1: Yup.string().label('Text entry label').required(),
inputLabel2: Yup.string().when('constraintType', {
is: 'spaceSeparation',
then: schema => schema
.label('Second word label')
.required(),
then: schema => schema.label('Second word label').required(),
otherwise: schema => schema.mixed().notRequired()
})
})
case 'choiceList':
return Yup.object({
constraintType: Yup.string()
.label('Constraint type')
.required(),
constraintType: Yup.string().label('Constraint type').required(),
listChoices: Yup.array().test(
'has-2-or-more',
'Choice list needs to have two or more non empty fields',

View file

@ -65,9 +65,8 @@ const Triggers = () => {
const classes = useStyles()
const [wizardType, setWizard] = useState(false)
const { data, loading: configLoading, refetch } = useQuery(GET_CONFIG)
const { data: customInfoReqData, loading: customInfoLoading } = useQuery(
GET_CUSTOM_REQUESTS
)
const { data: customInfoReqData, loading: customInfoLoading } =
useQuery(GET_CUSTOM_REQUESTS)
const [error, setError] = useState(null)
const [subMenu, setSubMenu] = useState(false)

View file

@ -45,9 +45,8 @@ const AdvancedTriggersSettings = memo(() => {
const [isEditingOverrides, setEditingOverrides] = useState(false)
const { data, loading: configLoading } = useQuery(GET_INFO)
const { data: customInfoReqData, loading: customInfoLoading } = useQuery(
GET_CUSTOM_REQUESTS
)
const { data: customInfoReqData, loading: customInfoLoading } =
useQuery(GET_CUSTOM_REQUESTS)
const customInfoRequests =
R.path(['customInfoRequests'])(customInfoReqData) ?? []

View file

@ -30,9 +30,7 @@ const displayRequirement = (code, customInfoRequests) => {
}
const defaultSchema = Yup.object().shape({
expirationTime: Yup.string()
.label('Expiration time')
.required(),
expirationTime: Yup.string().label('Expiration time').required(),
automation: Yup.string()
.label('Automation')
.matches(/(Manual|Automatic)/)
@ -60,9 +58,7 @@ const getOverridesSchema = (values, customInfoRequests) => {
return true
}
}),
expirationTime: Yup.string()
.label('Expiration time')
.required(),
expirationTime: Yup.string().label('Expiration time').required(),
automation: Yup.string()
.label('Automation')
.matches(/(Manual|Automatic)/)

View file

@ -110,9 +110,7 @@ const threshold = Yup.object().shape({
const requirement = Yup.object().shape({
requirement: Yup.string().required(),
suspensionDays: Yup.number()
.transform(transformNumber)
.nullable()
suspensionDays: Yup.number().transform(transformNumber).nullable()
})
const Schema = Yup.object()
@ -266,12 +264,8 @@ const typeSchema = Yup.object()
'The trigger type is required'
),
threshold: Yup.object({
threshold: Yup.number()
.transform(transformNumber)
.nullable(),
thresholdDays: Yup.number()
.transform(transformNumber)
.nullable()
threshold: Yup.number().transform(transformNumber).nullable(),
thresholdDays: Yup.number().transform(transformNumber).nullable()
})
})
.test(({ threshold, triggerType }, context) => {
@ -327,13 +321,8 @@ const typeOptions = [
const Type = ({ ...props }) => {
const classes = useStyles()
const {
errors,
touched,
values,
setTouched,
handleChange
} = useFormikContext()
const { errors, touched, values, setTouched, handleChange } =
useFormikContext()
const typeClass = {
[classes.error]: errors.triggerType && touched.triggerType
@ -484,24 +473,16 @@ const requirementSchema = Yup.object()
requirement: Yup.string().required(),
suspensionDays: Yup.number().when('requirement', {
is: value => value === 'suspend',
then: schema => schema
.nullable()
.transform(transformNumber),
otherwise: schema => schema
.nullable()
.transform(() => null)
then: schema => schema.nullable().transform(transformNumber),
otherwise: schema => schema.nullable().transform(() => null)
}),
customInfoRequestId: Yup.string().when('requirement', {
is: value => value !== 'custom',
then: schema => schema
.nullable()
.transform(() => '')
then: schema => schema.nullable().transform(() => '')
}),
externalService: Yup.string().when('requirement', {
is: value => value !== 'external',
then: schema => schema
.nullable()
.transform(() => '')
then: schema => schema.nullable().transform(() => '')
})
}).required()
})
@ -583,13 +564,8 @@ const Requirement = ({
customInfoRequests = []
}) => {
const classes = useStyles()
const {
touched,
errors,
values,
handleChange,
setTouched
} = useFormikContext()
const { touched, errors, values, handleChange, setTouched } =
useFormikContext()
const isSuspend = values?.requirement?.requirement === 'suspend'
const isCustom = values?.requirement?.requirement === 'custom'
@ -766,9 +742,9 @@ const RequirementInput = ({ customInfoRequests = [] }) => {
R.path(['requirement', 'customInfoRequestId'])(values) ?? ''
const isSuspend = requirement === 'suspend'
const display = customRequestId
? R.path(['customRequest', 'name'])(
? (R.path(['customRequest', 'name'])(
R.find(customReqIdMatches(customRequestId))(customInfoRequests)
) ?? ''
) ?? '')
: getView(requirementOptions, 'display')(requirement)
return (
@ -798,12 +774,12 @@ const RequirementView = ({
const classes = useStyles()
const display =
requirement === 'custom'
? R.path(['customRequest', 'name'])(
? (R.path(['customRequest', 'name'])(
R.find(customReqIdMatches(customInfoRequestId))(customInfoRequests)
) ?? ''
) ?? '')
: requirement === 'external'
? `External verification (${onlyFirstToUpper(externalService)})`
: getView(requirementOptions, 'display')(requirement)
? `External verification (${onlyFirstToUpper(externalService)})`
: getView(requirementOptions, 'display')(requirement)
const isSuspend = requirement === 'suspend'
return (
<Box display="flex" alignItems="baseline">

View file

@ -119,11 +119,10 @@ const Routes = () => {
{...transitionProps}
in={true}
mountOnEnter
unmountOnExit
>
<div className={classes.wrapper}>
<Dashboard />
</div>
unmountOnExit>
<div className={classes.wrapper}>
<Dashboard />
</div>
</Transition>
</PrivateRoute>
<PrivateRoute path="/machines" component={Machines} />
@ -139,19 +138,18 @@ const Routes = () => {
{...transitionProps}
in={!!matchPath(location.pathname, { path: route })}
mountOnEnter
unmountOnExit
>
unmountOnExit>
<div className={classes.wrapper}>
<PrivateRoute path={route} key={key}>
<Page name={key}/>
<Page name={key} />
</PrivateRoute>
</div>
</Transition>
</PrivateRoute>
))}
<PublicRoute path="/404"/>
))}
<PublicRoute path="/404" />
<PublicRoute path="*">
<Redirect to={{ pathname: '/404' }}/>
<Redirect to={{ pathname: '/404' }} />
</PublicRoute>
</Switch>
)

View file

@ -6,7 +6,8 @@ const WALLET_SCORING_DEFAULT_THRESHOLD = 9
const AUTOMATIC = 'automatic'
const MANUAL = 'manual'
const IP_CHECK_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
const IP_CHECK_REGEX =
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
const SWEEPABLE_CRYPTOS = ['ETH']

View file

@ -16,10 +16,10 @@ const formatName = idCardData => {
firstName && lastName
? `${R.o(R.toUpper, R.head)(firstName)}. ${lastName}`
: R.isNil(firstName)
? lastName
: R.isNil(lastName)
? firstName
: null
? lastName
: R.isNil(lastName)
? firstName
: null
return idCardData ? innerFormatName(idCardData) : null
}

View file

@ -20,11 +20,7 @@ const splitOnUpper = R.compose(
R.replace(/([A-Z])/g, ' $1'),
toFirstLower
)
const startCase = R.compose(
R.join(' '),
R.map(onlyFirstToUpper),
splitOnUpper
)
const startCase = R.compose(R.join(' '), R.map(onlyFirstToUpper), splitOnUpper)
const sentenceCase = R.compose(onlyFirstToUpper, R.join(' '), splitOnUpper)

View file

@ -7,6 +7,9 @@ import fixReactVirtualized from 'esbuild-plugin-react-virtualized'
export default defineConfig({
base: '/',
build: {
outDir: 'build'
},
server: {
port: 3001,
proxy: {
@ -19,18 +22,13 @@ export default defineConfig({
},
optimizeDeps: {
esbuildOptions: {
plugins: [
fixReactVirtualized,
],
plugins: [fixReactVirtualized]
}
},
plugins: [
react(),
svgr(),
],
plugins: [react(), svgr()],
resolve: {
alias: {
'src': fileURLToPath(new URL('./src', import.meta.url))
},
},
src: fileURLToPath(new URL('./src', import.meta.url))
}
}
})