Skip to content

Commit

Permalink
feat(form): number input with comma seperator
Browse files Browse the repository at this point in the history
  • Loading branch information
erfanmoghadasi committed Jul 3, 2024
1 parent c547b91 commit c2a905a
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"CodeGPT.apiKey": "CodeGPT Plus Beta"
}
10 changes: 10 additions & 0 deletions apps/docs/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,16 @@ export function App() {
],
},
},
{
id: 'form-number',
groupType: 'form',
type: 'number',
props: {
id: 'number one',
formId: '20',
label: 'number field (Form Id: 20)',
},
},
];

const [tabs, setTabs] = useState<TabData[]>([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Skeleton } from '@mui/material';

import { LoadingProps } from '@mui-builder/types/configs.type';

import useNumberFieldLoading from './useNumber.loading';

const NumberFieldLoading = (props: LoadingProps) => {
const { getNumberFieldLoadingProps } = useNumberFieldLoading(props);

return <Skeleton {...getNumberFieldLoadingProps()} />;
};

export default NumberFieldLoading;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FC } from 'react';

import { TextField } from '@mui/material';

import { NumberFieldProps } from './number.types';

import useNumberField from './useNumber';

const NumberField: FC<NumberFieldProps> = (props) => {
const { getFieldProps, show } = useNumberField(props);

if (show) return <TextField {...getFieldProps()} />;

return null;
};

export default NumberField;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TextFieldProps } from '@mui/material';

import { Api } from '@mui-builder/types/api.types';
import { Script } from '@mui-builder/types/script.types';

import { Dependesies, FormId, Id } from '../../../types/public.types';
import { Rule } from '../../../types/validation.types';

export type NumberFieldProps = Omit<TextFieldProps, 'onChange'> & {
value: string;
onChange: (value: string) => void;
} & {
id: Id;
formId: FormId;
script?: Script;
dependesies?: Dependesies;
propsController?: Record<string, any>;
api?: Api;
rule?: Rule;
show?: boolean;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { LoadingProps } from '@mui-builder/types/configs.type';

const useNumberFieldLoading = (props: LoadingProps) => {
const { animation = 'wave', sx, ...otherProps } = props;

const getNumberFieldLoadingProps = () => ({
sx: {
display: 'inline-block',
transform: 'unset',
width: '255px',
height: '56px',
mx: 0.5,
...sx,
},
animation,
...otherProps,
});

return { getNumberFieldLoadingProps };
};

export default useNumberFieldLoading;
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { useController, useWatch } from 'react-hook-form';

import useQueryBuilder from '@mui-builder/utils/useQueryBuilder/useQueryBuilder';
import UseScript from '@mui-builder/utils/useScript/useScript';

import axios from 'axios';

import { NumberFieldProps } from './number.types';

import useForms from '../../../hooks/useForms/useForms';
import usePropsController from '../../../hooks/usePropsController/usePropsController';
import useRule from '../../../hooks/useRule/useRule';

const UseNumberField = (props: NumberFieldProps) => {
const {
formId,
script,
api,
show = true,
dependesies,
helperText,
defaultValue,
onChange,
...numberFieldProps
} = props;
const { configs, queries } = api || {};

const { forms } = useForms();
const formMethod = forms?.[formId];
const { setProps, propsController } = usePropsController();

const newProps = propsController?.[numberFieldProps?.id] || {};

// Handle Script
const { scriptResult } = UseScript({
script,
formMethod,
forms,
formId,
setProps,
});

// Function to format the number with thousands separators
const formatNumber = (value: string) => {
return value.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

// Handle changes to the input field
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
// Remove existing commas from the input value
const rawValue = event.target.value.replace(/,/g, '');
// Check if the value is a valid number before calling onChange
if (!isNaN(Number(rawValue))) {
formMethod.setValue(numberFieldProps.id, rawValue);
}
};

// Handle Wtach Fields
useWatch({
control: formMethod.control,
name: dependesies ?? [],
});

// API Call
useQueryBuilder({
apiInstance: axios,
apiConfigs: configs ?? {},
apiQuery: queries ?? {},
formMethod,
formId,
forms,
});

// Controller
const {
field,
formState: { errors },
} = useController({
name: numberFieldProps.id,
control: formMethod.control,
disabled: numberFieldProps.disabled,
rules: useRule(numberFieldProps?.rule),
defaultValue,
});

const error = errors?.[numberFieldProps.id];

// Props
const getFieldProps = () => ({
...field,
...numberFieldProps,
helperText: error?.message ?? helperText,
error: !!error,
...scriptResult,
...newProps,
value: formatNumber(field.value ?? ''),
onChange: (e: React.ChangeEvent<HTMLInputElement>) => handleChange(e),
});

return { getFieldProps, show };
};

export default UseNumberField;
7 changes: 5 additions & 2 deletions packages/core/src/modules/form/src/types/public.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { CheckboxProps } from '../components/fields/checkbox/checkbox.types';
import { TextProps } from '../components/fields/text/text.types';
import { Form } from '../hooks/useForms/useForms.types';
import { NumberFieldProps } from '../components/fields/number/number.types';

export type FormId = string;

Expand All @@ -19,13 +20,15 @@ export type FormTypes =
| 'field-text'
| 'action-submit'
| 'auto-complete'
| 'checkbox';
| 'checkbox'
| 'number';

export type FieldProps =
| TextProps
| SubmitFieldProps
| AutoCompleteProps<AutoCompleteOptions>
| CheckboxProps;
| CheckboxProps
| NumberFieldProps

export type Dependesies = string[];

Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/modules/form/src/utils/selector/formSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { FormSelectorProps } from './formSelector.types';

import SubmitLoading from '../../components/actions/submit/submit.loading';
import TextLoading from '../../components/fields/text/text.loading';
import { NumberFieldProps } from '../../components/fields/number/number.types';
import NumberFieldLoading from '../../components/fields/number/number.loading';

const FormSelector: FC<FormSelectorProps> = ({
fieldType,
Expand Down Expand Up @@ -67,6 +69,17 @@ const FormSelector: FC<FormSelectorProps> = ({
</Suspense>
);

case 'number':
SelectedComponent = lazy(
() => import('../../components/fields/number/number')
);

return (
<Suspense key={fieldProps.id} fallback={<NumberFieldLoading {...loading} />}>
<SelectedComponent {...(fieldProps as NumberFieldProps)} />
</Suspense>
);

default:
SelectedComponent = Fragment;

Expand Down

0 comments on commit c2a905a

Please sign in to comment.