From 73025351b5ef8f2ce39796538c7a00e51f9af71e Mon Sep 17 00:00:00 2001 From: jhmullen Date: Wed, 3 Aug 2022 16:28:06 -0400 Subject: [PATCH] isolates vars and selectors to dual profiles --- .../cms/src/components/ProfileRenderer.jsx | 48 ++++++++++++++----- packages/cms/src/components/Viz/Viz.jsx | 18 +++++-- .../cms/src/components/sections/Section.jsx | 7 +-- .../sections/components/Selector.jsx | 21 ++++---- 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/packages/cms/src/components/ProfileRenderer.jsx b/packages/cms/src/components/ProfileRenderer.jsx index 7fd6d2809..bd481dd86 100644 --- a/packages/cms/src/components/ProfileRenderer.jsx +++ b/packages/cms/src/components/ProfileRenderer.jsx @@ -31,6 +31,20 @@ import "../css/layout.css"; import "./Profile.css"; +const splitComparisonKeys = obj => { + const split = { + profile: {}, + comparison: {} + }; + Object.keys(obj).forEach(k => { + split + [k.startsWith("compare_") ? "comparison" : "profile"] + [k.replace("compare_", "")] = + obj[k]; + }); + return split; +}; + class ProfileRenderer extends Component { constructor(props) { super(props); @@ -126,11 +140,11 @@ class ProfileRenderer extends Component { * This requires re-running materializers, because the user may have changed a variable * that would affect the "allowed" status of a given section. */ - onSetVariables(newVariables, forceMats) { - const {profile, selectors, setVarsLoading, formatterFunctions} = this.state; - const {id, variables} = profile; - const {locale, sectionID} = this.props; - const {params} = this.context.router; + onSetVariables(newVariables, forceMats, isComparison) { + const {profile, selectors, setVarsLoading, formatterFunctions, comparison} = this.state; + const {variables} = profile; + const compVars = comparison.variables; + const {locale} = this.props; // Users should ONLY call setVariables in a callback - never in the main execution, as this // would cause an infinite loop. However, should they do so anyway, try and prevent the infinite // loop by checking if the vars are in there already, only updating if they are not yet set. @@ -152,8 +166,16 @@ class ProfileRenderer extends Component { // If forceMats is not true, no materializers required. Using the locally stored _rawProfile and the now-combined // old and new variables, you have all that you need to make the profile update. else { - const newProfile = prepareProfile(variables._rawProfile, Object.assign({}, variables, newVariables), formatterFunctions, locale, selectors); - this.setState({profile: {...profile, ...newProfile}}); + const split = splitComparisonKeys(selectors); + if (isComparison) { + const newComparison = prepareProfile(compVars._rawProfile, Object.assign({}, compVars, newVariables), formatterFunctions, locale, split.comparison); + this.setState({comparison: {...comparison, ...newComparison}}); + } + else { + const newProfile = prepareProfile(variables._rawProfile, Object.assign({}, variables, newVariables), formatterFunctions, locale, split.profile); + this.setState({profile: {...profile, ...newProfile}}); + } + } } } @@ -176,20 +198,21 @@ class ProfileRenderer extends Component { } - onSelector(name, value) { + onSelector(name, value, isComparison) { const {comparison, profile, selectors, formatterFunctions} = this.state; const {locale} = this.props; - selectors[name] = value; + selectors[`${isComparison ? "compare_" : ""}${name}`] = value; + const split = splitComparisonKeys(selectors); const {variables} = profile; - const newProfile = prepareProfile(variables._rawProfile, variables, formatterFunctions, locale, selectors); + const newProfile = prepareProfile(variables._rawProfile, variables, formatterFunctions, locale, split.profile); const payload = {selectors, profile: {...profile, ...newProfile}}; if (comparison) { const compVars = comparison.variables; - const newComp = prepareProfile(compVars._rawProfile, compVars, formatterFunctions, locale, selectors); + const newComp = prepareProfile(compVars._rawProfile, compVars, formatterFunctions, locale, split.comparison); payload.comparison = {...comparison, ...newComp}; } @@ -229,7 +252,8 @@ class ProfileRenderer extends Component { if (Object.keys(selectors).length) { const compVars = comparison.variables; - const newComp = prepareProfile(compVars._rawProfile, compVars, formatterFunctions, locale, selectors); + const split = splitComparisonKeys(selectors); + const newComp = prepareProfile(compVars._rawProfile, compVars, formatterFunctions, locale, split.comparison); comparison = {...comparison, ...newComp}; } diff --git a/packages/cms/src/components/Viz/Viz.jsx b/packages/cms/src/components/Viz/Viz.jsx index 03181aa8b..b732654ba 100644 --- a/packages/cms/src/components/Viz/Viz.jsx +++ b/packages/cms/src/components/Viz/Viz.jsx @@ -55,9 +55,19 @@ class Viz extends Component { // Variables come from props in the CMS, and Context in the Front-end. const variables = this.props.variables || this.context.variables; + const compVariables = this.context.compVariables; + const isComparison = compVariables && compVariables.id === variables.id; // onSetVariables will either come from ProfileBuilder (CMS) or Profile (Front-end) // But either way, it is delivered via context. Have a backup no-op just in case. - const onSetVariables = this.context.onSetVariables ? this.context.onSetVariables : d => d; + let onSetVariables = d => d; + if (this.context.onSetVariables) { + if (isComparison) { + onSetVariables = (variables, forceMats) => this.context.onSetVariables(variables, forceMats, true); + } + else { + onSetVariables = this.context.onSetVariables; + } + } // Window opening is only supported on front-end profiles. If they didn't // come through context, then this Viz is in the CMS, so just replace it with a no-op. const onOpenModal = this.context.onOpenModal ? this.context.onOpenModal : d => d; @@ -175,7 +185,8 @@ Viz.childContextTypes = { onOpenModal: PropTypes.func, print: PropTypes.bool, updateSource: PropTypes.func, - variables: PropTypes.object + variables: PropTypes.object, + compVariables: PropTypes.object }; Viz.contextTypes = { @@ -186,7 +197,8 @@ Viz.contextTypes = { onSetVariables: PropTypes.func, onOpenModal: PropTypes.func, updateSource: PropTypes.func, - variables: PropTypes.object + variables: PropTypes.object, + compVariables: PropTypes.object }; Viz.defaultProps = { diff --git a/packages/cms/src/components/sections/Section.jsx b/packages/cms/src/components/sections/Section.jsx index 024141db0..69e9b4a58 100644 --- a/packages/cms/src/components/sections/Section.jsx +++ b/packages/cms/src/components/sections/Section.jsx @@ -115,7 +115,7 @@ class Section extends Component { * the variables back to their original state. This local intermediary function, passed down via context, * is responsible for keeping track of that, then in turn calling the props version of the function. */ - onSetVariables(newVariables) { + onSetVariables(newVariables, forceMats, isComparison) { const initialVariables = this.props.initialVariables || this.context.initialVariables || {}; const changedVariables = {}; Object.keys(newVariables).forEach(key => { @@ -125,7 +125,7 @@ class Section extends Component { changedVariables, showReset: Object.keys(changedVariables).length > 0 }); - if (this.props.onSetVariables) this.props.onSetVariables(newVariables); + if (this.props.onSetVariables) this.props.onSetVariables(newVariables, forceMats, isComparison); } /** @@ -134,7 +134,8 @@ class Section extends Component { */ resetVariables() { const {changedVariables} = this.state; - if (this.props.onSetVariables) this.props.onSetVariables(changedVariables); + const {comparison} = this.props.contents; + if (this.props.onSetVariables) this.props.onSetVariables(changedVariables, false, comparison); this.setState({ changedVariables: {}, showReset: false diff --git a/packages/cms/src/components/sections/components/Selector.jsx b/packages/cms/src/components/sections/components/Selector.jsx index fbb3be467..5403845ee 100644 --- a/packages/cms/src/components/sections/components/Selector.jsx +++ b/packages/cms/src/components/sections/components/Selector.jsx @@ -32,20 +32,24 @@ class Selector extends Component { } } + onSelectorWrapper(name, value) { + const {onSelector, variables, compVariables} = this.context; + const isComparison = compVariables && compVariables.id === variables.id; + onSelector(name, value, isComparison); + } + addComparison(comparison) { const {comparisons} = this.state; const filteredComparison = comparisons.concat([comparison]); - const {onSelector} = this.context; const {name} = this.props; - onSelector(name, filteredComparison); + this.onSelectorWrapper(name, filteredComparison); } removeComparison(option) { const {comparisons} = this.state; const filteredComparison = comparisons.filter(d => d !== option); - const {onSelector} = this.context; const {name} = this.props; - onSelector(name, filteredComparison); + this.onSelectorWrapper(name, filteredComparison); } renderItem(item, {handleClick}) { @@ -63,7 +67,7 @@ class Selector extends Component { render() { const {activeValue, comparisons} = this.state; - const {onSelector, print, variables} = this.context; + const {print, variables} = this.context; const {fontSize, id, loading, options, name, selectCutoff, title, type, t} = this.props; const slug = `${name}-${id}`; const labels = options.reduce((acc, d) => ({...acc, [d.option]: d.label}), {}); @@ -120,7 +124,7 @@ class Selector extends Component { {(print ? options.filter(b => b.option === activeValue) : options).map(b =>