Implement local state editting when creating new element

This commit is contained in:
pmoharana-cmd 2025-01-04 13:16:23 -05:00
parent 1f1658c708
commit 78170f7553
3 changed files with 100 additions and 42 deletions

View File

@ -10,7 +10,7 @@ import { Details } from "./Drawer";
type CreateDrawerProps = { type CreateDrawerProps = {
details: Details[]; details: Details[];
onCreate: (newItem: any) => void; onCreate: (newItem: any) => boolean;
}; };
const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
@ -31,10 +31,20 @@ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
})); }));
}; };
const initializeSelectField = (key: string) => {
if (!newItemContent[key]) {
setNewItemContent((prev: any) => ({
...prev,
[key]: [],
}));
}
};
const handleCreate = () => { const handleCreate = () => {
onCreate(newItemContent); if (onCreate(newItemContent)) {
setNewItemContent({}); setNewItemContent({});
setIsOpen(false); setIsOpen(false);
}
}; };
const toggleDrawer = () => { const toggleDrawer = () => {
@ -93,6 +103,7 @@ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
switch (detail.inputType) { switch (detail.inputType) {
case "select-one": case "select-one":
case "select-multiple": case "select-multiple":
initializeSelectField(detail.key);
inputField = ( inputField = (
<TagsInput <TagsInput
presetValue={[]} presetValue={[]}
@ -103,6 +114,17 @@ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
detail.presetOptionsSetter || detail.presetOptionsSetter ||
(() => {}) (() => {})
} }
onTagsChange={(
tags: Set<string>
) => {
setNewItemContent(
(prev: any) => ({
...prev,
[detail.key]:
Array.from(tags),
})
);
}}
/> />
); );
break; break;

View File

@ -29,6 +29,25 @@ type TableProps<T extends DataPoint> = {
details: Details[]; details: Details[];
}; };
/** Validates that all required fields in a new item have values */
const validateNewItem = (newItem: any, details: Details[]): boolean => {
const hasEmptyFields = details.some((detail) => {
const value = newItem[detail.key];
return (
value === undefined ||
value === null ||
value === "" ||
(Array.isArray(value) && value.length === 0)
);
});
if (hasEmptyFields) {
alert("Please fill in all fields before creating a new item");
return false;
}
return true;
};
/** Fuzzy search function */ /** Fuzzy search function */
const fuzzyFilter = ( const fuzzyFilter = (
row: Row<any>, row: Row<any>,
@ -60,39 +79,39 @@ export default function Table<T extends DataPoint>({
}: TableProps<T>) { }: TableProps<T>) {
const columnHelper = createColumnHelper<T>(); const columnHelper = createColumnHelper<T>();
/** Sorting function based on visibility */ // /** Sorting function based on visibility */
const visibilitySort = (a: T, b: T) => // const visibilitySort = (a: T, b: T) =>
a.visible === b.visible ? 0 : a.visible ? -1 : 1; // a.visible === b.visible ? 0 : a.visible ? -1 : 1;
// Sort data on load // // Sort data on load
useEffect(() => { // useEffect(() => {
setData((prevData) => prevData.sort(visibilitySort)); // setData((prevData) => prevData.sort(visibilitySort));
}, [setData]); // }, [setData]);
// Data manipulation methods // // Data manipulation methods
// TODO: Connect data manipulation methods to the database (deleteData, hideData, addData) // // TODO: Connect data manipulation methods to the database (deleteData, hideData, addData)
const deleteData = (dataId: number) => { // const deleteData = (dataId: number) => {
console.log(data); // console.log(data);
setData((currentData) => // setData((currentData) =>
currentData.filter((data) => data.id !== dataId) // currentData.filter((data) => data.id !== dataId)
); // );
}; // };
const hideData = (dataId: number) => { // const hideData = (dataId: number) => {
console.log(`Toggling visibility for data with ID: ${dataId}`); // console.log(`Toggling visibility for data with ID: ${dataId}`);
setData((currentData) => { // setData((currentData) => {
const newData = currentData // const newData = currentData
.map((data) => // .map((data) =>
data.id === dataId // data.id === dataId
? { ...data, visible: !data.visible } // ? { ...data, visible: !data.visible }
: data // : data
) // )
.sort(visibilitySort); // .sort(visibilitySort);
console.log(newData); // console.log(newData);
return newData; // return newData;
}); // });
}; // };
const addData = () => { const addData = () => {
setData([...data]); setData([...data]);
@ -104,8 +123,10 @@ export default function Table<T extends DataPoint>({
id: "options", id: "options",
cell: (props) => ( cell: (props) => (
<RowOptionMenu <RowOptionMenu
onDelete={() => deleteData(props.row.original.id)} onDelete={() => {}}
onHide={() => hideData(props.row.original.id)} onHide={() => {}}
// onDelete={() => deleteData(props.row.original.id)}
// onHide={() => hideData(props.row.original.id)}
/> />
), ),
}) })
@ -217,7 +238,15 @@ export default function Table<T extends DataPoint>({
> >
<CreateDrawer <CreateDrawer
details={details} details={details}
onCreate={(newItem) => {}} onCreate={(newItem) => {
if (!validateNewItem(newItem, details)) {
return false;
}
newItem.visible = true;
setData((prev) => [...prev, newItem]);
return true;
}}
/> />
</td> </td>
</tr> </tr>

View File

@ -8,12 +8,14 @@ interface TagsInputProps {
presetOptions: string[]; presetOptions: string[];
presetValue: string[]; presetValue: string[];
setPresetOptions: Dispatch<SetStateAction<string[]>>; setPresetOptions: Dispatch<SetStateAction<string[]>>;
onTagsChange?: (tags: Set<string>) => void;
} }
const TagsInput: React.FC<TagsInputProps> = ({ const TagsInput: React.FC<TagsInputProps> = ({
presetValue, presetValue,
presetOptions, presetOptions,
setPresetOptions, setPresetOptions,
onTagsChange,
}) => { }) => {
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const [cellSelected, setCellSelected] = useState(false); const [cellSelected, setCellSelected] = useState(false);
@ -70,23 +72,28 @@ const TagsInput: React.FC<TagsInputProps> = ({
const addTag = (e?: React.KeyboardEvent<HTMLInputElement>) => { const addTag = (e?: React.KeyboardEvent<HTMLInputElement>) => {
e?.stopPropagation(); e?.stopPropagation();
const newTags = new Set(Array.from(tags).concat(inputValue));
setOptions(new Set(Array.from(options).concat(inputValue))); setOptions(new Set(Array.from(options).concat(inputValue)));
setTags(new Set(Array.from(tags).concat(inputValue))); setTags(newTags);
setFilteredOptions(new Set(Array.from(options).concat(inputValue))); setFilteredOptions(new Set(Array.from(options).concat(inputValue)));
setInputValue(""); setInputValue("");
onTagsChange?.(newTags);
}; };
const handleSelectTag = (tagToAdd: string) => { const handleSelectTag = (tagToAdd: string) => {
console.log(tagToAdd);
console.log(tags);
if (!tags.has(tagToAdd)) { if (!tags.has(tagToAdd)) {
setTags(new Set(Array.from(tags).concat(tagToAdd))); const newTags = new Set(Array.from(tags).concat(tagToAdd));
setTags(newTags);
onTagsChange?.(newTags);
} }
}; };
const handleDeleteTag = (tagToDelete: string) => { const handleDeleteTag = (tagToDelete: string) => {
setTags(new Set(Array.from(tags).filter((tag) => tag !== tagToDelete))); const newTags = new Set(
Array.from(tags).filter((tag) => tag !== tagToDelete)
);
setTags(newTags);
onTagsChange?.(newTags);
}; };
const handleDeleteTagOption = (tagToDelete: string) => { const handleDeleteTagOption = (tagToDelete: string) => {