polkadot-js/apps

View on GitHub
packages/page-staking2/src/Pools/Create.tsx

Summary

Maintainability
B
5 hrs
Test Coverage
// Copyright 2017-2024 @polkadot/app-staking authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { BN } from '@polkadot/util';
import type { Params } from './types.js';

import React, { useMemo, useState } from 'react';

import { Button, Input, InputAddress, InputBalance, InputNumber, Modal, TxButton } from '@polkadot/react-components';
import { useApi, useToggle } from '@polkadot/react-hooks';
import { bnMax } from '@polkadot/util';

import { useTranslation } from '../translate.js';
import useAmountError from './useAmountError.js';

interface Props {
  className?: string;
  isDisabled?: boolean;
  ownAccounts?: string[];
  params: Params;
}

const MAX_META_LEN = 32;
const MIN_META_LEN = 3;

function Create ({ className, isDisabled, ownAccounts, params: { minCreateBond, minNominatorBond, nextPoolId } }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const [isOpen, toggleOpen] = useToggle();
  const [accountId, setAccount] = useState<string | null>(null);
  const [amount, setAmount] = useState<BN | undefined>();
  const [metadata, setMetadata] = useState('');

  const minValue = useMemo(
    () => minCreateBond && minNominatorBond &&
      bnMax(minCreateBond, minNominatorBond, api.consts.balances.existentialDeposit),
    [api, minCreateBond, minNominatorBond]
  );

  const isAmountError = useAmountError(accountId, amount, minValue);

  const isMetaError = useMemo(
    () => !metadata || (metadata.length < MIN_META_LEN) || (metadata.length > MAX_META_LEN),
    [metadata]
  );

  const extrinsic = useMemo(
    () => amount && accountId && !isAmountError && nextPoolId
      ? api.tx.utility.batch([
        api.tx.nominationPools.create(amount, accountId, accountId, accountId),
        api.tx.nominationPools.setMetadata(nextPoolId, metadata)
      ])
      : null,
    [api, accountId, amount, isAmountError, metadata, nextPoolId]
  );

  return (
    <>
      <Button
        icon='plus'
        isDisabled={isDisabled || !minValue}
        label={t('Add pool')}
        onClick={toggleOpen}
      />
      {isOpen && (
        <Modal
          className={className}
          header={t('Create nomination pool')}
          onClose={toggleOpen}
          size='large'
        >
          <Modal.Content>
            <Modal.Columns hint={t('The origin account will also be set as the pool admin, nominator and state toggler.')}>
              <InputAddress
                filter={ownAccounts}
                label={t('create pool from')}
                onChange={setAccount}
                type='account'
                value={accountId}
                withExclude
              />
            </Modal.Columns>
            <Modal.Columns hint={t('The initial value to assign to the pool. It is set to the maximum of the minimum bond and the minium nomination value.')}>
              <InputBalance
                autoFocus
                defaultValue={minValue}
                isError={isAmountError}
                label={t('initial value')}
                onChange={setAmount}
              />
            </Modal.Columns>
            <Modal.Columns hint={t('The metadata description to set for this pool')}>
              <Input
                isError={isMetaError}
                label={t('description')}
                maxLength={MAX_META_LEN}
                onChange={setMetadata}
              />
            </Modal.Columns>
            <Modal.Columns hint={t('The id that will be assigned to this nomination pool.')}>
              <InputNumber
                defaultValue={nextPoolId}
                isDisabled
                label={t('pool id')}
              />
            </Modal.Columns>
          </Modal.Content>
          <Modal.Actions>
            <TxButton
              accountId={accountId}
              extrinsic={extrinsic}
              icon='plus'
              isDisabled={!accountId || isAmountError || isMetaError}
              label={t('Create')}
              onStart={toggleOpen}
            />
          </Modal.Actions>
        </Modal>
      )}
    </>
  );
}

export default React.memo(Create);