-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added clients table to company dashboard
- Loading branch information
1 parent
2645397
commit 3db12cf
Showing
7 changed files
with
351 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
"use client"; | ||
|
||
import * as React from "react"; | ||
import { | ||
type ColumnDef, | ||
type ColumnFiltersState, | ||
type SortingState, | ||
type VisibilityState, | ||
flexRender, | ||
getCoreRowModel, | ||
getFilteredRowModel, | ||
getPaginationRowModel, | ||
getSortedRowModel, | ||
useReactTable | ||
} from "@tanstack/react-table"; | ||
import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react"; | ||
|
||
import { Button } from "@/components/ui/button"; | ||
import { Checkbox } from "@/components/ui/checkbox"; | ||
import { | ||
DropdownMenu, | ||
DropdownMenuCheckboxItem, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuLabel, | ||
DropdownMenuTrigger | ||
} from "@/components/ui/dropdown-menu"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; | ||
import type { User } from "@/types"; | ||
import { getAccessToken, getAllUsers } from "@/lib/authActions"; | ||
|
||
const columns: Array<ColumnDef<User>> = [ | ||
{ | ||
id: "select", | ||
header: ({ table }) => ( | ||
<Checkbox | ||
checked={table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && "indeterminate")} | ||
onCheckedChange={(value) => { | ||
table.toggleAllPageRowsSelected(value as boolean); | ||
}} | ||
aria-label="Select all" | ||
/> | ||
), | ||
cell: ({ row }) => ( | ||
<Checkbox | ||
checked={row.getIsSelected()} | ||
onCheckedChange={(value) => { | ||
row.toggleSelected(value as boolean); | ||
}} | ||
aria-label="Select row" | ||
/> | ||
), | ||
enableSorting: false, | ||
enableHiding: false | ||
}, | ||
{ | ||
accessorKey: "name", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => { | ||
column.toggleSorting(column.getIsSorted() === "asc"); | ||
}}> | ||
Name | ||
<ArrowUpDown className="ml-2 size-4" /> | ||
</Button> | ||
); | ||
} | ||
}, | ||
{ | ||
accessorKey: "email", | ||
header: ({ column }) => { | ||
return ( | ||
<Button | ||
variant="ghost" | ||
onClick={() => { | ||
column.toggleSorting(column.getIsSorted() === "asc"); | ||
}}> | ||
<ArrowUpDown className="ml-2 size-4" /> | ||
</Button> | ||
); | ||
} | ||
}, | ||
{ | ||
id: "actions", | ||
enableHiding: false, | ||
cell: ({ row }) => { | ||
const user = row.original; | ||
|
||
return ( | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button variant="ghost" className="size-8 p-0"> | ||
<span className="sr-only">Open menu</span> | ||
<MoreHorizontal className="size-4" /> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent align="end"> | ||
<DropdownMenuLabel>Actions</DropdownMenuLabel> | ||
<DropdownMenuItem | ||
onClick={() => { | ||
void navigator.clipboard.writeText(user.id.toString()); | ||
}}> | ||
Copy user ID | ||
</DropdownMenuItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
); | ||
} | ||
} | ||
]; | ||
|
||
export function UsersTable(): React.ReactElement { | ||
const [users, setUsers] = React.useState<User[]>([]); | ||
const [sorting, setSorting] = React.useState<SortingState>([]); | ||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]); | ||
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({}); | ||
const [rowSelection, setRowSelection] = React.useState({}); | ||
|
||
React.useEffect(() => { | ||
const fetchUsers = async (): Promise<void> => { | ||
const fetchedUsers = await getAllUsers(await getAccessToken()); | ||
setUsers(fetchedUsers); | ||
}; | ||
void fetchUsers(); | ||
}, []); | ||
|
||
const table = useReactTable({ | ||
data: users, | ||
columns, | ||
onSortingChange: setSorting, | ||
onColumnFiltersChange: setColumnFilters, | ||
getCoreRowModel: getCoreRowModel(), | ||
getPaginationRowModel: getPaginationRowModel(), | ||
getSortedRowModel: getSortedRowModel(), | ||
getFilteredRowModel: getFilteredRowModel(), | ||
onColumnVisibilityChange: setColumnVisibility, | ||
onRowSelectionChange: setRowSelection, | ||
state: { | ||
sorting, | ||
columnFilters, | ||
columnVisibility, | ||
rowSelection | ||
} | ||
}); | ||
|
||
return ( | ||
<div className="w-full text-foreground"> | ||
<div className="flex items-center py-4"> | ||
<Input | ||
placeholder="Filter by name..." | ||
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""} | ||
onChange={(event) => { | ||
table.getColumn("name")?.setFilterValue(event.target.value); | ||
}} | ||
className="max-w-sm" | ||
/> | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button variant="outline" className="ml-auto"> | ||
Columns <ChevronDown className="ml-2 size-4" /> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent align="end"> | ||
{table | ||
.getAllColumns() | ||
.filter((column) => column.getCanHide()) | ||
.map((column) => { | ||
return ( | ||
<DropdownMenuCheckboxItem | ||
key={column.id} | ||
className="capitalize" | ||
checked={column.getIsVisible()} | ||
onCheckedChange={(value) => { | ||
column.toggleVisibility(Boolean(value)); | ||
}}> | ||
{column.id} | ||
</DropdownMenuCheckboxItem> | ||
); | ||
})} | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
</div> | ||
<div className="rounded-md border border-border"> | ||
<Table> | ||
<TableHeader> | ||
{table.getHeaderGroups().map((headerGroup) => ( | ||
<TableRow key={headerGroup.id}> | ||
{headerGroup.headers.map((header) => { | ||
return ( | ||
<TableHead key={header.id}> | ||
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} | ||
</TableHead> | ||
); | ||
})} | ||
</TableRow> | ||
))} | ||
</TableHeader> | ||
<TableBody> | ||
{table.getRowModel().rows?.length !== 0 ? ( | ||
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> | ||
<div className="flex items-center justify-end space-x-2 py-4"> | ||
<div className="flex-1 text-sm text-muted-foreground"> | ||
{table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length} row(s) | ||
selected. | ||
</div> | ||
<div className="space-x-2"> | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
onClick={() => { | ||
table.previousPage(); | ||
}} | ||
disabled={!table.getCanPreviousPage()}> | ||
Previous | ||
</Button> | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
onClick={() => { | ||
table.nextPage(); | ||
}} | ||
disabled={!table.getCanNextPage()}> | ||
Next | ||
</Button> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.