import { useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useAuthStore } from '@/store/authStore'; import { useSidebarStore, SidebarItemConfig, CONSERVED_SIDEBAR_NAV_IDS } from '@/features/sidebar'; import { useLuckyMixAvailable } from '@/hooks/useLuckyMixAvailable'; import { ALL_NAV_ITEMS } from '@/config/navItems'; import { applySidebarReorderById } from '@/features/sidebar'; import { useListReorderDnd } from '@/hooks/useListReorderDnd'; import type { ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; import { ReorderGripHandle } from '@/features/settings/components/ReorderGripHandle'; import { SettingsGroup } from '@/features/settings/components/SettingsGroup'; import { SettingsToggle } from '@/features/settings/components/SettingsToggle'; const REORDER_TYPE = 'sidebar_reorder'; export function SidebarCustomizer() { const { t } = useTranslation(); const { items, setItems, toggleItem } = useSidebarStore(); const itemsRef = useRef(items); // React Compiler refs rule: ref kept in sync with the latest value for use in handlers; not render data. // eslint-disable-next-line react-hooks/refs itemsRef.current = items; const randomNavMode = useAuthStore(s => s.randomNavMode); const setRandomNavMode = useAuthStore(s => s.setRandomNavMode); const nowPlayingAtTop = useAuthStore(s => s.nowPlayingAtTop); const setNowPlayingAtTop = useAuthStore(s => s.setNowPlayingAtTop); const showLuckyMixMenu = useAuthStore(s => s.showLuckyMixMenu); const setShowLuckyMixMenu = useAuthStore(s => s.setShowLuckyMixMenu); const luckyMixBase = useLuckyMixAvailable(); const luckyMixAvailable = luckyMixBase && randomNavMode === 'separate'; const libraryItems = items.filter(cfg => { if (CONSERVED_SIDEBAR_NAV_IDS.has(cfg.id)) return false; if (!ALL_NAV_ITEMS[cfg.id] || ALL_NAV_ITEMS[cfg.id].section !== 'library') return false; if (randomNavMode === 'hub' && (cfg.id === 'randomMix' || cfg.id === 'randomAlbums' || cfg.id === 'luckyMix')) return false; if (randomNavMode === 'separate' && cfg.id === 'randomPicker') return false; if (cfg.id === 'luckyMix' && !luckyMixAvailable) return false; return true; }); const systemItems = items.filter(cfg => ALL_NAV_ITEMS[cfg.id]?.section === 'system'); const apply = useCallback((draggedId: string, target: ListReorderDropTarget) => { const section = ALL_NAV_ITEMS[draggedId]?.section; if (section !== 'library' && section !== 'system') return; const next = applySidebarReorderById(itemsRef.current, section, draggedId, target); if (next) setItems(next); }, [setItems]); const { isDragging, setContainer, onMouseMove, dropEdge } = useListReorderDnd({ type: REORDER_TYPE, apply }); const renderRow = (cfg: SidebarItemConfig, section: 'library' | 'system') => { const meta = ALL_NAV_ITEMS[cfg.id]; if (!meta) return null; const Icon = meta.icon; const edge = isDragging ? dropEdge(cfg.id) : null; return (