refactor: remove unnecessary state and ui improvements

This commit is contained in:
Ibrahima G. Coulibaly
2025-04-05 05:36:06 +00:00
parent ab503c642d
commit 1b72557aa2
5 changed files with 115 additions and 127 deletions

40
.idea/workspace.xml generated
View File

@@ -4,26 +4,12 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="chore: compress video icon"> <list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="refactor: init">
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereArea.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/sphereVolume.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/home/daniel/Projects/omni-tools/src/pages/tools/index.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/home/daniel/Projects/omni-tools/src/pages/tools/number/calculators/index.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/home/daniel/Projects/omni-tools/src/pages/tools/number/index.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ToolContent.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolContent.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/components/ToolContent.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolContent.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ToolInputAndResult.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolInputAndResult.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/input/NumericInputWithUnit.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/input/NumericInputWithUnit.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/components/input/NumericInputWithUnit.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/input/NumericInputWithUnit.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/datatables/data/index.ts" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/components/options/ToolOptions.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/options/ToolOptions.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/datatables/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datatables/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/datatables/types.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datatables/types.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/area_volume.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/ohms_law.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/ohms_law.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/types.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/types.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/wire_voltage_drop.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/data/wire_voltage_drop.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/tools/number/generic-calc/service.ts" beforeDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -415,14 +401,6 @@
<workItem from="1743103182313" duration="4264000" /> <workItem from="1743103182313" duration="4264000" />
<workItem from="1743348610793" duration="21855000" /> <workItem from="1743348610793" duration="21855000" />
</task> </task>
<task id="LOCAL-00127" summary="chore: show tooloptions in example">
<option name="closed" value="true" />
<created>1740619610168</created>
<option name="number" value="00127" />
<option name="presentableId" value="LOCAL-00127" />
<option name="project" value="LOCAL" />
<updated>1740619610169</updated>
</task>
<task id="LOCAL-00128" summary="refact: examples"> <task id="LOCAL-00128" summary="refact: examples">
<option name="closed" value="true" /> <option name="closed" value="true" />
<created>1740620866551</created> <created>1740620866551</created>
@@ -807,7 +785,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1743355166426</updated> <updated>1743355166426</updated>
</task> </task>
<option name="localTasksCounter" value="176" /> <task id="LOCAL-00176" summary="refactor: init">
<option name="closed" value="true" />
<created>1743827787241</created>
<option name="number" value="00176" />
<option name="presentableId" value="LOCAL-00176" />
<option name="project" value="LOCAL" />
<updated>1743827787241</updated>
</task>
<option name="localTasksCounter" value="177" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -854,7 +840,6 @@
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" /> <option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
<option name="CHECK_NEW_TODO" value="false" /> <option name="CHECK_NEW_TODO" value="false" />
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" /> <option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
<MESSAGE value="style: tools height" />
<MESSAGE value="chore: update meta" /> <MESSAGE value="chore: update meta" />
<MESSAGE value="feat: change pgn opacity" /> <MESSAGE value="feat: change pgn opacity" />
<MESSAGE value="feat: crop png" /> <MESSAGE value="feat: crop png" />
@@ -879,7 +864,8 @@
<MESSAGE value="fix: typos" /> <MESSAGE value="fix: typos" />
<MESSAGE value="feat: compress video" /> <MESSAGE value="feat: compress video" />
<MESSAGE value="chore: compress video icon" /> <MESSAGE value="chore: compress video icon" />
<option name="LAST_COMMIT_MESSAGE" value="chore: compress video icon" /> <MESSAGE value="refactor: init" />
<option name="LAST_COMMIT_MESSAGE" value="refactor: init" />
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState"> <component name="XSLT-Support.FileAssociations.UIState">
<expand /> <expand />

View File

@@ -57,6 +57,7 @@ interface ToolContentProps<T, I> extends ToolComponentProps {
setInput?: React.Dispatch<React.SetStateAction<I>>; setInput?: React.Dispatch<React.SetStateAction<I>>;
validationSchema?: any; validationSchema?: any;
onValuesChange?: (values: T) => void; onValuesChange?: (values: T) => void;
verticalGroups?: boolean;
} }
export default function ToolContent<T extends FormikValues, I>({ export default function ToolContent<T extends FormikValues, I>({
@@ -72,7 +73,8 @@ export default function ToolContent<T extends FormikValues, I>({
setInput, setInput,
validationSchema, validationSchema,
renderCustomInput, renderCustomInput,
onValuesChange onValuesChange,
verticalGroups
}: ToolContentProps<T, I>) { }: ToolContentProps<T, I>) {
return ( return (
<Box> <Box>
@@ -97,7 +99,7 @@ export default function ToolContent<T extends FormikValues, I>({
input={input} input={input}
onValuesChange={onValuesChange} onValuesChange={onValuesChange}
/> />
<ToolOptions getGroups={getGroups} /> <ToolOptions getGroups={getGroups} vertical={verticalGroups} />
{toolInfo && toolInfo.title && toolInfo.description && ( {toolInfo && toolInfo.title && toolInfo.description && (
<ToolInfo <ToolInfo

View File

@@ -143,8 +143,6 @@ export default function NumericInputWithUnit(props: {
<Select <Select
fullWidth fullWidth
disabled={disableChangingUnit} disabled={disableChangingUnit}
label="Prefix"
title="Prefix"
value={prefix} value={prefix}
onChange={(evt) => { onChange={(evt) => {
handlePrefixChange(evt.target.value || ''); handlePrefixChange(evt.target.value || '');

View File

@@ -13,10 +13,12 @@ export type GetGroupsType<T> = (
export default function ToolOptions<T extends FormikValues>({ export default function ToolOptions<T extends FormikValues>({
children, children,
getGroups getGroups,
vertical
}: { }: {
children?: ReactNode; children?: ReactNode;
getGroups: GetGroupsType<T> | null; getGroups: GetGroupsType<T> | null;
vertical?: boolean;
}) { }) {
const theme = useTheme(); const theme = useTheme();
const formikContext = useFormikContext<T>(); const formikContext = useFormikContext<T>();
@@ -49,6 +51,7 @@ export default function ToolOptions<T extends FormikValues>({
<Stack direction={'row'} spacing={2}> <Stack direction={'row'} spacing={2}>
<ToolOptionGroups <ToolOptionGroups
groups={getGroups({ ...formikContext, updateField }) ?? []} groups={getGroups({ ...formikContext, updateField }) ?? []}
vertical={vertical}
/> />
{children} {children}
</Stack> </Stack>

View File

@@ -2,6 +2,7 @@ import {
Autocomplete, Autocomplete,
Box, Box,
Radio, Radio,
Stack,
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
@@ -24,6 +25,8 @@ import 'nerdamer-prime/Solve';
import 'nerdamer-prime/Calculus'; import 'nerdamer-prime/Calculus';
import Qty from 'js-quantities'; import Qty from 'js-quantities';
import { CustomSnackBarContext } from 'contexts/CustomSnackBarContext'; import { CustomSnackBarContext } from 'contexts/CustomSnackBarContext';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
function numericSolveEquationFor( function numericSolveEquationFor(
equation: string, equation: string,
@@ -59,14 +62,6 @@ export default async function makeTool(
return function GenericCalc({ title }: ToolComponentProps) { return function GenericCalc({ title }: ToolComponentProps) {
const { showSnackBar } = useContext(CustomSnackBarContext); const { showSnackBar } = useContext(CustomSnackBarContext);
const [alternatesByVariable, setAlternatesByVariable] = useState<{
[key: string]: {
value: {
value: number;
unit: string;
};
}[];
}>({});
// For UX purposes we need to track what vars are // For UX purposes we need to track what vars are
const [valsBoundToPreset, setValsBoundToPreset] = useState<{ const [valsBoundToPreset, setValsBoundToPreset] = useState<{
@@ -110,12 +105,17 @@ export default async function makeTool(
newPresets[selection] = preset; newPresets[selection] = preset;
updateFieldFunc('presets', newPresets); updateFieldFunc('presets', newPresets);
// Clear old selection // Clear old selection using setState callback pattern
for (const key in valsBoundToPreset) { setValsBoundToPreset((prevState) => {
if (valsBoundToPreset[key] === selection) { const newState = { ...prevState };
delete valsBoundToPreset[key]; // Remove all keys bound to this selection
} Object.keys(newState).forEach((key) => {
} if (newState[key] === selection) {
delete newState[key];
}
});
return newState;
});
const selectionData = calcData.presets?.find( const selectionData = calcData.presets?.find(
(sel) => sel.title === selection (sel) => sel.title === selection
@@ -123,8 +123,12 @@ export default async function makeTool(
if (preset && preset != '<custom>') { if (preset && preset != '<custom>') {
if (selectionData) { if (selectionData) {
// Create an object with the new bindings
const newBindings: { [key: string]: string } = {};
for (const key in selectionData.bind) { for (const key in selectionData.bind) {
valsBoundToPreset[key] = selection; // Add to newBindings for later state update
newBindings[key] = selection;
if (currentValues.outputVariable === key) { if (currentValues.outputVariable === key) {
handleSelectedTargetChange('', updateFieldFunc); handleSelectedTargetChange('', updateFieldFunc);
@@ -142,6 +146,12 @@ export default async function makeTool(
updateFieldFunc updateFieldFunc
); );
} }
// Update state with new bindings
setValsBoundToPreset((prevState) => ({
...prevState,
...newBindings
}));
} else { } else {
throw new Error( throw new Error(
`Preset "${preset}" is not valid for selection "${selection}"` `Preset "${preset}" is not valid for selection "${selection}"`
@@ -179,7 +189,7 @@ export default async function makeTool(
unit: selection.source.columns[selection.bind[key]]?.unit || '' unit: selection.source.columns[selection.bind[key]]?.unit || ''
}; };
valsBoundToPreset[key] = selection.title; // We'll set this in useEffect instead of directly modifying state
} }
}); });
@@ -219,25 +229,6 @@ export default async function makeTool(
}); });
} }
calcData.variables.forEach((variable) => {
if (variable.alternates) {
variable.alternates.forEach((alt) => {
const altValue = getAlternate(
alt,
variable,
initialValues.vars[variable.name]
);
if (alternatesByVariable[variable.name] === undefined) {
alternatesByVariable[variable.name] = [];
}
alternatesByVariable[variable.name].push({
value: { value: altValue, unit: variable.unit }
});
});
}
});
return ( return (
<ToolContent <ToolContent
title={title} title={title}
@@ -250,52 +241,48 @@ export default async function makeTool(
' Generated from formula: ' + ' Generated from formula: ' +
calcData.formula calcData.formula
}} }}
verticalGroups
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
...(calcData.presets?.length ...(calcData.presets?.length
? [ ? [
{ {
title: 'Presets', title: 'Presets',
component: ( component: (
<Box> <Grid container spacing={2} maxWidth={500}>
<Table> {calcData.presets?.map((preset) => (
<TableHead> <Grid item xs={12} key={preset.title}>
<TableRow> <Stack
<TableCell>Option</TableCell> direction={'row'}
<TableCell>Value</TableCell> spacing={2}
</TableRow> alignItems={'center'}
</TableHead> justifyContent={'space-between'}
<TableBody> >
{calcData.presets?.map((preset) => ( <Typography>{preset.title}</Typography>
<TableRow key={preset.title}> <Autocomplete
<TableCell>{preset.title}</TableCell> disablePortal
<TableCell> id="combo-box-demo"
<Autocomplete value={values.presets[preset.title]}
disablePortal options={[
id="combo-box-demo" '<custom>',
value={values.presets[preset.title]} ...Object.keys(preset.source.data).sort()
options={[ ]}
'<custom>', sx={{ width: 300 }}
...Object.keys(preset.source.data).sort() onChange={(event, newValue) => {
]} handleSelectedPresetChange(
sx={{ width: 300 }} preset.title,
onChange={(event, newValue) => { newValue || '',
handleSelectedPresetChange( values,
preset.title, updateField
newValue || '', );
values, }}
updateField renderInput={(params) => (
); <TextField {...params} label="Preset" />
}} )}
renderInput={(params) => ( />
<TextField {...params} label="Preset" /> </Stack>
)} </Grid>
></Autocomplete> ))}
</TableCell> </Grid>
</TableRow>
))}
</TableBody>
</Table>
</Box>
) )
} }
] ]
@@ -400,8 +387,15 @@ export default async function makeTool(
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody>
{calcData.extraOutputs?.map((extraOutput) => ( </Table>
)
},
...(calcData.extraOutputs
? [
{
title: 'Extra outputs',
component: calcData.extraOutputs?.map((extraOutput) => (
<TableRow key={extraOutput.title}> <TableRow key={extraOutput.title}>
<TableCell> <TableCell>
{extraOutput.title} {extraOutput.title}
@@ -412,15 +406,14 @@ export default async function makeTool(
value: extraOutputs[extraOutput.title], value: extraOutputs[extraOutput.title],
unit: extraOutput.unit unit: extraOutput.unit
}} }}
></NumericInputWithUnit> />
</TableCell> </TableCell>
<TableCell></TableCell> <TableCell></TableCell>
</TableRow> </TableRow>
))} ))
</TableBody> }
</Table> ]
) : [])
}
]} ]}
compute={(values) => { compute={(values) => {
if (values.outputVariable === '') { if (values.outputVariable === '') {
@@ -429,10 +422,10 @@ export default async function makeTool(
} }
let expr: nerdamer.Expression | null = null; let expr: nerdamer.Expression | null = null;
for (const i of calcData.variables) { for (const variable of calcData.variables) {
if (i.name === values.outputVariable) { if (variable.name === values.outputVariable) {
if (i.formula !== undefined) { if (variable.formula !== undefined) {
expr = nerdamer(i.formula); expr = nerdamer(variable.formula);
} }
} }
} }
@@ -442,7 +435,6 @@ export default async function makeTool(
} }
if (expr == null) { if (expr == null) {
throw new Error('No formula found'); throw new Error('No formula found');
return;
} }
Object.keys(values.vars).forEach((key) => { Object.keys(values.vars).forEach((key) => {
@@ -463,10 +455,15 @@ export default async function makeTool(
if ((result as unknown as nerdamer.Expression[])?.length < 1) { if ((result as unknown as nerdamer.Expression[])?.length < 1) {
values.vars[values.outputVariable].value = NaN; values.vars[values.outputVariable].value = NaN;
if (calcData.extraOutputs !== undefined) { if (calcData.extraOutputs !== undefined) {
for (let i = 0; i < calcData.extraOutputs.length; i++) { // Update extraOutputs using setState
const extraOutput = calcData.extraOutputs[i]; setExtraOutputs((prevState) => {
extraOutputs[extraOutput.title] = NaN; const newState = { ...prevState };
} for (let i = 0; i < calcData.extraOutputs!.length; i++) {
const extraOutput = calcData.extraOutputs![i];
newState[extraOutput.title] = NaN;
}
return newState;
});
} }
throw new Error('No solution found for this input'); throw new Error('No solution found for this input');
} }
@@ -500,9 +497,11 @@ export default async function makeTool(
const result: nerdamer.Expression = expr.evaluate(); const result: nerdamer.Expression = expr.evaluate();
if (result) { if (result) {
extraOutputs[extraOutput.title] = parseFloat( // Update extraOutputs state properly
result.toDecimal() setExtraOutputs((prevState) => ({
); ...prevState,
[extraOutput.title]: parseFloat(result.toDecimal())
}));
} }
} }
} }