mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
BC-12 feat: store accounts table columns resizing to local storage.
This commit is contained in:
@@ -32,6 +32,8 @@ import TableWrapper from './Datatable/TableWrapper';
|
||||
import TableIndeterminateCheckboxRow from './Datatable/TableIndeterminateCheckboxRow';
|
||||
import TableIndeterminateCheckboxHeader from './Datatable/TableIndeterminateCheckboxHeader';
|
||||
|
||||
import { useResizeObserver } from './Datatable/utils';
|
||||
|
||||
/**
|
||||
* Datatable component.
|
||||
*/
|
||||
@@ -78,6 +80,9 @@ export default function DataTable(props) {
|
||||
TablePaginationRenderer,
|
||||
TableFooterRenderer,
|
||||
|
||||
onColumnResizing,
|
||||
initialColumnsWidths,
|
||||
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@@ -106,6 +111,9 @@ export default function DataTable(props) {
|
||||
pageIndex: initialPageIndex,
|
||||
pageSize: initialPageSize,
|
||||
expanded,
|
||||
columnResizing: {
|
||||
columnWidths: initialColumnsWidths || {},
|
||||
},
|
||||
},
|
||||
manualPagination,
|
||||
pageCount: controlledPageCount,
|
||||
@@ -164,6 +172,11 @@ export default function DataTable(props) {
|
||||
saveInvoke(onSelectedRowsChange, selectedFlatRows);
|
||||
}, [selectedRowIds, onSelectedRowsChange]);
|
||||
|
||||
// Column resizing observer.
|
||||
useResizeObserver(table.state, (current, columnWidth, columnsResizing) => {
|
||||
onColumnResizing && onColumnResizing(current, columnWidth, columnsResizing);
|
||||
});
|
||||
|
||||
return (
|
||||
<TableContext.Provider value={{ table, props }}>
|
||||
<TableWrapperRenderer>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { React } from 'react';
|
||||
|
||||
export const isCellLoading = (loading, cellsCoords, rowIndex, columnId) => {
|
||||
if (!loading) {
|
||||
return false;
|
||||
@@ -8,3 +10,26 @@ export const isCellLoading = (loading, cellsCoords, rowIndex, columnId) => {
|
||||
(cellCoord) => cellCoord[0] === rowIndex && cellCoord[1] === columnId,
|
||||
);
|
||||
};
|
||||
|
||||
export const useResizeObserver = (state, callback) => {
|
||||
// This Ref will contain the id of the column being resized or undefined
|
||||
const columnResizeRef = React.useRef();
|
||||
|
||||
React.useEffect(() => {
|
||||
// We are interested in calling the resize event only when "state.columnResizing?.isResizingColumn" changes from
|
||||
// a string to undefined, because it indicates that it WAS resizing but it no longer is.
|
||||
if (
|
||||
state.columnResizing &&
|
||||
!state.columnResizing?.isResizingColumn &&
|
||||
columnResizeRef.current
|
||||
) {
|
||||
// Trigger resize event
|
||||
callback(
|
||||
columnResizeRef.current,
|
||||
state.columnResizing.columnWidths[columnResizeRef.current],
|
||||
state.columnResizing,
|
||||
);
|
||||
}
|
||||
columnResizeRef.current = state.columnResizing?.isResizingColumn;
|
||||
}, [callback, state.columnResizing]);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@ import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { useMemorizedColumnsWidths } from '../../hooks';
|
||||
|
||||
/**
|
||||
* Accounts data-table.
|
||||
*/
|
||||
@@ -28,11 +30,8 @@ function AccountsDataTable({
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
const {
|
||||
isAccountsLoading,
|
||||
isAccountsFetching,
|
||||
accounts,
|
||||
} = useAccountsChartContext();
|
||||
const { isAccountsLoading, isAccountsFetching, accounts } =
|
||||
useAccountsChartContext();
|
||||
|
||||
// Retrieve accounts table columns.
|
||||
const columns = useAccountsTableColumns();
|
||||
@@ -80,6 +79,9 @@ function AccountsDataTable({
|
||||
const handleCellClick = (cell, event) => {
|
||||
openDrawer('account-drawer', { accountId: cell.row.original.id });
|
||||
};
|
||||
// Local storage memorizing columns widths.
|
||||
const [initialColumnsWidths, , handleColumnResizing] =
|
||||
useMemorizedColumnsWidths('accounts');
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
@@ -98,7 +100,7 @@ function AccountsDataTable({
|
||||
autoResetSelectedRows={false}
|
||||
expandColumnSpace={1}
|
||||
expandToggleColumn={2}
|
||||
selectionColumnWidth={50}
|
||||
selectionColumnWidth={45}
|
||||
TableCellRenderer={TableFastCell}
|
||||
TableRowsRenderer={TableVirtualizedListRows}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
@@ -108,6 +110,8 @@ function AccountsDataTable({
|
||||
vListrowHeight={42}
|
||||
vListOverscanRowCount={0}
|
||||
onCellClick={handleCellClick}
|
||||
initialColumnsWidths={initialColumnsWidths}
|
||||
onColumnResizing={handleColumnResizing}
|
||||
payload={{
|
||||
onEdit: handleEditAccount,
|
||||
onDelete: handleDeleteAccount,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useRef, useEffect, useMemo } from 'react';
|
||||
import React, { useRef, useEffect, useMemo } from 'react';
|
||||
import useAsync from './async';
|
||||
import useAutofocus from './useAutofocus';
|
||||
|
||||
// import use from 'async';
|
||||
|
||||
|
||||
/**
|
||||
* A custom useEffect hook that only triggers on updates, not on initial mount
|
||||
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
|
||||
@@ -49,11 +48,10 @@ const isCurrentFocus = (autoFocus, columnId, rowIndex) => {
|
||||
};
|
||||
|
||||
export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
|
||||
const focus = useMemo(() => isCurrentFocus(autoFocus, columnId, rowIndex), [
|
||||
autoFocus,
|
||||
columnId,
|
||||
rowIndex,
|
||||
]);
|
||||
const focus = useMemo(
|
||||
() => isCurrentFocus(autoFocus, columnId, rowIndex),
|
||||
[autoFocus, columnId, rowIndex],
|
||||
);
|
||||
useEffect(() => {
|
||||
if (ref.current && focus) {
|
||||
ref.current.focus();
|
||||
@@ -65,3 +63,46 @@ export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
|
||||
|
||||
export * from './useRequestPdf';
|
||||
export { useAsync, useAutofocus };
|
||||
|
||||
// Hook
|
||||
export function useLocalStorage(key, initialValue) {
|
||||
// State to store our value
|
||||
// Pass initial state function to useState so logic is only executed once
|
||||
const [storedValue, setStoredValue] = React.useState(() => {
|
||||
try {
|
||||
// Get from local storage by key
|
||||
const item = window.localStorage.getItem(key);
|
||||
// Parse stored json or if none return initialValue
|
||||
return item ? JSON.parse(item) : initialValue;
|
||||
} catch (error) {
|
||||
return initialValue;
|
||||
}
|
||||
});
|
||||
// Return a wrapped version of useState's setter function that ...
|
||||
// ... persists the new value to localStorage.
|
||||
const setValue = (value) => {
|
||||
try {
|
||||
// Allow value to be a function so we have same API as useState
|
||||
const valueToStore =
|
||||
value instanceof Function ? value(storedValue) : value;
|
||||
// Save state
|
||||
setStoredValue(valueToStore);
|
||||
// Save to local storage
|
||||
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||
} catch (error) {
|
||||
// A more advanced implementation would handle the error case
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
return [storedValue, setValue];
|
||||
}
|
||||
|
||||
|
||||
export function useMemorizedColumnsWidths(tableName) {
|
||||
const [get, save] = useLocalStorage(`${tableName}.columns_widths`, {});
|
||||
|
||||
const handleColumnResizing = (current, columnWidth, columnsResizing) => {
|
||||
save(columnsResizing.columnWidths);
|
||||
};
|
||||
return [get, save, handleColumnResizing];
|
||||
}
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
useSetGlobalErrors,
|
||||
useAuthToken,
|
||||
} from './state';
|
||||
import { useAppIntlContext } from '../components/AppIntlProvider';
|
||||
import { getCookie } from '../utils';
|
||||
|
||||
export default function useApiRequest() {
|
||||
const setGlobalErrors = useSetGlobalErrors();
|
||||
const { setLogout } = useAuthActions();
|
||||
const { currentLocale } = useAppIntlContext();
|
||||
|
||||
const currentLocale = getCookie('locale');
|
||||
|
||||
// Authentication token.
|
||||
const token = useAuthToken();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user