diff --git a/frontend/app/projects/[projectId]/folders/[folderId]/cases/page.tsx b/frontend/app/projects/[projectId]/folders/[folderId]/cases/page.tsx index 1ff50d2..d2ec5ca 100644 --- a/frontend/app/projects/[projectId]/folders/[folderId]/cases/page.tsx +++ b/frontend/app/projects/[projectId]/folders/[folderId]/cases/page.tsx @@ -4,6 +4,7 @@ import Config from "@/config/config"; const apiServer = Config.apiServer; import { Listbox, ListboxItem } from "@nextui-org/react"; import { useRouter } from "next/navigation"; +import TestCaseTable from "./test-case-table"; /** * fetch folder records @@ -56,7 +57,7 @@ export default function Page({ return ( <> - + {/* {cases.map((testCase, index) => ( ))} - + */} + > ); } diff --git a/frontend/app/projects/[projectId]/folders/[folderId]/cases/test-case-table.tsx b/frontend/app/projects/[projectId]/folders/[folderId]/cases/test-case-table.tsx new file mode 100644 index 0000000..be80fdb --- /dev/null +++ b/frontend/app/projects/[projectId]/folders/[folderId]/cases/test-case-table.tsx @@ -0,0 +1,239 @@ +import { useState, useMemo, useEffect, useCallback } from "react"; +import { + Table, + TableHeader, + TableColumn, + TableBody, + TableRow, + TableCell, + Button, + DropdownTrigger, + Dropdown, + DropdownMenu, + DropdownItem, + Selection, + SortDescriptor, +} from "@nextui-org/react"; +import { Plus, MoreVertical, ChevronDown } from "lucide-react"; + +function capitalize(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +const columns = [ + { name: "ID", uid: "id", sortable: true }, + { name: "TITLE", uid: "title", sortable: true }, + { name: "PRIORITY", uid: "priority", sortable: true }, + { name: "ACTIONS", uid: "actions" }, +]; + +const INITIAL_VISIBLE_COLUMNS = ["id", "title", "priority", "actions"]; + +type Case = { + id: number; + title: string; + state: number; + priority: number; + type: number; + automationStatus: number; + description: string; + template: number; + preConditions: string; + expectedResults: string; + folderId: number; + createdAt: string; + updatedAt: string; +}; + +export default function TestCaseTable({ cases }) { + const [filterValue, setFilterValue] = useState(""); + const [selectedKeys, setSelectedKeys] = useState(new Set([])); + const [visibleColumns, setVisibleColumns] = useState( + new Set(INITIAL_VISIBLE_COLUMNS) + ); + const [statusFilter, setStatusFilter] = useState("all"); + const [sortDescriptor, setSortDescriptor] = useState({ + column: "id", + direction: "ascending", + }); + + const hasSearchFilter = Boolean(filterValue); + + const headerColumns = useMemo(() => { + if (visibleColumns === "all") { + return columns; + } + + return columns.filter((column) => + Array.from(visibleColumns).includes(column.uid) + ); + }, [visibleColumns]); + + const filteredItems = useMemo(() => { + let filteredCases = [...cases]; + + if (hasSearchFilter) { + filteredCases = filteredCases.filter((itr) => + itr.title.toLowerCase().includes(filterValue.toLowerCase()) + ); + } + if (statusFilter !== "all") { + filteredCases = filteredCases.filter((itr) => + Array.from(statusFilter).includes(itr.state) + ); + } + + return filteredCases; + }, [cases, filterValue, statusFilter]); + + const sortedItems = useMemo(() => { + return [...filteredItems].sort((a: Case, b: Case) => { + const first = a[sortDescriptor.column as keyof Case] as number; + const second = b[sortDescriptor.column as keyof Case] as number; + const cmp = first < second ? -1 : first > second ? 1 : 0; + + return sortDescriptor.direction === "descending" ? -cmp : cmp; + }); + }, [sortDescriptor, filteredItems]); + + const renderCell = useCallback((testCase: Case, columnKey: Key) => { + const cellValue = testCase[columnKey as keyof Case]; + + switch (columnKey) { + case "id": + return {cellValue}; + case "title": + return {cellValue}; + case "actions": + return ( + + + + + + + + + View + Edit + Delete + + + + ); + default: + return cellValue; + } + }, []); + + const topContent = useMemo(() => { + return ( + + + + + + } + size="sm" + variant="flat" + > + Columns + + + + {columns.map((column) => ( + + {capitalize(column.name)} + + ))} + + + } + size="sm" + > + Add New + + + + + ); + }, [ + filterValue, + statusFilter, + visibleColumns, + cases.length, + hasSearchFilter, + ]); + + const classNames = useMemo( + () => ({ + wrapper: ["max-w-3xl"], + table: ["border-t-1"], + th: ["bg-transparent", "text-default-500", "border-b", "border-divider"], + td: [ + // changing the rows border radius + // first + "group-data-[first=true]:first:before:rounded-none", + "group-data-[first=true]:last:before:rounded-none", + // middle + "group-data-[middle=true]:before:rounded-none", + // last + "group-data-[last=true]:first:before:rounded-none", + "group-data-[last=true]:last:before:rounded-none", + ], + }), + [] + ); + + return ( + + + {(column) => ( + + {column.name} + + )} + + + {(item) => ( + + {(columnKey) => ( + {renderCell(item, columnKey)} + )} + + )} + + + ); +}