import React, { useRef } from "react"; import { Button, Stack, Flex, Field, NativeSelect, Input, HoverCard, Text, NumberInput, Box } from "@chakra-ui/react"; import { Plus, CircleMinus, Files, ClipboardPaste, Trash } from 'lucide-react'; // import { GrAdd, GrSubtractCircle } from "react-icons/gr"; // import { FaCopy, FaPaste, FaTrash } from "react-icons/fa"; // ============================================================================ // 1. FILTER ROW (The individual criteria inputs) // ============================================================================ const FilterRow = React.memo(({ filter, columns, setUrl, bundleId, copiedFilter }) => { const types = { AutoField: ["=", "<", ">", "<=", ">="], IntegerField: ["=", "<", ">", "<=", ">="], CharField: ["=", "contains"], DateTimeField: ["range"], }; const columnType = columns[filter.column]; const operators = types[columnType] || ["="]; // default to equals if unknown const handleRemoveFilter = () => { setUrl(prev => ({ ...prev, bundles: prev.bundles.map((bundle) => bundle.id === bundleId ? { ...bundle, filters: bundle.filters.filter((fil) => fil.id !== filter.id) } : bundle ), })); }; const updateFilterField = (field, value) => { setUrl(prev => ({ ...prev, bundles: prev.bundles.map(bundle => bundle.id === bundleId ? { ...bundle, filters: bundle.filters.map(fil => fil.id === filter.id ? { ...fil, [field]: value } : fil ), } : bundle ), })); }; const handleColumnChange = (newCol) => { setUrl((prev) => ({ ...prev, bundles: prev.bundles.map((bundle) => bundle.id === bundleId ? { ...bundle, filters: bundle.filters.map((fil) => fil.id === filter.id ? { ...fil, column: newCol, type: columns[newCol], operator: null, value: null } : fil ), } : bundle ), })); }; const handleDateChange = (type, newDate) => { const currentValue = filter.value || { start: null, end: null }; const updatedValue = { ...currentValue, [type]: newDate || null }; updateFilterField("value", updatedValue); updateFilterField("operator", "range"); }; return ( {/* Remove button */} Remove Filter {/* Copy / Paste Buttons */} Copy Filter Paste Filter {/* Column selector */} handleColumnChange(e.target.value)} > {Object.keys(columns).map((colName) => ( ))} {/* Operator selector */} {columnType === "DateTimeField" ? ( handleDateChange("start", e.target.value)} /> ) : ( updateFilterField("operator", e.target.value)}> {filter.type && operators.map((op) => )} )} {/* Value input */} {columnType === "DateTimeField" ? ( handleDateChange("end", e.target.value)} /> ) : columnType === "IntegerField" || columnType === "AutoField" ? ( updateFilterField("value", e.value)}> ) : ( updateFilterField("value", e.target.value)} /> )} ); }); // ============================================================================ // 2. FILTER BUNDLES (The AND logic groups) // ============================================================================ const FilterBundle = ({ bundle, columns, url, setUrl, copiedFilter }) => { const handleRemoveBundle = () => { setUrl(prev => ({ ...prev, bundles: prev.bundles.filter(b => b.id !== bundle.id) })); }; const handleAddFilter = () => { setUrl(prev => ({ ...prev, bundles: prev.bundles.map(b => b.id === bundle.id ? ({ ...b, filters: [ ...b.filters, { id: crypto.randomUUID(), column: null, type: null, operator: null, value: null } ] }) : (b) ), })); }; return ( {bundle.filters.map((filter) => ( ))} ); }; // ============================================================================ // 3. MAIN QUERY BUILDER (The Engine Wrapper) // ============================================================================ export default function QueryBuilder({ url, setUrl, allColumns, getColumns, pullTable, isLoading, isReadyRef }) { const copiedFilter = useRef(null); const handleAddBundle = () => { setUrl(prev => ({ ...prev, bundles: [ ...prev.bundles, { id: crypto.randomUUID(), filters: [{ id: crypto.randomUUID(), column: null, type: null, operator: null, value: null }], }, ], })); }; return ( {/* Top Controls: Source & Execute */} Data Source { const selectedView = e.target.value; setUrl(prev => ({ ...prev, source: selectedView })); // 🚨 FIXED: Now uses relative pathing for the production API const endpoint = "/api/v2/view_dash_event_search_columns"; getColumns(endpoint); }} > {/* Filter Builder Engine */} {url.source && allColumns?.types && ( Filters {url.bundles.map((bundle) => ( ))} )} ); }