/** * Component: Category Tree View with Toggle Switches * Documentation: documentation/frontend/components.md */ 'use client'; import React from 'react'; import { TORRENT_CATEGORIES, getChildIds, areAllChildrenSelected, isParentCategory, } from '@/lib/utils/torrent-categories'; interface CategoryTreeViewProps { selectedCategories: number[]; onChange: (categories: number[]) => void; defaultCategories?: number[]; // Categories to show "Default" badge for (e.g., [3030] for audiobook, [7020] for ebook) } export function CategoryTreeView({ selectedCategories, onChange, defaultCategories = [3030], // Default to audiobook category for backwards compatibility }: CategoryTreeViewProps) { const isDefaultCategory = (categoryId: number) => defaultCategories.includes(categoryId); const handleParentToggle = (parentId: number) => { const childIds = getChildIds(parentId); const allChildrenSelected = areAllChildrenSelected(parentId, selectedCategories); if (allChildrenSelected) { // Deselect parent and all children onChange( selectedCategories.filter( (id) => id !== parentId && !childIds.includes(id) ) ); } else { // Select parent and all children const newSelection = new Set(selectedCategories); newSelection.add(parentId); childIds.forEach((id) => newSelection.add(id)); onChange(Array.from(newSelection)); } }; const handleChildToggle = (childId: number) => { const isSelected = selectedCategories.includes(childId); if (isSelected) { // Deselect child onChange(selectedCategories.filter((id) => id !== childId)); } else { // Select child onChange([...selectedCategories, childId]); } }; const isParentSelected = (parentId: number) => { return areAllChildrenSelected(parentId, selectedCategories); }; const isChildSelected = (childId: number) => { return selectedCategories.includes(childId); }; return (
{TORRENT_CATEGORIES.map((category) => (
{/* Parent Category Header */}
{category.name} [{category.id}] {isDefaultCategory(category.id) && ( Default )}
{ if (isParentCategory(category.id)) { handleParentToggle(category.id); } else { handleChildToggle(category.id); } }} disabled={false} />
{/* Child Categories */} {category.children && category.children.length > 0 && (
{category.children.map((child) => (
{child.name} [{child.id}] {isDefaultCategory(child.id) && ( Default )}
handleChildToggle(child.id)} disabled={isParentSelected(category.id)} />
))}
)}
))}
); } interface ToggleSwitchProps { checked: boolean; onChange: () => void; disabled: boolean; } function ToggleSwitch({ checked, onChange, disabled }: ToggleSwitchProps) { return ( ); }