import { emptyFn, format } from '@ringcentral-integration/utils'; import { RcIcon, RcTextField, useDepsChange, useRefState, } from '@ringcentral/juno'; import { Search } from '@ringcentral/juno-icon'; import clsx from 'clsx'; import type { FunctionComponent } from 'react'; import React, { useEffect, useRef, useState } from 'react'; import { TOOLTIP_LONG_DELAY_TIME } from '../../lib/toolTipDelayTime'; import { AnimationPanel } from '../AnimationPanel'; import BackHeader from '../BackHeaderV2'; import { Tooltip } from '../Rcui/Tooltip'; import type { ListViewProps } from '../SelectList/ListView'; import selectListI18n from '../SelectList/i18n'; import i18n from './i18n'; import styles from './styles.scss'; export type SelectListBasicProps = { title: string; options?: ListViewProps['options']; otherOptions?: object[]; associatedOptions?: object[]; showMatched?: boolean; showOtherSection?: boolean; showAssociatedSection?: boolean; showRecentlySection?: boolean; placeholder?: string; searchOption: (option: any, text: string) => any; rightIcon?: JSX.Element; currentLocale: string; matchedTitle?: string; otherTitle?: string; associatedTitle?: string; recentlyTitle?: string; renderListView?: ( data: any, type: 'matched' | 'other' | 'associated' | 'custom' | 'recently', filter: string, // TODO: need type check scrollCheck: any, ) => React.ReactNode; open?: boolean; setOpen?: (...args: any[]) => any; scrollCheck?: ( scrollElmRef: any, matchElmRef: any, elm: any, type: any, ) => any; selectListBasicClassName?: string; backHeaderClassName?: string; listContainerClassName?: string; classes?: { searchInput?: string; noResult?: string; placeholder?: string; }; onBackClick?: () => any; contactSearch?: (arg: { searchString: string; fromField: SelectListBasicProps['field']; }) => Promise; field?: string; foundFromServerTitle?: string; showFoundFromServer?: boolean; foundFromServerEntities?: any[]; recentlyEntities?: any[]; serverEntitiesClientFilter?: 'none'; appName?: string; isSearching?: boolean; setShowSearchFromServerHint?: (state: boolean) => any; showSearchFromServerHint?: boolean; disabled?: boolean; }; const defaultRenderListView = () => { return null; }; export const SelectListBasic: FunctionComponent = ({ options = [], otherOptions = [], associatedOptions = [], showOtherSection = true, showAssociatedSection = false, showRecentlySection = false, placeholder = '', rightIcon = null, setOpen = emptyFn, open = false, renderListView = defaultRenderListView, scrollCheck = emptyFn, selectListBasicClassName = null, backHeaderClassName = null, listContainerClassName = null, classes = {}, onBackClick = undefined, matchedTitle = null, otherTitle = null, associatedTitle = null, recentlyTitle = null, contactSearch = null, field = null, foundFromServerTitle = null, showFoundFromServer = false, foundFromServerEntities = [], recentlyEntities, serverEntitiesClientFilter, appName = null, isSearching = false, disabled = false, title, searchOption, currentLocale, showMatched = true, ...rest }) => { const [filterRef, setFilter] = useRefState(''); const [showSearchFromServerHint, setShowSearchFromServerHint] = useState(false); const scrollElmRef = useRef(); const matchElmRef = useRef(); // When open change clear filter useEffect(() => { setFilter(''); setShowSearchFromServerHint(true); // eslint-disable-next-line react-hooks/exhaustive-deps }, [open]); useEffect(() => { if (isSearching) { setShowSearchFromServerHint(false); } }, [isSearching]); useDepsChange(() => { // null is invalid for RcTextField at disabled status but empty string works if (disabled) setFilter('', false); }, [disabled]); const filter = filterRef.current; // @ts-expect-error TS(2774): This condition will always return true since this ... Remove this comment to see the full error message const hasSearch = searchOption && filter; const matchOptions = hasSearch ? options.filter((option) => searchOption(option, filter)) : options; const matchOtherOptions = hasSearch ? otherOptions.filter((option) => searchOption(option, filter)) : otherOptions; const matchAssociatedOptions = hasSearch ? associatedOptions.filter((option) => searchOption(option, filter)) : associatedOptions; const filteredFoundFromServerOptions = hasSearch && serverEntitiesClientFilter !== 'none' ? foundFromServerEntities.filter((option) => searchOption(option, filter)) : foundFromServerEntities; const matchRecentlyOptions = hasSearch && recentlyEntities ? recentlyEntities.filter((option) => searchOption(option, filter)) : recentlyEntities; const hasResult = matchOptions.length + matchOtherOptions.length + matchAssociatedOptions.length + (matchRecentlyOptions?.length || 0) > 0 || options.length + otherOptions.length + associatedOptions.length + (recentlyEntities?.length || 0) === 0; const backHeaderOnclick = () => { setOpen(false); if (onBackClick) { return onBackClick(); } }; const foundFromServerHint = (

{format(i18n.getString('foundFromServerHint', currentLocale), { appName, })}

); const notResultFoundFromServer = (

{' '} {i18n.getString('notResultFoundFromServer', currentLocale)}

); const loading = (

{i18n.getString('loading', currentLocale)}

); const notFoundFromServer = showSearchFromServerHint ? foundFromServerHint : notResultFoundFromServer; const showLoading = isSearching ? loading : notFoundFromServer; matchedTitle = matchedTitle || selectListI18n.getString('matched', currentLocale); otherTitle = otherTitle || selectListI18n.getString('other', currentLocale); foundFromServerTitle = foundFromServerTitle || format(selectListI18n.getString('foundFromServer', currentLocale), { appName, }); associatedTitle = associatedTitle || selectListI18n.getString('associated', currentLocale); recentlyTitle = recentlyTitle || selectListI18n.getString('recently', currentLocale); return ( // @ts-expect-error TS(2322): Type 'string | null' is not assignable to type 'st... Remove this comment to see the full error message {open ? ( <>
{!filter && ( {placeholder} )} ), }} data-sign="searchBar" onChange={(event: any) => { if (event.target) { const value = event.target.value || ''; setFilter(value); } }} onKeyDown={(event) => { // Press enter to search contacts from server if (event.key !== 'Enter' || !showFoundFromServer) return; if (typeof contactSearch === 'function') { const searchString = filter ? filter.trim() : ''; if (searchString.length) { contactSearch({ searchString, // @ts-expect-error TS(2322): Type 'string | null' is not assignable to type 'st... Remove this comment to see the full error message fromField: field, }); } } }} disabled={disabled} />
' is not assignab... Remove this comment to see the full error message ref={scrollElmRef} data-sign="searchResult" > {hasResult || showFoundFromServer ? ( <> {showRecentlySection && (
{recentlyTitle && (
{recentlyTitle} ({matchRecentlyOptions?.length || 0})
)} {matchRecentlyOptions && matchRecentlyOptions.length > 0 && renderListView( matchRecentlyOptions, 'recently', filter, (elm: any, type: any) => scrollCheck(scrollElmRef, matchElmRef, elm, type), )}
)} {showMatched && (
' is not assignab... Remove this comment to see the full error message ref={matchElmRef} className={styles.text} data-sign={matchedTitle} > {matchedTitle && (
{matchedTitle} ({matchOptions.length})
)} {matchOptions.length > 0 && renderListView( matchOptions, 'matched', filter, (elm: any, type: any) => scrollCheck(scrollElmRef, matchElmRef, elm, type), )}
)} {showOtherSection && (
{otherTitle && (
{otherTitle} ({matchOtherOptions.length})
)} {matchOtherOptions.length > 0 && renderListView( matchOtherOptions, 'other', filter, (elm: any, type: any) => scrollCheck(scrollElmRef, matchElmRef, elm, type), )}
)} {showAssociatedSection && (
{associatedTitle && (
{associatedTitle} ({matchAssociatedOptions.length})
)} {matchAssociatedOptions.length > 0 && renderListView( matchAssociatedOptions, 'other', filter, (elm: any, type: any) => scrollCheck(scrollElmRef, matchElmRef, elm, type), )}
)} {showFoundFromServer && (
{foundFromServerTitle && (
{foundFromServerTitle} ( {filteredFoundFromServerOptions.length})
)} {filteredFoundFromServerOptions && filteredFoundFromServerOptions.length > 0 ? renderListView( filteredFoundFromServerOptions, 'custom', filter, (elm: any, type: any) => scrollCheck(scrollElmRef, matchElmRef, elm, type), ) : showLoading}
)} ) : (
{`${i18n.getString( 'noResultFoundFor', currentLocale, )} "${filter}"`}
)}
) : null}
); };