import {ReactElement, SyntheticEvent, useCallback, useEffect, useState} from 'react' import {Autocomplete, Box, CircularProgress, Theme, Typography,} from '@mui/material' import {makeStyles} from '@mui/styles' import TextField from '@mui/material/TextField' import {getItem, getItemHierarchy, searchItem} from '../dataaccess/ItemBackend'; import {ItemOption} from '../dto/ItemOption' import {useGlobalState} from '../state/GlobalState' // import {useNavigate, useParams} from "react-router-dom"; import {useRouter, dynamic } from "blitz"; let ReactJson if (process.browser){ ReactJson = dynamic(() => import("react-json-view")) } interface IItemOption { id: string name: string shortName?: string } const useStyles = makeStyles((theme: Theme) => ({ searchAreaHolder: { display: 'flex', flexGrow: 1, flexDirection: 'column', background: theme.palette.background.paper, padding: '2vh 2vw 2vh 2vw', }, jsonHolder: { display: 'flex', flexGrow: 1, alignItems: 'center', flexDirection: 'column', background: theme.palette.background.paper, maxHeight: '80vh', }, autocomplete: {}, })) export const SearchArea = () => { const classes = useStyles(); const router = useRouter() const params = router.query; const preferedLocale = useGlobalState((state) => state.preferedLocale) const preferedJsonViewerTheme = useGlobalState( useCallback((state) => state.preferedJsonViewerTheme, []), ) const [searchInputState, setSearchInput] = useGlobalState((state) => [ state.searchInput, state.setSearchInput, ]) const [setHierarchy, initHierarchy] = useGlobalState((state) => [state.setHierarchy, state.initHierarchy]) const [selectedItem, setSelectedItem] = useGlobalState((state) => [ state.selectedItem, state.setSelectedItem, ]) const [selectOptions, setSelecteOptions] = useState([]) const [isbusy, setIsBusy] = useState(false) const searchThreshold = 3 const handleNameInput = useCallback(async (input: string) => { const searchResults = await searchItem(input, preferedLocale) const options = searchResults?.map((res) => ({ id: res.item._id, name: res.locale.Name ? res.locale.Name : res.item._name, shortName: JSON.stringify(res.locale.ShortName) })) setSelecteOptions(options ? options : []) }, [preferedLocale]) const handleIDInput = useCallback(async (input: string) => { const itemJson = await getItem(input, preferedLocale) if (!itemJson) { setSelectedItem(undefined) setSearchInput('') return; } setSelectedItem(itemJson) const itemObj = { id: itemJson.item._id, name: itemJson.locale.Name ? itemJson.locale.Name : itemJson.item._name, shortName: itemJson.locale.ShortName } setSelecteOptions([itemObj]) setSearchInput(itemObj.name) // Update hierachy const itemHierarchy = await getItemHierarchy( itemJson.item, preferedLocale, ) setHierarchy(itemHierarchy ? itemHierarchy : {}) // eslint-disable-next-line }, []) // Need to only be created on startup useEffect(() => initHierarchy(), [initHierarchy]) useEffect(()=>{ if (selectedItem){ router.replace(`/search/${selectedItem.item._id}`) } },[selectedItem, router]) useEffect(() => { if (searchInputState && searchInputState.match(/([a-z0-9]{24})/)) { handleIDInput(searchInputState) } }, [handleIDInput, searchInputState]) const handleInput = useCallback(async (input: string) => { if (!input || input.length < searchThreshold || isbusy) { setSelectedItem(undefined) setSelecteOptions([]) setIsBusy(false) return } setIsBusy(true) if (input.match(/([a-z0-9]{24})/)) await handleIDInput(input) else await handleNameInput(input) setIsBusy(false) }, [handleIDInput, handleNameInput, isbusy, setSelectedItem]) useEffect(() => { if (!searchInputState && params.id) { const newId = (params.id as string).trim(); console.log(newId); setSearchInput(newId); (async () => await handleInput(newId))(); } }, [params, searchInputState, setSearchInput, handleInput, router]) const formatDisplayItems = () => { // If loading if (isbusy) return // If finished loading console.log(process.browser) if (selectedItem && ReactJson !== undefined) { return () } else return No data to display // return No data to display } const findOptionValue = (option: ItemOption, value: ItemOption): boolean => { return option.name?.toLocaleLowerCase() === value.name?.toLocaleLowerCase() || option.id?.toLocaleLowerCase() === value.id?.toLocaleLowerCase() || option.shortName?.toLocaleLowerCase() === value.shortName?.toLocaleLowerCase() } return ( ({name: elt.name, shortName: elt.shortName, id: elt.id}))} getOptionLabel={(option) => (option.name ? option.name : option.id) as string} isOptionEqualToValue={(option, value) => findOptionValue(option, value)} open={!isbusy && searchInputState.length >= searchThreshold && (searchInputState !== selectedItem?.locale.Name && searchInputState !== selectedItem?.item._name)} className={classes.autocomplete} inputValue={searchInputState ? searchInputState : ''} onInputChange={async (evt: SyntheticEvent, newValue: string) => { if (!evt) return setSelectedItem(undefined) setSearchInput(newValue) await handleInput(newValue.trim()) }} value={(() => { const selectedOption = selectOptions.find(elt => elt.id === searchInputState || elt.name === searchInputState); return selectedOption ? selectedOption : null; })()} onChange={async (event: SyntheticEvent, newValue: IItemOption | null) => { if (newValue) { const selectedOption = selectOptions.find( (elt) => elt.name === newValue.name, ) if (selectedOption) await handleIDInput(selectedOption.id) } }} renderInput={(params) => ( )} renderOption={(props, option ) => (
  • {option.name}
  • )} filterOptions={(options, state) => options.filter(elt => { return (elt.name?.toLocaleLowerCase().includes(state.inputValue.toLocaleLowerCase()) || elt.id?.toLocaleLowerCase().includes(state.inputValue.toLocaleLowerCase()) || elt.shortName?.toLocaleLowerCase().includes(state.inputValue.toLocaleLowerCase())) })} filterSelectedOptions /> {formatDisplayItems()}
    ) }