import React, { ReactNode } from 'react'; import Link from 'Components/Link/Link'; import { inputTypes } from 'Helpers/Props'; import { InputType } from 'Helpers/Props/inputTypes'; import { Kind } from 'Helpers/Props/kinds'; import { ValidationError, ValidationWarning } from 'typings/pending'; import translate from 'Utilities/String/translate'; import AutoCompleteInput from './AutoCompleteInput'; import CaptchaInput from './CaptchaInput'; import CheckInput from './CheckInput'; import { FormInputButtonProps } from './FormInputButton'; import FormInputHelpText from './FormInputHelpText'; import NumberInput from './NumberInput'; import OAuthInput from './OAuthInput'; import PasswordInput from './PasswordInput'; import PathInput from './PathInput'; import DownloadClientSelectInput from './Select/DownloadClientSelectInput'; import EnhancedSelectInput from './Select/EnhancedSelectInput'; import IndexerFlagsSelectInput from './Select/IndexerFlagsSelectInput'; import IndexerSelectInput from './Select/IndexerSelectInput'; import MonitorEpisodesSelectInput from './Select/MonitorEpisodesSelectInput'; import MonitorNewItemsSelectInput from './Select/MonitorNewItemsSelectInput'; import ProviderDataSelectInput from './Select/ProviderOptionSelectInput'; import QualityProfileSelectInput from './Select/QualityProfileSelectInput'; import RootFolderSelectInput from './Select/RootFolderSelectInput'; import SeriesTypeSelectInput from './Select/SeriesTypeSelectInput'; import UMaskInput from './Select/UMaskInput'; import DeviceInput from './Tag/DeviceInput'; import SeriesTagInput from './Tag/SeriesTagInput'; import TagSelectInput from './Tag/TagSelectInput'; import TextTagInput from './Tag/TextTagInput'; import TextArea from './TextArea'; import TextInput from './TextInput'; import styles from './FormInputGroup.css'; function getComponent(type: InputType) { switch (type) { case inputTypes.AUTO_COMPLETE: return AutoCompleteInput; case inputTypes.CAPTCHA: return CaptchaInput; case inputTypes.CHECK: return CheckInput; case inputTypes.DEVICE: return DeviceInput; case inputTypes.MONITOR_EPISODES_SELECT: return MonitorEpisodesSelectInput; case inputTypes.MONITOR_NEW_ITEMS_SELECT: return MonitorNewItemsSelectInput; case inputTypes.NUMBER: return NumberInput; case inputTypes.OAUTH: return OAuthInput; case inputTypes.PASSWORD: return PasswordInput; case inputTypes.PATH: return PathInput; case inputTypes.QUALITY_PROFILE_SELECT: return QualityProfileSelectInput; case inputTypes.INDEXER_SELECT: return IndexerSelectInput; case inputTypes.INDEXER_FLAGS_SELECT: return IndexerFlagsSelectInput; case inputTypes.DOWNLOAD_CLIENT_SELECT: return DownloadClientSelectInput; case inputTypes.ROOT_FOLDER_SELECT: return RootFolderSelectInput; case inputTypes.SELECT: return EnhancedSelectInput; case inputTypes.DYNAMIC_SELECT: return ProviderDataSelectInput; case inputTypes.TAG: case inputTypes.SERIES_TAG: return SeriesTagInput; case inputTypes.SERIES_TYPE_SELECT: return SeriesTypeSelectInput; case inputTypes.TEXT_AREA: return TextArea; case inputTypes.TEXT_TAG: return TextTagInput; case inputTypes.TAG_SELECT: return TagSelectInput; case inputTypes.UMASK: return UMaskInput; default: return TextInput; } } // TODO: Remove once all parent components are updated to TSX and we can refactor to a consistent type interface ValidationMessage { message: string; } interface FormInputGroupProps { className?: string; containerClassName?: string; inputClassName?: string; name: string; value?: unknown; values?: unknown[]; isDisabled?: boolean; type?: InputType; kind?: Kind; min?: number; max?: number; unit?: string; buttons?: ReactNode | ReactNode[]; helpText?: string; helpTexts?: string[]; helpTextWarning?: string; helpLink?: string; placeholder?: string; autoFocus?: boolean; includeNoChange?: boolean; includeNoChangeDisabled?: boolean; selectedValueOptions?: object; indexerFlags?: number; pending?: boolean; canEdit?: boolean; includeAny?: boolean; delimiters?: string[]; errors?: (ValidationMessage | ValidationError)[]; warnings?: (ValidationMessage | ValidationWarning)[]; onChange: (args: T) => void; } function FormInputGroup(props: FormInputGroupProps) { const { className = styles.inputGroup, containerClassName = styles.inputGroupContainer, inputClassName, type = 'text', unit, buttons = [], helpText, helpTexts = [], helpTextWarning, helpLink, pending, errors = [], warnings = [], ...otherProps } = props; const InputComponent = getComponent(type); const checkInput = type === inputTypes.CHECK; const hasError = !!errors.length; const hasWarning = !hasError && !!warnings.length; const buttonsArray = React.Children.toArray(buttons); const lastButtonIndex = buttonsArray.length - 1; const hasButton = !!buttonsArray.length; return (
{/* @ts-expect-error - need to pass through all the expected options */} {unit && (
{unit}
)}
{buttonsArray.map((button, index) => { if (!React.isValidElement(button)) { return button; } return React.cloneElement(button, { isLastButton: index === lastButtonIndex, }); })} {/*
{ pending && }
*/}
{!checkInput && helpText ? : null} {!checkInput && helpTexts ? (
{helpTexts.map((text, index) => { return ( ); })}
) : null} {(!checkInput || helpText) && helpTextWarning ? ( ) : null} {helpLink ? {translate('MoreInfo')} : null} {errors.map((error, index) => { return 'message' in error ? ( ) : ( ); })} {warnings.map((warning, index) => { return 'message' in warning ? ( ) : ( ); })}
); } export default FormInputGroup;