// tslint:disable:no-magic-numbers import MenuItem from '@material-ui/core/MenuItem'; import Paper from '@material-ui/core/Paper'; import Popper from '@material-ui/core/Popper'; import TextField from '@material-ui/core/TextField'; import CloseIcon from '@material-ui/icons/Close'; import OndemandVideoOutlinedIcon from '@material-ui/icons/OndemandVideoOutlined'; import PersonOutlineOutlinedIcon from '@material-ui/icons/PersonOutlineOutlined'; import SearchIcon from '@material-ui/icons/Search'; import Downshift from 'downshift'; import _isNil from 'ramda/src/isNil'; import React, { useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import { autocompleteRequested } from '../../redux/autocomplete/actionCreators'; import { State } from '../../redux/rootReducer'; import Course from '../../types/items/Course'; import User from '../../types/items/User'; import useStyles from './styles'; export interface GetFormattedResultsOptions { readonly courses: Course[]; readonly users: User[]; } const USERS_RESULT_COUNT = 2; const COURSES_RESULT_COUNT = 4; const getFormattedResults = ({ courses, users, }: GetFormattedResultsOptions) => { const updatedCourses = courses .map((course: Course) => ({ ...course, label: course.title, type: 'course', })) .slice(0, COURSES_RESULT_COUNT); const updatedUsers = users .map((user: User) => ({ ...user, label: [user.firstName, user.lastName].every(Boolean) ? `${user.firstName} ${user.lastName}` : user.email, type: 'user', })) .slice(0, USERS_RESULT_COUNT); return [...updatedCourses, ...updatedUsers]; }; function renderInput(inputProps: any) { const { InputProps, classes, ref, ...other } = inputProps; return ( ); } const renderSuggestion = (suggestionProps: any) => { const { suggestion, index, itemProps, highlightedIndex, selectedItem, } = suggestionProps; const isHighlighted = highlightedIndex === index; const isSelected = (selectedItem || '').indexOf(suggestion.label) > -1; const otherProps = isSelected ? { style: { fontWeight: isSelected ? 600 : 400, }, } : {}; const icon = suggestion.type === 'course' ? : ; return ( <>{icon} {suggestion.label} ); }; type AutocompleteType = 'navbar' | 'heroContent'; const autocompleteOptions = { heroContent: { inputProps: {}, }, navbar: { inputProps: { style: { paddingBottom: '12px', paddingTop: '12px', }, }, }, }; interface Options { readonly id: string; readonly type: AutocompleteType; } const POPPER_OFFSET = 4; const Autocomplete = ({ id, type }: Options) => { const classes = useStyles(); const { t } = useTranslation(); const additionalOptions = autocompleteOptions[type]; const popperNode: any = useRef({}); const [value, setValue] = useState(''); const history = useHistory(); const { courses, users } = useSelector((state: State) => state.autocomplete); const dispatch = useDispatch(); const results = getFormattedResults({ courses, users }); const handleChange = (changes: any) => { // TODO: abstract this operations if ( changes.hasOwnProperty('selectedItem') && !_isNil(changes.selectedItem) ) { setValue(changes.selectedItem); const item: any = results.filter( result => result.label === changes.selectedItem )[0]; const link = item.type === 'course' ? `/courses/${item.slug}` : // TODO: create username property as uniq db field `/instructors/${String( item.firstName + item.lastName ).toLowerCase()}`; setValue(''); history.push(link); } else if (changes.hasOwnProperty('inputValue')) { setValue(changes.inputValue); dispatch(autocompleteRequested(changes.inputValue)); } }; return (
{({ clearSelection, getInputProps, getItemProps, getLabelProps, getMenuProps, highlightedIndex, isOpen, selectedItem, }) => { const { onBlur, onFocus, ...inputProps } = getInputProps({ placeholder: t(`${[type]}.search.placeholder`), ...additionalOptions.inputProps, }); return (
{renderInput({ InputLabelProps: getLabelProps({ shrink: true } as any), InputProps: { onBlur, onFocus }, classes, fullWidth: true, inputProps, ref: popperNode, })} {String(inputProps.value).length > 0 && (
)}
{results.map((suggestion: any, index: number) => renderSuggestion({ highlightedIndex, index, itemProps: getItemProps({ item: suggestion.label }), selectedItem, suggestion, }) )}
); }}
); }; // tslint:disable-next-line:max-file-line-count export default Autocomplete;