"use client"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { ChevronRight, Copy as CopyIcon, ExternalLink, Eye, EyeOff, EyeOff as EyeOffIcon, Files, GripVertical, Loader2, Pencil, Plus, Power, PowerOff, Trash2, } from "lucide-react"; import React from "react"; import { CatalogIcon, LAYOUT_COLORS } from "@/components/admin/catalog-tree"; import { Badge } from "@/components/ui/badge"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuTrigger, } from "@/components/ui/context-menu"; import { translateCaption } from "@/lib/catalog-translations"; import { cn } from "@/lib/utils"; export interface FlatTreeNode { id: number; caption: string; parentId: number; enabled: string; visible: string; iconImage: number; iconColor: number; pageLayout: string; childCount: number; itemCount: number; depth: number; isExpanded: boolean; } export interface TreeItemProps { node: FlatTreeNode; sortMode: boolean; isSelected: boolean; isFocused: boolean; isMultiSelected: boolean; isAncestorOfSelected?: boolean; isOverlay?: boolean; onToggleExpand: (id: number) => void; onSelect: (id: number, e?: React.MouseEvent) => void; onAddSubpage: (parentId: number) => void; onToggleEnabled: (id: number, currentEnabled: string) => void; onToggleVisible: (id: number, currentVisible: string) => void; onDuplicate: (id: number) => void; onDelete: (id: number) => void; onOpenFull: (id: number) => void; isLoading?: boolean; } export function SortableTreeItem(props: TreeItemProps) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: props.node.id, disabled: !props.sortMode, }); const style = { transform: CSS.Transform.toString(transform), transition, }; return (
); } export const TreeItemContent = React.memo( function TreeItemContent({ node, sortMode, isSelected, isFocused, isMultiSelected, isAncestorOfSelected, isOverlay, isDragging, dragHandleProps, onToggleExpand, onSelect, onAddSubpage, onToggleEnabled, onToggleVisible, onDuplicate, onDelete, onOpenFull, isLoading, }: TreeItemProps & { isDragging?: boolean; dragHandleProps?: Record; }) { const isDisabled = node.enabled !== "1"; const isHidden = node.visible !== "1"; const italianName = translateCaption(node.caption); const layoutColor = LAYOUT_COLORS[node.pageLayout] || "bg-muted text-muted-foreground"; const content = ( // biome-ignore lint/a11y/useSemanticElements: wrapped by ContextMenuTrigger asChild (Radix); a real ) : ( )} {/* Icon */} {/* Caption */}
{italianName ?? node.caption} {italianName && ( {node.caption} )}
{/* Status indicators */}
{isHidden && } {isDisabled && ( OFF )} {node.itemCount > 0 && ( {node.itemCount} )} {node.pageLayout.replace("default_3x3", "3x3")}
); // In sort mode or overlay, no context menu if (sortMode || isOverlay) return content; return ( {content} {node.caption} #{node.id} onSelect(node.id)}> Edit onOpenFull(node.id)}> Open full editor navigator.clipboard.writeText(String(node.id))} > Copy ID onAddSubpage(node.id)}> Add subpage onDuplicate(node.id)}> Duplicate page onToggleEnabled(node.id, node.enabled)} > {isDisabled ? ( ) : ( )} {isDisabled ? "Enable" : "Disable"} onToggleVisible(node.id, node.visible)} > {isHidden ? ( ) : ( )} {isHidden ? "Show" : "Hide"} onDelete(node.id)} > Delete ); }, (prev, next) => { return ( prev.onSelect === next.onSelect && prev.node.id === next.node.id && prev.node.caption === next.node.caption && prev.node.enabled === next.node.enabled && prev.node.visible === next.node.visible && prev.node.itemCount === next.node.itemCount && prev.node.isExpanded === next.node.isExpanded && prev.node.depth === next.node.depth && prev.isSelected === next.isSelected && prev.isFocused === next.isFocused && prev.isMultiSelected === next.isMultiSelected && prev.isAncestorOfSelected === next.isAncestorOfSelected && prev.sortMode === next.sortMode && prev.isLoading === next.isLoading && prev.isDragging === next.isDragging ); }, );