Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1329 from open-apparel-registry/tw/connect-embed-…
Browse files Browse the repository at this point in the history
…config

Connect embed section of settings page to API
  • Loading branch information
TaiWilkin committed May 13, 2021
2 parents 5f1dee0 + 680632a commit a281902
Show file tree
Hide file tree
Showing 17 changed files with 387 additions and 105 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add models to persist embed config [#1304](https://github.com/open-apparel-registry/open-apparel-registry/pull/1304)
- Add API to get nonstandard fields for contributor [#1321](https://github.com/open-apparel-registry/open-apparel-registry/pull/1321)
- Add new admin reports [#1326](https://github.com/open-apparel-registry/open-apparel-registry/pull/1326)
- Connect embed section of settings page to API [#1329](https://github.com/open-apparel-registry/open-apparel-registry/pull/1329)

### Changed

Expand Down
4 changes: 3 additions & 1 deletion src/app/src/components/AppGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import Grid from '@material-ui/core/Grid';
import PropTypes from 'prop-types';

import { OARFont } from '../util/constants';

export default function AppGrid({
style,
title,
Expand All @@ -23,7 +25,7 @@ export default function AppGrid({
<Grid item xs={12}>
<h2
style={{
fontFamily: 'ff-tisa-sans-web-pro, sans-serif',
fontFamily: OARFont,
fontWeight: 'normal',
fontSize: '32px',
}}
Expand Down
25 changes: 4 additions & 21 deletions src/app/src/components/EmbeddedMapCode.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import { shape, string, bool } from 'prop-types';
import { string, bool } from 'prop-types';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import noop from 'lodash/noop';
import { toast } from 'react-toastify';

import { createIFrameHTML } from '../util/util';
import { OARFont } from '../util/constants';

const styles = {
sectionHeader: {
Expand All @@ -32,7 +33,7 @@ const styles = {
width: '90%',
marginTop: '20px',
color: 'rgb(0, 0, 0)',
fontFamily: 'ff-tisa-sans-web-pro,sans-serif',
fontFamily: OARFont,
padding: '10px',
},
embedButton: {
Expand All @@ -43,17 +44,8 @@ const styles = {
},
};

function EmbeddedMapCode({
color,
font,
width,
height,
fullWidth,
contributor,
}) {
function EmbeddedMapCode({ width, height, fullWidth, contributor }) {
const mapSettings = {
color,
font,
width,
height,
fullWidth,
Expand Down Expand Up @@ -82,19 +74,10 @@ function EmbeddedMapCode({
);
}

EmbeddedMapCode.defaultProps = {
font: null,
};

EmbeddedMapCode.propTypes = {
width: string.isRequired,
height: string.isRequired,
fullWidth: bool.isRequired,
color: string.isRequired,
font: shape({
label: string,
value: string,
}),
};

export default EmbeddedMapCode;
85 changes: 43 additions & 42 deletions src/app/src/components/EmbeddedMapConfig.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { connect } from 'react-redux';
import React from 'react';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import { func, shape, string, bool } from 'prop-types';

import { userPropType } from '../util/propTypes';
import { getEmbeddedMapSrc } from '../util/util';
Expand Down Expand Up @@ -29,30 +29,28 @@ const styles = {
},
};

function EmbeddedMapConfig({ user }) {
// TODO: Replace with backend configuration data
const [fields, setFields] = useState([
{ included: true, label: 'Years active', value: 'years_active' },
{ included: true, label: 'num_widgets', value: 'num_widgets' },
{
included: false,
label: 'some_other_field_name',
value: 'some_other_field_name',
},
]);
const [
function EmbeddedMapConfig({
user,
embedConfig: {
includeOtherContributorFields,
setIncludeOtherContributorFields,
] = useState(true);
const [color, setColor] = useState('#C74444');
const [font, setFont] = useState(null);
const [width, setWidth] = useState('780');
const [fullWidth, setFullWidth] = useState(false);
const [height, setHeight] = useState('440');

const mapSettings = {
color,
font,
width,
fullWidth,
height,
},
setEmbedConfig,
fields,
setFields,
errors,
}) {
const updateEmbedConfig = field => value =>
setEmbedConfig(config => ({
...config,
[field]: value,
}));

const mapSettings = {
width,
height,
fullWidth,
Expand All @@ -72,23 +70,26 @@ function EmbeddedMapConfig({ user }) {
includeOtherContributorFields={
includeOtherContributorFields
}
setIncludeOtherContributorFields={
setIncludeOtherContributorFields
}
setIncludeOtherContributorFields={updateEmbedConfig(
'includeOtherContributorFields',
)}
errors={errors}
/>
<EmbeddedMapThemeConfig
color={color}
setColor={setColor}
setColor={updateEmbedConfig('color')}
font={font}
setFont={setFont}
setFont={updateEmbedConfig('font')}
errors={errors}
/>
<EmbeddedMapSizeConfig
width={width}
setWidth={setWidth}
setWidth={updateEmbedConfig('width')}
height={height}
setHeight={setHeight}
setHeight={updateEmbedConfig('height')}
fullWidth={fullWidth}
setFullWidth={setFullWidth}
setFullWidth={updateEmbedConfig('fullWidth')}
errors={errors}
/>
</Grid>
<Grid item xs={6} style={{ ...styles.section, padding: '20px' }}>
Expand Down Expand Up @@ -122,16 +123,16 @@ EmbeddedMapConfig.defaultProps = {

EmbeddedMapConfig.propTypes = {
user: userPropType,
embedConfig: shape({
color: string.isRequired,
font: string.isRequired,
width: string.isRequired,
height: string.isRequired,
fullWidth: bool.isRequired,
includeOtherContributorFields: bool.isRequired,
}).isRequired,
setEmbedConfig: func.isRequired,
setFields: func.isRequired,
};

function mapStateToProps({
auth: {
user: { user },
},
}) {
return {
user,
};
}

export default connect(mapStateToProps)(EmbeddedMapConfig);
export default EmbeddedMapConfig;
143 changes: 143 additions & 0 deletions src/app/src/components/EmbeddedMapConfigWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React, { useState, useEffect, useCallback } from 'react';
import { connect } from 'react-redux';
import { toast } from 'react-toastify';

import { userPropType } from '../util/propTypes';
import { makeNonStandardFieldsURL, makeEmbedConfigURL } from '../util/util';
import apiRequest from '../util/apiRequest';
import EmbeddedMapConfig from './EmbeddedMapConfig';
import {
formatExistingConfig,
formatExistingFields,
combineEmbedAndNonstandardFields,
formatEmbedConfigForServer,
getErrorMessage,
} from '../util/embeddedMap';

function EmbeddedMapConfigWrapper({ user }) {
const [loading, setLoading] = useState(true);
// Used for field-specific validation errors
const [errors, setError] = useState(null);
const [embedConfig, setEmbedConfig] = useState(
formatExistingConfig(user.embed_config),
);
const [embedFields, setEmbedFields] = useState(
formatExistingFields(embedConfig.embed_fields),
);

const handleError = e => {
const errorMessage = getErrorMessage(e);
if (Array.isArray(errorMessage)) {
toast.error(`Error: ${errorMessage.join(', ')}`, {
position: 'bottom-left',
});
} else {
setError(errorMessage);
}
setLoading(false);
};

const handleSuccess = () => {
setLoading(false);
setError(null);
};

const fetchFields = useCallback(() => {
setLoading(true);
apiRequest
.get(makeNonStandardFieldsURL())
.then(({ data }) => {
setEmbedFields(
combineEmbedAndNonstandardFields(
user.embed_config.embed_fields,
data,
),
);
handleSuccess();
})
.catch(e => handleError(e));
}, [user]);

const createConfig = () => {
setLoading(true);
apiRequest
.post(
makeEmbedConfigURL(),
formatEmbedConfigForServer(embedConfig, embedFields),
)
.then(({ data }) => {
setEmbedConfig(formatExistingConfig(data));
handleSuccess();
})
.catch(e => handleError(e));
};

const updateConfig = () => {
setLoading(true);
apiRequest
.put(
makeEmbedConfigURL(embedConfig.id),
formatEmbedConfigForServer(embedConfig, embedFields),
)
.then(({ data }) => {
setEmbedConfig(formatExistingConfig(data));
handleSuccess();
})
.catch(e => handleError(e));
};

// Fetches and merges nonstandard fields from the database with fields
// from the user's EmbedConfig
useEffect(() => fetchFields(), [user, fetchFields]);

/* eslint-disable react-hooks/exhaustive-deps */
// Disabled exhaustive dependencies warning because we don't want to rerun
// in response to the loading state changing
// When the embed config or fields are updated, wait for 500ms. If no
// additional changes are made, update/create the embed config in the database.
useEffect(() => {
const handler = setTimeout(() => {
if (loading) return;
if (embedConfig.id) {
updateConfig();
} else {
createConfig();
}
}, 500);

return () => {
clearTimeout(handler);
};
}, [embedConfig, embedFields]);

return (
<EmbeddedMapConfig
user={user}
embedConfig={embedConfig}
setEmbedConfig={setEmbedConfig}
fields={embedFields}
setFields={setEmbedFields}
errors={errors}
/>
);
}

EmbeddedMapConfigWrapper.defaultProps = {
user: null,
};

EmbeddedMapConfigWrapper.propTypes = {
user: userPropType,
};

function mapStateToProps({
auth: {
user: { user },
},
}) {
return {
user,
};
}

export default connect(mapStateToProps)(EmbeddedMapConfigWrapper);
Loading

0 comments on commit a281902

Please sign in to comment.