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-intersection-observer": "^8.34.0",
|
||||
"react-lazy-load-image-component": "^1.6.0",
|
||||
"react-number-format": "^5.3.1",
|
||||
"react-quill": "2.0.0-beta.4",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router": "^6.15.0",
|
||||
|
||||
14
frontend/dashboard/pnpm-lock.yaml
generated
14
frontend/dashboard/pnpm-lock.yaml
generated
@@ -119,6 +119,9 @@ dependencies:
|
||||
react-lazy-load-image-component:
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0(react-dom@17.0.2)(react@17.0.2)
|
||||
react-number-format:
|
||||
specifier: ^5.3.1
|
||||
version: 5.3.1(react-dom@17.0.2)(react@17.0.2)
|
||||
react-quill:
|
||||
specifier: 2.0.0-beta.4
|
||||
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
|
||||
@@ -6797,6 +6800,17 @@ packages:
|
||||
react-dom: 17.0.2(react@17.0.2)
|
||||
dev: false
|
||||
|
||||
/react-number-format@5.3.1(react-dom@17.0.2)(react@17.0.2):
|
||||
resolution: {integrity: sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==}
|
||||
peerDependencies:
|
||||
react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2(react@17.0.2)
|
||||
dev: false
|
||||
|
||||
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
|
||||
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
||||
peerDependencies:
|
||||
|
||||
@@ -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-intersection-observer": "^8.34.0",
|
||||
"react-lazy-load-image-component": "^1.5.6",
|
||||
"react-number-format": "^5.3.1",
|
||||
"react-quill": "2.0.0-beta.4",
|
||||
"react-router": "^6.8.0",
|
||||
"react-router-dom": "^6.8.0",
|
||||
|
||||
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:
|
||||
specifier: ^1.5.6
|
||||
version: 1.5.6(react-dom@17.0.2)(react@17.0.2)
|
||||
react-number-format:
|
||||
specifier: ^5.3.1
|
||||
version: 5.3.1(react-dom@17.0.2)(react@17.0.2)
|
||||
react-quill:
|
||||
specifier: 2.0.0-beta.4
|
||||
version: 2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2)
|
||||
@@ -5313,6 +5316,17 @@ packages:
|
||||
react-dom: 17.0.2(react@17.0.2)
|
||||
dev: false
|
||||
|
||||
/react-number-format@5.3.1(react-dom@17.0.2)(react@17.0.2):
|
||||
resolution: {integrity: sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==}
|
||||
peerDependencies:
|
||||
react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2(react@17.0.2)
|
||||
dev: false
|
||||
|
||||
/react-quill@2.0.0-beta.4(react-dom@17.0.2)(react@17.0.2):
|
||||
resolution: {integrity: sha512-KyAHvAlPjP4xLElKZJefMth91Z6FbbXRvq9OSu6xN3KBaoasLP9p+3dcxg4Ywr4tBlpMGXcPszYSAgd5CpJ45Q==}
|
||||
peerDependencies:
|
||||
|
||||
@@ -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