feat: sum numbers init

This commit is contained in:
Ibrahima G. Coulibaly
2024-06-25 03:11:48 +01:00
parent bea0332020
commit cfe0d324fe
17 changed files with 324 additions and 49 deletions

View File

@@ -26,7 +26,7 @@ const exampleTools: { label: string; url: string }[] = [
{ label: 'Find and replace text', url: '' },
{ label: 'Convert emoji to image', url: '' },
{ label: 'Split a string', url: '/string/split' },
{ label: 'Calculate number sum', url: '' },
{ label: 'Calculate number sum', url: '/number/sum' },
{ label: 'Pixelate an image', url: '' }
];
export default function Home() {

View File

@@ -0,0 +1,3 @@
import { tool as numberSum } from './sum/meta';
export const numberTools = [numberSum];

View File

@@ -0,0 +1,157 @@
import { Box, Stack } from '@mui/material';
import Grid from '@mui/material/Grid';
import React, { useContext, useEffect, useState } from 'react';
import ToolTextInput from '../../../components/input/ToolTextInput';
import ToolTextResult from '../../../components/result/ToolTextResult';
import { Formik, useFormikContext } from 'formik';
import * as Yup from 'yup';
import ToolOptions from '../../../components/options/ToolOptions';
import { compute, NumberExtractionType } from './service';
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
import RadioWithTextField from '../../../components/options/RadioWithTextField';
import ToolOptionGroups from '../../../components/options/ToolOptionGroups';
import SimpleRadio from '../../../components/options/SimpleRadio';
import CheckboxWithDesc from '../../../components/options/CheckboxWithDesc';
const initialValues = {
extractionType: 'smart' as NumberExtractionType,
separator: '\\n',
printRunningSum: false
};
const extractionTypes: {
title: string;
description: string;
type: NumberExtractionType;
withTextField: boolean;
textValueAccessor?: keyof typeof initialValues;
}[] = [
{
title: 'Smart sum',
description: 'Auto detect numbers in the input.',
type: 'smart',
withTextField: false
},
{
title: 'Number Delimiter',
type: 'delimiter',
description:
'Input SeparatorCustomize the number separator here. (By default a line break.)',
withTextField: true,
textValueAccessor: 'separator'
}
];
export default function SplitText() {
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
// const formRef = useRef<FormikProps<typeof initialValues>>(null);
const { showSnackBar } = useContext(CustomSnackBarContext);
const FormikListenerComponent = () => {
const { values } = useFormikContext<typeof initialValues>();
useEffect(() => {
try {
const { extractionType, printRunningSum, separator } = values;
setResult(compute(input, extractionType, printRunningSum, separator));
} catch (exception: unknown) {
if (exception instanceof Error)
showSnackBar(exception.message, 'error');
}
}, [values, input]);
return null; // This component doesn't render anything
};
const validationSchema = Yup.object({
// splitSeparator: Yup.string().required('The separator is required')
});
return (
<Box>
<Grid container spacing={2}>
<Grid item xs={6}>
<ToolTextInput value={input} onChange={setInput} />
</Grid>
<Grid item xs={6}>
<ToolTextResult title={'Text pieces'} value={result} />
</Grid>
</Grid>
<ToolOptions>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={() => {}}
>
{({ setFieldValue, values }) => (
<Stack direction={'row'} spacing={2}>
<FormikListenerComponent />
<ToolOptionGroups
groups={[
{
title: 'Number extraction',
component: extractionTypes.map(
({
title,
description,
type,
withTextField,
textValueAccessor
}) =>
withTextField ? (
<RadioWithTextField
key={type}
radioValue={type}
title={title}
fieldName={'extractionType'}
description={description}
value={
textValueAccessor
? values[textValueAccessor].toString()
: ''
}
onRadioChange={(type) =>
setFieldValue('extractionType', type)
}
onTextChange={(val) =>
setFieldValue(textValueAccessor ?? '', val)
}
/>
) : (
<SimpleRadio
key={title}
onChange={() =>
setFieldValue('extractionType', type)
}
fieldName={'extractionType'}
value={values.extractionType}
description={description}
title={title}
/>
)
)
},
{
title: 'Running Sum',
component: (
<CheckboxWithDesc
title={'Print Running Sum'}
description={
"Display the sum as it's calculated step by step."
}
checked={values.printRunningSum}
onChange={(value) =>
setFieldValue('printRunningSum', value)
}
/>
)
}
]}
/>
</Stack>
)}
</Formik>
</ToolOptions>
</Box>
);
}

View File

@@ -0,0 +1,13 @@
import { defineTool } from '@tools/defineTool';
import { lazy } from 'react';
// import image from '@assets/text.png';
export const tool = defineTool('number', {
name: 'Number Sum Calculator',
path: 'sum',
// image,
description:
'Quickly calculate the sum of numbers in your browser. To get your sum, just enter your list of numbers in the input field, adjust the separator between the numbers in the options below, and this utility will add up all these numbers.',
keywords: ['sum'],
component: lazy(() => import('./index'))
});

View File

@@ -0,0 +1,29 @@
export type NumberExtractionType = 'smart' | 'delimiter';
function getAllNumbers(text: string): number[] {
const regex = /\d+/g;
const matches = text.match(regex);
return matches ? matches.map(Number) : [];
}
export const compute = (
input: string,
extractionType: NumberExtractionType,
printRunningSum: boolean,
separator: string
) => {
let numbers: number[] = [];
if (extractionType === 'smart') {
numbers = getAllNumbers(input);
} else {
const parts = input.split(separator);
// Filter out and convert parts that are numbers
numbers = parts
.filter((part) => !isNaN(Number(part)) && part.trim() !== '')
.map(Number);
}
return numbers.reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
);
};

View File

@@ -0,0 +1,6 @@
import { expect, describe, it } from 'vitest';
// import { } from './service';
//
// describe('sum', () => {
//
// })

View File

@@ -151,12 +151,12 @@ export default function SplitText() {
({ title, description, type }) => (
<RadioWithTextField
key={type}
type={type}
radioValue={type}
title={title}
fieldName={'splitSeparatorType'}
description={description}
value={values[`${type}Value`]}
onTypeChange={(type) =>
onRadioChange={(type) =>
setFieldValue('splitSeparatorType', type)
}
onTextChange={(val) =>

View File

@@ -6,7 +6,8 @@ export const tool = defineTool('string', {
name: 'String To morse',
path: 'to-morse',
// image,
description: '',
description:
"World's simplest browser-based utility for converting text to Morse code. Load your text in the input form on the left and you'll instantly get Morse code in the output area. Powerful, free, and fast. Load text get Morse code.",
keywords: ['to', 'morse'],
component: lazy(() => import('./index'))
});