import React, { FC, useEffect, useState } from 'react'; import classNames from 'classnames'; import { Input, Form, InputNumber, Button } from 'antd'; import { FieldUpdaterFunc } from '../../types/config-section'; import { StatusState } from '../../utils/input-statuses'; import { FormStatusIndicator } from './FormStatusIndicator'; import { PASSWORD_COMPLEXITY_RULES, REGEX_PASSWORD } from '../../utils/config-constants'; export const TEXTFIELD_TYPE_TEXT = 'default'; export const TEXTFIELD_TYPE_PASSWORD = 'password'; // Input.Password export const TEXTFIELD_TYPE_NUMBER = 'numeric'; // InputNumber export const TEXTFIELD_TYPE_TEXTAREA = 'textarea'; // Input.TextArea export const TEXTFIELD_TYPE_URL = 'url'; export type TextFieldProps = { fieldName: string; onSubmit?: () => void; onPressEnter?: () => void; onHandleSubmit?: () => void; className?: string; disabled?: boolean; label?: string; maxLength?: number; pattern?: string; placeholder?: string; required?: boolean; status?: StatusState; tip?: string; type?: string; useTrim?: boolean; useTrimLead?: boolean; value?: string | number; hasComplexityRequirements?: boolean; onBlur?: FieldUpdaterFunc; onChange?: FieldUpdaterFunc; }; export const TextField: FC = ({ className, disabled, fieldName, label, maxLength, onBlur, onChange, onPressEnter, onHandleSubmit, pattern, placeholder, required, status, tip, type, useTrim, value, hasComplexityRequirements, }) => { const [hasPwdChanged, setHasPwdChanged] = useState(false); const [showPwdButton, setShowPwdButton] = useState(false); const [form] = Form.useForm(); const handleChange = (e: any) => { // if an extra onChange handler was sent in as a prop, let's run that too. if (onChange) { const val = type === TEXTFIELD_TYPE_NUMBER ? e : e.target.value; setShowPwdButton(true); if (hasComplexityRequirements && REGEX_PASSWORD.test(val)) { setHasPwdChanged(true); } else { setHasPwdChanged(false); } onChange({ fieldName, value: useTrim ? val.trim() : val }); } }; useEffect(() => { form.setFieldsValue({ inputFieldPassword: value }); }, [value]); // if you blur a required field with an empty value, restore its original value in state (parent's state), if an onChange from parent is available. const handleBlur = (e: any) => { const val = e.target.value; if (onBlur) { onBlur({ value: val }); } }; const handlePressEnter = () => { if (onPressEnter) { onPressEnter(); } }; // Password Complexity rules const passwordComplexityRules = []; // display the appropriate Ant text field let Field = Input as | typeof Input | typeof InputNumber | typeof Input.TextArea | typeof Input.Password; let fieldProps = {}; if (type === TEXTFIELD_TYPE_TEXTAREA) { Field = Input.TextArea; fieldProps = { autoSize: true, }; } else if (type === TEXTFIELD_TYPE_PASSWORD) { PASSWORD_COMPLEXITY_RULES.forEach(element => { passwordComplexityRules.push(element); }); Field = Input.Password; fieldProps = { visibilityToggle: true, }; } else if (type === TEXTFIELD_TYPE_NUMBER) { Field = InputNumber; fieldProps = { type: 'number', min: 1, max: 10 ** maxLength - 1, }; } else if (type === TEXTFIELD_TYPE_URL) { fieldProps = { type: 'url', pattern, }; } const fieldId = `field-${fieldName}`; const { type: statusType } = status || {}; const containerClass = classNames({ 'formfield-container': true, 'textfield-container': true, [`type-${type}`]: true, required, [`status-${statusType}`]: status, }); return (
{label ? (
) : null} {!hasComplexityRequirements ? (

{tip}

) : (
{showPwdButton && (
)}

{tip}

)}
); }; export default TextField; TextField.defaultProps = { className: '', disabled: false, label: '', maxLength: 255, placeholder: '', required: false, status: null, tip: '', type: TEXTFIELD_TYPE_TEXT, value: '', pattern: '', useTrim: false, useTrimLead: false, hasComplexityRequirements: false, onSubmit: () => {}, onBlur: () => {}, onChange: () => {}, onPressEnter: () => {}, onHandleSubmit: () => {}, };