// 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 (
);
};
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;