Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* Used FE mocked sectors for the Sector input field.
* Removed the FE request to `GET /api/parent-companies/`.
* Refactored `Parent Company / Supplier Group` to act as a regular text input field (not a dropdown). Prepopulate only value that has been assisgned to a particular claim.
* [OSDEV-2295](https://opensupplyhub.atlassian.net/browse/OSDEV-2295) - UI: added divider between each record of the `isic-4` field from the same contribution.

### Release instructions
* Ensure that the following commands are included in the `post_deployment` command:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,13 @@ describe('FacilityDetailsGeneralFields component', () => {
id: 83090,
is_verified: false,
value: {
section: 'C',
division: '14',
group: '141',
class: '1410',
section: 'J - Information and communication',
division:
'62 - Computer programming, consultancy and related activities',
group:
'62 - Computer programming, consultancy and related activities',
class:
'620 - Computer programming, consultancy and related activities',
},
created_at: '2025-05-01T10:49:15.174025Z',
updated_at: '2025-05-01T10:58:25.043413Z',
Expand Down Expand Up @@ -215,6 +218,98 @@ describe('FacilityDetailsGeneralFields component', () => {
{ preloadedState },
);

test('renders ISIC 4 without divider when single block in contribution', () => {
const { queryByText, queryAllByRole } = renderComponent();

expect(
queryByText('Section: J - Information and communication'),
).toBeInTheDocument();
expect(
queryByText(
'Division: 62 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();
expect(
queryByText(
'Group: 62 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();
expect(
queryByText(
'Class: 620 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();

const dividers = queryAllByRole('separator');
expect(dividers.length).toBe(0);
});

test('renders ISIC 4 with divider between multiple blocks in same contribution', () => {
const multiIsicData = {
...mockData,
properties: {
...mockData.properties,
extended_fields: {
...mockData.properties.extended_fields,
isic_4: [
{
id: 90001,
is_verified: false,
value: {
raw_value: [
{
section:
'J - Information and communication',
division:
'62 - Computer programming, consultancy and related activities',
group:
'62 - Computer programming, consultancy and related activities',
class:
'620 - Computer programming, consultancy and related activities',
},
{
section:
'G - Wholesale and retail trade; repair of motor vehicles and motorcycles',
division:
'47 - Retail trade, except motor vehicles and motorcycles',
group:
'47 - Retail trade, except motor vehicles and motorcycles',
class:
'471 - Retail sale in non-specialized stores with food, beverages or tobacco predominating',
},
],
},
created_at: '2025-05-01T10:49:15.174025Z',
updated_at: '2025-05-01T10:58:25.043413Z',
contributor_name: 'Test Org',
contributor_id: 1139,
value_count: 1,
is_from_claim: false,
field_name: 'isic_4',
verified_count: 0,
},
],
},
},
};

const { getAllByRole, getByText } = renderComponent({
data: multiIsicData,
});

expect(
getByText('Section: J - Information and communication'),
).toBeInTheDocument();
expect(
getByText(
'Section: G - Wholesale and retail trade; repair of motor vehicles and motorcycles',
),
).toBeInTheDocument();

const dividers = getAllByRole('separator');
expect(dividers.length).toBeGreaterThanOrEqual(1);
});

test('renders only non-additional identifier extended fields when the show_additional_identifiers feature flag is false', () => {
const preloadedState = {
featureFlags: {
Expand Down Expand Up @@ -401,10 +496,24 @@ describe('FacilityDetailsGeneralFields component', () => {
const { getByText } = renderComponent();

expect(getByText('ISIC 4')).toBeInTheDocument();
expect(getByText('Section: C')).toBeInTheDocument();
expect(getByText('Division: 14')).toBeInTheDocument();
expect(getByText('Group: 141')).toBeInTheDocument();
expect(getByText('Class: 1410')).toBeInTheDocument();
expect(
getByText('Section: J - Information and communication'),
).toBeInTheDocument();
expect(
getByText(
'Division: 62 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();
expect(
getByText(
'Group: 62 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();
expect(
getByText(
'Class: 620 - Computer programming, consultancy and related activities',
),
).toBeInTheDocument();
});

test('does not render ISIC 4 section when object contains no valid ISIC-4 fields', () => {
Expand Down
25 changes: 18 additions & 7 deletions src/react/src/components/FacilityDetailsItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';

import FacilityDetailsDetail from './FacilityDetailsDetail';
import TitledDrawer from './TitledDrawer';
Expand Down Expand Up @@ -49,6 +50,7 @@ const FacilityDetailsItem = ({
additionalContentText = 'entry',
additionalContentTextPlural = 'entries',
partnerConfigFields,
showDivider,
}) => {
const [isOpen, setIsOpen] = useState(false);
const hasAdditionalContent = !embed && !!additionalContent?.length;
Expand Down Expand Up @@ -111,13 +113,20 @@ const FacilityDetailsItem = ({
/>
</div>
{isOpen &&
additionalContent.map(item => (
<div className={classes.itemWrapper} key={item.key}>
<FacilityDetailsDetail
{...item}
partnerConfigFields={partnerConfigFields}
/>
</div>
additionalContent.map((item, index) => (
<React.Fragment
key={item.key || `${label}-${index}`}
>
{index > 0 && showDivider ? <Divider /> : null}
<div className={classes.itemWrapper}>
<FacilityDetailsDetail
{...item}
partnerConfigFields={
partnerConfigFields
}
/>
</div>
</React.Fragment>
))}
</div>
</TitledDrawer>
Expand Down Expand Up @@ -154,6 +163,7 @@ FacilityDetailsItem.propTypes = {
baseUrl: PropTypes.string,
displayText: PropTypes.string,
}),
showDivider: PropTypes.bool,
};

FacilityDetailsItem.defaultProps = {
Expand All @@ -173,6 +183,7 @@ FacilityDetailsItem.defaultProps = {
additionalContentText: 'entry',
additionalContentTextPlural: 'entries',
partnerConfigFields: null,
showDivider: false,
};

export default withStyles(detailsStyles)(FacilityDetailsItem);
7 changes: 4 additions & 3 deletions src/react/src/util/constants.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import COLOURS from './COLOURS';
import { ISIC_DIVIDER } from './renderUtils';

export const DEFAULT_SORT_OPTION_INDEX = 2;
export const OTHER = 'Other';
Expand Down Expand Up @@ -1134,7 +1135,7 @@ export const EXTENDED_FIELD_TYPES = [
const rawValue = value?.raw_value ?? value ?? {};
const entries = Array.isArray(rawValue) ? rawValue : [rawValue];

return entries.reduce((acc, entry, index) => {
return entries.reduce((acc, entry) => {
const { section, division, group, class: isicClass } =
entry || {};
const lines = [
Expand All @@ -1148,8 +1149,8 @@ export const EXTENDED_FIELD_TYPES = [
return acc;
}

if (acc.length && index > 0) {
return acc.concat(['', ...lines]);
if (acc.length) {
return acc.concat([ISIC_DIVIDER, ...lines]);
}

return acc.concat(lines);
Expand Down
61 changes: 44 additions & 17 deletions src/react/src/util/renderUtils.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import React from 'react';
import Divider from '@material-ui/core/Divider';

/**
* Sentinel token inserted into ISIC value arrays to trigger divider rendering.
* Assumes ISIC data never contains this exact value; double-underscores reduce
* collision risk.
*/
export const ISIC_DIVIDER = '__ISIC_DIVIDER__';

const blockStyle = Object.freeze({
margin: 0,
display: 'block',
});

const dividerStyle = Object.freeze({
margin: '10px 0',
});

const renderUniqueListItems = (
fieldValue,
fieldName = '',
Expand All @@ -18,25 +30,40 @@ const renderUniqueListItems = (
return fieldValue;
}

const values = preserveOrder ? fieldValue : [...new Set(fieldValue)];

return values.map(value =>
fieldName === 'parent_company_os_id' ? (
<a
href={`/facilities/${value}`}
key={value}
style={blockStyle}
target="_blank"
rel="noopener noreferrer"
>
{value}
</a>
) : (
<span style={blockStyle} key={value}>
const shouldPreserveOrder = preserveOrder || fieldName === 'isic_4';

const values = shouldPreserveOrder ? fieldValue : [...new Set(fieldValue)];

let keySeq = 0;

return values.map(value => {
keySeq += 1;
const key = `${fieldName}-${keySeq}`;

if (fieldName === 'isic_4' && value === ISIC_DIVIDER) {
return <Divider key={key} style={dividerStyle} />;
}

if (fieldName === 'parent_company_os_id') {
return (
<a
href={`/facilities/${value}`}
key={key}
style={blockStyle}
target="_blank"
rel="noopener noreferrer"
>
{value}
</a>
);
}

return (
<span style={blockStyle} key={key}>
{value}
</span>
),
);
);
});
};

export default renderUniqueListItems;