import rhf and reusable components from his v3

This commit is contained in:
sangpenciptajs
2023-11-03 08:49:18 +07:00
parent 16449bd18b
commit bc429b6d52
64 changed files with 3102 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
import { ReactNode } from 'react';
// form
import { FormProvider as Form, UseFormReturn } from 'react-hook-form';
// ----------------------------------------------------------------------
type Props = {
children: ReactNode;
methods: UseFormReturn<any>;
onSubmit?: VoidFunction;
preventEnterSubmit?: boolean;
};
export default function FormProvider({ children, onSubmit, methods, preventEnterSubmit }: Props) {
const checkKeyDown = (e: any) => {
if (e.key === 'Enter' && preventEnterSubmit){
e.preventDefault();
}
};
return (
<Form {...methods}>
<form onSubmit={onSubmit} onKeyDown={(e) => checkKeyDown(e)}>{children}</form>
</Form>
);
}

View File

@@ -0,0 +1,102 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Autocomplete, AutocompleteProps, FormHelperText, TextField, UseAutocompleteProps } from '@mui/material';
import { useState } from 'react';
import { FilterOptionsState } from '@mui/material/useAutocomplete';
// ----------------------------------------------------------------------
interface IProps {
name: string,
label: string,
options: any,
getOptionLabel: (option: any) => string,
isOptionEqualToValue: any,
disableClearable: boolean,
freeSolo: boolean,
renderOption?: any,
onInputChange?: any,
onKeyDown?: any,
onKeyPress?: any,
noOptionsText?: string,
popupIcon?: any,
disabled?: boolean,
sx?: any,
sxTextField?: any,
InputProps?: any,
onSelect?: (option: any) => void,
filterOptions?: (options: any[], state: FilterOptionsState<any>) => any[];
}
const RHFAutocomplete = ( {name, label, options, ...rest} : IProps ) => {
const { control } = useFormContext();
const {
sx, sxTextField, InputProps,
onSelect,
getOptionLabel, filterOptions,
popupIcon,
isOptionEqualToValue, disableClearable,
freeSolo, renderOption,
onInputChange, onKeyDown, onKeyPress,
noOptionsText, disabled } = rest;
return (
<Controller
name={name}
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => {
return (
<>
<Autocomplete
disabled={disabled}
handleHomeEndKeys
getOptionLabel={getOptionLabel}
options={options}
freeSolo={freeSolo}
disableClearable={disableClearable}
isOptionEqualToValue={isOptionEqualToValue}
value={value}
filterOptions={filterOptions}
renderOption={renderOption}
onInputChange={onInputChange}
onKeyDown={onKeyDown}
onKeyPress={onKeyPress}
sx={sx}
popupIcon={popupIcon}
noOptionsText={noOptionsText}
renderInput={(params) => (
<TextField
{...params}
label={label}
sx={sxTextField}
InputProps={{
...params.InputProps,
...InputProps
}}
/>
)}
onChange={(e, newValue) => {
onChange(newValue);
onSelect && onSelect(newValue);
}}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocomplete;

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import Chip from '@mui/material/Chip';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import { FormHelperText } from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
import { useEffect } from 'react';
interface IProps {
name: string,
label: string,
options: any,
defaultValue: any
}
const RHFAutocompleteTags = ({ name, label, options, defaultValue, ...rest }: IProps) => {
const { control } = useFormContext();
const fixedOptions: any = [];
const [value, setValue] = React.useState([...fixedOptions]);
useEffect(() => {
setValue(defaultValue)
}, [options, defaultValue])
return (
<Controller
name={name}
control={control}
render={({ field: { onChange }, fieldState: { error } }) => {
return (
<>
<Autocomplete
multiple
id="fixed-tags-demo"
value={value}
onChange={(event, newValue) => {
setValue([
...fixedOptions,
...newValue.filter((option) => fixedOptions.indexOf(option) === -1),
]);
onChange(newValue);
}}
isOptionEqualToValue={(option, value)=>{
return option.optionID === value.optionID
}}
options={options}
getOptionLabel={(option: { optionID: string, optionLabel: string }) => `${option.optionLabel}` || ""}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => (
<React.Fragment key={index}>
<Chip
label={option?.optionLabel}
{...getTagProps({ index })}
/>
</React.Fragment>
))
}
renderInput={(params) => (
<TextField {...params} label={label} placeholder={label} />
)}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocompleteTags;

View File

@@ -0,0 +1,111 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Checkbox, FormControlLabel, FormGroup, FormControlLabelProps, Grid, FormHelperText } from '@mui/material';
import RHFDatePicker from './RHFDatePicker';
// ----------------------------------------------------------------------
interface RHFCheckboxProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
}
export function RHFCheckbox({ name, ...other }: RHFCheckboxProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<Checkbox {...field} checked={field.value} />
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
}
{...other}
/>
);
}
interface RHFCheckboxEndDateProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
endPeriodProp: any;
idx?: any;
}
export function RHFCheckboxEndDate({ name, endPeriodProp, idx, ...other }: RHFCheckboxEndDateProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) =>
<Checkbox
{...field} checked={field.value}
onChange={e => {
endPeriodProp(e.target.checked, idx)
}}
/>
}
/>
}
{...other}
/>
);
}
// ----------------------------------------------------------------------
interface RHFMultiCheckboxProps extends Omit<FormControlLabelProps, 'control' | 'label'> {
name: string;
options: string[];
}
export function RHFMultiCheckbox({ name, options, ...other }: RHFMultiCheckboxProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field }) => {
const onSelected = (option: string) =>
field.value.includes(option)
? field.value.filter((value: string) => value !== option)
: [...field.value, option];
return (
<FormGroup>
{options.map((option) => (
<FormControlLabel
key={option}
control={
<Checkbox
checked={field.value.includes(option)}
onChange={() => field.onChange(onSelected(option))}
/>
}
label={option}
{...other}
/>
))}
</FormGroup>
);
}}
/>
);
}

View File

@@ -0,0 +1,54 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
minDate?: any;
maxDate?: any;
disabled?: boolean;
}
export default function RHFDatePicker({ name, label, dateFormat, minDate, maxDate, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDatePicker
allowSameDateSelection={true}
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
inputFormat={dateFormat}
value={field.value}
mask={''}
minDate={(minDate) ? new Date(minDate) : null}
maxDate={(maxDate) ? new Date(maxDate) : null}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,53 @@
// form
import { useFormContext, Controller, useForm } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDateTimePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
onChange?: (date: any) => void;
disabled?: boolean;
}
export default function RHFDateTimePicker({ name, label, dateFormat, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth, onChange, disabled } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDateTimePicker
label={label}
onChange={(date) => {
field.onChange(date);
onChange && onChange(date);
}}
inputFormat={dateFormat}
value={field.value}
mask={''}
disabled={disabled}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,37 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
//
import Editor, { Props as EditorProps } from '../../editor';
// ----------------------------------------------------------------------
interface Props extends EditorProps {
name: string;
}
export default function RHFEditor({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<Editor
id={name}
value={field.value}
onChange={field.onChange}
error={!!error}
helperText={
<FormHelperText error sx={{ px: 2, textTransform: 'capitalize' }}>
{error?.message}
</FormHelperText>
}
{...other}
/>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import {
Radio,
RadioGroup,
FormHelperText,
RadioGroupProps,
FormControlLabel,
} from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
options: string[];
getOptionLabel?: string[];
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFRadioGroup({
name,
options,
getOptionLabel,
fullWidth,
disabled,
...other
}: IProps & RadioGroupProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<div>
<RadioGroup {...field} row {...other}>
{options.map((option, index) => (
<FormControlLabel
style={{width: (fullWidth)?'100%':''}}
key={option}
value={option}
control={<Radio />}
label={getOptionLabel?.length ? getOptionLabel[index] : option}
disabled={disabled}
/>
))}
</RadioGroup>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</div>
)}
/>
);
}

View File

@@ -0,0 +1,35 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
children: any;
}
export default function RHFSelect({ name, children, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
select
fullWidth
SelectProps={{ native: true }}
error={!!error}
helperText={error?.message}
{...other}
>
{children}
</TextField>
)}
/>
);
}

View File

@@ -0,0 +1,32 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormControl, FormHelperText, InputLabel, Select, SelectProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
id: string;
children: any;
}
export default function RHFSelectV2({ name, id, children, ...other }: IProps & SelectProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<FormControl fullWidth error={error !== undefined ? true : false}>
<InputLabel id={`${id}-label`}>{other.label}</InputLabel>
<Select {...field} labelId={`${id}-label`} id={id} fullWidth {...other}>
{children}
</Select>
{error && <FormHelperText>{error.message}</FormHelperText>}
</FormControl>
)}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Switch, FormControlLabel, FormControlLabelProps } from '@mui/material';
// ----------------------------------------------------------------------
type IProps = Omit<FormControlLabelProps, 'control'>;
interface Props extends IProps {
name: string;
}
export default function RHFSwitch({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) => <Switch {...field} checked={field.value} />}
/>
}
{...other}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps, Typography } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextField({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
{/* <Typography>
*
</Typography> */}
<TextField {...field} autoComplete="off" fullWidth error={!!error} helperText={error?.message} {...other} />
</>
)}
/>
);
}

View File

@@ -0,0 +1,42 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldMoney({ name, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (values[name] === '0') && setValue(name, '') }}
onBlur={() => { (values[name] === '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
startAdornment: <InputAdornment position="start">Rp</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// import AutoNumeric from "autonumeric"
// import { useEffect, useRef } from 'react';
// import React from 'react';
// ----------------------------------------------------------------------
interface IProps {
name: string;
endAdornment?: React.ReactNode;
}
export default function RHFTextFieldNumber({ name, endAdornment, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
// const ref = React.createRef();
// const mountedRef = useRef(false);
// useEffect(() => {
// mountedRef.current = true;
// new AutoNumeric(ref.current as HTMLElement)
// return () => {
// mountedRef.current = false;
// }
// }, [])
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (watch(name) == '0') && setValue(name, '') }}
onBlur={() => { (watch(name) == '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
inputComponent: MoneyFormat as any,
endAdornment: endAdornment,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,39 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldPercentage({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
endAdornment: <InputAdornment position="end">%</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,46 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider, TimePicker } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFTimePicker({ name, label, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TimePicker
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
value={field.value}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,112 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
// type
import {
UploadAvatar,
UploadMultiFile,
UploadSingleFile,
UploadProps,
UploadMultiFileProps,
} from '../../upload';
import { Accept } from 'react-dropzone';
// ----------------------------------------------------------------------
interface Props extends Omit<UploadProps, 'file'> {
name: string;
}
export function RHFUploadAvatar({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<div>
<UploadAvatar error={checkError} {...other} file={field.value} />
{checkError && (
<FormHelperText error sx={{ px: 2, textAlign: 'center' }}>
{error.message}
</FormHelperText>
)}
</div>
);
}}
/>
);
}
// ----------------------------------------------------------------------
export function RHFUploadSingleFile({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<UploadSingleFile
accept={"image/*" as unknown as Accept}
file={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}
// ----------------------------------------------------------------------
interface RHFUploadMultiFileProps extends Omit<UploadMultiFileProps, 'files'> {
name: string;
}
export function RHFUploadMultiFile({ name, ...other }: RHFUploadMultiFileProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && field.value?.length === 0;
return (
<UploadMultiFile
accept={"image/*" as unknown as Accept}
files={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error?.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}

View File

@@ -0,0 +1,12 @@
export * from './RHFCheckbox';
export * from './RHFUpload';
export { default as FormProvider } from './FormProvider';
export { default as RHFSwitch } from './RHFSwitch';
export { default as RHFAutocomplete } from './RHFAutocomplete';
export { default as RHFSelect } from './RHFSelect';
export { default as RHFEditor } from './RHFEditor';
export { default as RHFTextField } from './RHFTextField';
export { default as RHFRadioGroup } from './RHFRadioGroup';
export { default as RHFSelectV2 } from './RHFSelectV2';

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const DiscountPctFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function DiscountPctFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default DiscountPctFormat;

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const MoneyFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function MoneyFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default MoneyFormat;

View File

@@ -76,6 +76,7 @@
"react-hook-form": "^7.45.4",
"react-intersection-observer": "^8.34.0",
"react-lazy-load-image-component": "^1.6.0",
"react-number-format": "^5.3.1",
"react-quill": "2.0.0-beta.4",
"react-redux": "^8.1.2",
"react-router": "^6.15.0",

View File

@@ -119,6 +119,9 @@ dependencies:
react-lazy-load-image-component:
specifier: ^1.6.0
version: 1.6.0(react-dom@17.0.2)(react@17.0.2)
react-number-format:
specifier: ^5.3.1
version: 5.3.1(react-dom@17.0.2)(react@17.0.2)
react-quill:
specifier: 2.0.0-beta.4
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
@@ -6797,6 +6800,17 @@ packages:
react-dom: 17.0.2(react@17.0.2)
dev: false
/react-number-format@5.3.1(react-dom@17.0.2)(react@17.0.2):
resolution: {integrity: sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==}
peerDependencies:
react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
dependencies:
prop-types: 15.8.1
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
dev: false
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
peerDependencies:

View File

@@ -0,0 +1,26 @@
import { ReactNode } from 'react';
// form
import { FormProvider as Form, UseFormReturn } from 'react-hook-form';
// ----------------------------------------------------------------------
type Props = {
children: ReactNode;
methods: UseFormReturn<any>;
onSubmit?: VoidFunction;
preventEnterSubmit?: boolean;
};
export default function FormProvider({ children, onSubmit, methods, preventEnterSubmit }: Props) {
const checkKeyDown = (e: any) => {
if (e.key === 'Enter' && preventEnterSubmit){
e.preventDefault();
}
};
return (
<Form {...methods}>
<form onSubmit={onSubmit} onKeyDown={(e) => checkKeyDown(e)}>{children}</form>
</Form>
);
}

View File

@@ -0,0 +1,102 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Autocomplete, AutocompleteProps, FormHelperText, TextField, UseAutocompleteProps } from '@mui/material';
import { useState } from 'react';
import { FilterOptionsState } from '@mui/material/useAutocomplete';
// ----------------------------------------------------------------------
interface IProps {
name: string,
label: string,
options: any,
getOptionLabel: (option: any) => string,
isOptionEqualToValue: any,
disableClearable: boolean,
freeSolo: boolean,
renderOption?: any,
onInputChange?: any,
onKeyDown?: any,
onKeyPress?: any,
noOptionsText?: string,
popupIcon?: any,
disabled?: boolean,
sx?: any,
sxTextField?: any,
InputProps?: any,
onSelect?: (option: any) => void,
filterOptions?: (options: any[], state: FilterOptionsState<any>) => any[];
}
const RHFAutocomplete = ( {name, label, options, ...rest} : IProps ) => {
const { control } = useFormContext();
const {
sx, sxTextField, InputProps,
onSelect,
getOptionLabel, filterOptions,
popupIcon,
isOptionEqualToValue, disableClearable,
freeSolo, renderOption,
onInputChange, onKeyDown, onKeyPress,
noOptionsText, disabled } = rest;
return (
<Controller
name={name}
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => {
return (
<>
<Autocomplete
disabled={disabled}
handleHomeEndKeys
getOptionLabel={getOptionLabel}
options={options}
freeSolo={freeSolo}
disableClearable={disableClearable}
isOptionEqualToValue={isOptionEqualToValue}
value={value}
filterOptions={filterOptions}
renderOption={renderOption}
onInputChange={onInputChange}
onKeyDown={onKeyDown}
onKeyPress={onKeyPress}
sx={sx}
popupIcon={popupIcon}
noOptionsText={noOptionsText}
renderInput={(params) => (
<TextField
{...params}
label={label}
sx={sxTextField}
InputProps={{
...params.InputProps,
...InputProps
}}
/>
)}
onChange={(e, newValue) => {
onChange(newValue);
onSelect && onSelect(newValue);
}}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocomplete;

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import Chip from '@mui/material/Chip';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import { FormHelperText } from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
import { useEffect } from 'react';
interface IProps {
name: string,
label: string,
options: any,
defaultValue: any
}
const RHFAutocompleteTags = ({ name, label, options, defaultValue, ...rest }: IProps) => {
const { control } = useFormContext();
const fixedOptions: any = [];
const [value, setValue] = React.useState([...fixedOptions]);
useEffect(() => {
setValue(defaultValue)
}, [options, defaultValue])
return (
<Controller
name={name}
control={control}
render={({ field: { onChange }, fieldState: { error } }) => {
return (
<>
<Autocomplete
multiple
id="fixed-tags-demo"
value={value}
onChange={(event, newValue) => {
setValue([
...fixedOptions,
...newValue.filter((option) => fixedOptions.indexOf(option) === -1),
]);
onChange(newValue);
}}
isOptionEqualToValue={(option, value)=>{
return option.optionID === value.optionID
}}
options={options}
getOptionLabel={(option: { optionID: string, optionLabel: string }) => `${option.optionLabel}` || ""}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => (
<React.Fragment key={index}>
<Chip
label={option?.optionLabel}
{...getTagProps({ index })}
/>
</React.Fragment>
))
}
renderInput={(params) => (
<TextField {...params} label={label} placeholder={label} />
)}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocompleteTags;

View File

@@ -0,0 +1,111 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Checkbox, FormControlLabel, FormGroup, FormControlLabelProps, Grid, FormHelperText } from '@mui/material';
import RHFDatePicker from './RHFDatePicker';
// ----------------------------------------------------------------------
interface RHFCheckboxProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
}
export function RHFCheckbox({ name, ...other }: RHFCheckboxProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<Checkbox {...field} checked={field.value} />
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
}
{...other}
/>
);
}
interface RHFCheckboxEndDateProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
endPeriodProp: any;
idx?: any;
}
export function RHFCheckboxEndDate({ name, endPeriodProp, idx, ...other }: RHFCheckboxEndDateProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) =>
<Checkbox
{...field} checked={field.value}
onChange={e => {
endPeriodProp(e.target.checked, idx)
}}
/>
}
/>
}
{...other}
/>
);
}
// ----------------------------------------------------------------------
interface RHFMultiCheckboxProps extends Omit<FormControlLabelProps, 'control' | 'label'> {
name: string;
options: string[];
}
export function RHFMultiCheckbox({ name, options, ...other }: RHFMultiCheckboxProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field }) => {
const onSelected = (option: string) =>
field.value.includes(option)
? field.value.filter((value: string) => value !== option)
: [...field.value, option];
return (
<FormGroup>
{options.map((option) => (
<FormControlLabel
key={option}
control={
<Checkbox
checked={field.value.includes(option)}
onChange={() => field.onChange(onSelected(option))}
/>
}
label={option}
{...other}
/>
))}
</FormGroup>
);
}}
/>
);
}

View File

@@ -0,0 +1,54 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
minDate?: any;
maxDate?: any;
disabled?: boolean;
}
export default function RHFDatePicker({ name, label, dateFormat, minDate, maxDate, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDatePicker
allowSameDateSelection={true}
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
inputFormat={dateFormat}
value={field.value}
mask={''}
minDate={(minDate) ? new Date(minDate) : null}
maxDate={(maxDate) ? new Date(maxDate) : null}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,53 @@
// form
import { useFormContext, Controller, useForm } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDateTimePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
onChange?: (date: any) => void;
disabled?: boolean;
}
export default function RHFDateTimePicker({ name, label, dateFormat, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth, onChange, disabled } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDateTimePicker
label={label}
onChange={(date) => {
field.onChange(date);
onChange && onChange(date);
}}
inputFormat={dateFormat}
value={field.value}
mask={''}
disabled={disabled}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,37 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
//
import Editor, { Props as EditorProps } from '../../editor';
// ----------------------------------------------------------------------
interface Props extends EditorProps {
name: string;
}
export default function RHFEditor({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<Editor
id={name}
value={field.value}
onChange={field.onChange}
error={!!error}
helperText={
<FormHelperText error sx={{ px: 2, textTransform: 'capitalize' }}>
{error?.message}
</FormHelperText>
}
{...other}
/>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import {
Radio,
RadioGroup,
FormHelperText,
RadioGroupProps,
FormControlLabel,
} from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
options: string[];
getOptionLabel?: string[];
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFRadioGroup({
name,
options,
getOptionLabel,
fullWidth,
disabled,
...other
}: IProps & RadioGroupProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<div>
<RadioGroup {...field} row {...other}>
{options.map((option, index) => (
<FormControlLabel
style={{width: (fullWidth)?'100%':''}}
key={option}
value={option}
control={<Radio />}
label={getOptionLabel?.length ? getOptionLabel[index] : option}
disabled={disabled}
/>
))}
</RadioGroup>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</div>
)}
/>
);
}

View File

@@ -0,0 +1,35 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
children: any;
}
export default function RHFSelect({ name, children, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
select
fullWidth
SelectProps={{ native: true }}
error={!!error}
helperText={error?.message}
{...other}
>
{children}
</TextField>
)}
/>
);
}

View File

@@ -0,0 +1,32 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormControl, FormHelperText, InputLabel, Select, SelectProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
id: string;
children: any;
}
export default function RHFSelectV2({ name, id, children, ...other }: IProps & SelectProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<FormControl fullWidth error={error !== undefined ? true : false}>
<InputLabel id={`${id}-label`}>{other.label}</InputLabel>
<Select {...field} labelId={`${id}-label`} id={id} fullWidth {...other}>
{children}
</Select>
{error && <FormHelperText>{error.message}</FormHelperText>}
</FormControl>
)}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Switch, FormControlLabel, FormControlLabelProps } from '@mui/material';
// ----------------------------------------------------------------------
type IProps = Omit<FormControlLabelProps, 'control'>;
interface Props extends IProps {
name: string;
}
export default function RHFSwitch({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) => <Switch {...field} checked={field.value} />}
/>
}
{...other}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps, Typography } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextField({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
{/* <Typography>
*
</Typography> */}
<TextField {...field} autoComplete="off" fullWidth error={!!error} helperText={error?.message} {...other} />
</>
)}
/>
);
}

View File

@@ -0,0 +1,42 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldMoney({ name, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (values[name] === '0') && setValue(name, '') }}
onBlur={() => { (values[name] === '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
startAdornment: <InputAdornment position="start">Rp</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// import AutoNumeric from "autonumeric"
// import { useEffect, useRef } from 'react';
// import React from 'react';
// ----------------------------------------------------------------------
interface IProps {
name: string;
endAdornment?: React.ReactNode;
}
export default function RHFTextFieldNumber({ name, endAdornment, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
// const ref = React.createRef();
// const mountedRef = useRef(false);
// useEffect(() => {
// mountedRef.current = true;
// new AutoNumeric(ref.current as HTMLElement)
// return () => {
// mountedRef.current = false;
// }
// }, [])
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (watch(name) == '0') && setValue(name, '') }}
onBlur={() => { (watch(name) == '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
inputComponent: MoneyFormat as any,
endAdornment: endAdornment,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,39 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldPercentage({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
endAdornment: <InputAdornment position="end">%</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,46 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider, TimePicker } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFTimePicker({ name, label, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TimePicker
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
value={field.value}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,112 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
// type
import {
UploadAvatar,
UploadMultiFile,
UploadSingleFile,
UploadProps,
UploadMultiFileProps,
} from '../../upload';
import { Accept } from 'react-dropzone';
// ----------------------------------------------------------------------
interface Props extends Omit<UploadProps, 'file'> {
name: string;
}
export function RHFUploadAvatar({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<div>
<UploadAvatar error={checkError} {...other} file={field.value} />
{checkError && (
<FormHelperText error sx={{ px: 2, textAlign: 'center' }}>
{error.message}
</FormHelperText>
)}
</div>
);
}}
/>
);
}
// ----------------------------------------------------------------------
export function RHFUploadSingleFile({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<UploadSingleFile
accept={"image/*" as unknown as Accept}
file={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}
// ----------------------------------------------------------------------
interface RHFUploadMultiFileProps extends Omit<UploadMultiFileProps, 'files'> {
name: string;
}
export function RHFUploadMultiFile({ name, ...other }: RHFUploadMultiFileProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && field.value?.length === 0;
return (
<UploadMultiFile
accept={"image/*" as unknown as Accept}
files={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error?.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}

View File

@@ -0,0 +1,12 @@
export * from './RHFCheckbox';
export * from './RHFUpload';
export { default as FormProvider } from './FormProvider';
export { default as RHFSwitch } from './RHFSwitch';
export { default as RHFAutocomplete } from './RHFAutocomplete';
export { default as RHFSelect } from './RHFSelect';
export { default as RHFEditor } from './RHFEditor';
export { default as RHFTextField } from './RHFTextField';
export { default as RHFRadioGroup } from './RHFRadioGroup';
export { default as RHFSelectV2 } from './RHFSelectV2';

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const DiscountPctFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function DiscountPctFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default DiscountPctFormat;

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const MoneyFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function MoneyFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default MoneyFormat;

View File

@@ -74,6 +74,7 @@
"react-hook-form": "^7.43.0",
"react-intersection-observer": "^8.34.0",
"react-lazy-load-image-component": "^1.5.6",
"react-number-format": "^5.3.1",
"react-quill": "2.0.0-beta.4",
"react-router": "^6.8.0",
"react-router-dom": "^6.8.0",

View File

@@ -113,6 +113,9 @@ dependencies:
react-lazy-load-image-component:
specifier: ^1.5.6
version: 1.5.6(react-dom@17.0.2)(react@17.0.2)
react-number-format:
specifier: ^5.3.1
version: 5.3.1(react-dom@17.0.2)(react@17.0.2)
react-quill:
specifier: 2.0.0-beta.4
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
@@ -5313,6 +5316,17 @@ packages:
react-dom: 17.0.2(react@17.0.2)
dev: false
/react-number-format@5.3.1(react-dom@17.0.2)(react@17.0.2):
resolution: {integrity: sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==}
peerDependencies:
react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
dependencies:
prop-types: 15.8.1
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
dev: false
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
peerDependencies:

View File

@@ -0,0 +1,26 @@
import { ReactNode } from 'react';
// form
import { FormProvider as Form, UseFormReturn } from 'react-hook-form';
// ----------------------------------------------------------------------
type Props = {
children: ReactNode;
methods: UseFormReturn<any>;
onSubmit?: VoidFunction;
preventEnterSubmit?: boolean;
};
export default function FormProvider({ children, onSubmit, methods, preventEnterSubmit }: Props) {
const checkKeyDown = (e: any) => {
if (e.key === 'Enter' && preventEnterSubmit){
e.preventDefault();
}
};
return (
<Form {...methods}>
<form onSubmit={onSubmit} onKeyDown={(e) => checkKeyDown(e)}>{children}</form>
</Form>
);
}

View File

@@ -0,0 +1,102 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Autocomplete, AutocompleteProps, FormHelperText, TextField, UseAutocompleteProps } from '@mui/material';
import { useState } from 'react';
import { FilterOptionsState } from '@mui/material/useAutocomplete';
// ----------------------------------------------------------------------
interface IProps {
name: string,
label: string,
options: any,
getOptionLabel: (option: any) => string,
isOptionEqualToValue: any,
disableClearable: boolean,
freeSolo: boolean,
renderOption?: any,
onInputChange?: any,
onKeyDown?: any,
onKeyPress?: any,
noOptionsText?: string,
popupIcon?: any,
disabled?: boolean,
sx?: any,
sxTextField?: any,
InputProps?: any,
onSelect?: (option: any) => void,
filterOptions?: (options: any[], state: FilterOptionsState<any>) => any[];
}
const RHFAutocomplete = ( {name, label, options, ...rest} : IProps ) => {
const { control } = useFormContext();
const {
sx, sxTextField, InputProps,
onSelect,
getOptionLabel, filterOptions,
popupIcon,
isOptionEqualToValue, disableClearable,
freeSolo, renderOption,
onInputChange, onKeyDown, onKeyPress,
noOptionsText, disabled } = rest;
return (
<Controller
name={name}
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => {
return (
<>
<Autocomplete
disabled={disabled}
handleHomeEndKeys
getOptionLabel={getOptionLabel}
options={options}
freeSolo={freeSolo}
disableClearable={disableClearable}
isOptionEqualToValue={isOptionEqualToValue}
value={value}
filterOptions={filterOptions}
renderOption={renderOption}
onInputChange={onInputChange}
onKeyDown={onKeyDown}
onKeyPress={onKeyPress}
sx={sx}
popupIcon={popupIcon}
noOptionsText={noOptionsText}
renderInput={(params) => (
<TextField
{...params}
label={label}
sx={sxTextField}
InputProps={{
...params.InputProps,
...InputProps
}}
/>
)}
onChange={(e, newValue) => {
onChange(newValue);
onSelect && onSelect(newValue);
}}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocomplete;

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import Chip from '@mui/material/Chip';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import { FormHelperText } from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
import { useEffect } from 'react';
interface IProps {
name: string,
label: string,
options: any,
defaultValue: any
}
const RHFAutocompleteTags = ({ name, label, options, defaultValue, ...rest }: IProps) => {
const { control } = useFormContext();
const fixedOptions: any = [];
const [value, setValue] = React.useState([...fixedOptions]);
useEffect(() => {
setValue(defaultValue)
}, [options, defaultValue])
return (
<Controller
name={name}
control={control}
render={({ field: { onChange }, fieldState: { error } }) => {
return (
<>
<Autocomplete
multiple
id="fixed-tags-demo"
value={value}
onChange={(event, newValue) => {
setValue([
...fixedOptions,
...newValue.filter((option) => fixedOptions.indexOf(option) === -1),
]);
onChange(newValue);
}}
isOptionEqualToValue={(option, value)=>{
return option.optionID === value.optionID
}}
options={options}
getOptionLabel={(option: { optionID: string, optionLabel: string }) => `${option.optionLabel}` || ""}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => (
<React.Fragment key={index}>
<Chip
label={option?.optionLabel}
{...getTagProps({ index })}
/>
</React.Fragment>
))
}
renderInput={(params) => (
<TextField {...params} label={label} placeholder={label} />
)}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
);
}}
/>
);
}
export default RHFAutocompleteTags;

View File

@@ -0,0 +1,111 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Checkbox, FormControlLabel, FormGroup, FormControlLabelProps, Grid, FormHelperText } from '@mui/material';
import RHFDatePicker from './RHFDatePicker';
// ----------------------------------------------------------------------
interface RHFCheckboxProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
}
export function RHFCheckbox({ name, ...other }: RHFCheckboxProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<Checkbox {...field} checked={field.value} />
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
}
{...other}
/>
);
}
interface RHFCheckboxEndDateProps extends Omit<FormControlLabelProps, 'control'> {
name: string;
endPeriodProp: any;
idx?: any;
}
export function RHFCheckboxEndDate({ name, endPeriodProp, idx, ...other }: RHFCheckboxEndDateProps) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) =>
<Checkbox
{...field} checked={field.value}
onChange={e => {
endPeriodProp(e.target.checked, idx)
}}
/>
}
/>
}
{...other}
/>
);
}
// ----------------------------------------------------------------------
interface RHFMultiCheckboxProps extends Omit<FormControlLabelProps, 'control' | 'label'> {
name: string;
options: string[];
}
export function RHFMultiCheckbox({ name, options, ...other }: RHFMultiCheckboxProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field }) => {
const onSelected = (option: string) =>
field.value.includes(option)
? field.value.filter((value: string) => value !== option)
: [...field.value, option];
return (
<FormGroup>
{options.map((option) => (
<FormControlLabel
key={option}
control={
<Checkbox
checked={field.value.includes(option)}
onChange={() => field.onChange(onSelected(option))}
/>
}
label={option}
{...other}
/>
))}
</FormGroup>
);
}}
/>
);
}

View File

@@ -0,0 +1,54 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
minDate?: any;
maxDate?: any;
disabled?: boolean;
}
export default function RHFDatePicker({ name, label, dateFormat, minDate, maxDate, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDatePicker
allowSameDateSelection={true}
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
inputFormat={dateFormat}
value={field.value}
mask={''}
minDate={(minDate) ? new Date(minDate) : null}
maxDate={(maxDate) ? new Date(maxDate) : null}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,53 @@
// form
import { useFormContext, Controller, useForm } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDateTimePicker, LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
dateFormat: string;
fullWidth?: boolean;
onChange?: (date: any) => void;
disabled?: boolean;
}
export default function RHFDateTimePicker({ name, label, dateFormat, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth, onChange, disabled } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<DesktopDateTimePicker
label={label}
onChange={(date) => {
field.onChange(date);
onChange && onChange(date);
}}
inputFormat={dateFormat}
value={field.value}
mask={''}
disabled={disabled}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,37 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
//
import Editor, { Props as EditorProps } from '../../editor';
// ----------------------------------------------------------------------
interface Props extends EditorProps {
name: string;
}
export default function RHFEditor({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<Editor
id={name}
value={field.value}
onChange={field.onChange}
error={!!error}
helperText={
<FormHelperText error sx={{ px: 2, textTransform: 'capitalize' }}>
{error?.message}
</FormHelperText>
}
{...other}
/>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import {
Radio,
RadioGroup,
FormHelperText,
RadioGroupProps,
FormControlLabel,
} from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
options: string[];
getOptionLabel?: string[];
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFRadioGroup({
name,
options,
getOptionLabel,
fullWidth,
disabled,
...other
}: IProps & RadioGroupProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<div>
<RadioGroup {...field} row {...other}>
{options.map((option, index) => (
<FormControlLabel
style={{width: (fullWidth)?'100%':''}}
key={option}
value={option}
control={<Radio />}
label={getOptionLabel?.length ? getOptionLabel[index] : option}
disabled={disabled}
/>
))}
</RadioGroup>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</div>
)}
/>
);
}

View File

@@ -0,0 +1,35 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
children: any;
}
export default function RHFSelect({ name, children, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
select
fullWidth
SelectProps={{ native: true }}
error={!!error}
helperText={error?.message}
{...other}
>
{children}
</TextField>
)}
/>
);
}

View File

@@ -0,0 +1,32 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormControl, FormHelperText, InputLabel, Select, SelectProps } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
id: string;
children: any;
}
export default function RHFSelectV2({ name, id, children, ...other }: IProps & SelectProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<FormControl fullWidth error={error !== undefined ? true : false}>
<InputLabel id={`${id}-label`}>{other.label}</InputLabel>
<Select {...field} labelId={`${id}-label`} id={id} fullWidth {...other}>
{children}
</Select>
{error && <FormHelperText>{error.message}</FormHelperText>}
</FormControl>
)}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { Switch, FormControlLabel, FormControlLabelProps } from '@mui/material';
// ----------------------------------------------------------------------
type IProps = Omit<FormControlLabelProps, 'control'>;
interface Props extends IProps {
name: string;
}
export default function RHFSwitch({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) => <Switch {...field} checked={field.value} />}
/>
}
{...other}
/>
);
}

View File

@@ -0,0 +1,29 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { TextField, TextFieldProps, Typography } from '@mui/material';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextField({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
{/* <Typography>
*
</Typography> */}
<TextField {...field} autoComplete="off" fullWidth error={!!error} helperText={error?.message} {...other} />
</>
)}
/>
);
}

View File

@@ -0,0 +1,42 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldMoney({ name, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (values[name] === '0') && setValue(name, '') }}
onBlur={() => { (values[name] === '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
startAdornment: <InputAdornment position="start">Rp</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,61 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// import AutoNumeric from "autonumeric"
// import { useEffect, useRef } from 'react';
// import React from 'react';
// ----------------------------------------------------------------------
interface IProps {
name: string;
endAdornment?: React.ReactNode;
}
export default function RHFTextFieldNumber({ name, endAdornment, ...other }: IProps & TextFieldProps) {
const { control, watch, setValue } = useFormContext();
const values = watch();
// const ref = React.createRef();
// const mountedRef = useRef(false);
// useEffect(() => {
// mountedRef.current = true;
// new AutoNumeric(ref.current as HTMLElement)
// return () => {
// mountedRef.current = false;
// }
// }, [])
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
onFocus={() => { (watch(name) == '0') && setValue(name, '') }}
onBlur={() => { (watch(name) == '') && setValue(name, '0') }}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
inputComponent: MoneyFormat as any,
endAdornment: endAdornment,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,39 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
import MoneyFormat from '../../numeric_format/MoneyFormat';
// ----------------------------------------------------------------------
interface IProps {
name: string;
}
export default function RHFTextFieldPercentage({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TextField
{...field}
autoComplete="off"
fullWidth error={!!error}
helperText={error?.message}
{...other}
inputProps={{ min: 0, max: 5, style: { textAlign: 'right' } }}
InputProps={{
endAdornment: <InputAdornment position="end">%</InputAdornment>,
inputComponent: MoneyFormat as any,
}}
/>
</>
)}
/>
);
}

View File

@@ -0,0 +1,46 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText, TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider, TimePicker } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
// ----------------------------------------------------------------------
interface IProps {
name: string;
label: string;
fullWidth?: boolean;
disabled?: boolean;
}
export default function RHFTimePicker({ name, label, disabled, ...other }: IProps) {
const { control } = useFormContext();
const { fullWidth } = other;
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => (
<>
<TimePicker
disabled={disabled}
label={label}
onChange={(date) => field.onChange(date)}
value={field.value}
renderInput={(params) => <TextField fullWidth={fullWidth} {...params} />}
/>
{!!error && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)}
</>
)}
/>
</LocalizationProvider>
);
}

View File

@@ -0,0 +1,112 @@
// form
import { useFormContext, Controller } from 'react-hook-form';
// @mui
import { FormHelperText } from '@mui/material';
// type
import {
UploadAvatar,
UploadMultiFile,
UploadSingleFile,
UploadProps,
UploadMultiFileProps,
} from '../../upload';
import { Accept } from 'react-dropzone';
// ----------------------------------------------------------------------
interface Props extends Omit<UploadProps, 'file'> {
name: string;
}
export function RHFUploadAvatar({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<div>
<UploadAvatar error={checkError} {...other} file={field.value} />
{checkError && (
<FormHelperText error sx={{ px: 2, textAlign: 'center' }}>
{error.message}
</FormHelperText>
)}
</div>
);
}}
/>
);
}
// ----------------------------------------------------------------------
export function RHFUploadSingleFile({ name, ...other }: Props) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value;
return (
<UploadSingleFile
accept={"image/*" as unknown as Accept}
file={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}
// ----------------------------------------------------------------------
interface RHFUploadMultiFileProps extends Omit<UploadMultiFileProps, 'files'> {
name: string;
}
export function RHFUploadMultiFile({ name, ...other }: RHFUploadMultiFileProps) {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field, fieldState: { error } }) => {
const checkError = !!error && field.value?.length === 0;
return (
<UploadMultiFile
accept={"image/*" as unknown as Accept}
files={field.value}
error={checkError}
helperText={
checkError && (
<FormHelperText error sx={{ px: 2 }}>
{error?.message}
</FormHelperText>
)
}
{...other}
/>
);
}}
/>
);
}

View File

@@ -0,0 +1,12 @@
export * from './RHFCheckbox';
export * from './RHFUpload';
export { default as FormProvider } from './FormProvider';
export { default as RHFSwitch } from './RHFSwitch';
export { default as RHFAutocomplete } from './RHFAutocomplete';
export { default as RHFSelect } from './RHFSelect';
export { default as RHFEditor } from './RHFEditor';
export { default as RHFTextField } from './RHFTextField';
export { default as RHFRadioGroup } from './RHFRadioGroup';
export { default as RHFSelectV2 } from './RHFSelectV2';

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const DiscountPctFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function DiscountPctFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default DiscountPctFormat;

View File

@@ -0,0 +1,34 @@
import React from "react";
import { InputAttributes, NumericFormat, NumericFormatProps } from "react-number-format";
interface CustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const MoneyFormat = React.forwardRef<
NumericFormatProps<InputAttributes>,
CustomProps
>(function MoneyFormat(props, ref) {
const { onChange, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
thousandSeparator
valueIsNumericString
allowLeadingZeros={false}
/>
);
});
export default MoneyFormat;