import { useCallback, useState } from 'react'; import { useNavigate } from 'react-router'; import { useTranslation } from 'react-i18next'; import { AnimatePresence, motion } from 'framer-motion'; import * as DialogPrimitive from '@radix-ui/react-dialog'; import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, } from '@/components/primitives/Command'; import { usePlatform } from '@/platform'; import { useAuthStore } from '@/store/auth'; import { useTheme } from '@/hooks/useTheme'; import { cn } from '@/lib/utils'; import { backdrop, backdropTransition, commandPalette, commandPaletteTransition, } from '@/components/motion/transitions'; // Icons import { HomeIcon, SubscriptionIcon, WalletIcon, UsersIcon, ChatIcon, UserIcon, GamepadIcon, ClipboardIcon, InfoIcon, CogIcon, WheelIcon, PlusIcon, DownloadIcon, SunIcon, MoonIcon, } from '@/components/layout/AppShell/icons'; interface CommandPaletteProps { open: boolean; onOpenChange: (open: boolean) => void; wheelEnabled?: boolean; referralEnabled?: boolean; hasContests?: boolean; hasPolls?: boolean; } export function CommandPalette({ open, onOpenChange, wheelEnabled, referralEnabled, hasContests, hasPolls, }: CommandPaletteProps) { const { t } = useTranslation(); const navigate = useNavigate(); const { haptic } = usePlatform(); const isAdmin = useAuthStore((state) => state.isAdmin); const { toggleTheme, isDark } = useTheme(); const [search, setSearch] = useState(''); const runCommand = useCallback( (command: () => void) => { haptic.impact('light'); onOpenChange(false); command(); }, [haptic, onOpenChange], ); // Navigation items const navigationItems = [ { label: t('nav.dashboard'), icon: HomeIcon, path: '/' }, { label: t('nav.subscription'), icon: SubscriptionIcon, path: '/subscriptions' }, { label: t('nav.balance'), icon: WalletIcon, path: '/balance' }, ...(referralEnabled ? [{ label: t('nav.referral'), icon: UsersIcon, path: '/referral' }] : []), { label: t('nav.support'), icon: ChatIcon, path: '/support' }, ...(hasContests ? [{ label: t('nav.contests'), icon: GamepadIcon, path: '/contests' }] : []), ...(hasPolls ? [{ label: t('nav.polls'), icon: ClipboardIcon, path: '/polls' }] : []), ...(wheelEnabled ? [{ label: t('nav.wheel'), icon: WheelIcon, path: '/wheel' }] : []), { label: t('nav.info'), icon: InfoIcon, path: '/info' }, { label: t('nav.profile'), icon: UserIcon, path: '/profile' }, ...(isAdmin ? [{ label: t('admin.nav.title'), icon: CogIcon, path: '/admin' }] : []), ]; // Action items const actionItems = [ { label: t('balance.top_up') || 'Top up balance', icon: PlusIcon, action: () => navigate('/balance'), }, { label: t('subscription.get_config') || 'Get VPN config', icon: DownloadIcon, action: () => navigate('/subscriptions'), }, { label: isDark ? t('theme.light') || 'Light mode' : t('theme.dark') || 'Dark mode', icon: isDark ? SunIcon : MoonIcon, action: toggleTheme, }, { label: t('support.create_ticket') || 'Create support ticket', icon: ChatIcon, action: () => navigate('/support'), }, ]; return ( {open && ( <> {/* Backdrop */} {/* Content */} {t('common.no_results') || 'No results found.'} {/* Navigation */} {navigationItems.map((item) => ( runCommand(() => navigate(item.path))} > {item.label} ))} {/* Actions */} {actionItems.map((item) => ( runCommand(item.action)} > {item.label} ))} {/* Footer with keyboard hints */}
↑↓ navigate
select
esc close
)}
); }