import { useContext } from 'react'; import { Box, styled } from '@mui/material'; import { DataContext } from '../context/Context'; import ComponentWrapper from '../common/ComponentWrapper'; import { getFieldName } from '../permissions/getFieldName'; import { InputElemntProps, inputProps } from '../interface/inputfieldProps'; import { useDebouncedChange } from '@jsonforms/material-renderers'; import { getComponentProps } from '../common/getComponentProps'; import React from 'react'; import { useJsonForms } from '@jsonforms/react'; const InputElement = styled('input')( ({ theme, otpBoxStyle }) => ({ ...theme?.OTPInputBoxStyle, ...otpBoxStyle, }), ); const OTPInput = function (props: inputProps) { const { data, uischema, path, schema, handleChange, rootSchema } = props; const { pageName, permissions, theme ,serviceProvider} = useContext(DataContext); const uischemaData = uischema?.config?.main; const fieldName = getFieldName(path); const separator = uischemaData?.seperator || ''; const length = uischemaData?.length || 4; const [otp, setOtp] = React.useState(''); const eventToValue = (ev: any) => (ev === '' ? undefined : ev); const ctx = useJsonForms(); const dynamicStyle = React.useMemo(() => { return serviceProvider( ctx, { onClick: uischema.config?.main?.styleFunction || 'getStyle', }, { event: { _reactName: 'onClick' }, path, }, ); }, [data, path]); const componentStyle = { ...uischema.config?.style, ...dynamicStyle }; const [input, onChange] = useDebouncedChange( handleChange, '', data, path, eventToValue, ) as [string, any, () => void]; const inputRefs = React.useRef( new Array(length).fill(null), ); const focusInput = (targetIndex: number) => { const targetInput = inputRefs.current[targetIndex]; targetInput?.focus(); }; const selectInput = (targetIndex: number) => { const targetInput = inputRefs.current[targetIndex]; targetInput?.select(); }; const handleKeyDown = ( event: React.KeyboardEvent, currentIndex: number, ) => { switch (event.key) { case 'ArrowLeft': event.preventDefault(); if (currentIndex > 0) { focusInput(currentIndex - 1); selectInput(currentIndex - 1); } break; case 'ArrowRight': event.preventDefault(); if (currentIndex < length - 1) { focusInput(currentIndex + 1); selectInput(currentIndex + 1); } break; case 'Delete': case 'Backspace': event.preventDefault(); setOtp((prevOtp) => { const otpArray = prevOtp.split(''); otpArray[currentIndex] = ''; const newOtp = otpArray.join(''); onChange(newOtp); return newOtp; }); if (event.key === 'Backspace' && currentIndex > 0) { focusInput(currentIndex - 1); } break; default: break; } }; const handleOtpChange = ( event: React.ChangeEvent, currentIndex: number, ) => { const currentValue = event.target.value; if (uischemaData?.type === 'number' && !/^\d$/.test(currentValue)) return; if (uischemaData?.type === 'alphabet' && !/^[a-zA-Z]+$/.test(currentValue)) return; let indexToEnter = 0; while (indexToEnter <= currentIndex) { if (inputRefs.current[indexToEnter]?.value && indexToEnter < currentIndex) { indexToEnter += 1; } else { break; } } setOtp((prev) => { const otpArray = prev.split(''); const lastValue = currentValue[currentValue.length - 1]; otpArray[indexToEnter] = lastValue; const newOtp = otpArray.join(''); onChange(newOtp); return newOtp; }); if (currentValue !== '' && indexToEnter < length - 1) { focusInput(indexToEnter + 1); } }; const handleClick = ( event: React.MouseEvent, currentIndex: number, ) => { selectInput(currentIndex); }; const handlePaste = ( event: React.ClipboardEvent, currentIndex: number, ) => { event.preventDefault(); const clipboardData = event.clipboardData; if (clipboardData.types.includes('text/plain')) { let pastedText = clipboardData.getData('text/plain'); pastedText = pastedText.substring(0, length).trim(); let indexToEnter = 0; while (indexToEnter <= currentIndex) { if (inputRefs.current[indexToEnter]?.value && indexToEnter < currentIndex) { indexToEnter += 1; } else { break; } } const otpArray = otp.split(''); for (let i = indexToEnter; i < length; i++) { const lastValue = pastedText[i - indexToEnter] ?? ''; otpArray[i] = lastValue; } const newOtp = otpArray.join(''); setOtp(newOtp); onChange(newOtp); } }; return ( {new Array(length).fill(null).map((_, index) => ( { inputRefs.current[index] = ele!; }} theme={theme} onKeyDown={(event) => handleKeyDown(event, index)} onChange={(event) => handleOtpChange(event, index)} onClick={(event) => handleClick(event, index)} onPaste={(event) => handlePaste(event, index)} value={ uischemaData?.masking ? (otp[index] ? '•' : '') : (otp[index] ?? '') } aria-label={`Digit ${index + 1} of OTP`} otpBoxStyle={componentStyle} /> {index === length - 1 ? null : separator} ))} ); }; export default OTPInput;