/* eslint-disable react/no-multi-comp */ import clsx from 'clsx'; import type { KeyboardEvent } from 'react'; import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import i18n from '../RecipientsInput/i18n'; import { DropdownList } from './DropdownList'; import { PhoneNumberInput } from './PhoneNumberInput'; import type { RecipientsInputV2Handles, RecipientsInputV2Props, } from './RecipientsInputV2.interface'; import { SelectedRecipients } from './SelectedRecipients'; import styles from './styles.scss'; /** * Specs: * 1. When dialer buttons are pressed, the cursor should be moved to the end of the string, * and the focus set to the input field. RCINT-7706 * 2. Simplify recipient/recipients property */ function isSplitterKey(e: KeyboardEvent): boolean { if ( e.key === ',' || e.key === ';' || e.key === 'Enter' || (e.key === 'Unidentified' && // for Safari (FF cannot rely on keyCode...) (e.keyCode === 186 || // semicolon e.keyCode === 188 || // comma e.keyCode === 13)) // enter ) { return true; } return false; } export const RecipientsInputV2 = forwardRef< RecipientsInputV2Handles, RecipientsInputV2Props >( ( { className, enableTitle, recipients, multiple, useRCUI, value, removeFromRecipients, recipientsClassName, placeholder, currentLocale, onInputChange, onInputClear, label = `${i18n.getString('to', currentLocale)}:`, searchContactList, formatContactPhone, phoneTypeRenderer, phoneSourceNameRenderer, contactInfoRenderer, contactPhoneRenderer, addToRecipients, isLastInputFromDialpad, }, ref, ) => { const thisEl = useRef(null); const listEl = useRef(null); const inputEl = useRef(null); const [stateValue, setStateValue] = useState(value); const [selectedIndex, setSelectedIndex] = useState(0); const [isInputFocused, setIsInputFocused] = useState(false); const lastInputTimestamp = useRef(0); useImperativeHandle(ref, () => ({ focus() { setIsInputFocused(true); if (inputEl.current) { // @ts-expect-error TS(2339): Property 'focus' does not exist on type 'never'. inputEl.current.focus(); } }, blur() { setIsInputFocused(false); if (inputEl.current) { // @ts-expect-error TS(2339): Property 'blur' does not exist on type 'never'. inputEl.current.blur(); } }, })); useEffect(() => { const handler = ({ target }: MouseEvent) => { // @ts-expect-error TS(2339): Property 'contains' does not exist on type 'never'... Remove this comment to see the full error message if (thisEl.current && !thisEl.current.contains(target)) { if (inputEl.current) { // @ts-expect-error TS(2339): Property 'blur' does not exist on type 'never'. inputEl.current.blur(); } setIsInputFocused(false); } }; window.addEventListener('click', handler); return () => { window.removeEventListener('click', handler); }; }, []); // pass [] so this only runs on mount and unmount useEffect(() => { if ( value !== stateValue && Date.now() - lastInputTimestamp.current > 300 ) { setStateValue(value); } }, [value, stateValue]); const toNumberInput = !multiple && recipients.length ? null : ( { lastInputTimestamp.current = Date.now(); setStateValue(newValue); setSelectedIndex(0); onInputChange(newValue); if (listEl.current) { // @ts-expect-error TS(2339): Property 'setScrollPosition' does not exist on typ... Remove this comment to see the full error message listEl.current.setScrollPosition(0); } }} onClear={() => { setStateValue(''); onInputClear(); }} onFocus={() => { setIsInputFocused(true); }} /> ); return (
{ if (isInputFocused && stateValue.length >= 3) { if (e.key === 'ArrowUp') { if (selectedIndex > 0) { setSelectedIndex((prevIndex) => prevIndex - 1); if (selectedIndex - 1 < searchContactList.length - 4) { // @ts-expect-error TS(2531): Object is possibly 'null'. listEl.current.scrollUp(); } } } else if (e.key === 'ArrowDown') { if (selectedIndex < searchContactList.length - 1) { setSelectedIndex((prevIndex) => prevIndex + 1); if (selectedIndex + 1 > 4) { // @ts-expect-error TS(2531): Object is possibly 'null'. listEl.current.scrollDown(); } } } } if (isSplitterKey(e)) { e.preventDefault(); const trimmedValue = stateValue.trim(); const selectedContact = searchContactList[selectedIndex]; if (trimmedValue.length === 0 && !selectedContact) { return; } if (selectedContact && e.key === 'Enter') { addToRecipients({ ...selectedContact, }); } else { addToRecipients({ name: trimmedValue.replace(',', ''), phoneNumber: trimmedValue.replace(',', ''), }); } } }} > {label}
{toNumberInput}
{ setStateValue(''); onInputChange(''); addToRecipients(contact); }} recipientOptions={searchContactList} formatContactPhone={formatContactPhone} visibility={isInputFocused && !isLastInputFromDialpad} enableTitle={enableTitle} phoneTypeRenderer={phoneTypeRenderer} phoneSourceNameRenderer={phoneSourceNameRenderer} recipientInfoRenderer={contactInfoRenderer} recipientPhoneRenderer={contactPhoneRenderer} />
); }, ); RecipientsInputV2.defaultProps = { enableTitle: false, multiple: false, useRCUI: false, isLastInputFromDialpad: false, };