Skip to content

Commit

Permalink
UIIN-3205: Add getCallNumberQuery function to build a query string …
Browse files Browse the repository at this point in the history
…based on the call number and its type. (#2733)
  • Loading branch information
Dmytro-Melnyshyn authored Feb 7, 2025
1 parent e1f5297 commit a288eba
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* Display holdings names in `Consortial holdings` accordion for user without inventory permissions in member tenants. Fixes UIIN-3159.
* Remove the ability to share local instance when `Inventory: View, create instances` permission is assigned. Fixes UIIN-3166.
* *BREAKING* Use `browse` `1.5` interface that provides new Call Number Browse endpoints. Refs UIIN-3162.
* Add `getCallNumberQuery` function to build a query string based on the call number and its type. Refs UIIN-3205.

## [12.0.7](https://github.com/folio-org/ui-inventory/tree/v12.0.7) (2024-12-17)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v12.0.6...v12.0.7)
Expand Down
6 changes: 6 additions & 0 deletions src/components/BrowseResultsList/BrowseResultsList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ const mockContext = {
],
},
],
callNumberBrowseConfig: [
{
id: 'dewey',
typeIds: ['dewey-id', 'lc-id'],
},
],
subjectSources: [{ id: 'sourceId', name: 'sourceName' }],
subjectTypes: [{ id: 'typeId', name: 'typeName' }],
};
Expand Down
60 changes: 44 additions & 16 deletions src/components/BrowseResultsList/getBrowseResultsFormatter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ import '../../../test/jest/__mock__';
import { act, screen, fireEvent } from '@folio/jest-config-stripes/testing-library/react';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import queryString from 'query-string';

import { MultiColumnList } from '@folio/stripes-components';
import { browseModeOptions } from '@folio/stripes-inventory-components';
import {
browseCallNumberOptions,
browseModeOptions,
queryIndexes,
} from '@folio/stripes-inventory-components';

import {
renderWithIntl,
Expand Down Expand Up @@ -47,6 +52,13 @@ const data = {
],
},
],
callNumberBrowseConfig: [
{
id: 'dewey',
shelvingAlgorithm: 'dewey',
typeIds: ['dewey-id', 'lc-id'],
},
],
subjectSources: [{ id: 'sourceId1', name: 'sourceName1' }, { id: 'sourceId2', name: 'sourceName2' }],
subjectTypes: [{ id: 'typeId1', name: 'typeName1' }, { id: 'typeId2', name: 'typeName2' }],
};
Expand Down Expand Up @@ -92,19 +104,16 @@ describe('getBrowseResultsFormatter', () => {
};
const contentData = [
{
fullCallNumber: 'A 1958 A 8050',
callNumber: 'A 1958 A 8050',
shelfKey: '41958 A 48050',
fullCallNumber: 'CALL',
isAnchor: true,
totalRecords: 1,
instance: { id: 'ce9dd893-c812-49d5-8973-d55d018894c4', title: 'Test title' },
totalRecords: 0,
},
{
fullCallNumber: 'AAA',
callNumber: 'AAA',
shelfKey: '123456',
fullCallNumber: 'CALL SUF',
callNumber: 'CALL',
callNumberPrefix: 'PRE',
callNumberSuffix: 'SUF',
totalRecords: 2,
instance: { id: 'ce9dd893-c812-49d5-8973-d55d018894c4', title: 'Test title 2' },
},
];
const [anchorRecord, nonAnchorRecord] = contentData;
Expand All @@ -120,10 +129,10 @@ describe('getBrowseResultsFormatter', () => {
renderCallNumberList();

// Anchor row
expect(screen.getByText(anchorRecord.callNumber).tagName.toLowerCase()).toBe('strong');
expect(screen.getByText(anchorRecord.totalRecords).tagName.toLowerCase()).toBe('strong');
expect(screen.getByText('would be here').tagName.toLowerCase()).toBe('strong');
expect(screen.getByText('CALL').tagName.toLowerCase()).not.toBe('strong');
// Default row
expect(screen.getByText(nonAnchorRecord.callNumber).tagName.toLowerCase()).not.toBe('strong');
expect(screen.getByText('PRE CALL SUF').tagName.toLowerCase()).not.toBe('strong');
expect(screen.getByText(nonAnchorRecord.totalRecords).tagName.toLowerCase()).not.toBe('strong');
});

Expand All @@ -134,14 +143,33 @@ describe('getBrowseResultsFormatter', () => {
expect(screen.getByText(missedMatchText)).toBeInTheDocument();
});

it('should navigate to instance "Search" page when target column was clicked', async () => {
it('should not navigate to any page when anchor is clicked', async () => {
renderCallNumberList();

expect(history.location.pathname).toEqual(BROWSE_INVENTORY_ROUTE);

await act(async () => fireEvent.click(screen.getByText(anchorRecord.callNumber)));
await act(async () => fireEvent.click(screen.getByText(anchorRecord.fullCallNumber)));

expect(history.location.pathname).toEqual(INVENTORY_ROUTE);
expect(history.location.pathname).toEqual(BROWSE_INVENTORY_ROUTE);
});

describe('when call number title is clicked', () => {
it('should navigate to the instance "Search" page', async () => {
const { getByText } = renderCallNumberList({
formatter: getBrowseResultsFormatter({
data,
browseOption: browseCallNumberOptions.DEWEY,
}),
});

const query = queryString.stringify({
selectedBrowseResult: true,
qindex: queryIndexes.QUERY_SEARCH,
query: 'itemNormalizedCallNumbers="PRE CALL SUF" and (item.effectiveCallNumberComponents.typeId=="dewey-id" or item.effectiveCallNumberComponents.typeId=="lc-id")',
});

expect(getByText('PRE CALL SUF').href).toContain(`${INVENTORY_ROUTE}?${query}`);
});
});
});

Expand Down
45 changes: 39 additions & 6 deletions src/components/BrowseResultsList/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
browseClassificationOptions,
browseModeOptions,
browseClassificationIndexToId,
browseCallNumberIndexToId,
FACETS,
queryIndexes,
segments,
} from '@folio/stripes-inventory-components';

export const isRowPreventsClick = (row, browseOption) => {
Expand Down Expand Up @@ -103,22 +103,55 @@ export const getFullCallNumber = (row) => {
return fullCallNumber;
};

/**
* Constructs a query string for browsing call numbers based on the provided parameters.
*
* @param {string} qindex - The query index indicating the type of browse (e.g., callNumbers, dewey, lc).
* @param {Object} data - The data object containing configuration for call number browsing.
* @param {Object} row - The row object containing details of the item being browsed.
* @returns {string} - The constructed query string for browsing call numbers.
*/
const getCallNumberQuery = (qindex, data, row) => {
const fullCallNumber = getFullCallNumber(row);

const isCallNumberBrowse = Object.values(browseCallNumberOptions).includes(qindex);

if (!isCallNumberBrowse) {
return '';
}

let query = `itemNormalizedCallNumbers="${fullCallNumber}"`;

const callNumberBrowseConfigId = browseCallNumberIndexToId[qindex];

const callNumberBrowseTypes = data?.callNumberBrowseConfig
.find(config => config.id === callNumberBrowseConfigId)?.typeIds;

const callNumberBrowseTypesQuery = callNumberBrowseTypes
?.map(typeId => `item.effectiveCallNumberComponents.typeId=="${typeId}"`)
.join(' or ');

if (callNumberBrowseTypesQuery) {
query += ` and (${callNumberBrowseTypesQuery})`;
}

return query;
};

export const getSearchParams = (row, qindex, allFilters, data) => {
const filters = getExtraFilters(row, qindex, allFilters);
const classificationQuery = getClassificationQuery(qindex, data, row);
const callNumberQuery = getCallNumberQuery(qindex, data, row);

const classificationOption = {
qindex: queryIndexes.QUERY_SEARCH,
query: classificationQuery,
...filters,
};

const fullCallNumber = getFullCallNumber(row);

const callNumberOption = {
qindex: queryIndexes.ITEM_NORMALIZED_CALL_NUMBERS,
query: fullCallNumber,
segment: segments.items,
qindex: queryIndexes.QUERY_SEARCH,
query: callNumberQuery,
...filters,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const data = {
locations: [],
consortiaTenants,
classificationBrowseConfig: [],
callNumberBrowseConfig: [],
};

const query = {
Expand Down Expand Up @@ -149,16 +150,6 @@ describe('InstanceFiltersBrowse', () => {
});

describe('When callNumber browseType was selected', () => {
it('should call onClear handler if clear btn is clicked', () => {
renderInstanceFilters();
fireEvent.click(screen.getByLabelText('Clear selected Effective location (item) filters'));

expect(mockOnChange).toHaveBeenCalledWith({
name: FACETS.EFFECTIVE_LOCATION,
values: [],
});
});

it('should display "Held By" facet accordion', () => {
const { getByRole } = renderInstanceFilters({
data,
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export { default as useLocalStorageItems } from './useLocalStorageItems';
export * from './useQuickExport';
export * from '@folio/stripes-inventory-components/lib/queries/useInstanceDateTypes';
export * from './useCallNumberTypesQuery';
export * from './useCallNumberBrowseConfig';
1 change: 1 addition & 0 deletions src/hooks/useCallNumberBrowseConfig/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useCallNumberBrowseConfig';
35 changes: 35 additions & 0 deletions src/hooks/useCallNumberBrowseConfig/useCallNumberBrowseConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useQuery } from 'react-query';

import {
useNamespace,
useOkapiKy,
useStripes,
} from '@folio/stripes/core';
import {
CQL_FIND_ALL,
LIMIT_MAX,
} from '@folio/stripes-inventory-components';

const useCallNumberBrowseConfig = () => {
const stripes = useStripes();
const [namespace] = useNamespace({ key: 'call-number-browse-config' });
const centralTenantId = stripes.user.user?.consortium?.centralTenantId;
const ky = useOkapiKy({ tenant: centralTenantId });

const { data, isFetching } = useQuery(
[namespace],
() => ky.get('browse/config/instance-call-number', {
searchParams: {
limit: LIMIT_MAX,
query: CQL_FIND_ALL,
},
}).json(),
);

return {
callNumberBrowseConfig: data?.configs || [],
isCallNumberConfigLoading: isFetching,
};
};

export { useCallNumberBrowseConfig };
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
QueryClient,
QueryClientProvider,
} from 'react-query';

import {
renderHook,
act,
} from '@folio/jest-config-stripes/testing-library/react';
import { useOkapiKy } from '@folio/stripes/core';

import { useCallNumberBrowseConfig } from './useCallNumberBrowseConfig';

const queryClient = new QueryClient();

const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);

describe('useCallNumberBrowseConfig', () => {
beforeEach(() => {
useOkapiKy.mockClear().mockReturnValue({
get: () => ({
json: jest.fn().mockResolvedValue({ configs: [{ id: 'dewey' }] }),
}),
});
});

afterEach(() => {
jest.clearAllMocks();
});

it('should fetch config', async () => {
const { result } = renderHook(useCallNumberBrowseConfig, { wrapper });

await act(() => !result.current.isCallNumberConfigLoading);

expect(result.current.callNumberBrowseConfig).toEqual([{ id: 'dewey' }]);
});
});
14 changes: 11 additions & 3 deletions src/providers/DataProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import keyBy from 'lodash/keyBy';
import { stripesConnect } from '@folio/stripes/core';
import { useCommonData } from '@folio/stripes-inventory-components';

import { useClassificationBrowseConfig } from '../hooks';
import {
useCallNumberBrowseConfig,
useClassificationBrowseConfig,
} from '../hooks';
import { DataContext } from '../contexts';

// Provider which loads dictionary data used in various places in ui-inventory.
Expand All @@ -18,9 +21,12 @@ const DataProvider = ({

const { commonData, isCommonDataLoading } = useCommonData();
const { classificationBrowseConfig, isLoading: isBrowseConfigLoading } = useClassificationBrowseConfig();
const { callNumberBrowseConfig, isCallNumberConfigLoading } = useCallNumberBrowseConfig();

const areOtherDataLoading = isCommonDataLoading || isBrowseConfigLoading || isCallNumberConfigLoading;

const isLoading = useMemo(() => {
if (isCommonDataLoading || isBrowseConfigLoading) {
if (areOtherDataLoading) {
return true;
}
// eslint-disable-next-line guard-for-in
Expand All @@ -33,7 +39,7 @@ const DataProvider = ({
}

return false;
}, [resources, manifest, isCommonDataLoading, isBrowseConfigLoading]);
}, [resources, manifest, areOtherDataLoading]);

const data = useMemo(() => {
const loadedData = {
Expand All @@ -57,13 +63,15 @@ const DataProvider = ({
loadedData.holdingsSourcesByName = keyBy(commonData.holdingsSources, 'name');
loadedData.instanceRelationshipTypesById = keyBy(instanceRelationshipTypes, 'id');
loadedData.classificationBrowseConfig = classificationBrowseConfig;
loadedData.callNumberBrowseConfig = callNumberBrowseConfig;

return loadedData;
}, [
resources,
manifest,
commonData,
classificationBrowseConfig,
callNumberBrowseConfig,
]);

if (isLoading) {
Expand Down
Loading

0 comments on commit a288eba

Please sign in to comment.