[FEAT] generize the form model
This commit is contained in:
parent
4cf71f35b6
commit
3377f80fbc
@ -1,12 +1,7 @@
|
|||||||
import { ReactElement, ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { Button, Flex, IconButton, Text, Tooltip } from '@chakra-ui/react';
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
import {
|
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
|
||||||
MdErrorOutline,
|
|
||||||
MdHelpOutline,
|
|
||||||
MdLabelImportant,
|
|
||||||
MdRefresh,
|
|
||||||
} from 'react-icons/md';
|
|
||||||
|
|
||||||
export type FormGroupProps = {
|
export type FormGroupProps = {
|
||||||
error?: ReactNode;
|
error?: ReactNode;
|
||||||
|
37
front2/src/components/form/FormInput.tsx
Normal file
37
front2/src/components/form/FormInput.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
|
import { Input } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|
||||||
|
export type FormInputProps = {
|
||||||
|
form: UseFormidableReturn;
|
||||||
|
variableName: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
isRequired?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormInput = ({
|
||||||
|
form,
|
||||||
|
variableName,
|
||||||
|
ref,
|
||||||
|
placeholder,
|
||||||
|
...rest
|
||||||
|
}: FormInputProps) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
isModify={form.isModify[variableName]}
|
||||||
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
ref={ref}
|
||||||
|
value={form.values[variableName]}
|
||||||
|
onChange={(e) => form.setValues({ [variableName]: e.target.value })}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
62
front2/src/components/form/FormNumber.tsx
Normal file
62
front2/src/components/form/FormNumber.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Input,
|
||||||
|
NumberDecrementStepper,
|
||||||
|
NumberIncrementStepper,
|
||||||
|
NumberInput,
|
||||||
|
NumberInputField,
|
||||||
|
NumberInputProps,
|
||||||
|
NumberInputStepper,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|
||||||
|
export type FormNumberProps = Pick<
|
||||||
|
NumberInputProps,
|
||||||
|
'step' | 'defaultValue' | 'min' | 'max'
|
||||||
|
> & {
|
||||||
|
form: UseFormidableReturn;
|
||||||
|
variableName: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
isRequired?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormNumber = ({
|
||||||
|
form,
|
||||||
|
variableName,
|
||||||
|
ref,
|
||||||
|
placeholder,
|
||||||
|
step,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
defaultValue,
|
||||||
|
...rest
|
||||||
|
}: FormNumberProps) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
isModify={form.isModify[variableName]}
|
||||||
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<NumberInput
|
||||||
|
ref={ref}
|
||||||
|
value={form.values[variableName]}
|
||||||
|
onChange={(_, value) => form.setValues({ [variableName]: value })}
|
||||||
|
step={step}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
42
front2/src/components/form/FormSelect.tsx
Normal file
42
front2/src/components/form/FormSelect.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
import { SelectSingle } from '@/components/select/SelectSingle';
|
||||||
|
|
||||||
|
export type FormSelectProps = {
|
||||||
|
form: UseFormidableReturn;
|
||||||
|
variableName: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
isRequired?: boolean;
|
||||||
|
options?: object[];
|
||||||
|
keyInputValue?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormSelect = ({
|
||||||
|
form,
|
||||||
|
variableName,
|
||||||
|
ref,
|
||||||
|
placeholder,
|
||||||
|
options,
|
||||||
|
keyInputValue = 'name',
|
||||||
|
...rest
|
||||||
|
}: FormSelectProps) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
isModify={form.isModify[variableName]}
|
||||||
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<SelectSingle
|
||||||
|
ref={ref}
|
||||||
|
value={form.values[variableName]}
|
||||||
|
options={options}
|
||||||
|
onChange={(value) => form.setValues({ [variableName]: value })}
|
||||||
|
keyValue={keyInputValue}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
42
front2/src/components/form/FormSelectMultiple.tsx
Normal file
42
front2/src/components/form/FormSelectMultiple.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
import { SelectMultiple } from '@/components/select/SelectMultiple';
|
||||||
|
|
||||||
|
export type FormSelectMultipleProps = {
|
||||||
|
form: UseFormidableReturn;
|
||||||
|
variableName: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
isRequired?: boolean;
|
||||||
|
options?: object[];
|
||||||
|
keyInputValue?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormSelectMultiple = ({
|
||||||
|
form,
|
||||||
|
variableName,
|
||||||
|
ref,
|
||||||
|
placeholder,
|
||||||
|
options,
|
||||||
|
keyInputValue = 'name',
|
||||||
|
...rest
|
||||||
|
}: FormSelectMultipleProps) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
isModify={form.isModify[variableName]}
|
||||||
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<SelectMultiple
|
||||||
|
//ref={ref}
|
||||||
|
values={form.values[variableName]}
|
||||||
|
options={options}
|
||||||
|
onChange={(value) => form.setValues({ [variableName]: value })}
|
||||||
|
keyValue={keyInputValue}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
37
front2/src/components/form/FormTextarea.tsx
Normal file
37
front2/src/components/form/FormTextarea.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
|
import { Textarea } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|
||||||
|
export type FormTextareaProps = {
|
||||||
|
form: UseFormidableReturn;
|
||||||
|
variableName: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
isRequired?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormTextarea = ({
|
||||||
|
form,
|
||||||
|
variableName,
|
||||||
|
ref,
|
||||||
|
placeholder,
|
||||||
|
...rest
|
||||||
|
}: FormTextareaProps) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
isModify={form.isModify[variableName]}
|
||||||
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<Textarea
|
||||||
|
ref={ref}
|
||||||
|
value={form.values[variableName]}
|
||||||
|
onChange={(e) => form.setValues({ [variableName]: e.target.value })}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
@ -159,3 +159,5 @@ export const useFormidable = <TYPE extends object = object>({
|
|||||||
restoreValue,
|
restoreValue,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UseFormidableReturn = ReturnType<typeof useFormidable>;
|
||||||
|
@ -9,7 +9,6 @@ import {
|
|||||||
AlertDialogOverlay,
|
AlertDialogOverlay,
|
||||||
Button,
|
Button,
|
||||||
UseDisclosureReturn,
|
UseDisclosureReturn,
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
export type ConfirmPopUpProps = {
|
export type ConfirmPopUpProps = {
|
||||||
|
@ -30,6 +30,11 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||||||
|
|
||||||
import { Track, TrackResource } from '@/back-api';
|
import { Track, TrackResource } from '@/back-api';
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
|
import { FormInput } from '@/components/form/FormInput';
|
||||||
|
import { FormNumber } from '@/components/form/FormNumber';
|
||||||
|
import { FormSelect } from '@/components/form/FormSelect';
|
||||||
|
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
|
||||||
|
import { FormTextarea } from '@/components/form/FormTextarea';
|
||||||
import { useFormidable } from '@/components/form/Formidable';
|
import { useFormidable } from '@/components/form/Formidable';
|
||||||
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
||||||
import { SelectMultiple } from '@/components/select/SelectMultiple';
|
import { SelectMultiple } from '@/components/select/SelectMultiple';
|
||||||
@ -142,87 +147,45 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
|
|||||||
)}
|
)}
|
||||||
{!admin && (
|
{!admin && (
|
||||||
<>
|
<>
|
||||||
<FormGroup
|
<FormInput
|
||||||
|
form={form}
|
||||||
|
variableName="name"
|
||||||
isRequired
|
isRequired
|
||||||
isModify={form.isModify.name}
|
|
||||||
onRestore={() => form.restoreValue({ name: true })}
|
|
||||||
label="Title"
|
label="Title"
|
||||||
>
|
ref={initialRef}
|
||||||
<Input
|
/>
|
||||||
ref={initialRef}
|
<FormTextarea
|
||||||
value={form.values.name}
|
form={form}
|
||||||
onChange={(e) => form.setValues({ name: e.target.value })}
|
variableName="description"
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
isModify={form.isModify.description}
|
|
||||||
onRestore={() => form.restoreValue({ description: true })}
|
|
||||||
label="Description"
|
label="Description"
|
||||||
>
|
/>
|
||||||
<Textarea
|
<FormSelect
|
||||||
value={form.values.description}
|
form={form}
|
||||||
onChange={(e) =>
|
variableName="genderId"
|
||||||
form.setValues({ description: e.target.value })
|
options={dataGenders}
|
||||||
}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
isModify={form.isModify.genderId}
|
|
||||||
onRestore={() => form.restoreValue({ genderId: true })}
|
|
||||||
label="Gender"
|
label="Gender"
|
||||||
>
|
/>
|
||||||
<SelectSingle
|
<FormSelectMultiple
|
||||||
value={form.values.genderId}
|
form={form}
|
||||||
options={dataGenders}
|
variableName="artists"
|
||||||
onChange={(value) => form.setValues({ genderId: value })}
|
options={dataArtist}
|
||||||
keyValue="name"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
isModify={form.isModify.artists}
|
|
||||||
onRestore={() => form.restoreValue({ artists: true })}
|
|
||||||
label="Artist(s)"
|
label="Artist(s)"
|
||||||
>
|
/>
|
||||||
<SelectMultiple
|
<FormSelect
|
||||||
values={form.values.artists}
|
form={form}
|
||||||
options={dataArtist}
|
variableName="albumId"
|
||||||
onChange={(value) => form.setValues({ artists: value })}
|
options={dataAlbums}
|
||||||
keyValue="name"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
isModify={form.isModify.albumId}
|
|
||||||
onRestore={() => form.restoreValue({ albumId: true })}
|
|
||||||
label="Album"
|
label="Album"
|
||||||
>
|
/>
|
||||||
<SelectSingle
|
<FormNumber
|
||||||
value={form.values.albumId}
|
form={form}
|
||||||
options={dataAlbums}
|
variableName="track"
|
||||||
onChange={(value) => form.setValues({ albumId: value })}
|
|
||||||
keyValue="name"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
isModify={form.isModify.track}
|
|
||||||
onRestore={() => form.restoreValue({ track: true })}
|
|
||||||
label="Track n°"
|
label="Track n°"
|
||||||
>
|
step={1}
|
||||||
<NumberInput
|
defaultValue={0}
|
||||||
value={form.values.track}
|
min={0}
|
||||||
onChange={(_, value) => form.setValues({ track: value })}
|
max={1000}
|
||||||
step={1}
|
/>
|
||||||
defaultValue={0}
|
|
||||||
min={0}
|
|
||||||
max={1000}
|
|
||||||
>
|
|
||||||
<NumberInputField />
|
|
||||||
<NumberInputStepper>
|
|
||||||
<NumberIncrementStepper />
|
|
||||||
<NumberDecrementStepper />
|
|
||||||
</NumberInputStepper>
|
|
||||||
</NumberInput>
|
|
||||||
</FormGroup>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import { useMemo, useRef, useState } from 'react';
|
import { RefObject, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Flex,
|
Flex,
|
||||||
Input,
|
Input,
|
||||||
InputGroup,
|
|
||||||
InputRightElement,
|
|
||||||
Spinner,
|
Spinner,
|
||||||
Tag,
|
Tag,
|
||||||
TagCloseButton,
|
TagCloseButton,
|
||||||
@ -13,12 +11,7 @@ import {
|
|||||||
Wrap,
|
Wrap,
|
||||||
WrapItem,
|
WrapItem,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import {
|
import { MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
|
||||||
MdClose,
|
|
||||||
MdKeyboardArrowDown,
|
|
||||||
MdKeyboardArrowUp,
|
|
||||||
MdSearch,
|
|
||||||
} from 'react-icons/md';
|
|
||||||
|
|
||||||
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
@ -29,12 +22,14 @@ export type SelectMultipleProps = {
|
|||||||
onChange?: (value: (number | string)[] | undefined) => void;
|
onChange?: (value: (number | string)[] | undefined) => void;
|
||||||
keyKey?: string;
|
keyKey?: string;
|
||||||
keyValue?: string;
|
keyValue?: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectMultiple = ({
|
export const SelectMultiple = ({
|
||||||
options,
|
options,
|
||||||
onChange,
|
onChange,
|
||||||
values,
|
values,
|
||||||
|
ref,
|
||||||
keyKey = 'id',
|
keyKey = 'id',
|
||||||
keyValue = keyKey,
|
keyValue = keyKey,
|
||||||
}: SelectMultipleProps) => {
|
}: SelectMultipleProps) => {
|
||||||
@ -51,7 +46,7 @@ export const SelectMultiple = ({
|
|||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const ref = useRef<HTMLInputElement | null>(null);
|
const refFocus = ref ?? useRef<HTMLInputElement | null>(null);
|
||||||
const selectedOptions = useMemo(() => {
|
const selectedOptions = useMemo(() => {
|
||||||
if (isNullOrUndefined(values) || !transformedOption) {
|
if (isNullOrUndefined(values) || !transformedOption) {
|
||||||
return [];
|
return [];
|
||||||
@ -86,7 +81,7 @@ export const SelectMultiple = ({
|
|||||||
};
|
};
|
||||||
const onOpenClose = () => {
|
const onOpenClose = () => {
|
||||||
if (!showList) {
|
if (!showList) {
|
||||||
ref?.current?.focus();
|
refFocus?.current?.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -114,7 +109,7 @@ export const SelectMultiple = ({
|
|||||||
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={ref}
|
ref={refFocus}
|
||||||
width="full"
|
width="full"
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
//onSubmit={onSubmit}
|
//onSubmit={onSubmit}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useRef, useState } from 'react';
|
import { RefObject, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { Button, Flex, Input, Spinner } from '@chakra-ui/react';
|
import { Button, Flex, Input, Spinner } from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
@ -16,12 +16,14 @@ export type SelectSingleProps = {
|
|||||||
onChange?: (value: number | string | undefined) => void;
|
onChange?: (value: number | string | undefined) => void;
|
||||||
keyKey?: string;
|
keyKey?: string;
|
||||||
keyValue?: string;
|
keyValue?: string;
|
||||||
|
ref?: RefObject<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectSingle = ({
|
export const SelectSingle = ({
|
||||||
options,
|
options,
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
|
ref,
|
||||||
keyKey = 'id',
|
keyKey = 'id',
|
||||||
keyValue = keyKey,
|
keyValue = keyKey,
|
||||||
}: SelectSingleProps) => {
|
}: SelectSingleProps) => {
|
||||||
@ -37,7 +39,7 @@ export const SelectSingle = ({
|
|||||||
const [currentSearch, setCurrentSearch] = useState<string | undefined>(
|
const [currentSearch, setCurrentSearch] = useState<string | undefined>(
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
const ref = useRef<HTMLInputElement | null>(null);
|
const refFocus = ref ?? useRef<HTMLInputElement | null>(null);
|
||||||
const selectedOptions = useMemo(() => {
|
const selectedOptions = useMemo(() => {
|
||||||
if (isNullOrUndefined(value)) {
|
if (isNullOrUndefined(value)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -69,7 +71,7 @@ export const SelectSingle = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!showList || selectedOptions) {
|
if (!showList || selectedOptions) {
|
||||||
ref?.current?.focus();
|
refFocus?.current?.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ export const SelectSingle = ({
|
|||||||
<Flex direction="column" width="full" gap="0px">
|
<Flex direction="column" width="full" gap="0px">
|
||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={ref}
|
ref={refFocus}
|
||||||
width="full"
|
width="full"
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
//onSubmit={onSubmit}
|
//onSubmit={onSubmit}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user