SetCouncilParamsForm.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import React, { useEffect, useState } from 'react';
  2. import { getFormErrorLabelsProps } from './errorHandling';
  3. import { Divider, Form } from 'semantic-ui-react';
  4. import * as Yup from 'yup';
  5. import {
  6. GenericProposalForm,
  7. GenericFormValues,
  8. genericFormDefaultOptions,
  9. genericFormDefaultValues,
  10. withProposalFormData,
  11. ProposalFormExportProps,
  12. ProposalFormContainerProps,
  13. ProposalFormInnerProps
  14. } from './GenericProposalForm';
  15. import Validation from '../validationSchema';
  16. import { InputFormField } from './FormFields';
  17. import { withFormContainer } from './FormContainer';
  18. import { createType } from '@polkadot/types';
  19. import './forms.css';
  20. import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks';
  21. import _ from 'lodash';
  22. import { ElectionParameters } from '@joystream/types/council';
  23. import { PromiseComponent } from '@polkadot/joy-utils/react/components';
  24. export type FormValues = GenericFormValues & {
  25. announcingPeriod: string;
  26. votingPeriod: string;
  27. minVotingStake: string;
  28. revealingPeriod: string;
  29. minCouncilStake: string;
  30. newTermDuration: string;
  31. candidacyLimit: string;
  32. councilSize: string;
  33. };
  34. const defaultValues: FormValues = {
  35. ...genericFormDefaultValues,
  36. announcingPeriod: '',
  37. votingPeriod: '',
  38. minVotingStake: '',
  39. revealingPeriod: '',
  40. minCouncilStake: '',
  41. newTermDuration: '',
  42. candidacyLimit: '',
  43. councilSize: ''
  44. };
  45. type FormAdditionalProps = {}; // Aditional props coming all the way from export comonent into the inner form.
  46. type ExportComponentProps = ProposalFormExportProps<FormAdditionalProps, FormValues>;
  47. type FormContainerProps = ProposalFormContainerProps<ExportComponentProps>;
  48. type FormInnerProps = ProposalFormInnerProps<FormContainerProps, FormValues>;
  49. function createElectionParameters (values: FormValues): ElectionParameters {
  50. return new ElectionParameters({
  51. announcing_period: createType('BlockNumber', parseInt(values.announcingPeriod)),
  52. voting_period: createType('BlockNumber', parseInt(values.votingPeriod)),
  53. revealing_period: createType('BlockNumber', parseInt(values.revealingPeriod)),
  54. council_size: createType('u32', values.councilSize),
  55. candidacy_limit: createType('u32', values.candidacyLimit),
  56. new_term_duration: createType('BlockNumber', parseInt(values.newTermDuration)),
  57. min_council_stake: createType('Balance', values.minCouncilStake),
  58. min_voting_stake: createType('Balance', values.minVotingStake)
  59. });
  60. }
  61. const SetCouncilParamsForm: React.FunctionComponent<FormInnerProps> = props => {
  62. const { handleChange, errors, touched, values, setFieldValue, setFieldError } = props;
  63. const errorLabelsProps = getFormErrorLabelsProps<FormValues>(errors, touched);
  64. const [placeholders, setPlaceholders] = useState<{ [k in keyof FormValues]: string }>(defaultValues);
  65. const transport = useTransport();
  66. const [councilParams, error, loading] = usePromise<ElectionParameters | null>(() => transport.council.electionParameters(), null);
  67. useEffect(() => {
  68. if (councilParams) {
  69. const fetchedPlaceholders = { ...placeholders };
  70. const fieldsToPopulate = [
  71. 'announcing_period',
  72. 'voting_period',
  73. 'min_voting_stake',
  74. 'revealing_period',
  75. 'min_council_stake',
  76. 'new_term_duration',
  77. 'candidacy_limit',
  78. 'council_size'
  79. ] as const;
  80. fieldsToPopulate.forEach(field => {
  81. const camelCaseField = _.camelCase(field) as keyof FormValues;
  82. setFieldValue(camelCaseField, councilParams[field].toString());
  83. fetchedPlaceholders[camelCaseField] = councilParams[field].toString();
  84. });
  85. setPlaceholders(fetchedPlaceholders);
  86. }
  87. }, [councilParams]);
  88. // This logic may be moved somewhere else in the future, but it's quite easy to enforce it here:
  89. if (!errors.candidacyLimit && !errors.councilSize && parseInt(values.candidacyLimit) < parseInt(values.councilSize)) {
  90. setFieldError('candidacyLimit', `Candidacy limit must be >= council size (${values.councilSize})`);
  91. }
  92. return (
  93. <PromiseComponent error={error} loading={loading} message="Fetching current parameters...">
  94. <GenericProposalForm
  95. {...props}
  96. txMethod="createSetElectionParametersProposal"
  97. proposalType="SetElectionParameters"
  98. submitParams={[props.myMemberId, values.title, values.rationale, '{STAKE}', createElectionParameters(values)]}
  99. >
  100. <Divider horizontal>Voting </Divider>
  101. <Form.Group widths="equal" style={{ marginBottom: '8rem' }}>
  102. <InputFormField
  103. label="Announcing Period"
  104. help="Announcing period in blocks"
  105. onChange={handleChange}
  106. name="announcingPeriod"
  107. error={errorLabelsProps.announcingPeriod}
  108. value={values.announcingPeriod}
  109. placeholder={ placeholders.announcingPeriod }
  110. />
  111. <InputFormField
  112. label="Voting Period"
  113. help="Voting period in blocks"
  114. onChange={handleChange}
  115. name="votingPeriod"
  116. error={errorLabelsProps.votingPeriod}
  117. value={values.votingPeriod}
  118. placeholder={ placeholders.votingPeriod }
  119. />
  120. <InputFormField
  121. label="Revealing Period"
  122. help="Revealing period in blocks"
  123. fluid
  124. onChange={handleChange}
  125. name="revealingPeriod"
  126. error={errorLabelsProps.revealingPeriod}
  127. value={values.revealingPeriod}
  128. placeholder={ placeholders.revealingPeriod }
  129. />
  130. <InputFormField
  131. label="Minimum Voting Stake"
  132. help="The minimum voting stake"
  133. fluid
  134. onChange={handleChange}
  135. name="minVotingStake"
  136. error={errorLabelsProps.minVotingStake}
  137. value={values.minVotingStake}
  138. placeholder={ placeholders.minVotingStake }
  139. disabled
  140. />
  141. </Form.Group>
  142. <Divider horizontal>Council</Divider>
  143. <Form.Group widths="equal" style={{ marginBottom: '8rem' }}>
  144. <InputFormField
  145. label="Minimum Council Stake"
  146. help="The minimum council stake"
  147. fluid
  148. onChange={handleChange}
  149. name="minCouncilStake"
  150. error={errorLabelsProps.minCouncilStake}
  151. value={values.minCouncilStake}
  152. placeholder={ placeholders.minCouncilStake }
  153. disabled
  154. />
  155. <InputFormField
  156. label="New Term Duration"
  157. help="Duration of the new term in blocks"
  158. fluid
  159. onChange={handleChange}
  160. name="newTermDuration"
  161. error={errorLabelsProps.newTermDuration}
  162. value={values.newTermDuration}
  163. placeholder={ placeholders.newTermDuration }
  164. />
  165. <InputFormField
  166. label="Council Size"
  167. help="The size of the council (number of seats)"
  168. fluid
  169. onChange={handleChange}
  170. name="councilSize"
  171. error={errorLabelsProps.councilSize}
  172. value={values.councilSize}
  173. placeholder={ placeholders.councilSize }
  174. />
  175. <InputFormField
  176. label="Candidacy Limit"
  177. help="How many candidates that will be allowed in to the voting stage"
  178. fluid
  179. onChange={handleChange}
  180. name="candidacyLimit"
  181. error={errorLabelsProps.candidacyLimit}
  182. value={values.candidacyLimit}
  183. placeholder={ placeholders.candidacyLimit }
  184. />
  185. </Form.Group>
  186. </GenericProposalForm>
  187. </PromiseComponent>
  188. );
  189. };
  190. const FormContainer = withFormContainer<FormContainerProps, FormValues>({
  191. mapPropsToValues: (props: FormContainerProps) => ({
  192. ...defaultValues,
  193. ...(props.initialData || {})
  194. }),
  195. validationSchema: Yup.object().shape({
  196. ...genericFormDefaultOptions.validationSchema,
  197. ...Validation.SetElectionParameters()
  198. }),
  199. handleSubmit: genericFormDefaultOptions.handleSubmit,
  200. displayName: 'SetCouncilParamsForm'
  201. })(SetCouncilParamsForm);
  202. export default withProposalFormData<FormContainerProps, ExportComponentProps>(FormContainer);