Skip to content

Commit

Permalink
Merge branch 'main' into OSDEV-1523-export-csv-script
Browse files Browse the repository at this point in the history
  • Loading branch information
mazursasha1990 committed Jan 7, 2025
2 parents 2c9e31c + c94fbee commit d3f450d
Show file tree
Hide file tree
Showing 14 changed files with 572 additions and 5 deletions.
3 changes: 1 addition & 2 deletions doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* Release date: January 25, 2025

### Database changes

#### Migrations:

#### Scheme changes
Expand All @@ -23,12 +22,12 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
### Bugfix

### What's new
* [OSDEV-40](https://opensupplyhub.atlassian.net/browse/OSDEV-40) - Created new page for `/contribute` to choose between multiple & single location upload. Replaced current multiple list upload to `/contribute/multiple-locations`. Changed `Upload Data` to `Add Data` text.

### Release instructions:
* Ensure that the following commands are included in the `post_deployment` command:
* `migrate`
* `reindex_database`
* Run `[Release] Deploy` pipeline for the target environment with the flag `Clear the custom OpenSearch indexes and templates` set to true - to refresh the index mappings for the `moderation-events` index after disabling dynamic mapping for the new fields that don't have an explicit mapping defined. The `production-locations` will also be affected since it will clean all of our custom indexes and templates within the OpenSearch cluster.

## Release 1.27.0

Expand Down
6 changes: 6 additions & 0 deletions src/react/src/Routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import RegisterForm from './components/RegisterForm';
import ResetPasswordForm from './components/ResetPasswordForm';
import LoginForm from './components/LoginForm';
import Contribute from './components/Contribute';
import AddLocationData from './components/AddLocationData';
import Homepage from './components/Homepage';
import FacilityLists from './components/FacilityLists';
import FacilityListItems from './components/FacilityListItems';
Expand Down Expand Up @@ -46,6 +47,7 @@ import {
authResetPasswordFormRoute,
authConfirmRegistrationRoute,
contributeRoute,
multipleLocationRoute,
listsRoute,
facilityListItemsRoute,
facilitiesRoute,
Expand Down Expand Up @@ -142,6 +144,10 @@ class Routes extends Component {
<Route
exact
path={contributeRoute}
component={AddLocationData}
/>
<Route
path={multipleLocationRoute}
component={Contribute}
/>
<Route
Expand Down
52 changes: 52 additions & 0 deletions src/react/src/__tests__/components/AddLocationData.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import { MemoryRouter } from 'react-router-dom';
import renderWithProviders from '../../util/testUtils/renderWithProviders';
import AddLocationData from '../../components/AddLocationData';

describe('AddLocationData component', () => {
const mockAuthorizedState = {
auth: {
user: { user: { isAnon: false } },
session: { fetching: false },
},
};

const mockNotAuthorizedState = {
auth: {
user: { user: { isAnon: true } },
session: { fetching: false },
},
};

const renderComponent = (preloadedState = {}) => {
const theme = createMuiTheme({
palette: {
action: { main: '#000', dark: '#333' }, // Define a valid palette
getContrastText: jest.fn(() => '#fff'), // Mock the method to return a contrast color
},
});
return renderWithProviders(
<MuiThemeProvider theme={theme}>
<MemoryRouter>
<AddLocationData />
</MemoryRouter>
</MuiThemeProvider>,
{ preloadedState }
);
};

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

it('renders for the authorized user', () => {
const { getByText } = renderComponent(mockAuthorizedState);
expect(getByText('Add production location data to OS Hub')).toBeInTheDocument();
});

it('renders for the unauthorized user', () => {
const { getByText } = renderComponent(mockNotAuthorizedState);
expect(getByText('Log in to contribute to Open Supply Hub')).toBeInTheDocument();
});
});
200 changes: 200 additions & 0 deletions src/react/src/components/AddLocationData.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { withStyles, withTheme } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import CircularProgress from '@material-ui/core/CircularProgress';

import AppGrid from './AppGrid';

import { openInNewTab } from '../util/util';
import {
authLoginFormRoute,
InfoLink,
InfoPaths,
contributeProductionLocationRoute,
multipleLocationRoute,
} from '../util/constants';
import { makeAddLocationStyles } from '../util/styles';

import MessyIcon from './MessyIcon';
import PlaylistIcon from './PlaylistIcon';
import PinDropIcon from './PinDropIcon';
import RectangleCardFigure from './RectangleCardFigure';
import SliceCardFigure from './SliceCardFigure';
import SliceMessyFigure from './SliceMessyFigure';
import SliceMessyDuoFigure from './SliceMessyDuoFigure';

function AddLocationData({ classes, userHasSignedIn, fetchingSessionSignIn }) {
if (fetchingSessionSignIn) {
return (
<AppGrid title="Contribute">
<Grid container className="margin-bottom-64">
<Grid item xs={12}>
<CircularProgress />
</Grid>
</Grid>
</AppGrid>
);
}

if (!userHasSignedIn) {
return (
<AppGrid title="Contribute">
<Grid container className="margin-bottom-64">
<Grid item xs={12}>
<Link to={authLoginFormRoute} href={authLoginFormRoute}>
Log in to contribute to Open Supply Hub
</Link>
</Grid>
</Grid>
</AppGrid>
);
}

return (
<div className={classes.container}>
<Typography variant="display3" className={classes.title}>
Add production location data to OS Hub
</Typography>
<Typography variant="subheading" className={classes.description}>
Contribute your data here to help build the world’s most
complete, open and accessible map of global production:
</Typography>
<div className={classes.dataOptions}>
<Paper className={classes.card}>
<div className={classes.cardRectangleView}>
<RectangleCardFigure />
</div>
<div>
<PlaylistIcon className={classes.cardIcon} />
<Typography
variant="headline"
className={classes.cardTitle}
>
Upload a dataset with multiple production locations
using a{' '}
<span className={classes.highlight}>
spreadsheet.
</span>
</Typography>
<Typography
variant="subheading"
className={classes.cardSub}
>
This option is best if you have a large number of
production locations to contribute.
</Typography>
<Button
color="secondary"
variant="text"
component={Link}
className={classes.buttonStyle}
to={multipleLocationRoute}
>
Upload Multiple Locations
</Button>
<div className={classes.messyData}>
<MessyIcon className={classes.messyIcon} />
<div className={classes.messyContent}>
<Typography
variant="display1"
className={classes.messyTitle}
>
Have messy data?
</Typography>
<Typography
variant="subheading"
className={classes.messySub}
>
We can get it ready for you. All you need to
do is upload your data and we’ll take care
of the rest.
</Typography>
</div>
<div className={classes.cardSliceDuoView}>
<SliceMessyDuoFigure />
</div>
<div className={classes.cardSliceView}>
<SliceMessyFigure />
</div>
<button
type="button"
className={classes.secondaryButton}
onClick={() =>
openInNewTab(
`${InfoLink}/${InfoPaths.contribute}`,
)
}
>
Learn More
</button>
</div>
</div>
</Paper>
<Paper className={classes.card}>
<div>
<PinDropIcon className={classes.cardIcon} />
<Typography
variant="headline"
className={classes.cardTitle}
>
Add data for a
<br />
<span className={classes.highlight}>
single production location.
</span>
</Typography>
<Typography
variant="subheading"
className={classes.cardSub}
>
This option is best if you want to register your
production location or contribute data for one
production location at a time.
</Typography>
<Button
color="secondary"
variant="text"
component={Link}
className={classes.buttonStyle}
to={contributeProductionLocationRoute}
disabled
>
Add a Single Location
</Button>
</div>
<div className={classes.cardSliceView}>
<SliceCardFigure />
</div>
</Paper>
</div>
</div>
);
}

AddLocationData.propTypes = {
classes: PropTypes.object.isRequired,
userHasSignedIn: PropTypes.bool.isRequired,
fetchingSessionSignIn: PropTypes.bool.isRequired,
};

function mapStateToProps({
auth: {
user: { user },
session: { fetching },
},
}) {
return {
userHasSignedIn: !user.isAnon,
fetchingSessionSignIn: fetching,
};
}

export default connect(mapStateToProps)(
withTheme()(withStyles(makeAddLocationStyles)(AddLocationData)),
);
39 changes: 39 additions & 0 deletions src/react/src/components/MessyIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

export default function MessyIcon() {
return (
<SvgIcon viewBox="0 0 48 48" style={{ width: 48, height: 48 }}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M25.4094 24.8828H40.5335V30.5766L42.0001 42.0017H23.6465L25.4094 30.5575V24.8828ZM28.4342 27.9038V30.7885L27.1723 38.9807H38.5627L37.5087 30.7695V27.9038H28.4342Z"
fill="#191919"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M38.5168 32.185H27.4258V29.1641H38.5168V32.185Z"
fill="#191919"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M32.7184 15.8179C32.44 15.8179 32.2143 16.0433 32.2143 16.3214V25.8878H29.1895V16.3214C29.1895 14.3748 30.7694 12.7969 32.7184 12.7969H32.9705C34.9195 12.7969 36.4994 14.3748 36.4994 16.3214V25.8878H33.4746V16.3214C33.4746 16.0433 33.2489 15.8179 32.9705 15.8179H32.7184Z"
fill="#191919"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6 14.8125H15.4489L17.7175 17.0782H30.1986V20.0992H16.4646L14.1959 17.8335H9.02482V32.1831H25.6613V35.2041H6V14.8125Z"
fill="#191919"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.01562 6H34.2307V13.8042H31.2059V9.02098H11.0404V15.8182H8.01562V6Z"
fill="#191919"
/>
</SvgIcon>
);
}
13 changes: 13 additions & 0 deletions src/react/src/components/PinDropIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

export default function PinDropIcon() {
return (
<SvgIcon viewBox="0 0 48 48" style={{ width: 48, height: 48 }}>
<path
d="M24 32.95C27.3 30.2833 29.7917 27.7167 31.475 25.25C33.1583 22.7833 34 20.4667 34 18.3C34 15.3 33.0667 12.8333 31.2 10.9C29.3333 8.96667 26.9333 8 24 8C21.0667 8 18.6667 8.96667 16.8 10.9C14.9333 12.8333 14 15.3 14 18.3C14 20.4667 14.8417 22.7833 16.525 25.25C18.2083 27.7167 20.7 30.2833 24 32.95ZM24 38C19.3 34.5333 15.7917 31.1667 13.475 27.9C11.1583 24.6333 10 21.4333 10 18.3C10 14.1333 11.3 10.7083 13.9 8.025C16.5 5.34167 19.8667 4 24 4C28.1333 4 31.5 5.34167 34.1 8.025C36.7 10.7083 38 14.1333 38 18.3C38 21.4333 36.8417 24.6333 34.525 27.9C32.2083 31.1667 28.7 34.5333 24 38ZM24 22C25.1 22 26.0417 21.6083 26.825 20.825C27.6083 20.0417 28 19.1 28 18C28 16.9 27.6083 15.9583 26.825 15.175C26.0417 14.3917 25.1 14 24 14C22.9 14 21.9583 14.3917 21.175 15.175C20.3917 15.9583 20 16.9 20 18C20 19.1 20.3917 20.0417 21.175 20.825C21.9583 21.6083 22.9 22 24 22ZM10 44V40H38V44H10Z"
fill="#191919"
/>
</SvgIcon>
);
}
13 changes: 13 additions & 0 deletions src/react/src/components/PlaylistIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

export default function PlaylistIcon() {
return (
<SvgIcon viewBox="0 0 48 48" style={{ width: 48, height: 48 }}>
<path
d="M6 32V28H20V32H6ZM6 24V20H28V24H6ZM6 16V12H28V16H6ZM32 40V32H24V28H32V20H36V28H44V32H36V40H32Z"
fill="#191919"
/>
</SvgIcon>
);
}
23 changes: 23 additions & 0 deletions src/react/src/components/RectangleCardFigure.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

export default function RectangleCardFigure() {
return (
<SvgIcon viewBox="0 0 75 75" style={{ width: 75, height: 75 }}>
<g clipPath="url(#clip0_1799_23237)">
<path d="M0 0H75V75L0 0Z" fill="#FFA6D0" />
<path d="M0 37.5H37.5V75L0 37.5Z" fill="#FFA6D0" />
</g>
<defs>
<clipPath id="clip0_1799_23237">
<rect
width="75"
height="75"
fill="white"
transform="matrix(1 0 0 -1 0 75)"
/>
</clipPath>
</defs>
</SvgIcon>
);
}
Loading

0 comments on commit d3f450d

Please sign in to comment.