added the filter box and edited the table action to add the filter UI

This commit is contained in:
apcodes 2024-04-19 16:49:30 -04:00
parent d689e22dd8
commit 656edbfac7
4 changed files with 112 additions and 14 deletions

View File

@ -0,0 +1,73 @@
// FilterBox.tsx
import { useState } from "react";
const mockTags = ["food relief", "period poverty", "nutrition education"];
export const FilterBox = () => {
const [selectedTags, setSelectedTags] = useState<string[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const handleTagChange = (tag: string) => {
setSelectedTags((prevTags) =>
prevTags.includes(tag)
? prevTags.filter((t) => t !== tag)
: [...prevTags, tag]
);
};
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(e.target.value);
};
const renderSelectedTags = () =>
selectedTags.map((tag) => (
<div
key={tag}
className="bg-blue-100 text-blue-800 px-2 py-1 rounded-md flex items-center mr-2"
>
<span>{tag}</span>
<span
className="ml-2 cursor-pointer"
onClick={() => handleTagChange(tag)}
>
&times;
</span>
</div>
));
return (
<div className="bg-white border border-gray-300 rounded-md p-2">
<div className="mb-2">
<span className="font-semibold">Tags contains:</span>
</div>
<div className="flex flex-wrap mb-2 px-2 py-1 border border-gray-300 rounded w-full">
{selectedTags.length > 0 && renderSelectedTags()}
<input
type="text"
value={searchTerm}
onChange={handleSearchChange}
placeholder="Search tags..."
/>
</div>
<div className="max-h-48 overflow-y-auto">
{mockTags
.filter((tag) =>
tag.toLowerCase().includes(searchTerm.toLowerCase())
)
.map((tag) => (
<div key={tag} className="flex items-center">
<input
type="checkbox"
checked={selectedTags.includes(tag)}
onChange={() => handleTagChange(tag)}
className="mr-2"
/>
<label>{tag}</label>
</div>
))}
</div>
</div>
);
};

View File

@ -113,6 +113,7 @@ export const Table = () => {
}
// TODO: Filtering
// TODO: Sorting
const table = useReactTable({

View File

@ -1,46 +1,64 @@
/** The actions (Filter, Sort, Search) at the top of the table. */
// TableAction.tsx
import { MagnifyingGlassIcon } from "@heroicons/react/24/solid";
import { ChangeEventHandler, Dispatch, FunctionComponent, SetStateAction, useRef, useState } from "react";
import { ChangeEventHandler, FunctionComponent, useRef, useState } from "react";
import { FilterBox } from "../../components/FilterBox";
type TableActionProps = {
query: string
handleChange: ChangeEventHandler<HTMLInputElement>
}
query: string;
handleChange: ChangeEventHandler<HTMLInputElement>;
};
export const TableAction: FunctionComponent<TableActionProps> = ({query, handleChange}) => {
export const TableAction: FunctionComponent<TableActionProps> = ({
query,
handleChange,
}) => {
const searchInput = useRef<HTMLInputElement>(null);
const [searchActive, setSearchActive] = useState(false);
const [showFilterBox, setShowFilterBox] = useState(false);
const activateSearch = () => {
setSearchActive(true);
if (searchInput.current === null) { return; }
if (searchInput.current === null) {
return;
}
searchInput.current.focus();
searchInput.current.addEventListener("focusout", () => {
if (searchInput.current?.value.trim() === "") {
searchInput.current.value = "";
deactivateSearch();
}
})
}
});
};
const deactivateSearch = () => setSearchActive(false);
const toggleFilterBox = () => setShowFilterBox((prev) => !prev);
return (
<div className="w-auto flex flex-row gap-x-0.5 items-center justify-between text-xs font-medium text-gray-500 p-2">
<span className="p-1 rounded hover:bg-gray-100">Filter</span>
<span
className="p-1 rounded hover:bg-gray-100"
onClick={toggleFilterBox}
>
Filter
</span>
{showFilterBox && <FilterBox />}
<span className="p-1 rounded hover:bg-gray-100">Sort</span>
<span className="p-1 rounded hover:bg-gray-100" onClick={() => activateSearch()}>
<span className="p-1 rounded hover:bg-gray-100" onClick={activateSearch}>
<MagnifyingGlassIcon className="w-4 h-4 inline" />
</span>
<input
ref={searchInput}
className={"outline-none transition-all duration-300 " + (searchActive ? "w-48" : "w-0")}
className={
"outline-none transition-all duration-300 " +
(searchActive ? "w-48" : "w-0")
}
type="text"
name="search"
placeholder="Type to search..."
value={query ?? ""}
onChange={handleChange}
/>
/>
</div>
);
};
};

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "compass",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}