[FEAT] live edit, remove is operational with confirm pop-in.
need to upgrade the code to be reusable
This commit is contained in:
parent
de2a5c2413
commit
c6a223d444
@ -1,18 +1,21 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { ReactElement, ReactNode } from 'react';
|
||||
|
||||
import { Button, Flex, IconButton, Text, Tooltip } from '@chakra-ui/react';
|
||||
import {
|
||||
FormControl,
|
||||
FormControlProps,
|
||||
FormErrorMessage,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
} from '@chakra-ui/react';
|
||||
import { MdLabelImportant } from 'react-icons/md';
|
||||
MdErrorOutline,
|
||||
MdHelpOutline,
|
||||
MdLabelImportant,
|
||||
MdRefresh,
|
||||
} from 'react-icons/md';
|
||||
|
||||
export type FormGroupProps = FormControlProps & {
|
||||
export type FormGroupProps = {
|
||||
error?: ReactNode;
|
||||
help?: ReactNode;
|
||||
label?: ReactNode;
|
||||
isModify?: boolean;
|
||||
onRestore?: () => void;
|
||||
isRequired?: boolean;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const FormGroup = ({
|
||||
@ -20,16 +23,45 @@ export const FormGroup = ({
|
||||
error,
|
||||
help,
|
||||
label,
|
||||
...props
|
||||
isModify = false,
|
||||
isRequired = false,
|
||||
onRestore,
|
||||
}: FormGroupProps) => (
|
||||
<FormControl marginTop="4px" {...props}>
|
||||
{!!label && <FormLabel>{label}</FormLabel>}
|
||||
<Flex
|
||||
borderLeftWidth="3px"
|
||||
borderLeftColor={error ? 'red' : isModify ? 'blue' : '#00000000'}
|
||||
paddingLeft="7px"
|
||||
paddingY="4px"
|
||||
direction="column"
|
||||
>
|
||||
<Flex direction="row" width="full" gap="52px">
|
||||
{!!label && (
|
||||
<Text marginRight="auto" fontWeight="bold">
|
||||
{label}{' '}
|
||||
{isRequired && (
|
||||
<Text as="span" color="red.600">
|
||||
*
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
{!!onRestore && isModify && (
|
||||
<MdRefresh size="15px" onClick={onRestore} cursor="pointer" />
|
||||
)}
|
||||
</Flex>
|
||||
{children}
|
||||
{!!help && <FormHelperText>{help}</FormHelperText>}
|
||||
{!!help && (
|
||||
<Flex direction="row">
|
||||
<MdHelpOutline />
|
||||
<Text>{help}</Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<FormErrorMessage>
|
||||
<MdLabelImportant />
|
||||
{error}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
{!!error && (
|
||||
<Flex direction="row">
|
||||
<MdErrorOutline />
|
||||
<Text>{error}</Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { Box, Button, Flex, Text } from '@chakra-ui/react';
|
||||
|
||||
import { isNullOrUndefined } from '@/utils/validator';
|
||||
@ -45,7 +47,15 @@ export const FormSelectList = ({
|
||||
search,
|
||||
}: FormSelectListProps) => {
|
||||
const displayedValue = optionToOptionDisplay(options, selected, search);
|
||||
|
||||
const scrollToRef = useRef<HTMLButtonElement | null>(null);
|
||||
useEffect(() => {
|
||||
if (scrollToRef?.current) {
|
||||
scrollToRef?.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<Box position="relative">
|
||||
<Flex
|
||||
@ -75,6 +85,7 @@ export const FormSelectList = ({
|
||||
backgroundColor={data.isSelected ? 'green.800' : '0x00000000'}
|
||||
_hover={{ backgroundColor: 'gray.400' }}
|
||||
onClick={() => onSelectValue(data)}
|
||||
ref={data.isSelected ? scrollToRef : undefined}
|
||||
>
|
||||
<Text marginRight="auto" autoFocus={false}>
|
||||
{data.name}
|
||||
|
@ -1,14 +1,6 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
const getDifferences = (obj1: any, obj2: any): { [key: string]: boolean } => {
|
||||
const result: { [key: string]: boolean } = {};
|
||||
for (const key in obj1) {
|
||||
if (obj1.hasOwnProperty(key)) {
|
||||
result[key] = obj1[key] !== obj2[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
import { isArray, isNullOrUndefined, isObject } from '@/utils/validator';
|
||||
|
||||
const hasAnyTrue = (obj: { [key: string]: boolean }): boolean => {
|
||||
for (const key in obj) {
|
||||
@ -19,55 +11,153 @@ const hasAnyTrue = (obj: { [key: string]: boolean }): boolean => {
|
||||
return false;
|
||||
};
|
||||
|
||||
// const onChangeValue = (key: string, data) => {
|
||||
// console.log(`[${key}] data: ${data}`);
|
||||
// setNewData((previous) => {
|
||||
// if (previous === undefined) {
|
||||
// return previous;
|
||||
// }
|
||||
// if (previous[key] === data) {
|
||||
// return previous;
|
||||
// }
|
||||
// const tmp = { ...previous };
|
||||
// tmp[key] = data;
|
||||
// console.log(`data = ${JSON.stringify(tmp, null, 2)}`);
|
||||
// return tmp;
|
||||
// });
|
||||
// };
|
||||
function getDifferences(
|
||||
obj1: object,
|
||||
obj2: object
|
||||
): { [key: string]: boolean } {
|
||||
// Create an empty object to store the differences
|
||||
const result: { [key: string]: boolean } = {};
|
||||
// Recursive function to compare values
|
||||
function compareValues(value1: any, value2: any): boolean {
|
||||
// If both values are objects, compare their properties recursively
|
||||
if (isObject(value1) && isObject(value2)) {
|
||||
return hasAnyTrue(getDifferences(value1, value2));
|
||||
}
|
||||
// If both values are arrays, compare their elements
|
||||
if (isArray(value1) && isArray(value2)) {
|
||||
//console.log(`Check is array: ${JSON.stringify(value1)} =?= ${JSON.stringify(value2)}`);
|
||||
if (value1.length !== value2.length) {
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < value1.length; i++) {
|
||||
if (compareValues(value1[i], value2[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Otherwise, compare the values directly
|
||||
//console.log(`compare : ${value1} =?= ${value2}`);
|
||||
return value1 !== value2;
|
||||
}
|
||||
|
||||
export const useFormidable = <TYPE = object,>({
|
||||
// Get all keys from both objects
|
||||
const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
|
||||
|
||||
// Iterate over all keys
|
||||
for (const key of allKeys) {
|
||||
if (compareValues(obj1[key], obj2[key])) {
|
||||
result[key] = true;
|
||||
} else {
|
||||
result[key] = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export const useFormidable = <TYPE extends object = object>({
|
||||
initialValues = {} as TYPE,
|
||||
}: {
|
||||
initialValues?: TYPE;
|
||||
}) => {
|
||||
const [values, setValues] = useState<TYPE>({ ...initialValues } as TYPE);
|
||||
const initialData = useMemo<TYPE>(() => {
|
||||
setValues({ ...initialValues } as TYPE);
|
||||
return { ...initialValues } as TYPE;
|
||||
}, [initialValues, setValues]);
|
||||
const [initialData, setInitialData] = useState<TYPE>(initialValues);
|
||||
const [valueChange, setValueChange] = useState<{ [key: string]: boolean }>(
|
||||
{}
|
||||
);
|
||||
const [isFormModified, setIsFormModified] = useState<boolean>(false);
|
||||
useEffect(() => {
|
||||
setInitialData((previous) => {
|
||||
//console.log(`FORMIDABLE: useMemo initial Values(${JSON.stringify(initialValues)})`);
|
||||
const previousJson = JSON.stringify(previous);
|
||||
const newJson = JSON.stringify(initialValues);
|
||||
if (previousJson === newJson) {
|
||||
return previous;
|
||||
}
|
||||
//console.log(`FORMIDABLE: ==> update new values`);
|
||||
setValues({ ...initialValues });
|
||||
const ret = getDifferences(initialValues, initialValues);
|
||||
setValueChange(ret);
|
||||
setIsFormModified(hasAnyTrue(ret));
|
||||
return initialValues;
|
||||
});
|
||||
}, [
|
||||
initialValues,
|
||||
setInitialData,
|
||||
setValues,
|
||||
setValueChange,
|
||||
setIsFormModified,
|
||||
]);
|
||||
const setValuesExternal = useCallback(
|
||||
(data: object) => {
|
||||
//console.log(`FORMIDABLE: setValuesExternal(${JSON.stringify(data)}) ==> keys=${Object.keys(data)}`);
|
||||
setValues((previous) => {
|
||||
const newValues = { ...previous, ...data };
|
||||
const ret = getDifferences(initialData, values);
|
||||
const ret = getDifferences(initialData, newValues);
|
||||
setValueChange(ret);
|
||||
setIsFormModified(hasAnyTrue(ret));
|
||||
console.log(
|
||||
` ppppppppppppppppppp ${JSON.stringify(ret, null, 2)} ==> ${hasAnyTrue(ret)}`
|
||||
);
|
||||
return newValues;
|
||||
});
|
||||
},
|
||||
[setValues, initialData]
|
||||
);
|
||||
const restoreValue = useCallback(
|
||||
(data: object) => {
|
||||
setValues((previous) => {
|
||||
const keysInPrevious = Object.keys(previous);
|
||||
const newValue = { ...previous };
|
||||
let countModify = 0;
|
||||
//console.log(`restore value ${JSON.stringify(data, null, 2)}`);
|
||||
for (const key of Object.keys(data)) {
|
||||
if (!keysInPrevious.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
if (data[key] === false) {
|
||||
continue;
|
||||
}
|
||||
newValue[key] = initialValues[key];
|
||||
countModify++;
|
||||
}
|
||||
if (countModify === 0) {
|
||||
return previous;
|
||||
}
|
||||
//console.log(`initialData data ${JSON.stringify(initialData, null, 2)}`);
|
||||
//console.log(`New data ${JSON.stringify(newValue, null, 2)}`);
|
||||
const ret = getDifferences(initialData, newValue);
|
||||
setValueChange(ret);
|
||||
setIsFormModified(hasAnyTrue(ret));
|
||||
return newValue;
|
||||
});
|
||||
},
|
||||
[setValues, initialData, setIsFormModified, setValueChange]
|
||||
);
|
||||
const getDeltaData = useCallback(
|
||||
({ omit = [], only }: { omit?: string[]; only?: string[] }) => {
|
||||
const out = {};
|
||||
Object.keys(valueChange).forEach((key) => {
|
||||
if (omit.includes(key) || (only && !only.includes(key))) {
|
||||
return;
|
||||
}
|
||||
if (!valueChange[key]) {
|
||||
return;
|
||||
}
|
||||
const tmpValue = values[key];
|
||||
if (isNullOrUndefined(tmpValue)) {
|
||||
out[key] = null;
|
||||
} else {
|
||||
out[key] = tmpValue;
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
[valueChange, values]
|
||||
);
|
||||
return {
|
||||
values,
|
||||
valueChange,
|
||||
isFormModified,
|
||||
setValues: setValuesExternal,
|
||||
getDeltaData,
|
||||
restoreValue,
|
||||
};
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ export const SelectMultiple = ({
|
||||
|
||||
const selectValue = (data: SelectMultipleValueDisplayType) => {
|
||||
const newValues = values?.includes(data.id)
|
||||
? values.filter((elem) => data.id === elem)
|
||||
? values.filter((elem) => data.id !== elem)
|
||||
: [...(values ?? []), data.id];
|
||||
setShowList(false);
|
||||
if (onChange) {
|
||||
|
61
front2/src/components/popup/ConfirmPopUp.tsx
Normal file
61
front2/src/components/popup/ConfirmPopUp.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogBody,
|
||||
AlertDialogContent,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogOverlay,
|
||||
Button,
|
||||
UseDisclosureReturn,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
export type ConfirmPopUpProps = {
|
||||
title: string;
|
||||
body: string;
|
||||
confirmTitle: string;
|
||||
onConfirm: () => void;
|
||||
disclosure: UseDisclosureReturn;
|
||||
};
|
||||
|
||||
export const ConfirmPopUp = ({
|
||||
title,
|
||||
body,
|
||||
confirmTitle,
|
||||
onConfirm,
|
||||
disclosure,
|
||||
}: ConfirmPopUpProps) => {
|
||||
const onClickConfirm = () => {
|
||||
onConfirm();
|
||||
disclosure.onClose();
|
||||
};
|
||||
const cancelRef = useRef(null);
|
||||
return (
|
||||
<AlertDialog
|
||||
isOpen={disclosure.isOpen}
|
||||
leastDestructiveRef={cancelRef}
|
||||
onClose={disclosure.onClose}
|
||||
>
|
||||
<AlertDialogOverlay>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||
{title}
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>{body}</AlertDialogBody>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<Button onClick={disclosure.onClose} ref={cancelRef}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button colorScheme="red" onClick={onClickConfirm} ml={3}>
|
||||
{confirmTitle}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogOverlay>
|
||||
</AlertDialog>
|
||||
);
|
||||
};
|
@ -2,8 +2,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Input,
|
||||
Modal,
|
||||
ModalBody,
|
||||
@ -12,205 +11,246 @@ import {
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
NumberDecrementStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberInput,
|
||||
NumberInputField,
|
||||
NumberInputStepper,
|
||||
Text,
|
||||
Textarea,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { Formiz, useForm, useFormFields } from '@formiz/core';
|
||||
import {
|
||||
MdAdminPanelSettings,
|
||||
MdDeleteForever,
|
||||
MdEdit,
|
||||
MdRemove,
|
||||
} from 'react-icons/md';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { Album, Track } from '@/back-api';
|
||||
import { Track, TrackResource } from '@/back-api';
|
||||
import { FormGroup } from '@/components/form/FormGroup';
|
||||
import { useFormidable } from '@/components/form/Formidable';
|
||||
import { SelectMultiple } from '@/components/form/SelectMultiple';
|
||||
import { SelectSingle } from '@/components/form/SelectSingle';
|
||||
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
||||
import { useOrderedAlbums } from '@/service/Album';
|
||||
import { useOrderedArtists } from '@/service/Artist';
|
||||
import { useOrderedGenders } from '@/service/Gender';
|
||||
import { useSpecificTrack } from '@/service/Track';
|
||||
import { useServiceContext } from '@/service/ServiceContext';
|
||||
import { useSpecificTrack, useTrackService } from '@/service/Track';
|
||||
import { isNullOrUndefined } from '@/utils/validator';
|
||||
|
||||
export type TrackEditPopUpProps = {};
|
||||
|
||||
const getDifferences = (obj1: any, obj2: any): { [key: string]: boolean } => {
|
||||
const result: { [key: string]: boolean } = {};
|
||||
for (const key in obj1) {
|
||||
if (obj1.hasOwnProperty(key)) {
|
||||
result[key] = obj1[key] !== obj2[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const hasAnyTrue = (obj: { [key: string]: boolean }): boolean => {
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key) && obj[key] === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
|
||||
const { trackId } = useParams();
|
||||
const trackIdInt = isNullOrUndefined(trackId)
|
||||
? undefined
|
||||
: parseInt(trackId, 10);
|
||||
const { session } = useServiceContext();
|
||||
const { dataGenders } = useOrderedGenders(undefined);
|
||||
const { dataArtist } = useOrderedArtists(undefined);
|
||||
const { dataAlbums } = useOrderedAlbums(undefined);
|
||||
const { dataTrack } = useSpecificTrack(
|
||||
isNullOrUndefined(trackId) ? undefined : parseInt(trackId, 10)
|
||||
);
|
||||
const { store } = useTrackService();
|
||||
const { dataTrack } = useSpecificTrack(trackIdInt);
|
||||
const [admin, setAdmin] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const disclosure = useDisclosure();
|
||||
const onClose = () => {
|
||||
navigate('../../', { relative: 'path' });
|
||||
};
|
||||
const onSubmit = (values) => {
|
||||
console.log(`onSubmit = ${values}`);
|
||||
};
|
||||
const onValuesChange = (values, form) => {
|
||||
console.log(`onValuesChange = ${values}`);
|
||||
const onRemove = () => {
|
||||
if (isNullOrUndefined(trackIdInt)) {
|
||||
return;
|
||||
}
|
||||
store.remove(
|
||||
trackIdInt,
|
||||
TrackResource.remove({
|
||||
restConfig: session.getRestConfig(),
|
||||
params: {
|
||||
id: trackIdInt,
|
||||
},
|
||||
})
|
||||
);
|
||||
onClose();
|
||||
};
|
||||
const initialRef = useRef(null);
|
||||
const finalRef = useRef(null);
|
||||
const form = useForm<Track>({
|
||||
onSubmit,
|
||||
onValuesChange,
|
||||
initialValues: { ...dataTrack },
|
||||
onValid: () => console.log('onValid'),
|
||||
onInvalid: () => console.log('onInvalid'),
|
||||
const form = useFormidable<Track>({
|
||||
//onSubmit,
|
||||
//onValuesChange,
|
||||
initialValues: dataTrack,
|
||||
//onValid: () => console.log('onValid'),
|
||||
//onInvalid: () => console.log('onInvalid'),
|
||||
});
|
||||
const formValues = useFormFields({
|
||||
connect: form,
|
||||
selector: (field) => field.value,
|
||||
});
|
||||
/*
|
||||
const formValues = useFormFields({
|
||||
connect: form,
|
||||
fields: ['genderId'] as const,
|
||||
selector: 'value',
|
||||
});
|
||||
*/
|
||||
console.log(`dataTrack : ${JSON.stringify(dataTrack, null, 2)}`);
|
||||
console.log(`Redraw : ${JSON.stringify(formValues, null, 2)}`);
|
||||
const [newData, setNewData] = useState<Track>();
|
||||
const [changeData, setChangeData] = useState<{ [key: string]: boolean }>();
|
||||
const [changeOneData, setChangeOneData] = useState<boolean>(true);
|
||||
// initialize value when ready
|
||||
useEffect(() => {
|
||||
setNewData(dataTrack);
|
||||
}, [dataTrack, setNewData, setChangeData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!newData) {
|
||||
const onSave = async () => {
|
||||
if (isNullOrUndefined(trackIdInt)) {
|
||||
return;
|
||||
}
|
||||
const ret = getDifferences(dataTrack, newData);
|
||||
setChangeData(ret);
|
||||
///////////////////////setChangeOneData(hasAnyTrue(ret));
|
||||
console.log(
|
||||
`ChangeData=${JSON.stringify(ret, null, 2)} ChangeOneData=${hasAnyTrue(ret)}`
|
||||
const dataThatNeedToBeUpdated = form.getDeltaData({ omit: ['covers'] });
|
||||
console.log(`onSave = ${JSON.stringify(dataThatNeedToBeUpdated, null, 2)}`);
|
||||
store.update(
|
||||
TrackResource.patch({
|
||||
restConfig: session.getRestConfig(),
|
||||
data: dataThatNeedToBeUpdated,
|
||||
params: {
|
||||
id: trackIdInt,
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [dataTrack, newData, setChangeData, setChangeOneData]);
|
||||
|
||||
// const onChangeValue = (key: string, data) => {
|
||||
// console.log(`[${key}] data: ${data}`);
|
||||
// setNewData((previous) => {
|
||||
// if (previous === undefined) {
|
||||
// return previous;
|
||||
// }
|
||||
// if (previous[key] === data) {
|
||||
// return previous;
|
||||
// }
|
||||
// const tmp = { ...previous };
|
||||
// tmp[key] = data;
|
||||
// console.log(`data = ${JSON.stringify(tmp, null, 2)}`);
|
||||
// return tmp;
|
||||
// });
|
||||
// };
|
||||
|
||||
};
|
||||
return (
|
||||
<Formiz connect={form} autoForm>
|
||||
<form noValidate onSubmit={form.submit}>
|
||||
<Modal
|
||||
initialFocusRef={initialRef}
|
||||
finalFocusRef={finalRef}
|
||||
closeOnOverlayClick={false}
|
||||
onClose={onClose}
|
||||
isOpen={true}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Edit Track</ModalHeader>
|
||||
<ModalCloseButton ref={finalRef} />
|
||||
<Modal
|
||||
initialFocusRef={initialRef}
|
||||
finalFocusRef={finalRef}
|
||||
closeOnOverlayClick={false}
|
||||
onClose={onClose}
|
||||
isOpen={true}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Edit Track</ModalHeader>
|
||||
<ModalCloseButton ref={finalRef} />
|
||||
|
||||
<ModalBody pb={6}>
|
||||
<FormGroup isRequired>
|
||||
<FormLabel>Title</FormLabel>
|
||||
<ModalBody pb={6} gap="0px" paddingLeft="18px">
|
||||
{admin && (
|
||||
<>
|
||||
<FormGroup isRequired label="Id">
|
||||
<Text>{dataTrack?.id}</Text>
|
||||
</FormGroup>
|
||||
<FormGroup label="Data Id">
|
||||
<Text>{dataTrack?.dataId}</Text>
|
||||
</FormGroup>
|
||||
<FormGroup label="Action(s):">
|
||||
<Button
|
||||
onClick={disclosure.onOpen}
|
||||
marginRight="auto"
|
||||
variant="@danger"
|
||||
>
|
||||
<MdDeleteForever /> Remove Media
|
||||
</Button>
|
||||
</FormGroup>
|
||||
<ConfirmPopUp
|
||||
disclosure={disclosure}
|
||||
title="Remove track"
|
||||
body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`}
|
||||
confirmTitle="Remove"
|
||||
onConfirm={onRemove}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!admin && (
|
||||
<>
|
||||
<FormGroup
|
||||
isRequired
|
||||
isModify={form.valueChange.name}
|
||||
onRestore={() => form.restoreValue({ name: true })}
|
||||
label="Title"
|
||||
>
|
||||
<Input
|
||||
ref={initialRef}
|
||||
value={formValues.name}
|
||||
value={form.values.name}
|
||||
onChange={(e) => form.setValues({ name: e.target.value })}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<label>Description</label>
|
||||
<FormGroup
|
||||
isModify={form.valueChange.description}
|
||||
onRestore={() => form.restoreValue({ description: true })}
|
||||
label="Description"
|
||||
>
|
||||
<Textarea
|
||||
value={formValues.description}
|
||||
value={form.values.description}
|
||||
onChange={(e) =>
|
||||
form.setValues({ description: e.target.value })
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label>Gender</label>
|
||||
<FormGroup
|
||||
isModify={form.valueChange.genderId}
|
||||
onRestore={() => form.restoreValue({ genderId: true })}
|
||||
label="Gender"
|
||||
>
|
||||
<SelectSingle
|
||||
value={formValues.genderId}
|
||||
value={form.values.genderId}
|
||||
options={dataGenders}
|
||||
onChange={(value) => {
|
||||
form.setValues({ genderId: value });
|
||||
console.log(`event change value: ${value}`);
|
||||
console.log(
|
||||
`values: ${JSON.stringify(formValues, null, 2)}`
|
||||
);
|
||||
}}
|
||||
onChange={(value) => form.setValues({ genderId: value })}
|
||||
keyValue="name"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label>Artist(s)</label>
|
||||
<FormGroup
|
||||
isModify={form.valueChange.artists}
|
||||
onRestore={() => form.restoreValue({ artists: true })}
|
||||
label="Artist(s)"
|
||||
>
|
||||
<SelectMultiple
|
||||
values={formValues.artists}
|
||||
values={form.values.artists}
|
||||
options={dataArtist}
|
||||
onChange={(value) => form.setValues({ artists: value })}
|
||||
keyValue="name"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label>Album</label>
|
||||
<FormGroup
|
||||
isModify={form.valueChange.albumId}
|
||||
onRestore={() => form.restoreValue({ albumId: true })}
|
||||
label="Album"
|
||||
>
|
||||
<SelectSingle
|
||||
value={formValues.albumId}
|
||||
value={form.values.albumId}
|
||||
options={dataAlbums}
|
||||
onChange={(value) => form.setValues({ albumId: value })}
|
||||
keyValue="name"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormControl>
|
||||
<FormLabel>track n°</FormLabel>
|
||||
<FormGroup
|
||||
isModify={form.valueChange.track}
|
||||
onRestore={() => form.restoreValue({ track: true })}
|
||||
label="Track n°"
|
||||
>
|
||||
<NumberInput
|
||||
value={formValues.track}
|
||||
onChange={(value) => form.setValues({ track: value })}
|
||||
/>
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
{changeOneData && (
|
||||
<Button colorScheme="blue" mr={3} type="submit">
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</form>
|
||||
</Formiz>
|
||||
value={form.values.track}
|
||||
onChange={(_, value) => form.setValues({ track: value })}
|
||||
step={1}
|
||||
defaultValue={0}
|
||||
min={0}
|
||||
max={1000}
|
||||
>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
onClick={() => setAdmin((value) => !value)}
|
||||
marginRight="auto"
|
||||
>
|
||||
{admin ? (
|
||||
<>
|
||||
<MdEdit />
|
||||
Edit
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<MdAdminPanelSettings />
|
||||
Admin
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
{!admin && form.isFormModified && (
|
||||
<Button colorScheme="blue" mr={3} onClick={onSave}>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
@ -70,9 +70,9 @@ export default defineStyleConfig({
|
||||
'@danger': (props) =>
|
||||
customVariant({
|
||||
theme: props.theme,
|
||||
bg: mode('error.600', 'error.300')(props),
|
||||
bgHover: mode('error.700', 'error.400')(props),
|
||||
bgActive: mode('error.600', 'error.300')(props),
|
||||
bg: mode('error.600', 'error.600')(props),
|
||||
bgHover: mode('error.700', 'error.500')(props),
|
||||
bgActive: mode('error.600', 'error.500')(props),
|
||||
color: mode('white', 'error.900')(props),
|
||||
boxColorFocus: mode('error.900', 'error.500')(props),
|
||||
}),
|
||||
|
@ -14,6 +14,8 @@ export type DataStoreType<TYPE> = {
|
||||
data: TYPE[];
|
||||
get: <MODEL>(value: MODEL, key?: string) => TYPE | undefined;
|
||||
gets: <MODEL>(value: MODEL[] | undefined, key?: string) => TYPE[];
|
||||
update: (request: Promise<TYPE>, key?: string) => void;
|
||||
remove: (id: number | string, request: Promise<void>, key?: string) => void;
|
||||
};
|
||||
|
||||
export const useDataStore = <TYPE>(
|
||||
@ -85,16 +87,40 @@ export const useDataStore = <TYPE>(
|
||||
);
|
||||
|
||||
const update = useCallback(
|
||||
(value: TYPE, key?: string) => {
|
||||
(request: Promise<TYPE>, key?: string) => {
|
||||
const keyValue = key ?? primaryKey;
|
||||
const filterData = data.filter(
|
||||
(localData: TYPE) => localData[keyValue] === value[keyValue]
|
||||
);
|
||||
filterData.push(value);
|
||||
setData(filterData);
|
||||
request
|
||||
.then((responseData: TYPE) => {
|
||||
const filterData = data.filter(
|
||||
(localData: TYPE) => localData[keyValue] !== responseData[keyValue]
|
||||
);
|
||||
filterData.push(responseData);
|
||||
setData(filterData);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(`catch an error: ... ${JSON.stringify(error, null, 2)}`);
|
||||
});
|
||||
},
|
||||
[data, setData]
|
||||
);
|
||||
const remove = useCallback(
|
||||
(id: number | string, request: Promise<void>, key?: string) => {
|
||||
const keyValue = key ?? primaryKey;
|
||||
request
|
||||
.then(() => {
|
||||
const filterData = data.filter(
|
||||
(localData: TYPE) => localData[keyValue] !== id
|
||||
);
|
||||
setData(filterData);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(
|
||||
`catch an error on delete: ... ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
});
|
||||
},
|
||||
[data, setData]
|
||||
);
|
||||
|
||||
return { isLoading, error, data, get, gets }; //, update};
|
||||
return { isLoading, error, data, get, gets, update, remove };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user