Further refactoring of RaidCombobox
This commit is contained in:
parent
f96d78770a
commit
10e53b2b83
1 changed files with 61 additions and 43 deletions
|
|
@ -1,14 +1,9 @@
|
||||||
import { createRef, useCallback, useEffect, useRef, useState } from 'react'
|
import { createRef, useCallback, useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import {
|
import { Command, CommandGroup, CommandInput } from 'cmdk'
|
||||||
Command,
|
|
||||||
CommandEmpty,
|
|
||||||
CommandGroup,
|
|
||||||
CommandInput,
|
|
||||||
CommandItem,
|
|
||||||
} from 'cmdk'
|
|
||||||
import Popover from '~components/common/Popover'
|
import Popover from '~components/common/Popover'
|
||||||
import SegmentedControl from '~components/common/SegmentedControl'
|
import SegmentedControl from '~components/common/SegmentedControl'
|
||||||
import Segment from '~components/common/Segment'
|
import Segment from '~components/common/Segment'
|
||||||
|
|
@ -16,6 +11,7 @@ import RaidItem from '~components/raids/RaidItem'
|
||||||
import Tooltip from '~components/common/Tooltip'
|
import Tooltip from '~components/common/Tooltip'
|
||||||
|
|
||||||
import api from '~utils/api'
|
import api from '~utils/api'
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showAllRaidsOption: boolean
|
showAllRaidsOption: boolean
|
||||||
|
|
@ -32,8 +28,6 @@ import ArrowIcon from '~public/icons/Arrow.svg'
|
||||||
import CrossIcon from '~public/icons/Cross.svg'
|
import CrossIcon from '~public/icons/Cross.svg'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import classNames from 'classnames'
|
|
||||||
import { appState } from '~utils/appState'
|
|
||||||
|
|
||||||
const NUM_SECTIONS = 3
|
const NUM_SECTIONS = 3
|
||||||
|
|
||||||
|
|
@ -64,13 +58,16 @@ const RaidCombobox = (props: Props) => {
|
||||||
// Refs
|
// Refs
|
||||||
const listRef = createRef<HTMLDivElement>()
|
const listRef = createRef<HTMLDivElement>()
|
||||||
|
|
||||||
function slugToRaid(slug: string) {
|
// ----------------------------------------------
|
||||||
return appState.raidGroups
|
// Methods: Lifecycle Hooks
|
||||||
.filter((group) => group.section > 0)
|
// ----------------------------------------------
|
||||||
.flatMap((group) => group.raids)
|
|
||||||
.find((raid) => raid.slug === slug)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Fetch all raids on mount
|
||||||
|
useEffect(() => {
|
||||||
|
api.raidGroups().then((response) => sortGroups(response.data))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Set current raid and section when the component mounts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appState.party.raid) {
|
if (appState.party.raid) {
|
||||||
setCurrentRaid(appState.party.raid)
|
setCurrentRaid(appState.party.raid)
|
||||||
|
|
@ -78,6 +75,7 @@ const RaidCombobox = (props: Props) => {
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Update current raid when the currentRaidSlug prop changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.currentRaidSlug) {
|
if (props.currentRaidSlug) {
|
||||||
setCurrentRaid(slugToRaid(props.currentRaidSlug))
|
setCurrentRaid(slugToRaid(props.currentRaidSlug))
|
||||||
|
|
@ -86,9 +84,16 @@ const RaidCombobox = (props: Props) => {
|
||||||
|
|
||||||
// Scroll to the top of the list when the user switches tabs
|
// Scroll to the top of the list when the user switches tabs
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (listRef.current) listRef.current.scrollTop = 0
|
if (listRef.current) {
|
||||||
|
listRef.current.scrollTop = 0
|
||||||
|
}
|
||||||
}, [currentSection])
|
}, [currentSection])
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// Methods: Event Handlers
|
||||||
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
// Scroll to an item in the list when it is selected
|
||||||
const scrollToItem = useCallback(
|
const scrollToItem = useCallback(
|
||||||
(node) => {
|
(node) => {
|
||||||
if (!scrolled && open && currentRaid && listRef.current && node) {
|
if (!scrolled && open && currentRaid && listRef.current && node) {
|
||||||
|
|
@ -102,14 +107,13 @@ const RaidCombobox = (props: Props) => {
|
||||||
[scrolled, open, currentRaid, listRef]
|
[scrolled, open, currentRaid, listRef]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Methods: Convenience methods
|
// Reverse the sort order
|
||||||
|
|
||||||
function reverseSort() {
|
function reverseSort() {
|
||||||
if (sort === Sort.ASCENDING) setSort(Sort.DESCENDING)
|
if (sort === Sort.ASCENDING) setSort(Sort.DESCENDING)
|
||||||
else setSort(Sort.ASCENDING)
|
else setSort(Sort.ASCENDING)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort raids into defined groups
|
// Sorts the raid groups into sections
|
||||||
const sortGroups = useCallback(
|
const sortGroups = useCallback(
|
||||||
(groups: RaidGroup[]) => {
|
(groups: RaidGroup[]) => {
|
||||||
const sections: [RaidGroup[], RaidGroup[], RaidGroup[]] = [[], [], []]
|
const sections: [RaidGroup[], RaidGroup[], RaidGroup[]] = [[], [], []]
|
||||||
|
|
@ -123,6 +127,7 @@ const RaidCombobox = (props: Props) => {
|
||||||
[setSections]
|
[setSections]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Handle value change for the raid selection
|
||||||
function handleValueChange(raid: Raid) {
|
function handleValueChange(raid: Raid) {
|
||||||
setCurrentRaid(raid)
|
setCurrentRaid(raid)
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -130,6 +135,7 @@ const RaidCombobox = (props: Props) => {
|
||||||
if (props.onChange) props.onChange(raid)
|
if (props.onChange) props.onChange(raid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle the open state of the combobox
|
||||||
function toggleOpen() {
|
function toggleOpen() {
|
||||||
if (open) {
|
if (open) {
|
||||||
if (currentRaid) setCurrentSection(currentRaid.group.section)
|
if (currentRaid) setCurrentSection(currentRaid.group.section)
|
||||||
|
|
@ -138,33 +144,22 @@ const RaidCombobox = (props: Props) => {
|
||||||
setOpen(!open)
|
setOpen(!open)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the search query
|
||||||
function clearSearch() {
|
function clearSearch() {
|
||||||
setQuery('')
|
setQuery('')
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Methods: Rendering
|
||||||
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
// Renders each raid section
|
||||||
function renderRaidSections() {
|
function renderRaidSections() {
|
||||||
// Renders each raid section
|
|
||||||
return Array.from({ length: NUM_SECTIONS }, (_, i) => renderRaidSection(i))
|
return Array.from({ length: NUM_SECTIONS }, (_, i) => renderRaidSection(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders the specified raid section
|
||||||
function renderRaidSection(section: number) {
|
function renderRaidSection(section: number) {
|
||||||
// Renders the specified raid section
|
|
||||||
const currentSection = sections?.[section]
|
const currentSection = sections?.[section]
|
||||||
if (!currentSection) return
|
if (!currentSection) return
|
||||||
|
|
||||||
|
|
@ -175,8 +170,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
return sortedGroups.map((group, i) => renderRaidGroup(section, i))
|
return sortedGroups.map((group, i) => renderRaidGroup(section, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders the specified raid group
|
||||||
function renderRaidGroup(section: number, index: number) {
|
function renderRaidGroup(section: number, index: number) {
|
||||||
// Renders the specified raid group
|
|
||||||
if (!sections?.[section]?.[index]) return
|
if (!sections?.[section]?.[index]) return
|
||||||
|
|
||||||
const group = sections[section][index]
|
const group = sections[section][index]
|
||||||
|
|
@ -206,8 +201,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates a list of RaidItem components from the specified raids
|
||||||
function generateRaidItems(raids: Raid[]) {
|
function generateRaidItems(raids: Raid[]) {
|
||||||
// Generates a list of RaidItem components from the specified raids
|
|
||||||
return raids
|
return raids
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (a.element > 0 && b.element > 0) return a.element - b.element
|
if (a.element > 0 && b.element > 0) return a.element - b.element
|
||||||
|
|
@ -218,8 +213,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
.map((item, i) => renderRaidItem(item, i))
|
.map((item, i) => renderRaidItem(item, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders a RaidItem component for the specified raid
|
||||||
function renderRaidItem(raid: Raid, key: number) {
|
function renderRaidItem(raid: Raid, key: number) {
|
||||||
// Renders a RaidItem component for the specified raid
|
|
||||||
const isSelected = currentRaid?.id === raid.id
|
const isSelected = currentRaid?.id === raid.id
|
||||||
const isRef = isSelected ? scrollToItem : undefined
|
const isRef = isSelected ? scrollToItem : undefined
|
||||||
const imageUrl = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/raids/${raid.slug}.png`
|
const imageUrl = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/raids/${raid.slug}.png`
|
||||||
|
|
@ -240,8 +235,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders a SegmentedControl component for selecting raid sections.
|
||||||
function renderSegmentedControl() {
|
function renderSegmentedControl() {
|
||||||
// Renders a SegmentedControl component for selecting raid sections.
|
|
||||||
return (
|
return (
|
||||||
<SegmentedControl blended={true}>
|
<SegmentedControl blended={true}>
|
||||||
<Segment
|
<Segment
|
||||||
|
|
@ -272,8 +267,9 @@ const RaidCombobox = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders a Button for sorting raids and a Tooltip for explaining what it does.
|
||||||
|
|
||||||
function renderSortButton() {
|
function renderSortButton() {
|
||||||
// Renders a Button for sorting raids and a Tooltip for explaining what it does.
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
|
|
@ -293,8 +289,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders the content for the Popover trigger.
|
||||||
function renderTriggerContent() {
|
function renderTriggerContent() {
|
||||||
// Renders the content for the Popover trigger.
|
|
||||||
if (currentRaid) {
|
if (currentRaid) {
|
||||||
const element = (
|
const element = (
|
||||||
<>
|
<>
|
||||||
|
|
@ -323,8 +319,8 @@ const RaidCombobox = (props: Props) => {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders the search input for the raid combobox
|
||||||
function renderSearchInput() {
|
function renderSearchInput() {
|
||||||
// Renders the search input for the raid combobox
|
|
||||||
return (
|
return (
|
||||||
<div className="Bound Joined">
|
<div className="Bound Joined">
|
||||||
<CommandInput
|
<CommandInput
|
||||||
|
|
@ -347,6 +343,28 @@ const RaidCombobox = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// Methods: Utility
|
||||||
|
// ----------------------------------------------
|
||||||
|
function slugToRaid(slug: string) {
|
||||||
|
return appState.raidGroups
|
||||||
|
.filter((group) => group.section > 0)
|
||||||
|
.flatMap((group) => group.raids)
|
||||||
|
.find((raid) => raid.slug === slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// Render
|
||||||
|
// ----------------------------------------------
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
className="Flush"
|
className="Flush"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue