-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
590 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
nym-wallet/src/components/Bonding/forms/nym-node/FormContext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { createContext, useContext, useState } from 'react'; | ||
import { CurrencyDenom } from '@nymproject/types'; | ||
import { TBondNymNodeArgs, TBondMixNodeArgs } from 'src/types'; | ||
|
||
const defaultNymNodeValues: TBondNymNodeArgs['nymNode'] = { | ||
identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9', | ||
custom_http_port: 1, | ||
host: '1.1.1.1', | ||
}; | ||
|
||
const defaultCostParams = (denom: CurrencyDenom): TBondNymNodeArgs['costParams'] => ({ | ||
interval_operating_cost: { amount: '40', denom }, | ||
profit_margin_percent: '10', | ||
}); | ||
|
||
const defaultAmount = (denom: CurrencyDenom): TBondMixNodeArgs['pledge'] => ({ | ||
amount: '100', | ||
denom, | ||
}); | ||
|
||
interface FormContextType { | ||
step: 1 | 2 | 3 | 4; | ||
setStep: React.Dispatch<React.SetStateAction<1 | 2 | 3 | 4>>; | ||
nymNodeData: TBondNymNodeArgs['nymNode']; | ||
setNymNodeData: React.Dispatch<React.SetStateAction<TBondNymNodeArgs['nymNode']>>; | ||
costParams: TBondNymNodeArgs['costParams']; | ||
setCostParams: React.Dispatch<React.SetStateAction<TBondNymNodeArgs['costParams']>>; | ||
amountData: TBondMixNodeArgs['pledge']; | ||
setAmountData: React.Dispatch<React.SetStateAction<TBondMixNodeArgs['pledge']>>; | ||
signature?: string; | ||
setSignature: React.Dispatch<React.SetStateAction<string | undefined>>; | ||
onError: (e: string) => void; | ||
} | ||
|
||
const FormContext = createContext<FormContextType>({ | ||
step: 1, | ||
setStep: () => {}, | ||
nymNodeData: defaultNymNodeValues, | ||
setNymNodeData: () => {}, | ||
costParams: defaultCostParams('nym'), | ||
setCostParams: () => {}, | ||
amountData: defaultAmount('nym'), | ||
setAmountData: () => {}, | ||
signature: undefined, | ||
setSignature: () => {}, | ||
|
||
onError: (e: string) => {}, | ||
}); | ||
|
||
const FormContextProvider = ({ children }: { children: React.ReactNode }) => { | ||
// TODO - Make denom dynamic | ||
const denom = 'nym'; | ||
|
||
const [step, setStep] = useState<1 | 2 | 3 | 4>(1); | ||
const [nymNodeData, setNymNodeData] = useState<TBondNymNodeArgs['nymNode']>(defaultNymNodeValues); | ||
const [costParams, setCostParams] = useState<TBondNymNodeArgs['costParams']>(defaultCostParams(denom)); | ||
const [amountData, setAmountData] = useState<TBondNymNodeArgs['pledge']>(defaultAmount(denom)); | ||
const [signature, setSignature] = useState<string>(); | ||
|
||
const onError = (e: string) => { | ||
console.error(e); | ||
}; | ||
|
||
return ( | ||
<FormContext.Provider | ||
value={{ | ||
step, | ||
setStep, | ||
nymNodeData, | ||
setNymNodeData, | ||
costParams, | ||
setCostParams, | ||
amountData, | ||
setAmountData, | ||
signature, | ||
setSignature, | ||
onError, | ||
}} | ||
> | ||
{children} | ||
</FormContext.Provider> | ||
); | ||
}; | ||
|
||
export const useFormContext = () => useContext(FormContext); | ||
|
||
export default FormContextProvider; |
119 changes: 119 additions & 0 deletions
119
nym-wallet/src/components/Bonding/forms/nym-node/NymNodeAmount.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { Stack, TextField, Box, FormHelperText } from '@mui/material'; | ||
import { useForm } from 'react-hook-form'; | ||
import { TBondNymNodeArgs } from 'src/types'; | ||
import { yupResolver } from '@hookform/resolvers/yup'; | ||
import { SimpleModal } from 'src/components/Modals/SimpleModal'; | ||
import { nymNodeAmountSchema } from './amountValidationSchema'; | ||
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'; | ||
import { checkHasEnoughFunds } from 'src/utils'; | ||
|
||
const defaultNymNodeCostParamValues: TBondNymNodeArgs['costParams'] = { | ||
profit_margin_percent: '10', | ||
interval_operating_cost: { amount: '40', denom: 'nym' }, | ||
}; | ||
|
||
const defaultNymNodePledgeValue: TBondNymNodeArgs['pledge'] = { | ||
amount: '100', | ||
denom: 'nym', | ||
}; | ||
|
||
type NymNodeDataProps = { | ||
onClose: () => void; | ||
onBack: () => void; | ||
onNext: () => Promise<void>; | ||
step: number; | ||
}; | ||
|
||
const NymNodeAmount = ({ onClose, onBack, onNext, step }: NymNodeDataProps) => { | ||
const { | ||
formState: { errors }, | ||
register, | ||
getValues, | ||
setValue, | ||
setError, | ||
handleSubmit, | ||
} = useForm({ | ||
mode: 'all', | ||
defaultValues: { | ||
pledge: defaultNymNodePledgeValue, | ||
...defaultNymNodeCostParamValues, | ||
}, | ||
resolver: yupResolver(nymNodeAmountSchema()), | ||
}); | ||
|
||
console.log(errors, 'errors'); | ||
|
||
const handleRequestValidation = async () => { | ||
const values = getValues(); | ||
|
||
const hasSufficientTokens = await checkHasEnoughFunds(values.pledge.amount); | ||
|
||
if (hasSufficientTokens) { | ||
handleSubmit(onNext)(); | ||
} else { | ||
setError('pledge.amount', { message: 'Not enough tokens' }); | ||
} | ||
}; | ||
|
||
return ( | ||
<SimpleModal | ||
open | ||
onOk={handleRequestValidation} | ||
onClose={onClose} | ||
header="Bond Nym Node" | ||
subHeader={`Step ${step}/3`} | ||
okLabel="Next" | ||
onBack={onBack} | ||
okDisabled={Object.keys(errors).length > 0} | ||
> | ||
<Stack gap={3}> | ||
<CurrencyFormField | ||
required | ||
fullWidth | ||
label="Amount" | ||
autoFocus | ||
onChanged={(newValue) => { | ||
setValue('pledge.amount', newValue.amount, { shouldValidate: true }); | ||
}} | ||
validationError={errors.pledge?.amount?.message} | ||
denom={defaultNymNodePledgeValue.denom} | ||
initialValue={defaultNymNodePledgeValue.amount} | ||
/> | ||
|
||
<Box> | ||
<CurrencyFormField | ||
required | ||
fullWidth | ||
label="Operating cost" | ||
onChanged={(newValue) => { | ||
setValue('interval_operating_cost', newValue, { shouldValidate: true }); | ||
}} | ||
validationError={errors.interval_operating_cost?.amount?.message} | ||
denom={defaultNymNodeCostParamValues.interval_operating_cost.denom} | ||
initialValue={defaultNymNodeCostParamValues.interval_operating_cost.amount} | ||
/> | ||
<FormHelperText> | ||
Monthly operational costs of running your node. If your node is in the active set the amount will be paid | ||
back to you from the rewards. | ||
</FormHelperText> | ||
</Box> | ||
<Box> | ||
<TextField | ||
{...register('profit_margin_percent')} | ||
name="profit_margin_percent" | ||
label="Profit margin" | ||
error={Boolean(errors.profit_margin_percent)} | ||
helperText={errors.profit_margin_percent?.message} | ||
fullWidth | ||
/> | ||
<FormHelperText> | ||
The percentage of node rewards that you as the node operator take before rewards are distributed to operator | ||
and delegators. | ||
</FormHelperText> | ||
</Box> | ||
</Stack> | ||
</SimpleModal> | ||
); | ||
}; | ||
|
||
export default NymNodeAmount; |
113 changes: 113 additions & 0 deletions
113
nym-wallet/src/components/Bonding/forms/nym-node/NymNodeData.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React from 'react'; | ||
import { Stack, TextField, FormControlLabel, Checkbox } from '@mui/material'; | ||
import { useForm } from 'react-hook-form'; | ||
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; | ||
import { TBondNymNodeArgs } from 'src/types'; | ||
import { useFormContext } from './FormContext'; | ||
import { yupResolver } from '@hookform/resolvers/yup'; | ||
import * as yup from 'yup'; | ||
import { isValidHostname, validateRawPort } from 'src/utils'; | ||
import { SimpleModal } from 'src/components/Modals/SimpleModal'; | ||
|
||
const defaultNymNodeValues: TBondNymNodeArgs['nymNode'] = { | ||
identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9', | ||
custom_http_port: 1, | ||
host: '1.1.1.1', | ||
}; | ||
|
||
const yupValidationSchema = yup.object().shape({ | ||
identity_key: yup.string().required('Identity key is required'), | ||
host: yup | ||
.string() | ||
.required('A host is required') | ||
.test('no-whitespace', 'Host cannot contain whitespace', (value) => !/\s/.test(value || '')) | ||
.test('valid-host', 'A valid host is required', (value) => { | ||
return value ? isValidHostname(value) : false; | ||
}), | ||
|
||
custom_http_port: yup | ||
.number() | ||
.required('A custom http port is required') | ||
.test('valid-http', 'A valid http port is required', (value) => (value ? validateRawPort(value) : false)), | ||
}); | ||
|
||
type NymNodeDataProps = { | ||
onClose: () => void; | ||
onBack: () => void; | ||
onNext: () => Promise<void>; | ||
step: number; | ||
}; | ||
|
||
const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => { | ||
const { | ||
formState: { errors }, | ||
register, | ||
setValue, | ||
handleSubmit, | ||
} = useForm({ | ||
mode: 'all', | ||
defaultValues: defaultNymNodeValues, | ||
resolver: yupResolver(yupValidationSchema), | ||
}); | ||
|
||
const [showAdvancedOptions, setShowAdvancedOptions] = React.useState(false); | ||
|
||
const handleNext = async () => { | ||
handleSubmit(onNext)(); | ||
}; | ||
|
||
return ( | ||
<SimpleModal | ||
open | ||
onOk={handleNext} | ||
onClose={onClose} | ||
header="Bond Nym Node" | ||
subHeader={`Step ${step}/3`} | ||
okLabel="Next" | ||
okDisabled={Object.keys(errors).length > 0} | ||
> | ||
<Stack gap={3}> | ||
<IdentityKeyFormField | ||
autoFocus | ||
required | ||
fullWidth | ||
label="Identity Key" | ||
initialValue={defaultNymNodeValues.identity_key} | ||
errorText={errors.identity_key?.message?.toString()} | ||
onChanged={(value) => setValue('identity_key', value, { shouldValidate: true })} | ||
showTickOnValid={false} | ||
/> | ||
|
||
<TextField | ||
{...register('host')} | ||
name="host" | ||
label="Host" | ||
error={Boolean(errors.host)} | ||
helperText={errors.host?.message} | ||
required | ||
InputLabelProps={{ shrink: true }} | ||
/> | ||
|
||
<FormControlLabel | ||
control={<Checkbox onChange={() => setShowAdvancedOptions((show) => !show)} checked={showAdvancedOptions} />} | ||
label="Show advanced options" | ||
/> | ||
{showAdvancedOptions && ( | ||
<Stack direction="row" gap={3} sx={{ mb: 2 }}> | ||
<TextField | ||
{...register('custom_http_port')} | ||
name="custom_http_port" | ||
label="Custom HTTP port" | ||
error={Boolean(errors.custom_http_port)} | ||
helperText={errors.custom_http_port?.message} | ||
fullWidth | ||
InputLabelProps={{ shrink: true }} | ||
/> | ||
</Stack> | ||
)} | ||
</Stack> | ||
</SimpleModal> | ||
); | ||
}; | ||
|
||
export default NymNodeData; |
Oops, something went wrong.