import { createRef, useCallback, useEffect, useRef, useState } from 'react' import { useRouter } from 'next/router' import { useTranslation } from 'react-i18next' import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from 'cmdk' import Popover from '~components/common/Popover' import SegmentedControl from '~components/common/SegmentedControl' import Segment from '~components/common/Segment' import RaidItem from '~components/raids/RaidItem' import Tooltip from '~components/common/Tooltip' import api from '~utils/api' interface Props { showAllRaidsOption: boolean currentRaid?: Raid defaultRaid?: Raid onChange?: (raid?: Raid) => void onBlur?: (event: React.ChangeEvent) => void } import Button from '~components/common/Button' import ArrowIcon from '~public/icons/Arrow.svg' import CrossIcon from '~public/icons/Cross.svg' import './index.scss' import classNames from 'classnames' import { appState } from '~utils/appState' const NUM_SECTIONS = 3 enum Sort { ASCENDING, DESCENDING, } const RaidCombobox = (props: Props) => { // Set up router for locale const router = useRouter() const locale = router.locale || 'en' // Set up translations const { t } = useTranslation('common') // Component state const [open, setOpen] = useState(false) const [sort, setSort] = useState(Sort.DESCENDING) const [scrolled, setScrolled] = useState(false) // Data state const [currentSection, setCurrentSection] = useState(1) const [search, setSearch] = useState('') const [sections, setSections] = useState() const [currentRaid, setCurrentRaid] = useState() // Refs const listRef = createRef() const selectedRef = createRef() useEffect(() => { if (appState.party.raid) { setCurrentRaid(appState.party.raid) setCurrentSection(appState.party.raid.group.section) } }, []) // Scroll to the top of the list when the user switches tabs useEffect(() => { if (listRef.current) listRef.current.scrollTop = 0 }, [currentSection]) const scrollToItem = useCallback( (node) => { if ( !scrolled && open && currentRaid && listRef.current && node !== null ) { const listRect = listRef.current.getBoundingClientRect() const itemRect = node.getBoundingClientRect() const distance = itemRect.top - listRect.top listRef.current.scrollTop = distance setScrolled(true) } }, [open, currentRaid, listRef] ) // Methods: Convenience methods function reverseSort() { if (sort === Sort.ASCENDING) setSort(Sort.DESCENDING) else setSort(Sort.ASCENDING) } // Sort raids into defined groups const sortGroups = useCallback( (groups: RaidGroup[]) => { const sections: [RaidGroup[], RaidGroup[], RaidGroup[]] = [[], [], []] groups.forEach((group) => { if (group.section > 0) sections[group.section - 1].push(group) }) setSections(sections) }, [setSections] ) function handleValueChange(raid: Raid) { setCurrentRaid(raid) setOpen(false) setScrolled(false) if (props.onChange) props.onChange(raid) } function toggleOpen() { if (open) { if (currentRaid) setCurrentSection(currentRaid.group.section) setScrolled(false) } setOpen(!open) } function clearSearch() { setSearch('') } const linkClass = classNames({ wind: currentRaid && currentRaid.element == 1, fire: currentRaid && currentRaid.element == 2, water: currentRaid && currentRaid.element == 3, earth: currentRaid && currentRaid.element == 4, dark: currentRaid && currentRaid.element == 5, light: currentRaid && currentRaid.element == 6, }) // Fetch all raids on mount useEffect(() => { api.raidGroups().then((response) => sortGroups(response.data)) }, [sortGroups]) // Methods: Rendering function renderRaidSections() { let sections = [] for (let i = 0; i < NUM_SECTIONS; i++) { sections.push(renderRaidSection(i)) } return sections } function renderRaidSection(section: number) { if (!sections || !sections[section]) return else { const currentSection = sections[section] return currentSection .sort((a, b) => { if (sort === Sort.ASCENDING) return a.order - b.order else return b.order - a.order }) .map((group, i) => renderRaidGroup(section, i)) } } // Render JSX for each raid option, sorted into optgroups function renderRaidGroup(section: number, index: number) { let options = [] if (!sections || !sections[section] || !sections[section][index]) return else { const group = sections[section][index] options = group.raids .sort((a, b) => { if (a.element > 0 && b.element > 0) return a.element - b.element else if (a.name.en.includes('NM') && b.name.en.includes('NM')) return a.level < b.level ? -1 : 1 else return a.name.en < b.name.en ? -1 : 1 }) .map((item, i) => renderRaidItem(item, i)) return ( {group.name[locale]}
} > {options}
) } } function renderRaidItem(raid: Raid, key: number) { return ( handleValueChange(raid)} > {raid.name[locale]} ) } return (
{currentRaid?.group.name[locale]} / {currentRaid?.name[locale]}
{currentRaid.group.extra ? ( EX ) : ( '' )} ), rawValue: currentRaid?.id, } : undefined } >
0, })} onClick={clearSearch} >
{!search ? (
setCurrentSection(2)} > {t('raids.sections.events')} setCurrentSection(1)} > {t('raids.sections.raids')} setCurrentSection(3)} > {t('raids.sections.solo')}
) : ( '' )}
{renderRaidSections()}
) } export default RaidCombobox