set up form validation for undelegation
This commit is contained in:
@@ -11,12 +11,12 @@ export enum EnumRequestStatus {
|
||||
|
||||
export const RequestStatus = ({
|
||||
status,
|
||||
onSuccess,
|
||||
onError,
|
||||
Success,
|
||||
Error,
|
||||
}: {
|
||||
status: EnumRequestStatus
|
||||
onSuccess: () => void
|
||||
onError: () => void
|
||||
Success: React.ReactNode
|
||||
Error: React.ReactNode
|
||||
}) => {
|
||||
const theme: Theme = useTheme()
|
||||
return (
|
||||
@@ -26,8 +26,8 @@ export const RequestStatus = ({
|
||||
<CircularProgress size={48} />
|
||||
</div>
|
||||
)}
|
||||
{status === EnumRequestStatus.success && onSuccess()}
|
||||
{status === EnumRequestStatus.error && onError()}
|
||||
{status === EnumRequestStatus.success && Success}
|
||||
{status === EnumRequestStatus.error && Error}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ import React, { useState } from 'react'
|
||||
import { Button, Theme } from '@material-ui/core'
|
||||
import { Alert } from '@material-ui/lab'
|
||||
import { useTheme } from '@material-ui/styles'
|
||||
import { BondForm } from './BondForm'
|
||||
import { NymCard } from '../../components'
|
||||
import {
|
||||
EnumRequestStatus,
|
||||
RequestStatus,
|
||||
} from '../../components/RequestStatus'
|
||||
import { Layout } from '../../layouts'
|
||||
import { BondForm } from './BondForm'
|
||||
|
||||
export const Bond = () => {
|
||||
const [status, setStatus] = useState(EnumRequestStatus.initial)
|
||||
@@ -36,14 +36,14 @@ export const Bond = () => {
|
||||
<>
|
||||
<RequestStatus
|
||||
status={status}
|
||||
onSuccess={() => (
|
||||
Success={
|
||||
<Alert severity="success">Successfully bonded node</Alert>
|
||||
)}
|
||||
onError={() => (
|
||||
}
|
||||
Error={
|
||||
<Alert severity="error">
|
||||
An error occurred with the request: {message}
|
||||
</Alert>
|
||||
)}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
Button,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
@@ -40,7 +41,7 @@ export const DelegateForm = ({
|
||||
setValue,
|
||||
watch,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<TDelegateForm>({
|
||||
defaultValues,
|
||||
resolver: yupResolver(validationSchema),
|
||||
@@ -48,8 +49,8 @@ export const DelegateForm = ({
|
||||
|
||||
const watchNodeType = watch('nodeType', defaultValues.nodeType)
|
||||
|
||||
const onSubmit = (data: TDelegateForm) => {
|
||||
invoke('delegate_to_mixnode', {
|
||||
const onSubmit = async (data: TDelegateForm) => {
|
||||
await invoke('delegate_to_mixnode', {
|
||||
identity: data.identity,
|
||||
amount: { denom: 'punk', amount: data.amount },
|
||||
})
|
||||
@@ -119,10 +120,12 @@ export const DelegateForm = ({
|
||||
>
|
||||
<Button
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
disabled={isSubmitting}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disableElevation
|
||||
endIcon={isSubmitting && <CircularProgress size={20} />}
|
||||
>
|
||||
Delegate stake
|
||||
</Button>
|
||||
|
||||
@@ -31,8 +31,9 @@ export const Delegate = () => {
|
||||
setStatus(EnumRequestStatus.error)
|
||||
setMessage(message)
|
||||
}}
|
||||
onSuccess={() => {
|
||||
onSuccess={(message?: string) => {
|
||||
setStatus(EnumRequestStatus.success)
|
||||
setMessage(message)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -40,12 +41,12 @@ export const Delegate = () => {
|
||||
<>
|
||||
<RequestStatus
|
||||
status={status}
|
||||
onError={() => (
|
||||
Error={
|
||||
<Alert severity="error">
|
||||
An error occurred with the request: {message}
|
||||
</Alert>
|
||||
)}
|
||||
onSuccess={() => {}}
|
||||
}
|
||||
Success={<Alert severity="success">{message}</Alert>}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -17,7 +17,9 @@ import { ClientContext } from '../context/main'
|
||||
import { TClientDetails } from '../types/global'
|
||||
|
||||
export const SignIn = () => {
|
||||
const [mnemonic, setMnemonic] = useState<string>('')
|
||||
const [mnemonic, setMnemonic] = useState<string>(
|
||||
'alley mutual arrange escape army vacuum cherry ozone frame steel current smile dad subject primary foster lazy want perfect fury general eye cannon motor'
|
||||
)
|
||||
const [inputError, setInputError] = useState<string | undefined>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
|
||||
@@ -1,78 +1,111 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Alert } from '@material-ui/lab'
|
||||
import { Button, Grid, TextField, Theme } from '@material-ui/core'
|
||||
import { useGetBalance } from '../../hooks/useGetBalance'
|
||||
import React from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import {
|
||||
Button,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
Grid,
|
||||
TextField,
|
||||
Theme,
|
||||
} from '@material-ui/core'
|
||||
import { useTheme } from '@material-ui/styles'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
import { validationSchema } from './validationSchema'
|
||||
import { NodeTypeSelector } from '../../components/NodeTypeSelector'
|
||||
import { EnumNodeType } from '../../types/global'
|
||||
import { useTheme } from '@material-ui/styles'
|
||||
|
||||
export const UndelegateForm = () => {
|
||||
const [isValidAmount, setIsValidAmount] = useState(true)
|
||||
const [validIdentity, setValidIdentity] = useState(true)
|
||||
const [allocationWarning, setAllocationWarning] = useState<string>()
|
||||
const [nodeType, setNodeType] = useState(EnumNodeType.Mixnode)
|
||||
type TFormData = {
|
||||
nodeType: EnumNodeType
|
||||
identity: string
|
||||
}
|
||||
|
||||
const defaultValues = {
|
||||
nodeType: EnumNodeType.Mixnode,
|
||||
identity: '',
|
||||
}
|
||||
|
||||
export const UndelegateForm = ({
|
||||
onError,
|
||||
onSuccess,
|
||||
}: {
|
||||
onError: (message?: string) => void
|
||||
onSuccess: (message?: string) => void
|
||||
}) => {
|
||||
const {
|
||||
handleSubmit,
|
||||
register,
|
||||
setValue,
|
||||
watch,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<TFormData>({
|
||||
defaultValues,
|
||||
resolver: yupResolver(validationSchema),
|
||||
})
|
||||
const watchNodeType = watch('nodeType')
|
||||
|
||||
const onSubmit = async (data: TFormData) => {
|
||||
await invoke('undelegate_from_mixnode', { identity: data.identity })
|
||||
.then((res: any) => onSuccess(res))
|
||||
.catch((e) => onError(e))
|
||||
}
|
||||
|
||||
const { getBalance, accountBalance } = useGetBalance()
|
||||
const theme: Theme = useTheme()
|
||||
|
||||
const handleAmountChange = (event: any) => {
|
||||
// don't ask me about that. javascript works in mysterious ways
|
||||
// and this is apparently a good way of checking if string
|
||||
// is purely made of numeric characters
|
||||
const parsed = +event.target.value
|
||||
|
||||
if (isNaN(parsed)) {
|
||||
setIsValidAmount(false)
|
||||
} else {
|
||||
try {
|
||||
const allocationCheck = { error: undefined, message: '' }
|
||||
if (allocationCheck.error) {
|
||||
setAllocationWarning(allocationCheck.message)
|
||||
setIsValidAmount(false)
|
||||
} else {
|
||||
setAllocationWarning(allocationCheck.message)
|
||||
setIsValidAmount(true)
|
||||
}
|
||||
} catch {
|
||||
setIsValidAmount(false)
|
||||
}
|
||||
}
|
||||
// const parsed = +event.target.value
|
||||
// if (isNaN(parsed)) {
|
||||
// setIsValidAmount(false)
|
||||
// } else {
|
||||
// try {
|
||||
// const allocationCheck = { error: undefined, message: '' }
|
||||
// if (allocationCheck.error) {
|
||||
// setAllocationWarning(allocationCheck.message)
|
||||
// setIsValidAmount(false)
|
||||
// } else {
|
||||
// setAllocationWarning(allocationCheck.message)
|
||||
// setIsValidAmount(true)
|
||||
// }
|
||||
// } catch {
|
||||
// setIsValidAmount(false)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={() => {}}>
|
||||
<FormControl fullWidth>
|
||||
<div style={{ padding: theme.spacing(3, 5) }}>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item xs={12}>
|
||||
<NodeTypeSelector
|
||||
nodeType={nodeType}
|
||||
setNodeType={(nodeType) => setNodeType(nodeType)}
|
||||
nodeType={watchNodeType}
|
||||
setNodeType={(nodeType) => setValue('nodeType', nodeType)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
{...register('identity')}
|
||||
required
|
||||
variant="outlined"
|
||||
id="identity"
|
||||
name="identity"
|
||||
label="Node identity"
|
||||
error={!validIdentity}
|
||||
helperText={
|
||||
validIdentity
|
||||
? ''
|
||||
: "Please enter a valid identity like '824WyExLUWvLE2mpSHBatN4AoByuLzfnHFeHWiBYzg4z'"
|
||||
}
|
||||
error={!!errors.identity}
|
||||
helperText={errors.identity?.message}
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{allocationWarning && (
|
||||
{/* {allocationWarning && (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<Alert severity={!isValidAmount ? 'error' : 'info'}>
|
||||
{allocationWarning}
|
||||
</Alert>
|
||||
</Grid>
|
||||
)}
|
||||
)} */}
|
||||
</Grid>
|
||||
</div>
|
||||
<div
|
||||
@@ -86,15 +119,17 @@ export const UndelegateForm = () => {
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={!isValidAmount}
|
||||
disableElevation
|
||||
disabled={isSubmitting}
|
||||
endIcon={isSubmitting && <CircularProgress size={20} />}
|
||||
>
|
||||
Undelegate stake
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { NymCard } from '../../components'
|
||||
import { UndelegateForm } from './UndelegateForm'
|
||||
import { Layout } from '../../layouts'
|
||||
import {
|
||||
EnumRequestStatus,
|
||||
RequestStatus,
|
||||
} from '../../components/RequestStatus'
|
||||
import { Alert } from '@material-ui/lab'
|
||||
|
||||
export const Undelegate = () => {
|
||||
const [message, setMessage] = useState<string>()
|
||||
const [status, setStaus] = useState<EnumRequestStatus>(
|
||||
EnumRequestStatus.initial
|
||||
)
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<NymCard
|
||||
@@ -11,7 +21,31 @@ export const Undelegate = () => {
|
||||
subheader="Undelegate from a mixnode or gateway"
|
||||
noPadding
|
||||
>
|
||||
<UndelegateForm />
|
||||
<>
|
||||
{status === EnumRequestStatus.initial && (
|
||||
<UndelegateForm
|
||||
onError={(message) => {
|
||||
setMessage(message)
|
||||
setStaus(EnumRequestStatus.error)
|
||||
}}
|
||||
onSuccess={(message) => {
|
||||
setMessage(message)
|
||||
setStaus(EnumRequestStatus.success)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{status !== EnumRequestStatus.initial && (
|
||||
<RequestStatus
|
||||
status={status}
|
||||
Error={
|
||||
<Alert severity="error">
|
||||
An error occurred with the request: {message}
|
||||
</Alert>
|
||||
}
|
||||
Success={<Alert severity="success">{message}</Alert>}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</NymCard>
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import * as Yup from 'yup'
|
||||
import { validateKey } from '../../utils'
|
||||
|
||||
export const validationSchema = Yup.object().shape({
|
||||
identity: Yup.string()
|
||||
.required()
|
||||
.test('valid-id-key', 'A valid identity key is required', function (value) {
|
||||
return validateKey(value || '')
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user