Skip to content

Commit

Permalink
UIIN-2267: Browse Lists | Focus updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro-Melnyshyn committed Nov 28, 2023
1 parent 5638233 commit f616448
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Ignored hot key command on edit fields. Refs UIIN-2604.
* Don't render Fast Add record modal in a `<Paneset>` to re-calculate other `<Pane>`'s widths after closing. Fixes UIIN-2690.
* "Saving instance failed" modal does not show error message. Fixes UIIN-2686.
* Browse Lists | Focus updates. Fixes UIIN-2267.

## [10.0.6](https://github.com/folio-org/ui-inventory/tree/v10.0.6) (2023-11-24)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v10.0.5...v10.0.6)
Expand Down
41 changes: 39 additions & 2 deletions src/components/BrowseResultsList/BrowseResultsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
memo,
useCallback,
useContext,
useState,
} from 'react';
import {
useLocation,
} from 'react-router-dom';

import { useNamespace } from '@folio/stripes/core';
import {
MCLPagingTypes,
MultiColumnList,
Expand All @@ -28,6 +30,12 @@ import {
} from './constants';
import { isRowPreventsClick } from './utils';
import getBrowseResultsFormatter from './getBrowseResultsFormatter';
import {
getItem,
removeItem,
setItem,
} from '../../storage';
import { useDidUpdate } from '../../hooks';

import css from './BrowseResultsList.css';

Expand All @@ -52,24 +60,51 @@ const BrowseResultsList = ({
filters,
}) => {
const data = useContext(DataContext);
const [namespace] = useNamespace();
const { search } = useLocation();
const {
itemToView,
setItemToView,
deleteItemToView,
} = useItemToView('browse');
const selectedRowPersistKey = `${namespace}/browse.selectedRow`;

const [selectedRow, setSelectedRow] = useState(getItem(selectedRowPersistKey));

const handleRowClick = (e, row) => {
setItem(selectedRowPersistKey, row);
setSelectedRow(row);
};

const removeRowSelection = () => {
removeItem(selectedRowPersistKey);
setSelectedRow(null);
};

const handlePagination = (...params) => {
removeRowSelection();
onNeedMoreData(...params);
};

const browseOption = queryString.parse(search).qindex;
const listId = `browse-results-list-${browseOption}`;

const isSelected = useCallback(({ item, rowIndex }) => {
const isSelected = useCallback(({ item, rowIndex, criteria }) => {
if (isRowPreventsClick(item, browseOption)) return false;

if (!criteria) {
return false;
}

const itemIndex = itemToView?.selector && getItemToViewIndex(itemToView.selector);

return itemIndex === rowIndex;
}, [browseOption, itemToView]);

useDidUpdate(() => {
removeRowSelection();
}, [search]);

return (
<MultiColumnList
key={listId}
Expand All @@ -80,13 +115,15 @@ const BrowseResultsList = ({
visibleColumns={VISIBLE_COLUMNS_MAP[browseOption]}
isEmptyMessage={isEmptyMessage}
isSelected={isSelected}
onRowClick={handleRowClick}
selectedRow={selectedRow}
columnMapping={COLUMNS_MAPPING}
columnWidths={COLUMNS_WIDTHS[browseOption]}
loading={isLoading}
autosize
virtualize={false}
hasMargin
onNeedMoreData={onNeedMoreData}
onNeedMoreData={handlePagination}
pageAmount={BROWSE_RESULTS_COUNT}
pagingType={MCLPagingTypes.PREV_NEXT}
getCellClass={(defaultCellStyle) => `${defaultCellStyle} ${css.cellAlign}`}
Expand Down
3 changes: 3 additions & 0 deletions src/components/BrowseResultsPane/BrowseResultsPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const BrowseResultsPane = ({
isFetching,
isFiltersOpened,
pagination,
paneTitleRef,
toggleFiltersPane,
totalRecords,
}) => {
Expand Down Expand Up @@ -78,6 +79,7 @@ const BrowseResultsPane = ({
data-testid="browse-results-pane"
id="browse-inventory-results-pane"
padContent={false}
paneTitleRef={paneTitleRef}
defaultWidth="fill"
appIcon={<AppIcon app={namespace} />}
paneTitle={<FormattedMessage id="ui-inventory.title.browseCall" />}
Expand All @@ -102,6 +104,7 @@ BrowseResultsPane.propTypes = {
filters: PropTypes.object.isRequired,
isFetching: PropTypes.bool,
isFiltersOpened: PropTypes.bool.isRequired,
paneTitleRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
pagination: PropTypes.shape({
hasPrevPage: PropTypes.bool,
hasNextPage: PropTypes.bool,
Expand Down
10 changes: 10 additions & 0 deletions src/components/InstancesList/InstancesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class InstancesList extends React.Component {
constructor(props) {
super(props);

this.paneTitleRef = React.createRef();

this.state = {
showNewFastAddModal: false,
inTransitItemsExportInProgress: false,
Expand All @@ -177,8 +179,11 @@ class InstancesList extends React.Component {
const {
history,
namespace,
getParams,
} = this.props;

const params = getParams();

this.unlisten = history.listen((location) => {
const hasReset = new URLSearchParams(location.search).get('reset');

Expand All @@ -191,6 +196,10 @@ class InstancesList extends React.Component {
}
});

if (params.selectedBrowseResult === 'true') {
this.paneTitleRef.current.focus();
}

this.processLastSearchTerms();

registerLogoutListener(this.clearStorage, namespace, 'instances-list-logout', history);
Expand Down Expand Up @@ -1218,6 +1227,7 @@ class InstancesList extends React.Component {
editRecordComponent={InstanceForm}
onChangeIndex={onChangeIndex}
onSelectRow={this.onSelectRow}
paneTitleRef={this.paneTitleRef}
newRecordInitialValues={(this.state && this.state.copiedInstance) ? this.state.copiedInstance : {
discoverySuppress: false,
staffSuppress: false,
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export { default as useLastSearchTerms } from './useLastSearchTerms';
export { default as useLogout } from './useLogout';
export { default as useSearchForShadowInstanceTenants } from './useSearchForShadowInstanceTenants';
export { default as useUserTenantPermissions } from './useUserTenantPermissions';
export { default as useDidUpdate } from './useDidUpdate';
1 change: 1 addition & 0 deletions src/hooks/useDidUpdate/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './useDidUpdate';
18 changes: 18 additions & 0 deletions src/hooks/useDidUpdate/useDidUpdate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
useEffect,
useRef,
} from 'react';

const useDidUpdate = (cb, deps) => {
const hasMounted = useRef(false);

useEffect(() => {
if (hasMounted.current) {
cb();
} else {
hasMounted.current = true;
}
}, deps);
};

export default useDidUpdate;
2 changes: 2 additions & 0 deletions src/hooks/useInventoryBrowse/useInventoryBrowse.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const useInventoryBrowse = ({

const {
data = {},
isFetched,
isFetching,
isLoading,
} = useQuery(
Expand Down Expand Up @@ -127,6 +128,7 @@ const useInventoryBrowse = ({

return {
data: data.items,
isFetched,
isFetching,
isLoading,
pagination: {
Expand Down
30 changes: 28 additions & 2 deletions src/views/BrowseInventory/BrowseInventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ const BrowseInventory = () => {
const { isFiltersOpened, toggleFilters } = useFiltersToogle(`${namespace}/filters`);
const { deleteItemToView } = useItemToView('browse');

Check warning on line 47 in src/views/BrowseInventory/BrowseInventory.js

View workflow job for this annotation

GitHub Actions / github-actions-ci

'deleteItemToView' is assigned a value but never used. Allowed unused vars must match /React/u
const [pageConfig, setPageConfig] = useState(getLastBrowseOffset());
const hasFocusedSearchOptionOnMount = useRef(false);
const inputRef = useRef();
const indexRef = useRef();
const paneTitleRef = useRef();

const { search } = location;

Expand Down Expand Up @@ -81,13 +84,13 @@ const BrowseInventory = () => {

const {
data,
isFetched,
isFetching,
pagination,
totalRecords,
} = useInventoryBrowse({
filters: withExtraFilters,
pageParams: { pageConfig, setPageConfig },
options: { onSettled: deleteItemToView },
});

const { validateDataQuery } = useBrowseValidation(searchIndex);
Expand Down Expand Up @@ -128,7 +131,10 @@ const BrowseInventory = () => {
const onApplySearch = useCallback(() => {
const isSearchQueryValid = validateDataQuery(searchQuery);

if (isSearchQueryValid) applySearch();
if (isSearchQueryValid) {
applySearch();
paneTitleRef.current.focus();
}
}, [searchQuery, filters]);

const onChangeSearchIndex = useCallback((e) => {
Expand All @@ -141,6 +147,23 @@ const BrowseInventory = () => {
inputRef.current.focus();
}, [inputRef.current]);

useEffect(() => {
if (hasFocusedSearchOptionOnMount.current) {
return;
}

const handleSearchOptionFocus = () => {
indexRef.current.focus();
hasFocusedSearchOptionOnMount.current = true;
};

if (search && isFetched && !isFetching) {
handleSearchOptionFocus();
} else if (!search) {
handleSearchOptionFocus();
}
}, [isFetched, search, isFetching]);

return (
<PersistedPaneset
appId={namespace}
Expand All @@ -156,6 +179,7 @@ const BrowseInventory = () => {
/>

<SingleSearchForm
autoFocus={false}
applySearch={onApplySearch}
changeSearch={changeSearch}
disabled={!searchIndex}
Expand All @@ -167,6 +191,7 @@ const BrowseInventory = () => {
selectedIndex={searchIndex}
searchableIndexesPlaceholder={searchableIndexesPlaceholder}
inputType="textarea"
indexRef={indexRef}
inputRef={inputRef}
/>

Expand All @@ -189,6 +214,7 @@ const BrowseInventory = () => {
isFetching={isFetching}
isFiltersOpened={isFiltersOpened}
pagination={pagination}
paneTitleRef={paneTitleRef}
toggleFiltersPane={toggleFilters}
totalRecords={totalRecords}
/>
Expand Down
Loading

0 comments on commit f616448

Please sign in to comment.