Added status filter

This commit is contained in:
Khalim Conn-Kowlessar 2023-07-24 18:42:54 +01:00
parent 47eda2f336
commit 6f8e7b256e
5 changed files with 147 additions and 77 deletions

View file

@ -17,6 +17,9 @@ export default function StatusBadge({
}) {
const statusConfig = statusColor[status];
console.log("status");
console.log(status);
return (
<HoverCard>
<HoverCardTrigger>
@ -72,34 +75,34 @@ const statusColor: {
hoverText: "This portfolio has begun works",
propertyHoverText: "This property has begun works",
},
"completion; status 'on track'": {
"completion; status: on track": {
class: "bg-emerald-500 hover:bg-emerald-500",
text: "on track",
hoverText: "This portfolio is on track to be completed on time",
propertyHoverText: "This property is on track to be completed on time",
},
"completion; status 'delayed'": {
"completion; status: delayed": {
class: "bg-orange-400 hover:bg-orange-400",
text: "delayed",
hoverText:
"This portfolio is delayed and one or more properties require attention",
propertyHoverText: "This property is delayed and requires attention",
},
"completion; status 'at risk'": {
"completion; status: at risk": {
class: "bg-red-400 hover:bg-red-400",
text: "at risk",
hoverText:
"This portfolio is at risk. One or more properties require attention",
propertyHoverText: "This property is at risk and requires attention",
},
"completion; status 'completed'": {
"completion; status: completed": {
class: "bg-gray-400 hover:bg-gray-400",
text: "completed",
hoverText: "This portfolio has been completed",
propertyHoverText: "This property has been completed",
},
"needs review": {
class: "bg-emerald-300 hover:bg-emerald-300",
class: "bg-indigo-600 hover:bg-indigo-400",
text: "needs review",
hoverText: "The works in this portfolio has been completed and need review",
propertyHoverText: "The works on this property have been completed",

View file

@ -2,9 +2,11 @@
import {
ColumnDef,
ColumnFiltersState,
SortingState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
@ -22,6 +24,7 @@ import { useState } from "react";
import { DataTablePagination } from "./propertyTablePagination";
import { Property } from "./propertyTableColumns";
import React from "react";
import { Input } from "@/app/shadcn_components/ui/input";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<Property>[];
@ -55,6 +58,9 @@ export default function DataTable<TData, TValue>({
const [tableData, setTableData] = useState<Property[]>(data);
const [offset, setOffset] = useState(0);
const [currentPageIndex, setCurrentPageIndex] = useState(0);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
// add page change handlers for DataTablePagination
const loadPaginatedData = () => {
@ -76,63 +82,85 @@ export default function DataTable<TData, TValue>({
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onColumnFiltersChange: setColumnFilters,
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
pagination: { pageIndex: currentPageIndex, pageSize: 7 },
columnFilters,
},
});
return (
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id} className="h-14 py-4">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
<>
<div className="flex items-center py-4">
<Input
placeholder="Filter address"
value={(table.getColumn("address")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("address")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id} className="h-14 py-4">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<DataTablePagination
table={table}
loadPaginatedData={loadPaginatedData}
currentPageIndex={currentPageIndex}
setCurrentPageIndex={setCurrentPageIndex}
/>
</div>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="mb-2">
<DataTablePagination
table={table}
loadPaginatedData={loadPaginatedData}
currentPageIndex={currentPageIndex}
setCurrentPageIndex={setCurrentPageIndex}
/>
</div>
</div>
</>
);
}

View file

@ -1,6 +1,6 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { Column, ColumnDef } from "@tanstack/react-table";
import {
DropdownMenu,
DropdownMenuContent,
@ -13,7 +13,10 @@ import { Button } from "@/app/shadcn_components/ui/button";
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import StatusBadge from "@/app/components/StatusBadge";
import { HomeIcon } from "@heroicons/react/20/solid";
import { FunnelIcon } from "@heroicons/react/24/outline";
import { formatNumber } from "@/app/utils";
import { cn } from "@/lib/utils";
import { PortfolioStatus } from "@/app/db/schema/portfolio";
export type Property = {
id: number;
@ -26,6 +29,51 @@ export type Property = {
cost: number;
};
interface DataTableColumnHeaderProps<TData, TValue>
extends React.HTMLAttributes<HTMLDivElement> {
column: Column<TData, TValue>;
title: string;
}
export function DataTableFilterHeader<TData, TValue>({
column,
title,
className,
}: DataTableColumnHeaderProps<TData, TValue>) {
if (!column.getCanSort()) {
return <div className={cn(className)}>{title}</div>;
}
return (
<div className={cn("flex items-center space-x-2", className)}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
className="-ml-3 h-8 data-[state=open]:bg-accent"
>
<span>{title}</span>
<FunnelIcon className="ml-2 h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
{PortfolioStatus.map((status) => (
<DropdownMenuItem
key={status}
onClick={() => {
column.setFilterValue(status);
}}
>
{<StatusBadge status={status} isProperty={false} />}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}
export const columns: ColumnDef<Property>[] = [
{
accessorKey: "address",
@ -64,7 +112,14 @@ export const columns: ColumnDef<Property>[] = [
},
{
accessorKey: "status",
header: () => <div className="flex justify-center">Status</div>,
// header: () => <div className="flex justify-center">Status</div>,
header: ({ column }) => {
return (
<div className="flex justify-center">
<DataTableFilterHeader column={column} title="Status" />
</div>
);
},
cell: ({ row }) => {
const status = row.getValue("status") ?? "";
@ -144,17 +199,11 @@ export const columns: ColumnDef<Property>[] = [
</a>
</DropdownMenuItem>
<DropdownMenuItem
className="text-gray-700 cursor-pointer"
// disabled={true}
>
<DropdownMenuItem className="text-gray-700 cursor-pointer">
Settings
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-red-500 focus:text-red-700 cursor-pointer"
// disabled={true}
>
<DropdownMenuItem className="text-red-500 focus:text-red-700 cursor-pointer">
Delete Property
</DropdownMenuItem>
</DropdownMenuContent>
@ -162,6 +211,5 @@ export const columns: ColumnDef<Property>[] = [
</div>
);
},
meta: {},
},
];

View file

@ -54,7 +54,6 @@ export function DataTablePagination<TData>({
className="hidden h-8 w-8 p-0 lg:flex"
onClick={() => {
setCurrentPageIndex(0);
// table.setPageIndex(0);
}}
disabled={!table.getCanPreviousPage()}
>
@ -66,7 +65,6 @@ export function DataTablePagination<TData>({
className="h-8 w-8 p-0"
onClick={() => {
setCurrentPageIndex(currentPageIndex - 1);
// table.previousPage();
}}
disabled={!table.getCanPreviousPage()}
>
@ -79,7 +77,6 @@ export function DataTablePagination<TData>({
onClick={() => {
requestMoreData();
setCurrentPageIndex(currentPageIndex + 1);
// table.nextPage();
}}
disabled={!table.getCanNextPage()}
>

View file

@ -1,10 +1,4 @@
import { PencilSquareIcon, HomeIcon } from "@heroicons/react/24/outline";
import { formatNumber } from "@/app/utils";
import Link from "next/link";
import { ArrowRightCircleIcon } from "@heroicons/react/20/solid";
import { Badge } from "@/app/shadcn_components/ui/badge";
import type { PortfolioStatus } from "@/app/db/schema/portfolio";
import StatusBadge from "@/app/components/StatusBadge";
import { HomeIcon } from "@heroicons/react/24/outline";
import { getPortfolio } from "./utils";
import { Toolbar } from "@/app/components/portfolio/Toolbar";
import DataTable from "@/app/portfolio/[slug]/components/propertyTable";
@ -95,7 +89,7 @@ function SummaryBox({
const energySavingsFormatted = formatKwh(energySavings);
return (
<div className="p-6 bg-white rounded-lg shadow leading-relaxed">
<div className="p-6 bg-white rounded-lg leading-relaxed">
<h2 className="text-2xl font-bold mb-4 text-gray-700 text-center">
Portfolio Summary
</h2>