Modal.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2017-2019 @polkadot/app-contracts authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import { I18nProps } from '@polkadot/react-components/types';
  5. import BN from 'bn.js';
  6. import React from 'react';
  7. import { Abi } from '@polkadot/api-contract';
  8. import { Button, Input, InputAddress, InputNumber, Modal, TxComponent } from '@polkadot/react-components';
  9. import ABI from './ABI';
  10. export interface ContractModalProps extends I18nProps {
  11. basePath: string;
  12. isNew?: boolean;
  13. isOpen: boolean;
  14. onClose?: () => void;
  15. }
  16. export interface ContractModalState {
  17. abi?: string | null;
  18. accountId?: string | null;
  19. contractAbi?: Abi | null;
  20. gasLimit: BN;
  21. isAbiSupplied: boolean;
  22. isAbiValid: boolean;
  23. isBusy: boolean;
  24. isNameValid: boolean;
  25. name?: string | null;
  26. tags: string[];
  27. }
  28. class ContractModal<P extends ContractModalProps, S extends ContractModalState> extends TxComponent<P, S> {
  29. // horrible :(
  30. protected defaultState: S = {
  31. accountId: null,
  32. gasLimit: new BN(0),
  33. isAbiSupplied: false,
  34. isAbiValid: false,
  35. isBusy: false,
  36. isNameValid: false,
  37. name: null,
  38. tags: [] as string[]
  39. } as S;
  40. public state: S = this.defaultState;
  41. protected isContract?: boolean;
  42. public render (): React.ReactNode {
  43. const { isOpen, t } = this.props;
  44. return (
  45. <Modal
  46. className='app--contracts-Modal'
  47. dimmer='inverted'
  48. onClose={this.onClose}
  49. open={isOpen}
  50. >
  51. <Modal.Header>
  52. {t(this.headerText)}
  53. </Modal.Header>
  54. <Modal.Content>
  55. {this.renderContent()}
  56. </Modal.Content>
  57. <Modal.Actions>
  58. {this.renderButtons()}
  59. </Modal.Actions>
  60. </Modal>
  61. );
  62. }
  63. protected headerText = '';
  64. protected renderContent: () => React.ReactNode | null = (): React.ReactNode => null;
  65. protected renderButtons: () => React.ReactNode | null = (): React.ReactNode => null;
  66. protected renderInputAbi (): React.ReactNode {
  67. const { t } = this.props;
  68. const { isBusy } = this.state;
  69. return (
  70. <ABI
  71. help={t(
  72. this.isContract
  73. ? 'The ABI for the WASM code. Since we will be making a call into the code, the ABI is required and stored for future operations such as sending messages.'
  74. : 'The ABI for the WASM code. In this step it is optional, but setting it here simplifies the setup of contract instances.'
  75. )}
  76. label={t(
  77. this.isContract
  78. ? 'contract ABI'
  79. : 'contract ABI (optional)'
  80. )}
  81. onChange={this.onAddAbi}
  82. isDisabled={isBusy}
  83. isRequired={this.isContract}
  84. />
  85. );
  86. }
  87. protected renderInputAccount (): React.ReactNode {
  88. const { t } = this.props;
  89. const { accountId, isBusy } = this.state;
  90. return (
  91. <InputAddress
  92. help={t('Specify the user account to use for this deployment. And fees will be deducted from this account.')}
  93. isDisabled={isBusy}
  94. isInput={false}
  95. label={t('deployment account')}
  96. onChange={this.onChangeAccount}
  97. type='account'
  98. value={accountId}
  99. />
  100. );
  101. }
  102. protected renderInputName (): React.ReactNode {
  103. const { isNew, t } = this.props;
  104. const { isBusy, isNameValid, name } = this.state;
  105. return (
  106. <Input
  107. help={t(
  108. this.isContract
  109. ? 'A name for the deployed contract to help users distinguish. Only used for display purposes.'
  110. : 'A name for this WASM code to help users distinguish. Only used for display purposes.'
  111. )}
  112. isDisabled={isBusy}
  113. isError={!isNameValid}
  114. label={t(
  115. this.isContract
  116. ? 'contract name'
  117. : 'code bundle name'
  118. )}
  119. onChange={this.onChangeName}
  120. onEnter={this[isNew ? 'sendTx' : 'submit']}
  121. value={name || ''}
  122. />
  123. );
  124. }
  125. protected renderInputGas (): React.ReactNode {
  126. const { t } = this.props;
  127. const { gasLimit, isBusy } = this.state;
  128. const isGasValid = !gasLimit.isZero();
  129. return (
  130. <InputNumber
  131. help={t('The maximum amount of gas that can be used by this deployment, if the code requires more, the deployment will fail.')}
  132. isDisabled={isBusy}
  133. isError={!isGasValid}
  134. label={t('maximum gas allowed')}
  135. onChange={this.onChangeGas}
  136. onEnter={this.sendTx}
  137. value={gasLimit || ''}
  138. />
  139. );
  140. }
  141. protected renderCancelButton (): React.ReactNode {
  142. const { t } = this.props;
  143. return (
  144. <>
  145. <Button
  146. icon='cancel'
  147. isNegative
  148. onClick={this.onClose}
  149. label={t('Cancel')}
  150. />
  151. <Button.Or />
  152. </>
  153. );
  154. }
  155. protected reset = (): void => {
  156. this.setState(
  157. this.defaultState
  158. );
  159. }
  160. protected toggleBusy = (isBusy?: boolean): () => void =>
  161. (): void => {
  162. this.setState((state: S): S => {
  163. return {
  164. isBusy: isBusy === undefined ? !state.isBusy : isBusy
  165. } as unknown as S;
  166. });
  167. }
  168. protected onClose = (): void => {
  169. const { onClose } = this.props;
  170. const { isBusy } = this.state;
  171. onClose && onClose();
  172. if (!isBusy) {
  173. this.reset();
  174. }
  175. }
  176. protected onAddAbi = (abi: string | null | undefined, contractAbi: Abi | null = null, isAbiSupplied = false): void => {
  177. this.setState({ abi, contractAbi, isAbiSupplied, isAbiValid: !!abi });
  178. }
  179. protected onChangeAccount = (accountId: string | null): void => {
  180. this.setState({ accountId });
  181. }
  182. protected onChangeName = (name: string): void => {
  183. this.setState({ name, isNameValid: name.length !== 0 });
  184. }
  185. protected onChangeGas = (gasLimit: BN | undefined): void => {
  186. this.setState({ gasLimit: gasLimit || new BN(0) });
  187. }
  188. }
  189. export default ContractModal;