refactor: tools folder inside pages

This commit is contained in:
Ibrahima G. Coulibaly
2025-02-23 01:38:42 +01:00
parent 62f084eb45
commit 64936ab11f
117 changed files with 447 additions and 194 deletions

View File

@@ -0,0 +1,76 @@
// Import necessary modules and functions
import { describe, expect, it } from 'vitest';
import { listOfIntegers } from './service';
// Define test cases for the listOfIntegers function
describe('listOfIntegers function', () => {
it('should generate a list of integers with comma separator', () => {
const initialValue = 1;
const step = 2;
const count = 5;
const separator = ', ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('1, 3, 5, 7, 9');
});
it('should generate a list of integers with dash separator', () => {
const initialValue = 0;
const step = 3;
const count = 4;
const separator = ' - ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('0 - 3 - 6 - 9');
});
it('should handle negative initial value and step', () => {
const initialValue = -10;
const step = -2;
const count = 5;
const separator = ' ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('-10 -12 -14 -16 -18');
});
it('should handle negative initial value and positive step', () => {
const initialValue = -10;
const step = 2;
const count = 5;
const separator = ' ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('-10 -8 -6 -4 -2');
});
it('should float value', () => {
const initialValue = -10;
const step = 2.5;
const count = 5;
const separator = ' ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('-10 -7.5 -5 -2.5 0');
});
it('should generate a constant sequence if the step is 0', () => {
const initialValue = 1;
const step = 0;
const count = 5;
const separator = ' ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('1 1 1 1 1');
});
it('should generate a constant sequence if the step is 0', () => {
const initialValue = 1;
const step = 0;
const count = 5;
const separator = ' ';
const result = listOfIntegers(initialValue, count, step, separator);
expect(result).toBe('1 1 1 1 1');
});
});

View File

@@ -0,0 +1,79 @@
import { Box } from '@mui/material';
import React, { useState } from 'react';
import ToolTextResult from '@components/result/ToolTextResult';
import ToolOptions from '@components/options/ToolOptions';
import { listOfIntegers } from './service';
import ToolInputAndResult from '@components/ToolInputAndResult';
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
const initialValues = {
firstValue: '1',
numberOfNumbers: '10',
step: '1',
separator: '\\n'
};
export default function SplitText() {
const [result, setResult] = useState<string>('');
return (
<Box>
<ToolInputAndResult
result={<ToolTextResult title={'Total'} value={result} />}
/>
<ToolOptions
getGroups={({ values, updateField }) => [
{
title: 'Arithmetic sequence option',
component: (
<Box>
<TextFieldWithDesc
description={'Start sequence from this number.'}
value={values.firstValue}
onOwnChange={(val) => updateField('firstValue', val)}
type={'number'}
/>
<TextFieldWithDesc
description={'Increase each element by this amount'}
value={values.step}
onOwnChange={(val) => updateField('step', val)}
type={'number'}
/>
<TextFieldWithDesc
description={'Number of elements in sequence.'}
value={values.numberOfNumbers}
onOwnChange={(val) => updateField('numberOfNumbers', val)}
type={'number'}
/>
</Box>
)
},
{
title: 'Separator',
component: (
<TextFieldWithDesc
description={
'Separate elements in the arithmetic sequence by this character.'
}
value={values.separator}
onOwnChange={(val) => updateField('separator', val)}
/>
)
}
]}
compute={(optionsValues) => {
const { firstValue, numberOfNumbers, separator, step } =
optionsValues;
setResult(
listOfIntegers(
Number(firstValue),
Number(numberOfNumbers),
Number(step),
separator
)
);
}}
initialValues={initialValues}
/>
</Box>
);
}

View File

@@ -0,0 +1,14 @@
import { defineTool } from '@tools/defineTool';
import { lazy } from 'react';
// import image from '@assets/text.png';
export const tool = defineTool('number', {
name: 'Generate numbers',
path: 'generate',
shortDescription: 'Quickly calculate a list of integers in your browser',
// image,
description:
'Quickly calculate a list of integers in your browser. To get your list, just specify the first integer, change value and total count in the options below, and this utility will generate that many integers',
keywords: ['generate'],
component: lazy(() => import('./index'))
});

View File

@@ -0,0 +1,13 @@
export function listOfIntegers(
first_value: number,
number_of_numbers: number,
step: number,
separator: string
) {
const result: number[] = [];
for (let i: number = 0; i < number_of_numbers; i++) {
const value: number = first_value + i * step;
result.push(value);
}
return result.join(separator);
}

View File

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

View File

@@ -0,0 +1,113 @@
import { Box } from '@mui/material';
import React, { useState } from 'react';
import ToolTextInput from '@components/input/ToolTextInput';
import ToolTextResult from '@components/result/ToolTextResult';
import ToolOptions from '@components/options/ToolOptions';
import { compute, NumberExtractionType } from './service';
import RadioWithTextField from '@components/options/RadioWithTextField';
import SimpleRadio from '@components/options/SimpleRadio';
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
import ToolInputAndResult from '@components/ToolInputAndResult';
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>('');
return (
<Box>
<ToolInputAndResult
input={<ToolTextInput value={input} onChange={setInput} />}
result={<ToolTextResult title={'Total'} value={result} />}
/>
<ToolOptions
getGroups={({ values, updateField }) => [
{
title: 'Number extraction',
component: extractionTypes.map(
({
title,
description,
type,
withTextField,
textValueAccessor
}) =>
withTextField ? (
<RadioWithTextField
key={type}
checked={type === values.extractionType}
title={title}
fieldName={'extractionType'}
description={description}
value={
textValueAccessor
? values[textValueAccessor].toString()
: ''
}
onRadioClick={() => updateField('extractionType', type)}
onTextChange={(val) =>
textValueAccessor
? updateField(textValueAccessor, val)
: null
}
/>
) : (
<SimpleRadio
key={title}
onClick={() => updateField('extractionType', type)}
checked={values.extractionType === type}
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) => updateField('printRunningSum', value)}
/>
)
}
]}
compute={(optionsValues, input) => {
const { extractionType, printRunningSum, separator } = optionsValues;
setResult(compute(input, extractionType, printRunningSum, separator));
}}
initialValues={initialValues}
input={input}
/>
</Box>
);
}

View File

@@ -0,0 +1,14 @@
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.',
shortDescription: 'Quickly sum numbers',
keywords: ['sum'],
component: lazy(() => import('./index'))
});

View File

@@ -0,0 +1,37 @@
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
): 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);
}
if (printRunningSum) {
let result: string = '';
let sum: number = 0;
for (const i of numbers) {
sum = sum + i;
result = result + sum + '\n';
}
return result;
} else
return numbers
.reduce((previousValue, currentValue) => previousValue + currentValue, 0)
.toString();
};

View File

@@ -0,0 +1,64 @@
import { describe, expect, it } from 'vitest';
import { compute } from './service';
describe('compute function', () => {
it('should correctly sum numbers in smart extraction mode', () => {
const input = 'The 2 cats have 4 and 7 kittens';
const result = compute(input, 'smart', false, ',');
expect(result).toBe('13');
});
it('should correctly sum numbers with custom delimiter', () => {
const input = '2,4,7';
const result = compute(input, 'delimiter', false, ',');
expect(result).toBe('13');
});
it('should return running sum in smart extraction mode', () => {
const input = 'The 2 cats have 4 and 7 kittens';
const result = compute(input, 'smart', true, ',');
expect(result).toBe('2\n6\n13\n');
});
it('should return running sum with custom delimiter', () => {
const input = '2,4,7';
const result = compute(input, 'delimiter', true, ',');
expect(result).toBe('2\n6\n13\n');
});
it('should handle empty input gracefully in smart mode', () => {
const input = '';
const result = compute(input, 'smart', false, ',');
expect(result).toBe('0');
});
it('should handle empty input gracefully in delimiter mode', () => {
const input = '';
const result = compute(input, 'delimiter', false, ',');
expect(result).toBe('0');
});
it('should handle input with no numbers in smart mode', () => {
const input = 'There are no numbers here';
const result = compute(input, 'smart', false, ',');
expect(result).toBe('0');
});
it('should handle input with no numbers in delimiter mode', () => {
const input = 'a,b,c';
const result = compute(input, 'delimiter', false, ',');
expect(result).toBe('0');
});
it('should ignore non-numeric parts in delimiter mode', () => {
const input = '2,a,4,b,7';
const result = compute(input, 'delimiter', false, ',');
expect(result).toBe('13');
});
it('should handle different separators', () => {
const input = '2;4;7';
const result = compute(input, 'delimiter', false, ';');
expect(result).toBe('13');
});
});