Compare commits

...

2 Commits

Author SHA1 Message Date
Mark Sinclair d0462eb4ad Add URL to operator T&Cs to default memos used during bonding for wallet and CLI 2024-05-29 17:15:17 +01:00
Mark Sinclair fef2e1afd0 nym-wallet: add checkbox to accept T&Cs for operators 2024-05-29 17:14:49 +01:00
5 changed files with 70 additions and 6 deletions
@@ -324,10 +324,10 @@ impl ExecuteMsg {
ExecuteMsg::AdvanceCurrentEpoch { .. } => "advancing current epoch".into(), ExecuteMsg::AdvanceCurrentEpoch { .. } => "advancing current epoch".into(),
ExecuteMsg::ReconcileEpochEvents { .. } => "reconciling epoch events".into(), ExecuteMsg::ReconcileEpochEvents { .. } => "reconciling epoch events".into(),
ExecuteMsg::BondMixnode { mix_node, .. } => { ExecuteMsg::BondMixnode { mix_node, .. } => {
format!("bonding mixnode {}", mix_node.identity_key) format!("bonding mixnode {}, accepted https://nymtech.net/terms-and-conditions/operators/v1.0.0", mix_node.identity_key)
} }
ExecuteMsg::BondMixnodeOnBehalf { mix_node, .. } => { ExecuteMsg::BondMixnodeOnBehalf { mix_node, .. } => {
format!("bonding mixnode {} on behalf", mix_node.identity_key) format!("bonding mixnode {} on behalf, accepted https://nymtech.net/terms-and-conditions/operators/v1.0.0", mix_node.identity_key)
} }
ExecuteMsg::PledgeMore {} => "pledging additional tokens".into(), ExecuteMsg::PledgeMore {} => "pledging additional tokens".into(),
ExecuteMsg::PledgeMoreOnBehalf { .. } => "pledging additional tokens on behalf".into(), ExecuteMsg::PledgeMoreOnBehalf { .. } => "pledging additional tokens on behalf".into(),
@@ -346,10 +346,10 @@ impl ExecuteMsg {
"updating mixnode configuration on behalf".into() "updating mixnode configuration on behalf".into()
} }
ExecuteMsg::BondGateway { gateway, .. } => { ExecuteMsg::BondGateway { gateway, .. } => {
format!("bonding gateway {}", gateway.identity_key) format!("bonding gateway {}, accepted https://nymtech.net/terms-and-conditions/operators/v1.0.0", gateway.identity_key)
} }
ExecuteMsg::BondGatewayOnBehalf { gateway, .. } => { ExecuteMsg::BondGatewayOnBehalf { gateway, .. } => {
format!("bonding gateway {} on behalf", gateway.identity_key) format!("bonding gateway {} on behalf, accepted https://nymtech.net/terms-and-conditions/operators/v1.0.0", gateway.identity_key)
} }
ExecuteMsg::UnbondGateway { .. } => "unbonding gateway".into(), ExecuteMsg::UnbondGateway { .. } => "unbonding gateway".into(),
ExecuteMsg::UnbondGatewayOnBehalf { .. } => "unbonding gateway on behalf".into(), ExecuteMsg::UnbondGatewayOnBehalf { .. } => "unbonding gateway on behalf".into(),
@@ -6,6 +6,7 @@ import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyForm
import { yupResolver } from '@hookform/resolvers/yup/dist/yup'; import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
import { GatewayData } from '../../../pages/bonding/types'; import { GatewayData } from '../../../pages/bonding/types';
import { gatewayValidationSchema } from './gatewayValidationSchema'; import { gatewayValidationSchema } from './gatewayValidationSchema';
import { TermsAndConditions, TermsAndConditionsHelp } from './TermsAndConditions';
const GatewayInitForm = ({ const GatewayInitForm = ({
gatewayData, gatewayData,
@@ -21,6 +22,7 @@ const GatewayInitForm = ({
formState: { errors }, formState: { errors },
handleSubmit, handleSubmit,
setValue, setValue,
setError,
} = useForm({ resolver: yupResolver(gatewayValidationSchema), defaultValues: gatewayData }); } = useForm({ resolver: yupResolver(gatewayValidationSchema), defaultValues: gatewayData });
const handleRequestValidation = (event: { detail: { step: number } }) => { const handleRequestValidation = (event: { detail: { step: number } }) => {
@@ -30,7 +32,11 @@ const GatewayInitForm = ({
...data, ...data,
version: clean(data.version) as string, version: clean(data.version) as string,
}; };
onNext(validatedData); if (!validatedData.acceptedTermsAndConditions) {
setError('acceptedTermsAndConditions', { message: 'You must accept the terms and conditions' });
} else {
onNext(validatedData);
}
})(); })();
} }
}; };
@@ -117,6 +123,17 @@ const GatewayInitForm = ({
/> />
</Stack> </Stack>
)} )}
<FormControlLabel
{...register('acceptedTermsAndConditions')}
name="acceptedTermsAndConditions"
required
control={<Checkbox />}
label={<TermsAndConditions error={Boolean(errors.acceptedTermsAndConditions)} />}
/>
<TermsAndConditionsHelp
error={Boolean(errors.acceptedTermsAndConditions)}
helperText={errors.acceptedTermsAndConditions?.message}
/>
</Stack> </Stack>
); );
}; };
@@ -6,6 +6,7 @@ import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyForm
import { yupResolver } from '@hookform/resolvers/yup/dist/yup'; import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
import { mixnodeValidationSchema } from './mixnodeValidationSchema'; import { mixnodeValidationSchema } from './mixnodeValidationSchema';
import { MixnodeData } from '../../../pages/bonding/types'; import { MixnodeData } from '../../../pages/bonding/types';
import { TermsAndConditions, TermsAndConditionsHelp } from './TermsAndConditions';
const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; onNext: (data: any) => void }) => { const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; onNext: (data: any) => void }) => {
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false); const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
@@ -15,6 +16,7 @@ const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; on
formState: { errors }, formState: { errors },
handleSubmit, handleSubmit,
setValue, setValue,
setError,
} = useForm({ resolver: yupResolver(mixnodeValidationSchema), defaultValues: mixnodeData }); } = useForm({ resolver: yupResolver(mixnodeValidationSchema), defaultValues: mixnodeData });
const handleRequestValidation = (event: { detail: { step: number } }) => { const handleRequestValidation = (event: { detail: { step: number } }) => {
@@ -24,7 +26,11 @@ const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; on
...data, ...data,
version: clean(data.version), version: clean(data.version),
}; };
onNext(validatedData); if (!validatedData.acceptedTermsAndConditions) {
setError('acceptedTermsAndConditions', { message: 'You must accept the terms and conditions' });
} else {
onNext(validatedData);
}
})(); })();
} }
}; };
@@ -110,6 +116,17 @@ const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; on
/> />
</Stack> </Stack>
)} )}
<FormControlLabel
{...register('acceptedTermsAndConditions')}
name="acceptedTermsAndConditions"
required
control={<Checkbox />}
label={<TermsAndConditions error={Boolean(errors.acceptedTermsAndConditions)} />}
/>
<TermsAndConditionsHelp
error={Boolean(errors.acceptedTermsAndConditions)}
helperText={errors.acceptedTermsAndConditions?.message}
/>
</Stack> </Stack>
); );
}; };
@@ -0,0 +1,29 @@
import React from 'react';
import Typography from '@mui/material/Typography';
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
export const TermsAndConditions: React.FC<{
error?: boolean;
}> = ({ error }) => (
<Typography display="inline" color={(theme) => (error ? theme.palette.error.main : undefined)}>
I agree to the{' '}
<a href="https://nymtech.net/terms-and-conditions/operators/v1.0.0" target="_blank" rel="noreferrer">
operator terms and conditions
</a>
</Typography>
);
export const TermsAndConditionsHelp: React.FC<{
error?: boolean;
helperText?: string;
}> = ({ error, helperText }) => {
if (!error || !helperText) {
return null;
}
return (
<Typography color="error.main" display="flex" alignItems="center">
<WarningAmberIcon sx={{ mr: 1 }} />
{helperText}
</Typography>
);
};
+1
View File
@@ -11,6 +11,7 @@ export type NodeIdentity = {
host: string; host: string;
version: string; version: string;
mixPort: number; mixPort: number;
acceptedTermsAndConditions?: boolean;
}; };
export type MixnodeData = NodeIdentity & { export type MixnodeData = NodeIdentity & {