/* eslint-disable @typescript-eslint/no-explicit-any */ import _ from "lodash"; import { ChooserColumn } from "../../../data/setting"; import ColumnChooserView from "./ColumnChooserView"; import { useEffect, useMemo, useRef, useState } from "react"; import useClickOutside from "../../../../../utils/useClickOutside"; /** The display order used by `sortedSelectedColumns`. */ const byOrder = (a: ChooserColumn, b: ChooserColumn) => (a.order ?? 0) - (b.order ?? 0); export type ColumnChooserProps = { uiElementGroupData: Record; toggleColumnChooser: boolean; columns: ChooserColumn[]; config: { uiElementGroupId: string }; onChooserClick: () => void; onModelUpdate: ( callBack: ((args: any) => void) | null, fieldName: string, value: any, ) => void; setToggleColumnChooser: (status: boolean) => void; setTogglePopup: (status: boolean) => void; }; const ColumnChooser = (props: ColumnChooserProps) => { const [searchInput, setSearchInput] = useState(""); const [localAllColumns, setLocalAllColumns] = useState([]); const [localSelectedColumns, setLocalSelectedColumns] = useState< ChooserColumn[] >([]); const popupChooserRef = useRef(null); // Reset local state from model when popup opens useEffect(() => { if (props.toggleColumnChooser) { setLocalAllColumns( _.cloneDeep( props.uiElementGroupData?.setting?.columnChooser?.allColumns ?? [], ), ); setLocalSelectedColumns( _.cloneDeep( props.uiElementGroupData?.setting?.columnChooser?.selectedColumns ?? [], ), ); setSearchInput(""); } }, [props.toggleColumnChooser]); const searchedColumns = useMemo( () => localAllColumns.filter((c: ChooserColumn) => c.label.toLowerCase().includes(searchInput?.toLowerCase()), ), [searchInput, localAllColumns], ); const sortedSelectedColumns = useMemo(() => { const sColumns = _.cloneDeep(localSelectedColumns); return sColumns?.sort(byOrder); }, [localSelectedColumns]); // The old guard required `textContent !== "Column Chooser"` to close, i.e. a // click on the menu entry that opened this popup was ignored. As an *exempt* // predicate that polarity inverts: exempt exactly the "Column Chooser" target. useClickOutside( popupChooserRef, props.toggleColumnChooser, () => props.onChooserClick(), (target) => target.textContent === "Column Chooser", ); const onFieldAddOrRemove = (id: number) => { const allColumns = _.cloneDeep(localAllColumns); const sColumns = _.cloneDeep(localSelectedColumns); const sColumn = allColumns.find((a: ChooserColumn) => a.id === id); let selectedColumns: ChooserColumn[] = []; if (sColumn?.selected) { selectedColumns = sColumns?.filter((a: ChooserColumn) => a.id !== id); selectedColumns = selectedColumns.map((s, index: number) => { s.order = index + 1; return s; }); } else if (sColumn) { selectedColumns = [ ...sColumns, { ...sColumn, selected: true, order: sColumns.length }, ]; } allColumns.forEach((column: ChooserColumn) => { if (column.id === id) { column.selected = !column.selected; } }); setLocalAllColumns(allColumns); setLocalSelectedColumns(selectedColumns); }; const excludeIncludeToCard = (id: number) => { const selectedColumns = _.cloneDeep(localSelectedColumns); selectedColumns.forEach((column: ChooserColumn) => { if (column.id === id) { column.includeInCard = !column.includeInCard; } }); setLocalSelectedColumns(selectedColumns); }; const toggleFreeze = (id: number) => { const selectedColumns = _.cloneDeep(localSelectedColumns); const freezeIndex = selectedColumns.findIndex( (column: ChooserColumn) => column.id === id, ); selectedColumns.forEach((column: ChooserColumn, index: number) => { if (index <= freezeIndex) { column.isFreezed = true; } else { column.isFreezed = column.primary || false; } }); setLocalSelectedColumns(selectedColumns); }; const onChooserApply = () => { const updatedUiElementGroupData = { ...props.uiElementGroupData, setting: { ...props.uiElementGroupData.setting, columnChooser: { ...props.uiElementGroupData.setting.columnChooser, allColumns: _.cloneDeep(localAllColumns), selectedColumns: _.cloneDeep(localSelectedColumns), appliedColumns: _.cloneDeep(sortedSelectedColumns), }, }, }; props.setToggleColumnChooser(false); props.setTogglePopup(false); props.onModelUpdate( null, props.config.uiElementGroupId, updatedUiElementGroupData, ); }; const onChooserRestore = () => { const restoredAll = _.cloneDeep(props.columns); // Sort by `order` exactly as `sortedSelectedColumns` does. Without it the // local array kept the declaration order while the list rendered in `order` // order, so `toggleFreeze` — which freezes by *index* into the local array — // froze the wrong rows after a restore. const restoredSelected = restoredAll.filter((c) => c.selected).sort(byOrder); setLocalAllColumns(restoredAll); setLocalSelectedColumns(restoredSelected); }; const onFieldDragEnd = (result: any) => { if (!result.destination) return; if (result.destination.index === result.source.index) return; const clonedSelectedColumns = _.cloneDeep(sortedSelectedColumns); const movedItem = clonedSelectedColumns.splice(result.source.index, 1)[0]; clonedSelectedColumns.splice(result.destination.index, 0, movedItem); clonedSelectedColumns.forEach((column: ChooserColumn, index: number) => { column.order = index + 1; }); setLocalSelectedColumns(clonedSelectedColumns); }; return ( ); }; export default ColumnChooser;