Show where a scale edit lands, for all three measures at once
Each ledger row derived only from its own input, so typing a dollar figure left the units and price rows blank -- which are precisely the two numbers that say whether you just asked for a volume change or a price change. The plug toggle decided it and then showed you nothing. Adds a Result line under the edit rows carrying value, units and price together, resolved the same way the server resolves the increments: a price input multiplies through volume, a dollar input with plug = volume scales units in proportion, anything else holds units. Measures that actually move are picked out in blue against the ones that hold, so plug = price reads as price moving alone and plug = volume as price standing still. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
546af67639
commit
de6064b4f2
@ -296,6 +296,51 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se
|
|||||||
}
|
}
|
||||||
const dollarsOnly = filled('value') && !filled('units') && !filled('price')
|
const dollarsOnly = filled('value') && !filled('units') && !filled('price')
|
||||||
|
|
||||||
|
// Where the edit lands, for all three measures at once. The rows above each
|
||||||
|
// show only their own input, so a dollar figure entered with plug = volume
|
||||||
|
// left units and price blank -- exactly the two numbers you need to see to
|
||||||
|
// know whether you asked for a price change or a volume change.
|
||||||
|
const numOf = (key, field) => {
|
||||||
|
const raw = derived[key]?.[field]
|
||||||
|
const n = parseFloat(raw)
|
||||||
|
return isFinite(n) ? n : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const outcome = (() => {
|
||||||
|
const curValue = basisOf('value') ?? 0
|
||||||
|
const curUnits = basisOf('units') ?? 0
|
||||||
|
if (!filled('value') && !filled('units') && !filled('price')) return null
|
||||||
|
|
||||||
|
let newValue, newUnits
|
||||||
|
|
||||||
|
if (filled('price') && !filled('value')) {
|
||||||
|
// price is the input; dollars fall out of price x volume
|
||||||
|
const targetPrice = numOf('price', 'new')
|
||||||
|
newUnits = filled('units') ? numOf('units', 'new') : curUnits
|
||||||
|
newValue = targetPrice != null && newUnits != null ? targetPrice * newUnits : null
|
||||||
|
} else {
|
||||||
|
newValue = filled('value') ? numOf('value', 'new') : curValue
|
||||||
|
if (filled('units')) newUnits = numOf('units', 'new')
|
||||||
|
else if (dollarsOnly && scalePlug === 'volume') newUnits = curValue === 0 ? null
|
||||||
|
: curUnits * (newValue / curValue)
|
||||||
|
else newUnits = curUnits
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue == null || newUnits == null) return null
|
||||||
|
const newPrice = newUnits === 0 ? null : newValue / newUnits
|
||||||
|
const curPriceLocal = curUnits === 0 ? null : curValue / curUnits
|
||||||
|
return {
|
||||||
|
value: newValue,
|
||||||
|
units: newUnits,
|
||||||
|
price: newPrice,
|
||||||
|
moved: {
|
||||||
|
value: Math.abs(newValue - curValue) > 1e-9,
|
||||||
|
units: Math.abs(newUnits - curUnits) > 1e-9,
|
||||||
|
price: curPriceLocal != null && newPrice != null && Math.abs(newPrice - curPriceLocal) > 1e-9,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
const setEdit = (key, field, raw) =>
|
const setEdit = (key, field, raw) =>
|
||||||
setScaleInputs(prev => ({ ...prev, [key]: { field, raw } }))
|
setScaleInputs(prev => ({ ...prev, [key]: { field, raw } }))
|
||||||
|
|
||||||
@ -407,6 +452,22 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se
|
|||||||
})}
|
})}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{outcome && (
|
||||||
|
<>
|
||||||
|
<tr>{rule}{measures.map(m => <td key={m.key} className="p-0 px-2"><div className="border-t border-gray-300 my-1" /></td>)}</tr>
|
||||||
|
<tr className="font-semibold text-gray-700">
|
||||||
|
<td className="pr-3 whitespace-nowrap">Result</td>
|
||||||
|
{measures.map(m => (
|
||||||
|
<td key={m.key} className={numCell}>
|
||||||
|
<span className={outcome.moved[m.key] ? 'text-blue-600' : 'text-gray-400'}>
|
||||||
|
{fmtNum(outcome[m.key], m.dp)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user