polkadot-js/apps

View on GitHub
packages/page-assets/src/Overview/Create/Info.tsx

Summary

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

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

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

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

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

interface Props {
  assetIds: BN[];
  className?: string;
  defaultValue: InfoState | null;
  onChange: (info: InfoState | null) => void;
  openId: BN;
}

function Info ({ assetIds, className = '', defaultValue, onChange, openId }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const [initial] = useState(() => defaultValue);
  const [initialId] = useState(() => openId);
  const [accountId, setAccountId] = useState<string | null>(null);
  const [assetId, setAssetId] = useState<BN | undefined>();
  const [assetDecimals, setAssetDecimals] = useState<BN | undefined>();
  const [assetName, setAssetName] = useState<string | null | undefined>(() => defaultValue?.assetName);
  const [assetSymbol, setAssetSymbol] = useState<string | null | undefined>(() => defaultValue?.assetSymbol);
  const [minBalance, setMinBalance] = useState<BN | undefined>();

  const [siDecimals, siSymbol] = useMemo(
    () => assetDecimals && assetSymbol
      ? [assetDecimals.toNumber(), assetSymbol.toUpperCase()]
      : [0, 'NONE'],
    [assetDecimals, assetSymbol]
  );

  const isValidDecimals = useMemo(
    () => !!assetDecimals && assetDecimals.lten(20),
    [assetDecimals]
  );

  const isValidName = useMemo(
    () => !!assetName && assetName.length >= 3 && assetName.length <= 32,
    [assetName]
  );

  const isValidSymbol = useMemo(
    () => !!assetSymbol && assetSymbol.length >= 3 && assetSymbol.length <= 7,
    [assetSymbol]
  );

  const isValidId = useMemo(
    () => !!assetId && assetId.gt(BN_ZERO) && !assetIds.some((a) => a.eq(assetId)),
    [assetId, assetIds]
  );

  useEffect((): void => {
    onChange(
      assetId && assetName && assetSymbol && assetDecimals && isValidId && isValidName && isValidSymbol && isValidDecimals && accountId && minBalance && !minBalance.isZero()
        ? { accountId, assetDecimals, assetId, assetName, assetSymbol, minBalance }
        : null
    );
  }, [api, accountId, assetDecimals, assetId, assetIds, assetName, assetSymbol, isValidId, isValidName, isValidSymbol, isValidDecimals, minBalance, onChange]);

  return (
    <Modal.Content className={className}>
      <Modal.Columns hint={t('The account that is to be used to create this asset and setup the initial metadata.')}>
        <InputAddress
          defaultValue={initial?.accountId}
          label={t('creator account')}
          onChange={setAccountId}
          type='account'
        />
      </Modal.Columns>
      <Modal.Columns hint={t('The descriptive name for this asset.')}>
        <Input
          autoFocus
          defaultValue={initial?.assetName}
          isError={!isValidName}
          label={t('asset name')}
          onChange={setAssetName}
        />
      </Modal.Columns>
      <Modal.Columns hint={t('The symbol that will represent this asset.')}>
        <Input
          defaultValue={initial?.assetSymbol}
          isError={!isValidSymbol}
          label={t('asset symbol')}
          onChange={setAssetSymbol}
        />
      </Modal.Columns>
      <Modal.Columns hint={t('The number of decimals for this token. Max allowed via the UI is set to 20.')}>
        <InputNumber
          defaultValue={initial?.assetDecimals}
          isError={!isValidDecimals}
          label={t('asset decimals')}
          onChange={setAssetDecimals}
        />
      </Modal.Columns>
      <Modal.Columns hint={t('The minimum balance for the asset. This is specified in the units and decimals as requested.')}>
        <InputBalance
          defaultValue={initial?.minBalance}
          isZeroable={false}
          label={t('minimum balance')}
          onChange={setMinBalance}
          siDecimals={siDecimals}
          siSymbol={siSymbol}
        />
      </Modal.Columns>
      <Modal.Columns hint={t('The selected id for the asset. This should not match an already-existing asset id.')}>
        <InputNumber
          defaultValue={initial?.assetId || initialId}
          isError={!isValidId}
          isZeroable={false}
          label={t('asset id')}
          onChange={setAssetId}
        />
      </Modal.Columns>
    </Modal.Content>
  );
}

export default React.memo(Info);