import rhf and reusable components from his v3
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
112
frontend/client-portal/src/components/hook-form/v2/RHFUpload.tsx
Normal file
112
frontend/client-portal/src/components/hook-form/v2/RHFUpload.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
frontend/client-portal/src/components/hook-form/v2/index.ts
Normal file
12
frontend/client-portal/src/components/hook-form/v2/index.ts
Normal 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';
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -76,6 +76,7 @@
|
|||||||
"react-hook-form": "^7.45.4",
|
"react-hook-form": "^7.45.4",
|
||||||
"react-intersection-observer": "^8.34.0",
|
"react-intersection-observer": "^8.34.0",
|
||||||
"react-lazy-load-image-component": "^1.6.0",
|
"react-lazy-load-image-component": "^1.6.0",
|
||||||
|
"react-number-format": "^5.3.1",
|
||||||
"react-quill": "2.0.0-beta.4",
|
"react-quill": "2.0.0-beta.4",
|
||||||
"react-redux": "^8.1.2",
|
"react-redux": "^8.1.2",
|
||||||
"react-router": "^6.15.0",
|
"react-router": "^6.15.0",
|
||||||
|
|||||||
14
frontend/dashboard/pnpm-lock.yaml
generated
14
frontend/dashboard/pnpm-lock.yaml
generated
@@ -119,6 +119,9 @@ dependencies:
|
|||||||
react-lazy-load-image-component:
|
react-lazy-load-image-component:
|
||||||
specifier: ^1.6.0
|
specifier: ^1.6.0
|
||||||
version: 1.6.0(react-dom@17.0.2)(react@17.0.2)
|
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:
|
react-quill:
|
||||||
specifier: 2.0.0-beta.4
|
specifier: 2.0.0-beta.4
|
||||||
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
|
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)
|
react-dom: 17.0.2(react@17.0.2)
|
||||||
dev: false
|
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):
|
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
|
||||||
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
111
frontend/dashboard/src/components/hook-form/v2/RHFCheckbox.tsx
Normal file
111
frontend/dashboard/src/components/hook-form/v2/RHFCheckbox.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
frontend/dashboard/src/components/hook-form/v2/RHFEditor.tsx
Normal file
37
frontend/dashboard/src/components/hook-form/v2/RHFEditor.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
35
frontend/dashboard/src/components/hook-form/v2/RHFSelect.tsx
Normal file
35
frontend/dashboard/src/components/hook-form/v2/RHFSelect.tsx
Normal 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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
frontend/dashboard/src/components/hook-form/v2/RHFSwitch.tsx
Normal file
29
frontend/dashboard/src/components/hook-form/v2/RHFSwitch.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
112
frontend/dashboard/src/components/hook-form/v2/RHFUpload.tsx
Normal file
112
frontend/dashboard/src/components/hook-form/v2/RHFUpload.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
frontend/dashboard/src/components/hook-form/v2/index.ts
Normal file
12
frontend/dashboard/src/components/hook-form/v2/index.ts
Normal 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';
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -74,6 +74,7 @@
|
|||||||
"react-hook-form": "^7.43.0",
|
"react-hook-form": "^7.43.0",
|
||||||
"react-intersection-observer": "^8.34.0",
|
"react-intersection-observer": "^8.34.0",
|
||||||
"react-lazy-load-image-component": "^1.5.6",
|
"react-lazy-load-image-component": "^1.5.6",
|
||||||
|
"react-number-format": "^5.3.1",
|
||||||
"react-quill": "2.0.0-beta.4",
|
"react-quill": "2.0.0-beta.4",
|
||||||
"react-router": "^6.8.0",
|
"react-router": "^6.8.0",
|
||||||
"react-router-dom": "^6.8.0",
|
"react-router-dom": "^6.8.0",
|
||||||
|
|||||||
14
frontend/hospital-portal/pnpm-lock.yaml
generated
14
frontend/hospital-portal/pnpm-lock.yaml
generated
@@ -113,6 +113,9 @@ dependencies:
|
|||||||
react-lazy-load-image-component:
|
react-lazy-load-image-component:
|
||||||
specifier: ^1.5.6
|
specifier: ^1.5.6
|
||||||
version: 1.5.6(react-dom@17.0.2)(react@17.0.2)
|
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:
|
react-quill:
|
||||||
specifier: 2.0.0-beta.4
|
specifier: 2.0.0-beta.4
|
||||||
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
|
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)
|
react-dom: 17.0.2(react@17.0.2)
|
||||||
dev: false
|
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):
|
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
|
||||||
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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';
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user