Skip to content

Commit

Permalink
code refactoring and additional unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SKarolFolio committed Nov 12, 2024
1 parent e1b4dd7 commit a12fb72
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 59 deletions.
60 changes: 60 additions & 0 deletions src/common/hooks/useComplexLookupSearchResults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useCallback, useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { useIntl } from 'react-intl';
import { type Row } from '@components/Table';
import { useSearchContext } from '@common/hooks/useSearchContext';
import { ComplexLookupSearchResultsProps } from '@components/ComplexLookupField/ComplexLookupSearchResults';
import state from '@state';

export const useComplexLookupSearchResults = ({
onTitleClick,
tableConfig,
searchResultsFormatter,
}: ComplexLookupSearchResultsProps) => {
const { onAssignRecord } = useSearchContext();
const data = useRecoilValue(state.search.data);
const sourceData = useRecoilValue(state.search.sourceData);
const { formatMessage } = useIntl();

const applyActionItems = useCallback(
(rows: Row[]): Row[] =>
rows?.map(row => {
const formattedRow: Row = { ...row };

Object.entries(tableConfig.columns).forEach(([key, column]) => {
formattedRow[key] = {
...row[key],
children: column.formatter
? column.formatter({ row, formatMessage, onAssign: onAssignRecord, onTitleClick })
: row[key].label,
};
});

return formattedRow;
}),
[onAssignRecord, tableConfig],
);

const formattedData = useMemo(
() => applyActionItems(searchResultsFormatter(data || [], sourceData || [])),
[applyActionItems, data],
);

const listHeader = useMemo(
() =>
Object.keys(tableConfig.columns).reduce((accum, key) => {
const { label, position, className } = (tableConfig.columns[key] || {}) as SearchResultsTableColumn;

accum[key] = {
label: label ? formatMessage({ id: label }) : '',
position: position,
className: className,
};

return accum;
}, {} as Row),
[tableConfig],
);

return { formattedData, listHeader };
};
8 changes: 4 additions & 4 deletions src/common/services/schema/schemaWithDuplicates.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export class SchemaWithDuplicatesService implements ISchemaWithDuplicatesService

constructor(
private schema: Map<string, SchemaEntry>,
private selectedEntriesService: ISelectedEntries,
private entryPropertiesGeneratorService?: IEntryPropertiesGeneratorService,
private readonly selectedEntriesService: ISelectedEntries,
private readonly entryPropertiesGeneratorService?: IEntryPropertiesGeneratorService,
) {
this.set(schema);
this.isManualDuplication = true;
Expand Down Expand Up @@ -107,7 +107,7 @@ export class SchemaWithDuplicatesService implements ISchemaWithDuplicatesService
if (!entry || entry.cloneOf) return;

const { children } = entry;
let updatedEntryUuid = newUuids?.[index] || uuidv4();
let updatedEntryUuid = newUuids?.[index] ?? uuidv4();
const isFirstAssociatedEntryElem = parentEntry?.dependsOn && newUuids && index === 0;

if (isFirstAssociatedEntryElem) {
Expand All @@ -126,7 +126,7 @@ export class SchemaWithDuplicatesService implements ISchemaWithDuplicatesService
newUuids,
});

if (controlledByEntry && controlledByEntry?.uuid) {
if (controlledByEntry?.uuid) {
this.schema.set(controlledByEntry.uuid, controlledByEntry);
}

Expand Down
10 changes: 5 additions & 5 deletions src/common/services/userValues/userValueTypes/simpleLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class SimpleLookupUserValueService extends UserValueType implements IUser
private contents?: UserValueContents[];

constructor(
private apiClient: IApiClient,
private cacheService: ILookupCacheService,
private readonly apiClient: IApiClient,
private readonly cacheService: ILookupCacheService,
) {
super();
}
Expand Down Expand Up @@ -60,7 +60,7 @@ export class SimpleLookupUserValueService extends UserValueType implements IUser
}

this.value = {
uuid: uuid || '',
uuid: uuid ?? '',
contents: this.contents,
};

Expand All @@ -70,7 +70,7 @@ export class SimpleLookupUserValueService extends UserValueType implements IUser
private checkDefaultGroupValues(groupUri?: string, itemUri?: string) {
if (!groupUri || !itemUri) return false;

return (DEFAULT_GROUP_VALUES as DefaultGroupValues)[groupUri as string]?.value === itemUri;
return (DEFAULT_GROUP_VALUES as DefaultGroupValues)[groupUri]?.value === itemUri;
}

private generateContentItem({
Expand Down Expand Up @@ -100,7 +100,7 @@ export class SimpleLookupUserValueService extends UserValueType implements IUser
?.find(
({ label: optionLabel, value }) => value.uri === mappedUri || value.label === label || optionLabel === label,
);
const selectedLabel = typesMap && itemUri ? loadedOption?.label || itemUri : loadedOption?.label || label;
const selectedLabel = typesMap && itemUri ? (loadedOption?.label ?? itemUri) : (loadedOption?.label ?? label);

const contentItem = {
label: selectedLabel,
Expand Down
58 changes: 8 additions & 50 deletions src/components/ComplexLookupField/ComplexLookupSearchResults.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { FC, useCallback, useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { FormattedMessage, useIntl } from 'react-intl';
import { FC } from 'react';
import { TableFlex, type Row } from '@components/Table';
import { useSearchContext } from '@common/hooks/useSearchContext';
import state from '@state';
import { useComplexLookupSearchResults } from '@common/hooks/useComplexLookupSearchResults';

type ComplexLookupSearchResultsProps = {
export type ComplexLookupSearchResultsProps = {
onTitleClick?: (id: string, title?: string, headingType?: string) => void;
tableConfig: SearchResultsTableConfig;
searchResultsFormatter: (data: any[], sourceData?: SourceDataDTO) => Row[];
Expand All @@ -16,50 +13,11 @@ export const ComplexLookupSearchResults: FC<ComplexLookupSearchResultsProps> = (
tableConfig,
searchResultsFormatter,
}) => {
const { onAssignRecord } = useSearchContext();
const data = useRecoilValue(state.search.data);
const sourceData = useRecoilValue(state.search.sourceData);
const { formatMessage } = useIntl();

const applyActionItems = useCallback(
(rows: Row[]): Row[] =>
rows.map(row => {
const formattedRow: Row = { ...row };

Object.entries(tableConfig.columns).forEach(([key, column]) => {
formattedRow[key] = {
...row[key],
children: column.formatter
? column.formatter({ row, formatMessage, onAssign: onAssignRecord, onTitleClick })
: row[key].label,
};
});

return formattedRow;
}),
[onAssignRecord, tableConfig],
);

const formattedData = useMemo(
() => applyActionItems(searchResultsFormatter(data || [], sourceData || [])),
[applyActionItems, data],
);

const listHeader = useMemo(
() =>
Object.keys(tableConfig.columns).reduce((accum, key) => {
const { label, position, className } = (tableConfig.columns[key] || {}) as SearchResultsTableColumn;

accum[key] = {
label: label ? <FormattedMessage id={label} /> : '',
position: position,
className: className,
};

return accum;
}, {} as Row),
[tableConfig],
);
const { listHeader, formattedData } = useComplexLookupSearchResults({
onTitleClick,
tableConfig,
searchResultsFormatter,
});

return (
<div className="search-result-list">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { useRecoilValue } from 'recoil';
import { renderHook } from '@testing-library/react';
import { useSearchContext } from '@common/hooks/useSearchContext';
import { useComplexLookupSearchResults } from '@common/hooks/useComplexLookupSearchResults';
import { ComplexLookupSearchResultsProps } from '@components/ComplexLookupField/ComplexLookupSearchResults';
import { Row } from '@components/Table';

jest.mock('recoil');
jest.mock('@common/hooks/useSearchContext', () => ({
useSearchContext: jest.fn(),
}));

const data = [
{
id: '1',
name: { label: 'Item 1' },
description: { label: 'Description 1' },
},
];
const sourceData = [
{
id: '1',
name: 'Item 1',
description: 'Description 1',
},
];
const tableConfig = {
columns: {
name: {
label: 'name.label',
position: 1,
formatter: ({ row }: any) => row.name.label,
},
description: {
label: 'description.label',
position: 2,
},
},
};
const searchResultsFormatter = (data: Row[]) => data;

describe('useComplesLookupSearchResults', () => {
beforeEach(() => {
(useSearchContext as jest.Mock).mockReturnValue({
onAssignRecord: jest.fn(),
});
(useRecoilValue as jest.Mock).mockReturnValueOnce(data).mockReturnValueOnce(sourceData);
});

it('returns "formattedData" and "listHeader"', () => {
const props: ComplexLookupSearchResultsProps = {
onTitleClick: jest.fn(),
tableConfig,
searchResultsFormatter,
};

const { result } = renderHook(() => useComplexLookupSearchResults(props));

expect(result.current.formattedData).toEqual([
{
id: '1',
name: {
label: 'Item 1',
children: 'Item 1',
},
description: {
label: 'Description 1',
children: 'Description 1',
},
},
]);

expect(result.current.listHeader).toEqual({
name: {
label: 'name.label',
position: 1,
className: undefined,
},
description: {
label: 'description.label',
position: 2,
className: undefined,
},
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { render } from '@testing-library/react';
import { useComplexLookupSearchResults } from '@common/hooks/useComplexLookupSearchResults';
import { ComplexLookupSearchResults } from '@components/ComplexLookupField/ComplexLookupSearchResults';
import { TableFlex } from '@components/Table';

jest.mock('@components/Table');
jest.mock('@common/hooks/useComplexLookupSearchResults');

const listHeader = ['Column 1', 'Column 2'];
const formattedData = [
{ id: '1', values: ['Data 1', 'Data 2'] },
{ id: '2', values: ['Data 3', 'Data 4'] },
];

const onTitleClick = jest.fn();
const searchResultsFormatter = jest.fn();
const tableConfig = {} as SearchResultsTableConfig;

describe('ComplexLookupSearchResults', () => {
it('renders "TableFlex" component with the required props', () => {
(useComplexLookupSearchResults as jest.Mock).mockReturnValue({
listHeader,
formattedData,
});
(TableFlex as jest.Mock).mockReturnValue(<div>Mock TableFlex</div>);

render(
<ComplexLookupSearchResults
onTitleClick={onTitleClick}
tableConfig={tableConfig}
searchResultsFormatter={searchResultsFormatter}
/>,
);

expect(TableFlex as jest.Mock).toHaveBeenCalledWith(
{ header: listHeader, data: formattedData, className: 'results-list' },
{},
);
});
});

0 comments on commit a12fb72

Please sign in to comment.