useDragNDropColumns.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import {useEffect, useMemo, useState} from 'react';
  2. import type {DragEndEvent} from '@dnd-kit/core';
  3. import {arrayMove} from '@dnd-kit/sortable';
  4. export type Column = {
  5. column: string | undefined;
  6. id: number;
  7. };
  8. interface UseDragAndDropColumnsProps {
  9. columns: string[];
  10. setColumns: (columns: string[]) => void;
  11. }
  12. const extractColumns = (editableColumns: Column[]) => {
  13. return editableColumns.map(({column}) => column ?? '');
  14. };
  15. export function useDragNDropColumns({columns, setColumns}: UseDragAndDropColumnsProps) {
  16. const mappedColumns = useMemo(() => {
  17. return columns.map((column, i) => ({id: i + 1, column}));
  18. }, [columns]);
  19. const [editableColumns, setEditableColumns] = useState<Column[]>(mappedColumns);
  20. useEffect(() => {
  21. setEditableColumns(prevEditableColumns => {
  22. // Only update if there's a change between columns and editableColumns
  23. if (
  24. JSON.stringify(prevEditableColumns.map(c => c.column)) !== JSON.stringify(columns)
  25. ) {
  26. return mappedColumns;
  27. }
  28. return prevEditableColumns;
  29. });
  30. }, [columns, mappedColumns]);
  31. const [nextId, setNextId] = useState(editableColumns.length + 1);
  32. function insertColumn() {
  33. setEditableColumns(oldEditableColumns => {
  34. const newEditableColumns = oldEditableColumns.slice();
  35. newEditableColumns.push({id: nextId, column: undefined});
  36. setNextId(nextId + 1); // make sure to increment the id for the next time
  37. setColumns(extractColumns(newEditableColumns));
  38. return newEditableColumns;
  39. });
  40. }
  41. function updateColumnAtIndex(i: number, column: string) {
  42. setEditableColumns(oldEditableColumns => {
  43. const newEditableColumns = [...oldEditableColumns];
  44. newEditableColumns[i].column = column;
  45. setColumns(extractColumns(newEditableColumns));
  46. return newEditableColumns;
  47. });
  48. }
  49. function deleteColumnAtIndex(i: number) {
  50. setEditableColumns(oldEditableColumns => {
  51. if (oldEditableColumns.length === 1) {
  52. setColumns(['']);
  53. return [{id: 1, column: undefined}];
  54. }
  55. const newEditableColumns = [
  56. ...oldEditableColumns.slice(0, i),
  57. ...oldEditableColumns.slice(i + 1),
  58. ];
  59. setColumns(extractColumns(newEditableColumns));
  60. return newEditableColumns;
  61. });
  62. }
  63. function onDragEnd(event: DragEndEvent) {
  64. const {active, over} = event;
  65. if (active.id !== over?.id) {
  66. const oldIndex = editableColumns.findIndex(({id}) => id === active.id);
  67. const newIndex = editableColumns.findIndex(({id}) => id === over?.id);
  68. setEditableColumns(oldEditableColumns => {
  69. const newEditableColumns = arrayMove(oldEditableColumns, oldIndex, newIndex);
  70. setColumns(extractColumns(newEditableColumns));
  71. return newEditableColumns;
  72. });
  73. }
  74. }
  75. return {
  76. editableColumns,
  77. insertColumn,
  78. updateColumnAtIndex,
  79. deleteColumnAtIndex,
  80. onDragEnd,
  81. };
  82. }