Files
rowy/src/hooks/useTable/useTableConfig.ts
2021-09-07 12:50:53 +10:00

168 lines
4.9 KiB
TypeScript

import { useEffect } from "react";
import { useDebouncedCallback } from "use-debounce";
import _camelCase from "lodash/camelCase";
import _sortBy from "lodash/sortBy";
import useDoc, { DocActions } from "../useDoc";
import { FieldType } from "constants/fields";
import { arrayMover, formatPath } from "../../utils/fns";
import { db, deleteField } from "../../firebase";
export type ColumnConfig = {
fieldName: string;
key: string;
name: string;
type: FieldType;
index: number;
width?: number;
editable?: boolean;
config: { [key: string]: any };
[key: string]: any;
};
const useTableConfig = (tablePath?: string) => {
const [tableConfigState, documentDispatch] = useDoc({
path: tablePath ? formatPath(tablePath) : "",
});
useEffect(() => {
const { doc, columns, rowHeight } = tableConfigState;
// TODO: REMOVE THIS
// Copy columns, rowHeight to tableConfigState
if (doc && columns !== doc.columns) {
documentDispatch({ columns: doc.columns });
}
if (doc && rowHeight !== doc.rowHeight) {
documentDispatch({ rowHeight: doc.rowHeight });
}
}, [tableConfigState.doc]);
/** used for specifying the table in use
* @param table firestore collection path
*/
const setTable = (table: string) => {
documentDispatch({
path: formatPath(table),
columns: [],
doc: null,
ref: db.doc(formatPath(table)),
loading: true,
});
};
/** used for creating a new column
* @param name of column.
* @param type of column
* @param data additional column properties
*/
const addColumn = (name: string, type: FieldType, data?: any) => {
//TODO: validation
const { columns } = tableConfigState;
const newIndex = Object.keys(columns).length ?? 0;
let updatedColumns = { ...columns };
const key = _camelCase(name);
updatedColumns[key] = { name, key, type, ...data, index: newIndex ?? 0 };
documentDispatch({
action: DocActions.update,
data: { columns: updatedColumns },
});
};
/** used for updating the width of column
* @param index of column.
* @param width number of pixels, eg: 120
*/
const [resize] = useDebouncedCallback((index: number, width: number) => {
const { columns } = tableConfigState;
const numberOfFixedColumns = Object.values(columns).filter(
(col: any) => col.fixed && !col.hidden
).length;
const columnsArray = _sortBy(
Object.values(columns).filter((col: any) => !col.hidden && !col.fixed),
"index"
);
let column: any = columnsArray[index - numberOfFixedColumns];
column.width = width;
let updatedColumns = columns;
updatedColumns[column.key] = column;
documentDispatch({
action: DocActions.update,
data: { columns: updatedColumns },
});
}, 1000);
// type updatable = { field: string; value: unknown };
/** used for updating column properties such as type,name etc.
* @param index of column.
* @param {updatable[]} updatables properties to be updated
*/
const updateColumn = (key: string, updates: any) => {
const { columns } = tableConfigState;
const updatedColumns = {
...columns,
[key]: { ...columns[key], ...updates },
};
documentDispatch({
action: DocActions.update,
data: { columns: updatedColumns },
});
};
/** remove column by index
* @param index of column.
*/
const remove = (key: string) => {
const { columns } = tableConfigState;
let updatedColumns = columns;
updatedColumns[key] = deleteField();
documentDispatch({
action: DocActions.update,
data: { columns: updatedColumns },
});
};
/** reorder columns by key
* @param draggedColumnKey column being repositioned.
* @param droppedColumnKey column being .
*/
const reorder = (draggedColumnKey: string, droppedColumnKey: string) => {
const { columns } = tableConfigState;
const oldIndex = columns[draggedColumnKey].index;
const newIndex = columns[droppedColumnKey].index;
const columnsArray = _sortBy(Object.values(columns), "index");
arrayMover(columnsArray, oldIndex, newIndex);
let updatedColumns = columns;
columnsArray
.filter((c) => c) // arrayMover has a bug creating undefined items
.forEach((column: any, index) => {
updatedColumns[column.key] = { ...column, index };
});
documentDispatch({
action: DocActions.update,
data: { columns: updatedColumns },
});
};
/** changing table configuration used for things such as row height
* @param key name of parameter eg. rowHeight
* @param value new value eg. 65
*/
const updateConfig = (key: string, value: unknown) => {
documentDispatch({
action: DocActions.update,
data: { [key]: value },
});
};
const actions = {
updateColumn,
updateConfig,
addColumn,
resize,
setTable,
remove,
reorder,
};
return [tableConfigState, actions];
};
export default useTableConfig;