@@ -12,11 +12,7 @@ import {
1212 Divider ,
1313 Alert ,
1414} from "antd" ;
15- import {
16- LockOutlined ,
17- UnlockOutlined ,
18- QuestionCircleOutlined ,
19- } from "@ant-design/icons" ;
15+ import { LockOutlined , QuestionCircleOutlined } from "@ant-design/icons" ;
2016import { CaseVisualState , CurrentCaseState } from "../store" ;
2117import { thousandFormatter } from "../../../components/chart/options/common" ;
2218import EquationVisualizer from "./EquationVisualizer" ;
@@ -48,19 +44,7 @@ const InputRow = ({
4844 </ Space >
4945 </ Col >
5046 < Col span = { 2 } align = "center" >
51- { isModel && (
52- < Button
53- type = "text"
54- icon = {
55- locked ? (
56- < LockOutlined className = "lock-icon" />
57- ) : (
58- < UnlockOutlined className = "unlock-icon" />
59- )
60- }
61- onClick = { ( ) => toggleLock ( field ) }
62- />
63- ) }
47+ { ! isModel && < LockOutlined className = "lock-icon static-lock" /> }
6448 </ Col >
6549 < Col span = { 8 } >
6650 < Input
@@ -69,7 +53,7 @@ const InputRow = ({
6953 const val = e . target . value . replace ( / , / g, "" ) ;
7054 handleInputChange ( field , val ) ;
7155 } }
72- disabled = { ! isModel || locked || isCalculationTarget }
56+ disabled = { ! isModel || isCalculationTarget }
7357 className = "modelling-input"
7458 />
7559 </ Col >
@@ -106,13 +90,13 @@ const AdvancedModellingTool = () => {
10690 selectedDriver : "cop" ,
10791 activeScenario : "model" ,
10892 lockedFields : {
109- price : true ,
110- volume : true ,
111- land : true ,
112- cop : true ,
113- odi : true ,
114- secondary : true ,
115- tertiary : true ,
93+ price : false ,
94+ volume : false ,
95+ land : false ,
96+ cop : false ,
97+ odi : false ,
98+ secondary : false ,
99+ tertiary : false ,
116100 } ,
117101 modelValues : {
118102 price : 0 ,
@@ -262,12 +246,57 @@ const AdvancedModellingTool = () => {
262246 ) {
263247 setLockedFields ( storedData . lockedFields ) ;
264248 }
265- if (
266- storedData . modelValues &&
267- ! isEqual ( storedData . modelValues , modelValues )
268- ) {
269- setModelValues ( storedData . modelValues ) ;
249+
250+ if ( storedData . modelValues ) {
251+ // Check for stale data (matches feasible)
252+ const fields = [
253+ "price" ,
254+ "volume" ,
255+ "land" ,
256+ "cop" ,
257+ "odi" ,
258+ "secondary" ,
259+ "tertiary" ,
260+ ] ;
261+ const targetSegment =
262+ dashboardData ?. find ( ( d ) => d . id === selectedSegmentId ) || { } ;
263+
264+ const isStale = fields . every ( ( f ) => {
265+ const val = storedData . modelValues [ f ] ;
266+ const feasible = getSegmentAnswer ( "feasible" , f , targetSegment ) ;
267+ return val === feasible ;
268+ } ) ;
269+
270+ if ( isStale ) {
271+ const getPrefillValue = ( field ) => {
272+ const currentVal = getSegmentAnswer (
273+ "current" ,
274+ field ,
275+ targetSegment
276+ ) ;
277+ return currentVal !== 0
278+ ? currentVal
279+ : getSegmentAnswer ( "feasible" , field , targetSegment ) ;
280+ } ;
281+
282+ const refreshedValues = {
283+ price : getPrefillValue ( "price" ) ,
284+ volume : getPrefillValue ( "volume" ) ,
285+ cop : getPrefillValue ( "cop" ) ,
286+ land : getPrefillValue ( "land" ) ,
287+ odi : getPrefillValue ( "odi" ) ,
288+ secondary : getPrefillValue ( "secondary" ) ,
289+ tertiary : getPrefillValue ( "tertiary" ) ,
290+ } ;
291+
292+ if ( ! isEqual ( refreshedValues , modelValues ) ) {
293+ setModelValues ( refreshedValues ) ;
294+ }
295+ } else if ( ! isEqual ( storedData . modelValues , modelValues ) ) {
296+ setModelValues ( storedData . modelValues ) ;
297+ }
270298 }
299+
271300 if (
272301 storedData . calculationResult &&
273302 ! isEqual ( storedData . calculationResult , calculationResult )
@@ -278,7 +307,7 @@ const AdvancedModellingTool = () => {
278307 }
279308 }
280309 // eslint-disable-next-line react-hooks/exhaustive-deps
281- } , [ advancedModelingConfig ] ) ;
310+ } , [ advancedModelingConfig , selectedSegmentId , dashboardData ] ) ;
282311
283312 // Find primary commodity QIDs
284313 const focusCommodityGroup = useMemo ( ( ) => {
@@ -441,14 +470,21 @@ const AdvancedModellingTool = () => {
441470 const isModelValuesEmpty = Object . values ( modelValues ) . every ( ( v ) => v === 0 ) ;
442471
443472 if ( segment && isModelValuesEmpty ) {
473+ const getPrefillValue = ( field ) => {
474+ const currentVal = getSegmentAnswer ( "current" , field ) ;
475+ return currentVal !== 0
476+ ? currentVal
477+ : getSegmentAnswer ( "feasible" , field ) ;
478+ } ;
479+
444480 setModelValues ( {
445- price : getSegmentAnswer ( "feasible" , "price" ) ,
446- volume : getSegmentAnswer ( "feasible" , "volume" ) ,
447- cop : getSegmentAnswer ( "feasible" , "cop" ) ,
448- land : getSegmentAnswer ( "feasible" , "land" ) ,
449- odi : getSegmentAnswer ( "feasible" , "odi" ) ,
450- secondary : getSegmentAnswer ( "feasible" , "secondary" ) ,
451- tertiary : getSegmentAnswer ( "feasible" , "tertiary" ) ,
481+ price : getPrefillValue ( "price" ) ,
482+ volume : getPrefillValue ( "volume" ) ,
483+ cop : getPrefillValue ( "cop" ) ,
484+ land : getPrefillValue ( "land" ) ,
485+ odi : getPrefillValue ( "odi" ) ,
486+ secondary : getPrefillValue ( "secondary" ) ,
487+ tertiary : getPrefillValue ( "tertiary" ) ,
452488 } ) ;
453489 }
454490 // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -467,12 +503,51 @@ const AdvancedModellingTool = () => {
467503 } ;
468504
469505 const handleSegmentChange = ( newSegmentId ) => {
470- // Check if we already have data for this segment in the store
471506 const storedData = advancedModelingConfig ?. segmentData ?. [ newSegmentId ] ;
507+ const newSegment = dashboardData ?. find ( ( d ) => d . id === newSegmentId ) || { } ;
472508
473- if ( storedData ) {
474- // Just switch the segment ID in the store
475- // Effect 2 will handle loading the data into local state
509+ const getPrefillValue = ( field , target ) => {
510+ const currentVal = getSegmentAnswer ( "current" , field , target ) ;
511+ return currentVal !== 0
512+ ? currentVal
513+ : getSegmentAnswer ( "feasible" , field , target ) ;
514+ } ;
515+
516+ let finalModelValues = {
517+ price : getPrefillValue ( "price" , newSegment ) ,
518+ volume : getPrefillValue ( "volume" , newSegment ) ,
519+ cop : getPrefillValue ( "cop" , newSegment ) ,
520+ land : getPrefillValue ( "land" , newSegment ) ,
521+ odi : getPrefillValue ( "odi" , newSegment ) ,
522+ secondary : getPrefillValue ( "secondary" , newSegment ) ,
523+ tertiary : getPrefillValue ( "tertiary" , newSegment ) ,
524+ } ;
525+
526+ // Detect stale data if storedData exists
527+ if ( storedData ?. modelValues ) {
528+ const fields = [
529+ "price" ,
530+ "volume" ,
531+ "land" ,
532+ "cop" ,
533+ "odi" ,
534+ "secondary" ,
535+ "tertiary" ,
536+ ] ;
537+ const isStale = fields . every ( ( f ) => {
538+ const val = storedData . modelValues [ f ] ;
539+ const feasible = getSegmentAnswer ( "feasible" , f , newSegment ) ;
540+ return val === feasible ;
541+ } ) ;
542+
543+ if ( ! isStale ) {
544+ // Keep user customisations if NOT stale
545+ finalModelValues = storedData . modelValues ;
546+ }
547+ }
548+
549+ if ( storedData && finalModelValues === storedData . modelValues ) {
550+ // Just switch the segment ID in the store if data is NOT stale
476551 CaseVisualState . update ( ( s ) => ( {
477552 ...s ,
478553 scenarioModeling : {
@@ -488,20 +563,7 @@ const AdvancedModellingTool = () => {
488563 } ,
489564 } ) ) ;
490565 } else {
491- // Generate defaults for the new segment
492- const newSegment =
493- dashboardData ?. find ( ( d ) => d . id === newSegmentId ) || { } ;
494-
495- const defaultModelValues = {
496- price : getSegmentAnswer ( "feasible" , "price" , newSegment ) ,
497- volume : getSegmentAnswer ( "feasible" , "volume" , newSegment ) ,
498- cop : getSegmentAnswer ( "feasible" , "cop" , newSegment ) ,
499- land : getSegmentAnswer ( "feasible" , "land" , newSegment ) ,
500- odi : getSegmentAnswer ( "feasible" , "odi" , newSegment ) ,
501- secondary : getSegmentAnswer ( "feasible" , "secondary" , newSegment ) ,
502- tertiary : getSegmentAnswer ( "feasible" , "tertiary" , newSegment ) ,
503- } ;
504-
566+ // Create or update segment data with refreshed values
505567 const defaultCalculationResult = {
506568 value : null ,
507569 change : 0 ,
@@ -513,19 +575,18 @@ const AdvancedModellingTool = () => {
513575 } ;
514576
515577 const defaultLockedFields = {
516- price : true ,
517- volume : true ,
518- land : true ,
519- cop : true ,
520- odi : true ,
521- secondary : true ,
522- tertiary : true ,
578+ price : false ,
579+ volume : false ,
580+ land : false ,
581+ cop : false ,
582+ odi : false ,
583+ secondary : false ,
584+ tertiary : false ,
523585 } ;
524586
525587 const defaultActiveScenario = "model" ;
526588 const defaultSelectedDriver = "cop" ;
527589
528- // Update store with new ID AND new segment data
529590 CaseVisualState . update ( ( s ) => {
530591 const prevConfig = s . scenarioModeling ?. config ?. advancedModeling ;
531592 return {
@@ -541,11 +602,16 @@ const AdvancedModellingTool = () => {
541602 segmentData : {
542603 ...prevConfig ?. segmentData ,
543604 [ newSegmentId ] : {
544- modelValues : defaultModelValues ,
545- calculationResult : defaultCalculationResult ,
546- lockedFields : defaultLockedFields ,
547- activeScenario : defaultActiveScenario ,
548- selectedDriver : defaultSelectedDriver ,
605+ ...( storedData || { } ) ,
606+ modelValues : finalModelValues ,
607+ calculationResult :
608+ storedData ?. calculationResult || defaultCalculationResult ,
609+ lockedFields :
610+ storedData ?. lockedFields || defaultLockedFields ,
611+ activeScenario :
612+ storedData ?. activeScenario || defaultActiveScenario ,
613+ selectedDriver :
614+ storedData ?. selectedDriver || defaultSelectedDriver ,
549615 } ,
550616 } ,
551617 } ,
@@ -874,13 +940,13 @@ const AdvancedModellingTool = () => {
874940 profit : 0 ,
875941 } ) ;
876942 setLockedFields ( {
877- price : true ,
878- volume : true ,
879- land : true ,
880- cop : true ,
881- odi : true ,
882- secondary : true ,
883- tertiary : true ,
943+ price : false ,
944+ volume : false ,
945+ land : false ,
946+ cop : false ,
947+ odi : false ,
948+ secondary : false ,
949+ tertiary : false ,
884950 } ) ;
885951 } }
886952 >
0 commit comments