"use client"; /** * Side panel shown when a node is selected. For precedent/halacha nodes it * deep-links into the existing precedent library (/precedents/[id]) so the * graph is a navigation surface, not a dead-end visualization. */ import Link from "next/link"; import { ExternalLink, X } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import type { GraphNode } from "@/lib/api/graph"; const TYPE_LABELS: Record = { precedent: "פסיקה", halacha: "הלכה", topic: "נושא", practice_area: "תחום", gap: "פסיקה חסרה", }; const GAP_STATUS_LABELS: Record = { open: "ממתינה לקליטה", uploaded: "הועלתה", closed: "טופלה", irrelevant: "לא רלוונטית", }; const PA_LABELS: Record = { rishuy_uvniya: "רישוי ובנייה", betterment_levy: "היטל השבחה", compensation_197: "פיצויים (ס׳ 197)", appeals_committee: "ועדת ערר", }; const SOURCE_LABELS: Record = { external_upload: "פסיקה חיצונית", internal_committee: "החלטת ועדה", cited_only: "מוזכר בלבד", nevo_seed: "נבו", }; export function GraphNodePanel({ node, onClose, }: { node: GraphNode; onClose: () => void; }) { const isPrecedentLike = node.type === "precedent" || node.type === "halacha"; const isGap = node.type === "gap"; return (
{TYPE_LABELS[node.type] ?? node.type}

{node.label}

{isPrecedentLike && ( )} {node.practice_area && ( )} {node.source_kind && ( )} {node.precedent_level && } {isGap && ( <> {node.gap_status && ( )}

פסיקה זו מצוטטת בקורפוס אך אינה קיימת בו — מועמדת לקליטה.

)} {!isPrecedentLike && !isGap && (

לחיצה על נקודה זו מתמקדת בשכניה — כל הפסיקות המשויכות אליה.

)}
{isPrecedentLike && node.case_law_id && ( )} {isGap && ( )}
); } function Row({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); }