import React, { useState, useMemo } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { api } from '@/lib/api'; import { SettingsLayout } from './components/SettingsLayout'; import { SettingsCard } from './components/SettingsCard'; import { Switch } from '@/components/ui/switch'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { RefreshCw, Mail, Heart, Users, RefreshCcw, Key, Search, Settings, Truck, CreditCard, BarChart3, Puzzle } from 'lucide-react'; import { toast } from 'sonner'; import { __ } from '@/lib/i18n'; import { useNavigate } from 'react-router-dom'; interface Module { id: string; label: string; description: string; category: string; icon: string; enabled: boolean; features: string[]; is_addon?: boolean; version?: string; author?: string; has_settings?: boolean; } interface ModulesData { modules: Record; grouped: Record; categories: Record; } export default function Modules() { const queryClient = useQueryClient(); const navigate = useNavigate(); const [searchQuery, setSearchQuery] = useState(''); const [selectedCategory, setSelectedCategory] = useState(null); const { data: modulesData, isLoading } = useQuery({ queryKey: ['modules'], queryFn: async () => { const response = await api.get('/modules'); // api.get returns JSON directly, not wrapped in .data return response as ModulesData; }, }); const toggleModule = useMutation({ mutationFn: async ({ moduleId, enabled }: { moduleId: string; enabled: boolean }) => { return api.post('/modules/toggle', { module_id: moduleId, enabled }); }, onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: ['modules'] }); toast.success( variables.enabled ? __('Module enabled successfully') : __('Module disabled successfully') ); }, onError: (error: any) => { toast.error(error?.message || __('Failed to toggle module')); }, }); const getIcon = (iconName: string) => { const icons: Record = { mail: Mail, heart: Heart, users: Users, 'refresh-cw': RefreshCcw, key: Key, truck: Truck, 'credit-card': CreditCard, 'bar-chart-3': BarChart3, puzzle: Puzzle, }; const Icon = icons[iconName] || Puzzle; return ; }; // Filter modules based on search and category const filteredGrouped = useMemo(() => { if (!modulesData?.grouped) return {}; const filtered: Record = {}; Object.entries(modulesData.grouped).forEach(([category, modules]) => { // Filter by category if selected if (selectedCategory && category !== selectedCategory) return; // Filter by search query const matchingModules = modules.filter((module) => { if (!searchQuery) return true; const query = searchQuery.toLowerCase(); return ( module.label.toLowerCase().includes(query) || module.description.toLowerCase().includes(query) || module.features.some((f) => f.toLowerCase().includes(query)) ); }); if (matchingModules.length > 0) { filtered[category] = matchingModules; } }); return filtered; }, [modulesData, searchQuery, selectedCategory]); const categories = Object.keys(modulesData?.categories || {}); return ( {/* Search and Filters */}
{/* Search Input */}
setSearchQuery(e.target.value)} className="!pl-9" />
{/* Category Pills */}
{categories.map((category) => ( ))}
{/* Info Card */}

{__( 'Modules allow you to enable only the features you need. Disabling unused modules improves performance and reduces clutter in your admin panel.' )}

💡 {__('Tip: When you disable a module, its menu items and settings will be hidden from the admin panel, and its features will be disabled on the frontend.')}

{/* Module Categories */} {Object.keys(filteredGrouped).length === 0 && (

{__('No modules found matching your search')}

)} {Object.entries(filteredGrouped).map(([category, modules]) => { if (modules.length === 0) return null; return (
{modules.map((module) => (
{/* Icon */}
{getIcon(module.icon)}
{/* Content */}

{module.label}

{module.enabled && ( {__('Active')} )} {module.is_addon && ( {__('Addon')} )}

{module.description}

{/* Features List */} {module.features && module.features.length > 0 && (
    {module.features.map((feature, index) => (
  • • {feature}
  • ))}
)}
{/* Actions */}
{/* Settings Gear Icon */} {module.has_settings && module.enabled && ( )} {/* Toggle Switch */} toggleModule.mutate({ moduleId: module.id, enabled }) } disabled={toggleModule.isPending} />
))}
); })}
); }