Skip to main content

Converting Units

For a Corva frontend app, prefer the helpers exported by @corva/ui/utils. They combine the conversion library with the effective company, user, and dashboard preference supplied by the Corva host.

Follow the active Corva preference

Pass the value, unit type, and known source unit to convertValue. When the target unit is omitted, the helper converts to the effective Corva preference.

import { convertValue, getUnitDisplay } from '@corva/ui/utils';

function PressureValue({ valuePsi }) {
const value = convertValue(valuePsi, 'pressure', 'psi', null, 1);
const unit = getUnitDisplay('pressure');

return <span>{value} {unit}</span>;
}

The source unit (psi in this example) must describe the value received from the dataset or API. It must not be inferred from the user's display preference.

Keep the number and label together. For example, use the same conversion and unit label in a chart axis, tooltip, legend, table cell, and exported value.

After confirming the producer's data contract, keep the field path, unit type, and source unit together in app code. This makes the assumption reviewable and prevents different components from interpreting the same field differently:

export const PRESSURE_MEASUREMENT = {
field: 'data.pressure',
unitType: 'pressure',
sourceUnit: 'psi',
};

Do not add this constant until the dataset contract or producer has confirmed psi. See Find the source value and source unit for the verification workflow.

Convert to an explicit unit

Pass a target unit when an app setting or a fixed workflow requirement controls the display:

import { convertValue, getUnitDisplay } from '@corva/ui/utils';

const pressureKpa = convertValue(1000, 'pressure', 'psi', 'kPa', 1);
const label = getUnitDisplay('pressure', 'kPa');

Add a unit selector to app settings

Use the units exposed for the measurement type rather than maintaining your own list. Save only the selected abbreviation in appSettings.

import { MenuItem, TextField } from '@material-ui/core';
import {
getUnitPreference,
getUnitsByType,
} from '@corva/ui/utils';

export default function AppSettings({ settings, onSettingChange }) {
const pressureUnit = settings.pressureUnit ?? getUnitPreference('pressure');

return (
<TextField
select
fullWidth
label="Pressure unit"
value={pressureUnit}
onChange={event => onSettingChange('pressureUnit', event.target.value)}
>
{getUnitsByType('pressure').map(unit => (
<MenuItem key={unit.abbr} value={unit.abbr}>
{unit.display}
</MenuItem>
))}
</TextField>
);
}

Use the saved setting when rendering the app, and otherwise follow the Corva preference:

import {
convertValue,
getUnitDisplay,
getUnitPreference,
} from '@corva/ui/utils';

const displayUnit = appSettings.pressureUnit ?? getUnitPreference('pressure');
const displayValue = convertValue(sourceValue, 'pressure', 'psi', displayUnit, 1);
const displayLabel = getUnitDisplay('pressure', displayUnit);

See App Context and Settings for the complete app settings lifecycle.

Convert editable values back before saving

If a user edits a converted value, convert it from the display unit back to the source or canonical unit before sending it to an API:

const displayUnit = appSettings.pressureUnit ?? getUnitPreference('pressure');

const pressurePsi = convertValue(
enteredValue,
'pressure',
displayUnit,
'psi',
4
);

Choose precision deliberately. Display precision can be lower than the precision used for a round-trip conversion or API write.

Use corva-convert-units directly

Use the lower-level corva-convert-units package when you need conversion without Corva preference resolution—for example, in a standalone utility or when both source and target units are explicit.

The current @corva/create-app frontend scaffold installs the package's 1.x API. With that version:

import convert from 'corva-convert-units';

const pressureKpa = convert(1000, 'pressure').from('psi').to('kPa');
const pressureUnits = convert().list('pressure');
Check the installed major version

corva-convert-units 3.x has a different API from the 1.x version currently installed by @corva/create-app. Use the version in the generated app's package.json and lockfile, and do not copy an example written for another major version. For a Corva frontend app, @corva/ui/utils is the safer default because it also respects platform preferences.

Useful helpers

HelperPurpose
convertValue(value, type, from, to?, precision?)Convert a value. Omit to to follow the effective Corva preference.
getUnitPreference(type)Get the effective target unit for a measurement type.
getUnitDisplay(type, unit?)Get the label to show with the converted value.
getUnitsByType(type)Get the available units for a selector.
getAllUnitTypes()Get the supported measurement types.

See the live @corva/ui unit conversion examples for the current helper behavior.

Test unit-aware UI

Before release, verify:

  • Metric and imperial preferences, plus any custom unit used by the customer
  • Zero, negative, null, and missing values
  • Matching labels in charts, tooltips, tables, and exports
  • App-setting fallback when an override has not been saved
  • Editable-value conversion in both directions
  • Precision and rounding at the limits expected by the workflow

Avoid changing only the unit label, mutating fetched data in place, or caching a preference at module load time. The app should recalculate display values when Corva remounts it after a preference change.