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')
|
||||
|
||||
// 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) =>
|
||||
setScaleInputs(prev => ({ ...prev, [key]: { field, raw } }))
|
||||
|
||||
@ -407,6 +452,22 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se
|
||||
})}
|
||||
</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>
|
||||
</table>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user