Add single tag selection and editting row (#52)

This commit is contained in:
Prajwal Moharana 2025-01-04 15:10:07 -05:00 committed by GitHub
parent 251222167d
commit dff05af79c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 150 additions and 54 deletions

View File

@ -108,7 +108,6 @@ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
switch (detail.inputType) { switch (detail.inputType) {
case "select-one": case "select-one":
case "select-multiple":
initializeSelectField(detail.key); initializeSelectField(detail.key);
inputField = ( inputField = (
<TagsInput <TagsInput
@ -121,6 +120,40 @@ const CreateDrawer: FunctionComponent<CreateDrawerProps> = ({
detail.presetOptionsSetter || detail.presetOptionsSetter ||
(() => {}) (() => {})
} }
singleValue={true}
onTagsChange={(
tags: Set<string>
) => {
setNewItemContent(
(prev: any) => ({
...prev,
[detail.key]:
tags.size > 0
? Array.from(
tags
)[0]
: null,
})
);
}}
/>
);
break;
case "select-multiple":
initializeSelectField(detail.key);
inputField = (
<TagsInput
key={`${detail.key}-${renderKey}`}
presetValue={
newItemContent[detail.key] || []
}
presetOptions={
detail.presetOptionsValues || []
}
setPresetOptions={
detail.presetOptionsSetter ||
(() => {})
}
onTagsChange={( onTagsChange={(
tags: Set<string> tags: Set<string>
) => { ) => {

View File

@ -48,12 +48,14 @@ const Drawer: FunctionComponent<DrawerProps> = ({
const [isFavorite, setIsFavorite] = useState(false); const [isFavorite, setIsFavorite] = useState(false);
const [tempRowContent, setTempRowContent] = useState(rowContent); const [tempRowContent, setTempRowContent] = useState(rowContent);
const onRowUpdate = (updatedRow: any) => {}; const handleTempRowContentChangeHTML = (
const handleTempRowContentChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => { ) => {
const { name, value } = e.target; const { name, value } = e.target;
handleTempRowContentChange(name, value);
};
const handleTempRowContentChange = (name: string, value: any) => {
setTempRowContent((prev: any) => ({ setTempRowContent((prev: any) => ({
...prev, ...prev,
[name]: value, [name]: value,
@ -68,10 +70,22 @@ const Drawer: FunctionComponent<DrawerProps> = ({
}; };
const toggleDrawer = () => { const toggleDrawer = () => {
if (setRowContent && isOpen) {
setRowContent((prev: any) => {
return prev.map((row: any) => {
if (row.id === tempRowContent.id) {
return tempRowContent;
}
return row;
});
});
}
setIsOpen(!isOpen); setIsOpen(!isOpen);
if (isFull) { if (isFull) {
setIsFull(!isFull); setIsFull(!isFull);
} }
console.log("Send API request to update row content");
}; };
const toggleDrawerFullScreen = () => setIsFull(!isFull); const toggleDrawerFullScreen = () => setIsFull(!isFull);
@ -143,16 +157,15 @@ const Drawer: FunctionComponent<DrawerProps> = ({
switch (detail.inputType) { switch (detail.inputType) {
case "select-one": case "select-one":
case "select-multiple":
valueToRender = ( valueToRender = (
<div className="flex-1"> <div className="flex-1">
<div className="hover:bg-gray-50 rounded-md px-2 py-1"> <div className="rounded-md px-2 py-1">
<TagsInput <TagsInput
presetValue={ presetValue={
typeof value === typeof value ===
"string" "string"
? [value] ? [value]
: value : value || []
} }
presetOptions={ presetOptions={
detail.presetOptionsValues || detail.presetOptionsValues ||
@ -162,6 +175,51 @@ const Drawer: FunctionComponent<DrawerProps> = ({
detail.presetOptionsSetter || detail.presetOptionsSetter ||
(() => {}) (() => {})
} }
singleValue={true}
onTagsChange={(
tags: Set<string>
) => {
const tagsArray =
Array.from(tags);
handleTempRowContentChange(
detail.key,
tagsArray.length > 0
? tagsArray[0]
: null
);
}}
/>
</div>
</div>
);
break;
case "select-multiple":
valueToRender = (
<div className="flex-1">
<div className="rounded-md px-2 py-1">
<TagsInput
presetValue={
typeof value ===
"string"
? [value]
: value || []
}
presetOptions={
detail.presetOptionsValues ||
[]
}
setPresetOptions={
detail.presetOptionsSetter ||
(() => {})
}
onTagsChange={(
tags: Set<string>
) => {
handleTempRowContentChange(
detail.key,
Array.from(tags)
);
}}
/> />
</div> </div>
</div> </div>
@ -175,7 +233,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({
name={detail.key} name={detail.key}
value={value} value={value}
onChange={ onChange={
handleTempRowContentChange handleTempRowContentChangeHTML
} }
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
rows={4} rows={4}
@ -203,7 +261,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({
name={detail.key} name={detail.key}
value={value} value={value}
onChange={ onChange={
handleTempRowContentChange handleTempRowContentChangeHTML
} }
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
className="w-full p-1 focus:outline-gray-200 bg-transparent" className="w-full p-1 focus:outline-gray-200 bg-transparent"
@ -221,7 +279,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({
name={detail.key} name={detail.key}
value={value} value={value}
onChange={ onChange={
handleTempRowContentChange handleTempRowContentChangeHTML
} }
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
className="w-full p-1 font-normal hover:text-gray-400 focus:outline-gray-200 underline text-gray-500 bg-transparent" className="w-full p-1 font-normal hover:text-gray-400 focus:outline-gray-200 underline text-gray-500 bg-transparent"

View File

@ -33,7 +33,7 @@ export const FilterBox = () => {
> >
<span>{tag}</span> <span>{tag}</span>
<span <span
className="ml-2 cursor-pointer" className="cursor-pointer"
onClick={() => handleTagChange(tag)} onClick={() => handleTagChange(tag)}
> >
&times; &times;

View File

@ -113,10 +113,6 @@ export default function Table<T extends DataPoint>({
// }); // });
// }; // };
const addData = () => {
setData([...data]);
};
// Add data manipulation options to the first column // Add data manipulation options to the first column
columns.unshift( columns.unshift(
columnHelper.display({ columnHelper.display({
@ -139,11 +135,6 @@ export default function Table<T extends DataPoint>({
setQuery(String(target.value)); setQuery(String(target.value));
}; };
const handleCellChange = (e: ChangeEvent, key: Key) => {
const target = e.target as HTMLInputElement;
console.log(key);
};
// TODO: Filtering // TODO: Filtering
// TODO: Sorting // TODO: Sorting
@ -163,16 +154,6 @@ export default function Table<T extends DataPoint>({
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}); });
const handleRowData = (row: any) => {
const rowData: any = {};
row.cells.forEach((cell: any) => {
rowData[cell.column.id] = cell.value;
});
// Use rowData object containing data from all columns for the current row
console.log(rowData);
return rowData;
};
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<div className="flex flex-row justify-end"> <div className="flex flex-row justify-end">

View File

@ -99,7 +99,7 @@ export default function UserTable({ data, setData }: UserTableProps) {
cell: (info) => ( cell: (info) => (
<div className="flex flex-wrap gap-2 items-center px-2"> <div className="flex flex-wrap gap-2 items-center px-2">
<Tag> <Tag>
{info.getValue().length != 0 {info.getValue() && info.getValue().length != 0
? info.getValue() ? info.getValue()
: "no role"} : "no role"}
</Tag> </Tag>

View File

@ -9,6 +9,7 @@ interface TagsInputProps {
presetValue: string[]; presetValue: string[];
setPresetOptions: Dispatch<SetStateAction<string[]>>; setPresetOptions: Dispatch<SetStateAction<string[]>>;
onTagsChange?: (tags: Set<string>) => void; onTagsChange?: (tags: Set<string>) => void;
singleValue?: boolean;
} }
const TagsInput: React.FC<TagsInputProps> = ({ const TagsInput: React.FC<TagsInputProps> = ({
@ -16,6 +17,7 @@ const TagsInput: React.FC<TagsInputProps> = ({
presetOptions, presetOptions,
setPresetOptions, setPresetOptions,
onTagsChange, onTagsChange,
singleValue = false,
}) => { }) => {
const [inputValue, setInputValue] = useState(""); const [inputValue, setInputValue] = useState("");
const [cellSelected, setCellSelected] = useState(false); const [cellSelected, setCellSelected] = useState(false);
@ -65,6 +67,10 @@ const TagsInput: React.FC<TagsInputProps> = ({
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => { const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && inputValue.trim()) { if (e.key === "Enter" && inputValue.trim()) {
if (singleValue && tags.size >= 1) {
// Don't add new tag if we're in single value mode and already have a tag
return;
}
addTag(e); addTag(e);
} }
}; };
@ -81,7 +87,11 @@ const TagsInput: React.FC<TagsInputProps> = ({
}; };
const handleSelectTag = (tagToAdd: string) => { const handleSelectTag = (tagToAdd: string) => {
if (!tags.has(tagToAdd)) { if (singleValue) {
const newTags = new Set([tagToAdd]);
setTags(newTags);
onTagsChange?.(newTags);
} else if (!tags.has(tagToAdd)) {
const newTags = new Set(Array.from(tags).concat(tagToAdd)); const newTags = new Set(Array.from(tags).concat(tagToAdd));
setTags(newTags); setTags(newTags);
onTagsChange?.(newTags); onTagsChange?.(newTags);
@ -151,31 +161,45 @@ const TagsInput: React.FC<TagsInputProps> = ({
active active
tags={tags} tags={tags}
/> />
<input {(!singleValue || tags.size === 0) && (
type="text" <input
value={inputValue} type="text"
placeholder="Search for an option..." value={inputValue}
onChange={handleInputChange} placeholder={
onKeyDown={handleAddTag} singleValue && tags.size > 0
className="focus:outline-none bg-transparent" ? ""
autoFocus : "Search for an option..."
/> }
onChange={handleInputChange}
onKeyDown={handleAddTag}
className="focus:outline-none bg-transparent"
autoFocus
/>
)}
</div> </div>
<div className="flex rounded-b-md bg-white flex-col border-t border-gray-100 text-2xs font-medium text-gray-500 p-2"> <div className="flex rounded-b-md bg-white flex-col border-t border-gray-100 text-2xs font-medium text-gray-500 p-2">
<p className="capitalize"> <p className="capitalize">
Select an option or create one {singleValue && tags.size > 0
? "Only one option can be selected"
: "Select an option or create one"}
</p> </p>
<TagDropdown {(!singleValue || tags.size === 0) && (
handleDeleteTag={handleDeleteTagOption} <>
handleEditTag={handleEditTag} <TagDropdown
handleAdd={handleSelectTag} handleDeleteTag={
tags={filteredOptions} handleDeleteTagOption
/> }
{inputValue.length > 0 && ( handleEditTag={handleEditTag}
<CreateNewTagAction handleAdd={handleSelectTag}
input={inputValue} tags={filteredOptions}
addTag={addTag} />
/> {inputValue.length > 0 && (
<CreateNewTagAction
input={inputValue}
addTag={addTag}
/>
)}
</>
)} )}
</div> </div>
</div> </div>

View File

@ -8,7 +8,7 @@ export interface Tags {
export const TagsArray = ({ tags, handleDelete, active = false }: Tags) => { export const TagsArray = ({ tags, handleDelete, active = false }: Tags) => {
return ( return (
<div className="flex ml-2 flex-wrap gap-2 items-center min-h-[24px] min-w-[100px] rounded-md hover:bg-gray-100 p-1"> <div className="flex flex-wrap gap-2 items-center min-h-[24px] min-w-[100px] rounded-md hover:bg-gray-100 p-1">
{Array.from(tags).length > 0 ? ( {Array.from(tags).length > 0 ? (
Array.from(tags).map((tag, index) => { Array.from(tags).map((tag, index) => {
return ( return (