import React, { useEffect, useState } from 'react' import { useSnapshot } from 'valtio' import { appState } from '~utils/appState' import api from '~utils/api' import * as Dialog from '@radix-ui/react-dialog' import CharacterResult from '~components/CharacterResult' import WeaponResult from '~components/WeaponResult' import SummonResult from '~components/SummonResult' import './index.scss' import CrossIcon from '~public/icons/Cross.svg' interface Props { send: (object: Character | Weapon | Summon, position: number) => any placeholderText: string fromPosition: number object: 'weapons' | 'characters' | 'summons', children: React.ReactNode } const SearchModal = (props: Props) => { let { grid } = useSnapshot(appState) let searchInput = React.createRef() const [objects, setObjects] = useState<{[id: number]: GridCharacter | GridWeapon | GridSummon}>() const [open, setOpen] = useState(false) const [query, setQuery] = useState('') const [results, setResults] = useState({}) const [loading, setLoading] = useState(false) const [message, setMessage] = useState('') const [totalResults, setTotalResults] = useState(0) useEffect(() => { setObjects(grid[props.object]) }, [grid, props.object]) useEffect(() => { if (searchInput.current) searchInput.current.focus() }, [searchInput]) function inputChanged(event: React.ChangeEvent) { const text = event.target.value if (text.length) { setQuery(text) setLoading(true) setMessage('') if (text.length > 2) fetchResults() } else { setQuery('') setResults({}) setMessage('') } } function fetchResults() { // Exclude objects in grid from search results // unless the object is in the position that the user clicked // so that users can replace object versions with // compatible other objects. const excludes = (objects) ? Object.values(objects) .filter(filterExclusions) .map((o) => { return (o.object) ? o.object.name.en : undefined }).join(',') : '' api.search(props.object, query, excludes) .then(response => { setResults(response.data) setTotalResults(response.data.length) setLoading(false) }) .catch(error => { setMessage(error) setLoading(false) }) } function filterExclusions(gridObject: GridCharacter | GridWeapon | GridSummon) { if (objects && gridObject.object && gridObject.object.granblue_id === objects[props.fromPosition]?.object.granblue_id) return null else return gridObject } function sendData(result: Character | Weapon | Summon) { props.send(result, props.fromPosition) setOpen(false) } function renderResults() { switch(props.object) { case 'weapons': return renderWeaponSearchResults(results) break case 'summons': return renderSummonSearchResults(results) break case 'characters': return renderCharacterSearchResults(results) break } } function renderWeaponSearchResults(results: { [key: string]: any }) { const elements = results.map((result: Weapon) => { return { sendData(result) }} /> }) return (
    {elements}
) } function renderSummonSearchResults(results: { [key: string]: any }) { const elements = results.map((result: Summon) => { return { sendData(result) }} /> }) return (
    {elements}
) } function renderCharacterSearchResults(results: { [key: string]: any }) { const elements = results.map((result: Character) => { return { sendData(result) }} /> }) return (
    {elements}
) } function renderEmptyState() { let string = '' if (query === '') { string = `No ${props.object}` } else if (query.length < 3) { string = `Type at least 3 characters` } else { string = `No results found for '${query}'` } return (

{string}

) } function resetAndClose() { setQuery('') setResults({}) setOpen(true) } return ( {props.children} { ((Object.entries(results).length == 0) ? renderEmptyState() : renderResults()) } ) } export default SearchModal