diff --git a/doc/release/RELEASE-NOTES.md b/doc/release/RELEASE-NOTES.md index 8d0283c06..f66003075 100644 --- a/doc/release/RELEASE-NOTES.md +++ b/doc/release/RELEASE-NOTES.md @@ -67,6 +67,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html * [OSDEV-1695](https://opensupplyhub.atlassian.net/browse/OSDEV-1695) - [SLC] Enabled the claim button for updated production locations when a moderation event has a pending status. Disabled claim button explicitly if production location has pending claim status. * [OSDEV-1701](https://opensupplyhub.atlassian.net/browse/OSDEV-1701) - Refactored "Go Back" button in production location info page. * [OSDEV-1672](https://opensupplyhub.atlassian.net/browse/OSDEV-1672) - SLC. Implement collecting contribution data page (FE) - All Multi-Selects on the page have been fixed. They resize based on the number of items selected. +* [OSDEV-1696](https://opensupplyhub.atlassian.net/browse/OSDEV-1696) - Added loader on single production location fetch; added error handling; added cleanup hook to clear production location data on component unmount. * [OSDEV-1653](https://opensupplyhub.atlassian.net/browse/OSDEV-1653) - Added asterisks next to each required form field (Name, Address, and Country) on the "Search by Name and Address" tab. Highlighted an empty field and displayed an error message if it loses focus. Added proper styles for the error messages. * [OSDEV-1589](https://opensupplyhub.atlassian.net/browse/OSDEV-1589) - Fixed layout issue on new `contribute` page. diff --git a/src/react/src/components/Contribute/ProductionLocationInfo.jsx b/src/react/src/components/Contribute/ProductionLocationInfo.jsx index 7e4d02703..6bf3e6773 100644 --- a/src/react/src/components/Contribute/ProductionLocationInfo.jsx +++ b/src/react/src/components/Contribute/ProductionLocationInfo.jsx @@ -12,6 +12,7 @@ import IconButton from '@material-ui/core/IconButton'; import Typography from '@material-ui/core/Typography'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp'; +import CircularProgress from '@material-ui/core/CircularProgress'; import StyledSelect from '../Filters/StyledSelect'; import { productionLocationInfoStyles } from '../../util/styles'; import { @@ -29,6 +30,7 @@ import { updateProductionLocation, fetchProductionLocationByOsId, resetPendingModerationEvent, + resetSingleProductionLocation, } from '../../actions/contributeProductionLocation'; import { fetchSingleModerationEvent, @@ -69,9 +71,12 @@ const ProductionLocationInfo = ({ singleModerationEventItemError, fetchProductionLocation, singleProductionLocationData, + singleProductionLocationFetching, + singleProductionLocationError, innerWidth, handleCleanupContributionRecord, handleResetPendingModerationEvent, + handleResetSingleProductionLocation, }) => { const location = useLocation(); const history = useHistory(); @@ -362,6 +367,14 @@ const ProductionLocationInfo = ({ moderationID, ]); + useEffect(() => { + if (!isEmpty(singleProductionLocationError)) { + toast(singleProductionLocationError[0]); + } + }, [singleProductionLocationError]); + + useEffect(() => () => handleResetSingleProductionLocation(), []); + return ( <>
@@ -372,391 +385,403 @@ const ProductionLocationInfo = ({ {`Use the form below to edit the name, address, and country for your production location. ${instructionExtraMessage}`} - -
- + ) : ( + +
- Location Name - - - Enter the name of the production location that you - are uploading. - - + Location Name + + + Enter the name of the production location that + you are uploading. + + - } - FormHelperTextProps={{ - className: classes.helperText, - }} - error={nameTouched && isEmpty(inputName)} - /> -
-
- - Address - - + } + FormHelperTextProps={{ + className: classes.helperText, + }} + error={nameTouched && isEmpty(inputName)} + /> +
+
- Enter the address of the production location. We - will use this to plot the location on a map. - - + Address + + + Enter the address of the production location. We + will use this to plot the location on a map. + + - } - FormHelperTextProps={{ - className: classes.helperText, - }} - error={addressTouched && isEmpty(inputAddress)} - /> -
-
- - Country - - + } + FormHelperTextProps={{ + className: classes.helperText, + }} + error={addressTouched && isEmpty(inputAddress)} + /> +
+
- Select the country where the production site is - located. - - -
-
-
-
+ Country + + - Additional information + Select the country where the production site is + located. - - {isExpanded ? ( - - ) : ( - - )} - +
- +
- Expand this section to add more data about your - production location, including product types, number - of workers, parent company and more. - - {isExpanded && ( - <> -
- - Sector(s) - - - Select the sector(s) that this location - operates in. For example: Apparel, - Electronics, Renewable Energy. - - -
-
+ - + + {isExpanded ? ( + + ) : ( + + )} + +
+ + Expand this section to add more data about your + production location, including product types, + number of workers, parent company and more. + + {isExpanded && ( + <> +
- Product Type(s) - - + Sector(s) + + + Select the sector(s) that this + location operates in. For example: + Apparel, Electronics, Renewable + Energy. + + +
+
- Enter the type of products produced at - this location. For example: Shirts, - Laptops, Solar Panels. - + + Product Type(s) + + + Enter the type of products produced + at this location. For example: + Shirts, Laptops, Solar Panels. + - -
-
- - Location Type(s) - - - Select the location type(s) for this - production location. For example: Final - Product Assembly, Raw Materials - Production or Processing, Office/HQ. - - -
-
- - Processing Type(s) - - +
+
- Select the type of processing activities - that take place at this location. For - example: Printing, Tooling, Assembly. - - -
-
- + Location Type(s) + + + Select the location type(s) for this + production location. For example: + Final Product Assembly, Raw + Materials Production or Processing, + Office/HQ. + + +
+
- Number of Workers - - + Processing Type(s) + + + Select the type of processing + activities that take place at this + location. For example: Printing, + Tooling, Assembly. + + +
+
- Enter a number or a range for the number - of people employed at the location. For - example: 100, 100-150. - - - setNumberOfWorkers(e.target.value) - } - placeholder="Enter the number of workers as a number or range" - helperText={ - !isValidNumberOfWorkers( - numberOfWorkers, - ) && ( - - ) - } - FormHelperTextProps={{ - className: classes.helperText, - }} - InputProps={{ - classes: { - input: ` + + Number of Workers + + + Enter a number or a range for the + number of people employed at the + location. For example: 100, 100-150. + + + setNumberOfWorkers( + e.target.value, + ) + } + placeholder="Enter the number of workers as a number or range" + helperText={ + !isValidNumberOfWorkers( + numberOfWorkers, + ) && ( + + ) + } + FormHelperTextProps={{ + className: classes.helperText, + }} + InputProps={{ + classes: { + input: ` ${ !isValidNumberOfWorkers( numberOfWorkers, ) && classes.errorStyle }`, - notchedOutline: - classes.notchedOutlineStyles, - }, - }} - aria-label="Number of Workers" - /> -
-
- - Parent Company - - +
+
- Enter the company that holds majority - ownership for this production. - - -
- - )} -
-
- - -
- + + Parent Company + + + Enter the company that holds + majority ownership for this + production. + + +
+ + )} +
+
+ + +
+
+ )}
{showProductionLocationDialog && (pendingModerationEventData?.cleaned_data || @@ -793,6 +818,8 @@ ProductionLocationInfo.defaultProps = { singleModerationEventItem: null, singleModerationEventItemFetching: false, singleModerationEventItemError: null, + singleProductionLocationFetching: false, + singleProductionLocationError: null, }; ProductionLocationInfo.propTypes = { @@ -811,11 +838,14 @@ ProductionLocationInfo.propTypes = { singleModerationEventItemError: array, fetchProductionLocation: func.isRequired, singleProductionLocationData: productionLocationPropType.isRequired, + singleProductionLocationFetching: bool, + singleProductionLocationError: array, submitMethod: string.isRequired, classes: object.isRequired, innerWidth: number.isRequired, handleCleanupContributionRecord: func.isRequired, handleResetPendingModerationEvent: func.isRequired, + handleResetSingleProductionLocation: func.isRequired, }; const mapStateToProps = ({ @@ -829,7 +859,11 @@ const mapStateToProps = ({ fetching: pendingModerationEventFetching, error: pendingModerationEventError, }, - singleProductionLocation: { data: singleProductionLocationData }, + singleProductionLocation: { + data: singleProductionLocationData, + fetching: singleProductionLocationFetching, + error: singleProductionLocationError, + }, }, dashboardContributionRecord: { singleModerationEvent: { @@ -851,6 +885,8 @@ const mapStateToProps = ({ singleModerationEventItemFetching, singleModerationEventItemError, singleProductionLocationData, + singleProductionLocationFetching, + singleProductionLocationError, innerWidth, }); @@ -871,6 +907,8 @@ function mapDispatchToProps(dispatch) { dispatch(cleanupContributionRecord()), handleResetPendingModerationEvent: () => dispatch(resetPendingModerationEvent()), + handleResetSingleProductionLocation: () => + dispatch(resetSingleProductionLocation()), }; }