polkadot-js/apps

View on GitHub
packages/react-components/src/InputConsts/index.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
// Copyright 2017-2024 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { ApiPromise } from '@polkadot/api';
import type { ConstantCodec } from '@polkadot/types/metadata/decorate/types';
import type { DropdownOptions } from '../util/types.js';
import type { ConstValue, ConstValueBase } from './types.js';

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

import { useApi } from '@polkadot/react-hooks';

import LinkedWrapper from '../InputExtrinsic/LinkedWrapper.js';
import keyOptions from './options/key.js';
import sectionOptions from './options/section.js';
import SelectKey from './SelectKey.js';
import SelectSection from './SelectSection.js';

interface Props {
  className?: string;
  defaultValue: ConstValueBase;
  isError?: boolean;
  label: React.ReactNode;
  onChange?: (value: ConstValue) => void;
  withLabel?: boolean;
}

function getValue (api: ApiPromise, { method, section }: ConstValueBase): ConstValue {
  const firstSec = Object.keys(api.consts)[0];
  const firstMet = Object.keys(api.consts[firstSec])[0];
  const value = api.consts[section]?.[method]
    ? { method, section }
    : { method: firstMet, section: firstSec };

  return {
    ...value,
    meta: (api.consts[value.section][value.method] as ConstantCodec).meta
  };
}

function InputConsts ({ className = '', defaultValue, label, onChange, withLabel }: Props): React.ReactElement<Props> {
  const { api } = useApi();
  const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(() => keyOptions(api, defaultValue.section));
  const [optionsSection] = useState<DropdownOptions>(() => sectionOptions(api));
  const [value, setValue] = useState<ConstValue>(() => getValue(api, defaultValue));

  const _onKeyChange = useCallback(
    (newValue: ConstValueBase): void => {
      if (value.section !== newValue.section || value.method !== newValue.method) {
        const { method, section } = newValue;
        const meta = (api.consts[section][method] as ConstantCodec).meta;
        const updated = { meta, method, section };

        setValue(updated);
        onChange && onChange(updated);
      }
    },
    [api, onChange, value]
  );

  const _onSectionChange = useCallback(
    (newSection: string): void => {
      if (newSection !== value.section) {
        const optionsMethod = keyOptions(api, newSection);

        setOptionsMethod(optionsMethod);
        _onKeyChange({ method: optionsMethod[0].value, section: newSection });
      }
    },
    [_onKeyChange, api, value]
  );

  return (
    <LinkedWrapper
      className={className}
      label={label}
      withLabel={withLabel}
    >
      <SelectSection
        className='small'
        onChange={_onSectionChange}
        options={optionsSection}
        value={value}
      />
      <SelectKey
        className='large'
        onChange={_onKeyChange}
        options={optionsMethod}
        value={value}
      />
    </LinkedWrapper>
  );
}

export default React.memo(InputConsts);