Files
thrilltrack-explorer/src-old/components/moderation/DependencyTreeView.tsx

84 lines
3.0 KiB
TypeScript

import { Badge } from '@/components/ui/badge';
import { CheckCircle2, Clock, XCircle, ChevronRight } from 'lucide-react';
import { SubmissionItemWithDeps } from '@/lib/submissionItemsService';
import { cn } from '@/lib/utils';
interface DependencyTreeViewProps {
items: SubmissionItemWithDeps[];
}
export function DependencyTreeView({ items }: DependencyTreeViewProps) {
// Build tree structure - root items (no depends_on)
const rootItems = items.filter(item => !item.depends_on);
const getStatusIcon = (status: string) => {
switch (status) {
case 'approved':
return <CheckCircle2 className="w-4 h-4 text-green-600" />;
case 'rejected':
return <XCircle className="w-4 h-4 text-destructive" />;
case 'pending':
default:
return <Clock className="w-4 h-4 text-muted-foreground" />;
}
};
const getItemLabel = (item: SubmissionItemWithDeps): string => {
const data = typeof item.item_data === 'object' && item.item_data !== null && !Array.isArray(item.item_data)
? item.item_data as Record<string, unknown>
: {};
const name = 'name' in data && typeof data.name === 'string' ? data.name : 'Unnamed';
const type = item.item_type.replace('_', ' ');
return `${name} (${type})`;
};
const renderItem = (item: SubmissionItemWithDeps, level: number = 0) => {
const dependents = items.filter(i => i.depends_on === item.id);
const hasChildren = dependents.length > 0;
return (
<div key={item.id} className={cn("space-y-2", level > 0 && "ml-6 border-l-2 border-border pl-4")}>
<div className="flex items-center gap-2">
{level > 0 && <ChevronRight className="w-4 h-4 text-muted-foreground" />}
{getStatusIcon(item.status)}
<span className={cn(
"text-sm",
item.status === 'approved' && "text-green-700 dark:text-green-400",
item.status === 'rejected' && "text-destructive",
item.status === 'pending' && "text-foreground"
)}>
{getItemLabel(item)}
</span>
<Badge variant={item.status === 'approved' ? 'default' : item.status === 'rejected' ? 'destructive' : 'secondary'} className="text-xs">
{item.status}
</Badge>
{item.depends_on && (
<Badge variant="outline" className="text-xs">
depends on parent
</Badge>
)}
</div>
{hasChildren && dependents.map(dep => renderItem(dep, level + 1))}
</div>
);
};
if (items.length <= 1) {
return null; // Don't show tree for single items
}
return (
<div className="space-y-3 p-4 border rounded-lg bg-muted/30">
<div className="flex items-center gap-2 mb-3">
<span className="text-sm font-semibold">Submission Items ({items.length})</span>
<Badge variant="outline" className="text-xs">
Composite Submission
</Badge>
</div>
<div className="space-y-2">
{rootItems.map(item => renderItem(item))}
</div>
</div>
);
}