├── .eslintrc.json
├── app
├── favicon.ico
├── page.tsx
├── users
│ ├── definitions.ts
│ ├── userSchema.ts
│ ├── data-table-view-options.tsx
│ ├── data-table-toolbar.tsx
│ ├── data-table-row-actions.tsx
│ ├── data-table-column-header.tsx
│ ├── columns.tsx
│ ├── data-table.tsx
│ ├── data-table-pagination.tsx
│ ├── data-table-faceted-filter.tsx
│ └── users.ts
├── layout.tsx
└── globals.css
├── next.config.mjs
├── postcss.config.js
├── lib
└── utils.ts
├── types.d.ts
├── components.json
├── .gitignore
├── public
├── vercel.svg
└── next.svg
├── prettier.config.js
├── tsconfig.json
├── notes.md
├── components
└── ui
│ ├── separator.tsx
│ ├── input.tsx
│ ├── badge.tsx
│ ├── popover.tsx
│ ├── button.tsx
│ ├── table.tsx
│ ├── dialog.tsx
│ ├── command.tsx
│ ├── select.tsx
│ └── dropdown-menu.tsx
├── package.json
├── README.md
└── tailwind.config.ts
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EliteArmy/shadcn-tables-example/HEAD/app/favicon.ico
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/types.d.ts:
--------------------------------------------------------------------------------
1 | type User = {
2 | id: string;
3 | userName: string;
4 | phone: string;
5 | email: string;
6 | location: string;
7 | role: "client" | "provider";
8 | status: "active" | "inactive";
9 | image: string;
10 | rtn?: string;
11 | otherInformation?: string;
12 |
13 | createdAt?: date;
14 | updatedAt?: date;
15 | };
16 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "default",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.ts",
8 | "css": "app/globals.css",
9 | "baseColor": "slate",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils"
16 | }
17 | }
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { columns } from "@/app/users/columns";
2 | import DataTable from "@/app/users/data-table";
3 | import { users } from "@/app/users/users";
4 |
5 | export default async function Home() {
6 | // This is where you would fetch external data:
7 | // const exampleExternalData = await fetchExternalDataFunction();
8 |
9 | // In Our example we use local data
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/app/users/definitions.ts:
--------------------------------------------------------------------------------
1 | import { CheckCircledIcon, CrossCircledIcon } from "@radix-ui/react-icons";
2 |
3 | export const usersStatus = [
4 | {
5 | value: "active",
6 | label: "Active",
7 | icon: CheckCircledIcon,
8 | },
9 | {
10 | value: "inactive",
11 | label: "Inactive",
12 | icon: CrossCircledIcon,
13 | },
14 | ];
15 |
16 | export const usersRole = [
17 | {
18 | value: "client",
19 | label: "Client",
20 | },
21 | {
22 | value: "provider",
23 | label: "Provider",
24 | },
25 | ];
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { Inter } from "next/font/google";
3 |
4 | import "./globals.css";
5 |
6 | const inter = Inter({ subsets: ["latin"] });
7 |
8 | export const metadata: Metadata = {
9 | title: "Create Next App",
10 | description: "Generated by create next app",
11 | };
12 |
13 | export default function RootLayout({
14 | children,
15 | }: Readonly<{
16 | children: React.ReactNode;
17 | }>) {
18 | return (
19 |
20 | {children}
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: ["@ianvs/prettier-plugin-sort-imports"],
3 | singleQuote: false,
4 | semi: true,
5 | bracketSameLine: true,
6 | printWidth: 100,
7 | trailingComma: "es5",
8 | importOrder: [
9 | "^(react/(.*)$)|^(react$)",
10 | "^(next/(.*)$)|^(next$)",
11 | "",
12 | "",
13 | "^types$",
14 | "^@/env(.*)$",
15 | "^@/types/(.*)$",
16 | "^@/config/(.*)$",
17 | "^@/lib/(.*)$",
18 | "^@/hooks/(.*)$",
19 | "^@/components/ui/(.*)$",
20 | "^@/components/(.*)$",
21 | "^@/styles/(.*)$",
22 | "^@/app/(.*)$",
23 | "",
24 | "^[./]",
25 | ],
26 | };
27 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/notes.md:
--------------------------------------------------------------------------------
1 | documentation: https://nextjs.org/docs
2 | npx create-next-app@latest
3 |
4 | documentation: https://ui.shadcn.com/docs/components/data-table
5 | npx shadcn-ui@latest init
6 |
7 | npx shadcn-ui@latest add table
8 | npx shadcn-ui@latest add badge
9 | npx shadcn-ui@latest add button
10 | npx shadcn-ui@latest add command
11 | npx shadcn-ui@latest add popover
12 | npx shadcn-ui@latest add separator
13 | npx shadcn-ui@latest add dropdown-menu
14 | npx shadcn-ui@latest add input
15 | npx shadcn-ui@latest add select
16 |
17 | npm install @radix-ui/react-icons
18 |
19 | documentation: https://tanstack.com/table/latest/docs/introduction
20 | npm install @tanstack/react-table
21 |
22 | documentatino: https://zod.dev
23 | npm install zod
24 |
--------------------------------------------------------------------------------
/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SeparatorPrimitive from "@radix-ui/react-separator"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Separator = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(
12 | (
13 | { className, orientation = "horizontal", decorative = true, ...props },
14 | ref
15 | ) => (
16 |
27 | )
28 | )
29 | Separator.displayName = SeparatorPrimitive.Root.displayName
30 |
31 | export { Separator }
32 |
--------------------------------------------------------------------------------
/app/users/userSchema.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | export enum Role {
4 | "provider" = "provider",
5 | "client" = "client",
6 | }
7 | export enum UserStatus {
8 | "active" = "active",
9 | "inactive" = "inactive",
10 | }
11 |
12 | export const UserSchema = z.object({
13 | id: z.string(),
14 |
15 | userName: z.string({}).trim().min(5),
16 |
17 | phone: z.string({}).trim().min(8),
18 |
19 | email: z.string({}).email().trim().or(z.literal("")).optional(),
20 |
21 | location: z.string({}).trim().or(z.literal("")).optional(),
22 |
23 | role: z.nativeEnum(Role, {}),
24 |
25 | status: z.nativeEnum(UserStatus, {}),
26 |
27 | otherInformation: z.string({}).trim().or(z.literal("")).optional(),
28 |
29 | rtn: z.string({}).trim().or(z.literal("")).optional(),
30 |
31 | image: z.string().or(z.literal("")).optional(),
32 |
33 | createdAt: z.date().optional(),
34 | updatedAt: z.date().optional(),
35 | });
36 |
--------------------------------------------------------------------------------
/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | )
21 | }
22 | )
23 | Input.displayName = "Input"
24 |
25 | export { Input }
26 |
--------------------------------------------------------------------------------
/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva, type VariantProps } from "class-variance-authority"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | }
24 | )
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | )
34 | }
35 |
36 | export { Badge, badgeVariants }
37 |
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shadcn-tables-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@radix-ui/react-dialog": "^1.0.5",
13 | "@radix-ui/react-dropdown-menu": "^2.0.6",
14 | "@radix-ui/react-icons": "^1.3.0",
15 | "@radix-ui/react-popover": "^1.0.7",
16 | "@radix-ui/react-select": "^2.0.0",
17 | "@radix-ui/react-separator": "^1.0.3",
18 | "@radix-ui/react-slot": "^1.0.2",
19 | "@tanstack/react-table": "^8.13.2",
20 | "class-variance-authority": "^0.7.0",
21 | "clsx": "^2.1.0",
22 | "cmdk": "^1.0.0",
23 | "lucide-react": "^0.358.0",
24 | "next": "14.1.3",
25 | "next-themes": "^0.3.0",
26 | "react": "^18",
27 | "react-dom": "^18",
28 | "tailwind-merge": "^2.2.1",
29 | "tailwindcss-animate": "^1.0.7",
30 | "zod": "^3.22.4"
31 | },
32 | "devDependencies": {
33 | "@ianvs/prettier-plugin-sort-imports": "^4.2.1",
34 | "@types/node": "^20",
35 | "@types/react": "^18",
36 | "@types/react-dom": "^18",
37 | "autoprefixer": "^10.0.1",
38 | "eslint": "^8",
39 | "eslint-config-next": "14.1.3",
40 | "postcss": "^8",
41 | "tailwindcss": "^3.3.0",
42 | "typescript": "^5"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as PopoverPrimitive from "@radix-ui/react-popover"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Popover = PopoverPrimitive.Root
9 |
10 | const PopoverTrigger = PopoverPrimitive.Trigger
11 |
12 | const PopoverContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
16 |
17 |
27 |
28 | ))
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName
30 |
31 | export { Popover, PopoverTrigger, PopoverContent }
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 |
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 |
19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/app/users/data-table-view-options.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
4 | import { MixerHorizontalIcon } from "@radix-ui/react-icons";
5 | import { Table } from "@tanstack/react-table";
6 |
7 | import { Button } from "@/components/ui/button";
8 | import {
9 | DropdownMenu,
10 | DropdownMenuCheckboxItem,
11 | DropdownMenuContent,
12 | DropdownMenuLabel,
13 | DropdownMenuSeparator,
14 | } from "@/components/ui/dropdown-menu";
15 |
16 | interface DataTableViewOptionsProps {
17 | table: Table;
18 | }
19 |
20 | export function DataTableViewOptions({ table }: DataTableViewOptionsProps) {
21 | return (
22 |
23 |
24 |
28 |
29 |
30 | {"Edit Columns"}
31 |
32 | {table
33 | .getAllColumns()
34 | .filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide())
35 | .map((column) => {
36 | return (
37 | column.toggleVisibility(!!value)}>
42 | {column.id}
43 |
44 | );
45 | })}
46 |
47 |
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/app/users/data-table-toolbar.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Cross2Icon } from "@radix-ui/react-icons";
4 | import { Table } from "@tanstack/react-table";
5 |
6 | import { Button } from "@/components/ui/button";
7 | import { Input } from "@/components/ui/input";
8 | import { usersStatus } from "@/app/users/definitions";
9 |
10 | import { DataTableFacetedFilter } from "./data-table-faceted-filter";
11 | import { DataTableViewOptions } from "./data-table-view-options";
12 |
13 | interface DataTableToolbarProps {
14 | table: Table;
15 | }
16 |
17 | export function DataTableToolbar({ table }: DataTableToolbarProps) {
18 | const isFiltered = table.getState().columnFilters.length > 0;
19 |
20 | return (
21 |
22 |
23 | table.getColumn("userName")?.setFilterValue(event.target.value)}
27 | className="h-8 w-[150px] lg:w-[250px]"
28 | />
29 |
30 | {table.getColumn("status") && (
31 |
36 | )}
37 |
38 | {isFiltered && (
39 |
46 | )}
47 |
48 |
49 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 222.2 84% 4.9%;
9 |
10 | --card: 0 0% 100%;
11 | --card-foreground: 222.2 84% 4.9%;
12 |
13 | --popover: 0 0% 100%;
14 | --popover-foreground: 222.2 84% 4.9%;
15 |
16 | --primary: 222.2 47.4% 11.2%;
17 | --primary-foreground: 210 40% 98%;
18 |
19 | --secondary: 210 40% 96.1%;
20 | --secondary-foreground: 222.2 47.4% 11.2%;
21 |
22 | --muted: 210 40% 96.1%;
23 | --muted-foreground: 215.4 16.3% 46.9%;
24 |
25 | --accent: 210 40% 96.1%;
26 | --accent-foreground: 222.2 47.4% 11.2%;
27 |
28 | --destructive: 0 84.2% 60.2%;
29 | --destructive-foreground: 210 40% 98%;
30 |
31 | --border: 214.3 31.8% 91.4%;
32 | --input: 214.3 31.8% 91.4%;
33 | --ring: 222.2 84% 4.9%;
34 |
35 | --radius: 0.5rem;
36 | }
37 |
38 | .dark {
39 | --background: 222.2 84% 4.9%;
40 | --foreground: 210 40% 98%;
41 |
42 | --card: 222.2 84% 4.9%;
43 | --card-foreground: 210 40% 98%;
44 |
45 | --popover: 222.2 84% 4.9%;
46 | --popover-foreground: 210 40% 98%;
47 |
48 | --primary: 210 40% 98%;
49 | --primary-foreground: 222.2 47.4% 11.2%;
50 |
51 | --secondary: 217.2 32.6% 17.5%;
52 | --secondary-foreground: 210 40% 98%;
53 |
54 | --muted: 217.2 32.6% 17.5%;
55 | --muted-foreground: 215 20.2% 65.1%;
56 |
57 | --accent: 217.2 32.6% 17.5%;
58 | --accent-foreground: 210 40% 98%;
59 |
60 | --destructive: 0 62.8% 30.6%;
61 | --destructive-foreground: 210 40% 98%;
62 |
63 | --border: 217.2 32.6% 17.5%;
64 | --input: 217.2 32.6% 17.5%;
65 | --ring: 212.7 26.8% 83.9%;
66 | }
67 | }
68 |
69 | @layer base {
70 | * {
71 | @apply border-border;
72 | }
73 | body {
74 | @apply bg-background text-foreground;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default: "bg-primary text-primary-foreground hover:bg-primary/90",
13 | destructive:
14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15 | outline:
16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17 | secondary:
18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19 | ghost: "hover:bg-accent hover:text-accent-foreground",
20 | link: "text-primary underline-offset-4 hover:underline",
21 | },
22 | size: {
23 | default: "h-10 px-4 py-2",
24 | sm: "h-9 rounded-md px-3",
25 | lg: "h-11 rounded-md px-8",
26 | icon: "h-10 w-10",
27 | },
28 | },
29 | defaultVariants: {
30 | variant: "default",
31 | size: "default",
32 | },
33 | }
34 | )
35 |
36 | export interface ButtonProps
37 | extends React.ButtonHTMLAttributes,
38 | VariantProps {
39 | asChild?: boolean
40 | }
41 |
42 | const Button = React.forwardRef(
43 | ({ className, variant, size, asChild = false, ...props }, ref) => {
44 | const Comp = asChild ? Slot : "button"
45 | return (
46 |
51 | )
52 | }
53 | )
54 | Button.displayName = "Button"
55 |
56 | export { Button, buttonVariants }
57 |
--------------------------------------------------------------------------------
/app/users/data-table-row-actions.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | // import { UserSchema } from "@/app/users/userSchema";
4 | import Link from "next/link";
5 | import { DotsHorizontalIcon } from "@radix-ui/react-icons";
6 | import { Row } from "@tanstack/react-table";
7 | import { Eye, Pencil, Trash2 } from "lucide-react";
8 |
9 | import { Button } from "@/components/ui/button";
10 | import {
11 | DropdownMenu,
12 | DropdownMenuContent,
13 | DropdownMenuItem,
14 | DropdownMenuTrigger,
15 | } from "@/components/ui/dropdown-menu";
16 |
17 | interface DataTableRowActionsProps {
18 | row: Row;
19 | }
20 |
21 | export function DataTableRowActions({ row }: DataTableRowActionsProps) {
22 | // const user = UserSchema.parse(row.original);
23 | // console.log(user.id); // Note: use the id for any action (example: delete, view, edit)
24 |
25 | return (
26 |
27 |
28 |
32 |
33 |
34 |
35 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/app/users/data-table-column-header.tsx:
--------------------------------------------------------------------------------
1 | import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon, EyeNoneIcon } from "@radix-ui/react-icons";
2 | import { Column } from "@tanstack/react-table";
3 |
4 | import { cn } from "@/lib/utils";
5 | import { Button } from "@/components/ui/button";
6 | import {
7 | DropdownMenu,
8 | DropdownMenuContent,
9 | DropdownMenuItem,
10 | DropdownMenuSeparator,
11 | DropdownMenuTrigger,
12 | } from "@/components/ui/dropdown-menu";
13 |
14 | interface DataTableColumnHeaderProps extends React.HTMLAttributes {
15 | column: Column;
16 | title: string;
17 | }
18 |
19 | export function DataTableColumnHeader({
20 | column,
21 | title,
22 | className,
23 | }: DataTableColumnHeaderProps) {
24 | if (!column.getCanSort()) {
25 | return {title}
;
26 | }
27 |
28 | return (
29 |
30 |
31 |
32 |
42 |
43 |
44 | column.toggleSorting(false)}>
45 |
46 | {"Asc"}
47 |
48 | column.toggleSorting(true)}>
49 |
50 | {"Desc"}
51 |
52 |
53 | column.toggleVisibility(false)}>
54 |
55 | {"Hide"}
56 |
57 |
58 |
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss"
2 |
3 | const config = {
4 | darkMode: ["class"],
5 | content: [
6 | './pages/**/*.{ts,tsx}',
7 | './components/**/*.{ts,tsx}',
8 | './app/**/*.{ts,tsx}',
9 | './src/**/*.{ts,tsx}',
10 | ],
11 | prefix: "",
12 | theme: {
13 | container: {
14 | center: true,
15 | padding: "2rem",
16 | screens: {
17 | "2xl": "1400px",
18 | },
19 | },
20 | extend: {
21 | colors: {
22 | border: "hsl(var(--border))",
23 | input: "hsl(var(--input))",
24 | ring: "hsl(var(--ring))",
25 | background: "hsl(var(--background))",
26 | foreground: "hsl(var(--foreground))",
27 | primary: {
28 | DEFAULT: "hsl(var(--primary))",
29 | foreground: "hsl(var(--primary-foreground))",
30 | },
31 | secondary: {
32 | DEFAULT: "hsl(var(--secondary))",
33 | foreground: "hsl(var(--secondary-foreground))",
34 | },
35 | destructive: {
36 | DEFAULT: "hsl(var(--destructive))",
37 | foreground: "hsl(var(--destructive-foreground))",
38 | },
39 | muted: {
40 | DEFAULT: "hsl(var(--muted))",
41 | foreground: "hsl(var(--muted-foreground))",
42 | },
43 | accent: {
44 | DEFAULT: "hsl(var(--accent))",
45 | foreground: "hsl(var(--accent-foreground))",
46 | },
47 | popover: {
48 | DEFAULT: "hsl(var(--popover))",
49 | foreground: "hsl(var(--popover-foreground))",
50 | },
51 | card: {
52 | DEFAULT: "hsl(var(--card))",
53 | foreground: "hsl(var(--card-foreground))",
54 | },
55 | },
56 | borderRadius: {
57 | lg: "var(--radius)",
58 | md: "calc(var(--radius) - 2px)",
59 | sm: "calc(var(--radius) - 4px)",
60 | },
61 | keyframes: {
62 | "accordion-down": {
63 | from: { height: "0" },
64 | to: { height: "var(--radix-accordion-content-height)" },
65 | },
66 | "accordion-up": {
67 | from: { height: "var(--radix-accordion-content-height)" },
68 | to: { height: "0" },
69 | },
70 | },
71 | animation: {
72 | "accordion-down": "accordion-down 0.2s ease-out",
73 | "accordion-up": "accordion-up 0.2s ease-out",
74 | },
75 | },
76 | },
77 | plugins: [require("tailwindcss-animate")],
78 | } satisfies Config
79 |
80 | export default config
--------------------------------------------------------------------------------
/app/users/columns.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { ColumnDef } from "@tanstack/react-table";
4 | import clsx from "clsx";
5 |
6 | import { DataTableColumnHeader } from "@/app/users/data-table-column-header";
7 | import { DataTableRowActions } from "@/app/users/data-table-row-actions";
8 | import { usersRole, usersStatus } from "@/app/users/definitions";
9 |
10 | export const columns: ColumnDef[] = [
11 | {
12 | accessorKey: "userName",
13 | header: ({ column }) => ,
14 | cell: ({ row }) => {
15 | return {row.getValue("userName")}
;
16 | },
17 | },
18 | {
19 | accessorKey: "phone",
20 | header: ({ column }) => ,
21 | },
22 | {
23 | accessorKey: "email",
24 | header: ({ column }) => ,
25 | },
26 | {
27 | accessorKey: "location",
28 | header: ({ column }) => ,
29 | },
30 | {
31 | accessorKey: "role",
32 | header: ({ column }) => ,
33 | cell: ({ row }) => {
34 | const role = usersRole.find((role) => role.value === row.getValue("role"));
35 |
36 | if (!role) {
37 | // If a value is not what you expect or does not exist you can return null.
38 | return null;
39 | }
40 |
41 | return {role.label};
42 | },
43 | },
44 | {
45 | accessorKey: "rtn",
46 | header: ({ column }) => ,
47 | },
48 | {
49 | accessorKey: "otherInformation",
50 | header: ({ column }) => ,
51 | },
52 | {
53 | accessorKey: "status",
54 | header: ({ column }) => ,
55 | cell: ({ row }) => {
56 | const status = usersStatus.find((status) => status.value === row.getValue("status"));
57 |
58 | if (!status) {
59 | return null;
60 | }
61 |
62 | return (
63 |
68 | {status.icon && }
69 | {status.label}
70 |
71 | );
72 | },
73 | filterFn: (row, id, value) => {
74 | return value.includes(row.getValue(id));
75 | },
76 | },
77 | {
78 | id: "actions",
79 | cell: ({ row }) => ,
80 | },
81 | ];
82 |
--------------------------------------------------------------------------------
/components/ui/table.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Table = React.forwardRef<
6 | HTMLTableElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
16 | ))
17 | Table.displayName = "Table"
18 |
19 | const TableHeader = React.forwardRef<
20 | HTMLTableSectionElement,
21 | React.HTMLAttributes
22 | >(({ className, ...props }, ref) => (
23 |
24 | ))
25 | TableHeader.displayName = "TableHeader"
26 |
27 | const TableBody = React.forwardRef<
28 | HTMLTableSectionElement,
29 | React.HTMLAttributes
30 | >(({ className, ...props }, ref) => (
31 |
36 | ))
37 | TableBody.displayName = "TableBody"
38 |
39 | const TableFooter = React.forwardRef<
40 | HTMLTableSectionElement,
41 | React.HTMLAttributes
42 | >(({ className, ...props }, ref) => (
43 | tr]:last:border-b-0",
47 | className
48 | )}
49 | {...props}
50 | />
51 | ))
52 | TableFooter.displayName = "TableFooter"
53 |
54 | const TableRow = React.forwardRef<
55 | HTMLTableRowElement,
56 | React.HTMLAttributes
57 | >(({ className, ...props }, ref) => (
58 |
66 | ))
67 | TableRow.displayName = "TableRow"
68 |
69 | const TableHead = React.forwardRef<
70 | HTMLTableCellElement,
71 | React.ThHTMLAttributes
72 | >(({ className, ...props }, ref) => (
73 | |
81 | ))
82 | TableHead.displayName = "TableHead"
83 |
84 | const TableCell = React.forwardRef<
85 | HTMLTableCellElement,
86 | React.TdHTMLAttributes
87 | >(({ className, ...props }, ref) => (
88 | |
93 | ))
94 | TableCell.displayName = "TableCell"
95 |
96 | const TableCaption = React.forwardRef<
97 | HTMLTableCaptionElement,
98 | React.HTMLAttributes
99 | >(({ className, ...props }, ref) => (
100 |
105 | ))
106 | TableCaption.displayName = "TableCaption"
107 |
108 | export {
109 | Table,
110 | TableHeader,
111 | TableBody,
112 | TableFooter,
113 | TableHead,
114 | TableRow,
115 | TableCell,
116 | TableCaption,
117 | }
118 |
--------------------------------------------------------------------------------
/app/users/data-table.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import {
5 | ColumnDef,
6 | ColumnFiltersState,
7 | flexRender,
8 | getCoreRowModel,
9 | getFilteredRowModel,
10 | getPaginationRowModel,
11 | getSortedRowModel,
12 | SortingState,
13 | useReactTable,
14 | VisibilityState,
15 | } from "@tanstack/react-table";
16 |
17 | import {
18 | Table,
19 | TableBody,
20 | TableCell,
21 | TableHead,
22 | TableHeader,
23 | TableRow,
24 | } from "@/components/ui/table";
25 |
26 | import { DataTablePagination } from "./data-table-pagination";
27 | import { DataTableToolbar } from "./data-table-toolbar";
28 |
29 | interface DataTableProps {
30 | columns: ColumnDef[];
31 | data: TData[];
32 | }
33 |
34 | export default function DataTable({ columns, data }: DataTableProps) {
35 | const [sorting, setSorting] = React.useState([]);
36 | const [columnVisibility, setColumnVisibility] = React.useState({
37 | location: false,
38 | otherInformation: false,
39 | });
40 | const [columnFilters, setColumnFilters] = React.useState([]);
41 |
42 | const table = useReactTable({
43 | data,
44 | columns,
45 | state: {
46 | sorting,
47 | columnVisibility,
48 | columnFilters,
49 | },
50 | enableRowSelection: true,
51 | getCoreRowModel: getCoreRowModel(),
52 | onSortingChange: setSorting,
53 | getSortedRowModel: getSortedRowModel(),
54 | onColumnVisibilityChange: setColumnVisibility,
55 | getFilteredRowModel: getFilteredRowModel(),
56 | getPaginationRowModel: getPaginationRowModel(),
57 | onColumnFiltersChange: setColumnFilters,
58 | });
59 |
60 | return (
61 |
62 |
63 |
64 |
65 |
66 | {table.getHeaderGroups().map((headerGroup) => (
67 |
68 | {headerGroup.headers.map((header) => {
69 | return (
70 |
71 | {header.isPlaceholder
72 | ? null
73 | : flexRender(header.column.columnDef.header, header.getContext())}
74 |
75 | );
76 | })}
77 |
78 | ))}
79 |
80 |
81 | {table.getRowModel().rows?.length ? (
82 | table.getRowModel().rows.map((row) => (
83 |
84 | {row.getVisibleCells().map((cell) => (
85 |
86 | {flexRender(cell.column.columnDef.cell, cell.getContext())}
87 |
88 | ))}
89 |
90 | ))
91 | ) : (
92 |
93 |
94 | {"No data results"}
95 |
96 |
97 | )}
98 |
99 |
100 |
101 |
102 |
103 | );
104 | }
105 |
--------------------------------------------------------------------------------
/app/users/data-table-pagination.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ChevronLeftIcon,
3 | ChevronRightIcon,
4 | DoubleArrowLeftIcon,
5 | DoubleArrowRightIcon,
6 | } from "@radix-ui/react-icons";
7 | import { Table } from "@tanstack/react-table";
8 |
9 | import { Button } from "@/components/ui/button";
10 | import {
11 | Select,
12 | SelectContent,
13 | SelectItem,
14 | SelectTrigger,
15 | SelectValue,
16 | } from "@/components/ui/select";
17 |
18 | interface DataTablePaginationProps {
19 | table: Table;
20 | }
21 |
22 | export function DataTablePagination({ table }: DataTablePaginationProps) {
23 | return (
24 |
25 |
26 | {table.getFilteredSelectedRowModel().rows.length} of{" "}
27 | {table.getFilteredRowModel().rows.length} {"row(s) selected"}.
28 |
29 |
30 |
31 |
{"Rows per page"}
32 |
48 |
49 |
50 | {"Page"} {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
51 |
52 |
53 |
61 |
69 |
77 |
85 |
86 |
87 |
88 | );
89 | }
90 |
--------------------------------------------------------------------------------
/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as DialogPrimitive from "@radix-ui/react-dialog"
5 | import { X } from "lucide-react"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Dialog = DialogPrimitive.Root
10 |
11 | const DialogTrigger = DialogPrimitive.Trigger
12 |
13 | const DialogPortal = DialogPrimitive.Portal
14 |
15 | const DialogClose = DialogPrimitive.Close
16 |
17 | const DialogOverlay = React.forwardRef<
18 | React.ElementRef,
19 | React.ComponentPropsWithoutRef
20 | >(({ className, ...props }, ref) => (
21 |
29 | ))
30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31 |
32 | const DialogContent = React.forwardRef<
33 | React.ElementRef,
34 | React.ComponentPropsWithoutRef
35 | >(({ className, children, ...props }, ref) => (
36 |
37 |
38 |
46 | {children}
47 |
48 |
49 | Close
50 |
51 |
52 |
53 | ))
54 | DialogContent.displayName = DialogPrimitive.Content.displayName
55 |
56 | const DialogHeader = ({
57 | className,
58 | ...props
59 | }: React.HTMLAttributes) => (
60 |
67 | )
68 | DialogHeader.displayName = "DialogHeader"
69 |
70 | const DialogFooter = ({
71 | className,
72 | ...props
73 | }: React.HTMLAttributes) => (
74 |
81 | )
82 | DialogFooter.displayName = "DialogFooter"
83 |
84 | const DialogTitle = React.forwardRef<
85 | React.ElementRef,
86 | React.ComponentPropsWithoutRef
87 | >(({ className, ...props }, ref) => (
88 |
96 | ))
97 | DialogTitle.displayName = DialogPrimitive.Title.displayName
98 |
99 | const DialogDescription = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | DialogDescription.displayName = DialogPrimitive.Description.displayName
110 |
111 | export {
112 | Dialog,
113 | DialogPortal,
114 | DialogOverlay,
115 | DialogClose,
116 | DialogTrigger,
117 | DialogContent,
118 | DialogHeader,
119 | DialogFooter,
120 | DialogTitle,
121 | DialogDescription,
122 | }
123 |
--------------------------------------------------------------------------------
/app/users/data-table-faceted-filter.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons";
3 | import { Column } from "@tanstack/react-table";
4 |
5 | import { cn } from "@/lib/utils";
6 | import { Badge } from "@/components/ui/badge";
7 | import { Button } from "@/components/ui/button";
8 | import {
9 | Command,
10 | CommandEmpty,
11 | CommandGroup,
12 | CommandInput,
13 | CommandItem,
14 | CommandList,
15 | CommandSeparator,
16 | } from "@/components/ui/command";
17 | import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
18 | import { Separator } from "@/components/ui/separator";
19 |
20 | interface DataTableFacetedFilterProps {
21 | column?: Column;
22 | title?: string;
23 | options: {
24 | label: string;
25 | value: string;
26 | icon?: React.ComponentType<{ className?: string }>;
27 | }[];
28 | }
29 |
30 | export function DataTableFacetedFilter({
31 | column,
32 | title,
33 | options,
34 | }: DataTableFacetedFilterProps) {
35 | const facets = column?.getFacetedUniqueValues();
36 | const selectedValues = new Set(column?.getFilterValue() as string[]);
37 |
38 | return (
39 |
40 |
41 |
71 |
72 |
73 |
74 |
75 |
76 | {"No Filter results"}
77 |
78 | {options.map((option) => {
79 | const isSelected = selectedValues.has(option.value);
80 | return (
81 | {
84 | if (isSelected) {
85 | selectedValues.delete(option.value);
86 | } else {
87 | selectedValues.add(option.value);
88 | }
89 | const filterValues = Array.from(selectedValues);
90 | column?.setFilterValue(filterValues.length ? filterValues : undefined);
91 | }}>
92 |
99 |
100 |
101 | {option.icon && }
102 | {option.label}
103 | {facets?.get(option.value) && (
104 |
105 | {facets.get(option.value)}
106 |
107 | )}
108 |
109 | );
110 | })}
111 |
112 | {selectedValues.size > 0 && (
113 | <>
114 |
115 |
116 | column?.setFilterValue(undefined)}
118 | className="justify-center text-center">
119 | {"Clean Filters"}
120 |
121 |
122 | >
123 | )}
124 |
125 |
126 |
127 |
128 | );
129 | }
130 |
--------------------------------------------------------------------------------
/components/ui/command.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as React from 'react';
4 | import { type DialogProps } from '@radix-ui/react-dialog';
5 | import { Command as CommandPrimitive } from 'cmdk';
6 | import { Search } from 'lucide-react';
7 |
8 | import { cn } from '@/lib/utils';
9 | import { Dialog, DialogContent } from '@/components/ui/dialog';
10 |
11 | const Command = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef
14 | >(({ className, ...props }, ref) => (
15 |
23 | ));
24 | Command.displayName = CommandPrimitive.displayName;
25 |
26 | interface CommandDialogProps extends DialogProps {}
27 |
28 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
29 | return (
30 |
37 | );
38 | };
39 |
40 | const CommandInput = React.forwardRef<
41 | React.ElementRef,
42 | React.ComponentPropsWithoutRef
43 | >(({ className, ...props }, ref) => (
44 |
47 |
48 |
56 |
57 | ));
58 |
59 | CommandInput.displayName = CommandPrimitive.Input.displayName;
60 |
61 | const CommandList = React.forwardRef<
62 | React.ElementRef,
63 | React.ComponentPropsWithoutRef
64 | >(({ className, ...props }, ref) => (
65 |
70 | ));
71 |
72 | CommandList.displayName = CommandPrimitive.List.displayName;
73 |
74 | const CommandEmpty = React.forwardRef<
75 | React.ElementRef,
76 | React.ComponentPropsWithoutRef
77 | >((props, ref) => (
78 |
83 | ));
84 |
85 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
86 |
87 | const CommandGroup = React.forwardRef<
88 | React.ElementRef,
89 | React.ComponentPropsWithoutRef
90 | >(({ className, ...props }, ref) => (
91 |
99 | ));
100 |
101 | CommandGroup.displayName = CommandPrimitive.Group.displayName;
102 |
103 | const CommandSeparator = React.forwardRef<
104 | React.ElementRef,
105 | React.ComponentPropsWithoutRef
106 | >(({ className, ...props }, ref) => (
107 |
112 | ));
113 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
114 |
115 | const CommandItem = React.forwardRef<
116 | React.ElementRef,
117 | React.ComponentPropsWithoutRef
118 | >(({ className, ...props }, ref) => (
119 |
127 | ));
128 |
129 | CommandItem.displayName = CommandPrimitive.Item.displayName;
130 |
131 | const CommandShortcut = ({ className, ...props }: React.HTMLAttributes) => {
132 | return (
133 |
137 | );
138 | };
139 | CommandShortcut.displayName = 'CommandShortcut';
140 |
141 | export {
142 | Command,
143 | CommandDialog,
144 | CommandInput,
145 | CommandList,
146 | CommandEmpty,
147 | CommandGroup,
148 | CommandItem,
149 | CommandShortcut,
150 | CommandSeparator,
151 | };
152 |
--------------------------------------------------------------------------------
/components/ui/select.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SelectPrimitive from "@radix-ui/react-select"
5 | import { Check, ChevronDown, ChevronUp } from "lucide-react"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Select = SelectPrimitive.Root
10 |
11 | const SelectGroup = SelectPrimitive.Group
12 |
13 | const SelectValue = SelectPrimitive.Value
14 |
15 | const SelectTrigger = React.forwardRef<
16 | React.ElementRef,
17 | React.ComponentPropsWithoutRef
18 | >(({ className, children, ...props }, ref) => (
19 | span]:line-clamp-1",
23 | className
24 | )}
25 | {...props}
26 | >
27 | {children}
28 |
29 |
30 |
31 |
32 | ))
33 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
34 |
35 | const SelectScrollUpButton = React.forwardRef<
36 | React.ElementRef,
37 | React.ComponentPropsWithoutRef
38 | >(({ className, ...props }, ref) => (
39 |
47 |
48 |
49 | ))
50 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
51 |
52 | const SelectScrollDownButton = React.forwardRef<
53 | React.ElementRef,
54 | React.ComponentPropsWithoutRef
55 | >(({ className, ...props }, ref) => (
56 |
64 |
65 |
66 | ))
67 | SelectScrollDownButton.displayName =
68 | SelectPrimitive.ScrollDownButton.displayName
69 |
70 | const SelectContent = React.forwardRef<
71 | React.ElementRef,
72 | React.ComponentPropsWithoutRef
73 | >(({ className, children, position = "popper", ...props }, ref) => (
74 |
75 |
86 |
87 |
94 | {children}
95 |
96 |
97 |
98 |
99 | ))
100 | SelectContent.displayName = SelectPrimitive.Content.displayName
101 |
102 | const SelectLabel = React.forwardRef<
103 | React.ElementRef,
104 | React.ComponentPropsWithoutRef
105 | >(({ className, ...props }, ref) => (
106 |
111 | ))
112 | SelectLabel.displayName = SelectPrimitive.Label.displayName
113 |
114 | const SelectItem = React.forwardRef<
115 | React.ElementRef,
116 | React.ComponentPropsWithoutRef
117 | >(({ className, children, ...props }, ref) => (
118 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | {children}
133 |
134 | ))
135 | SelectItem.displayName = SelectPrimitive.Item.displayName
136 |
137 | const SelectSeparator = React.forwardRef<
138 | React.ElementRef,
139 | React.ComponentPropsWithoutRef
140 | >(({ className, ...props }, ref) => (
141 |
146 | ))
147 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName
148 |
149 | export {
150 | Select,
151 | SelectGroup,
152 | SelectValue,
153 | SelectTrigger,
154 | SelectContent,
155 | SelectLabel,
156 | SelectItem,
157 | SelectSeparator,
158 | SelectScrollUpButton,
159 | SelectScrollDownButton,
160 | }
161 |
--------------------------------------------------------------------------------
/app/users/users.ts:
--------------------------------------------------------------------------------
1 | export const users: User[] = [
2 | {
3 | id: "9953ed85-31a0-4db9-acc8-e25b76176443",
4 | userName: "John Miller",
5 | phone: "+1-555-0101",
6 | email: "john.miller@example.com",
7 | role: "client",
8 | status: "inactive",
9 | location: "4306 Highland Drive, Seattle, WA 98109",
10 | image: "john.miller.jpg",
11 | rtn: "US2347908701",
12 | otherInformation: "John Miller works in a tech startup in Seattle.",
13 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
14 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
15 | },
16 | {
17 | id: "328c2bef-d84b-44a2-b5ae-03bd6550c4c4",
18 | userName: "Elizabeth Smith",
19 | phone: "+44-020-8102",
20 | email: "elizabeth.smith@example.co.uk",
21 | role: "client",
22 | status: "active",
23 | location: "22 Camden Road, London, NW1 9DP",
24 | image: "elizabeth.smith.jpg",
25 | rtn: "UK6574829302",
26 | otherInformation: "Elizabeth Smith works in a financial consultancy in London.",
27 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
28 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
29 | },
30 | {
31 | id: "9543e3a4-99f2-4fcb-ba5d-f2aaebff6716",
32 | userName: "Noah Wilson",
33 | phone: "+61-8-9200-1234",
34 | email: "noah.wilson@example.com.au",
35 | role: "provider",
36 | status: "inactive",
37 | location: "305 Murray Street, Perth, WA 6000",
38 | image: "noah.wilson.jpg",
39 | rtn: "AU9085471203",
40 | otherInformation: "Noah Wilson is involved in the mining industry in Perth.",
41 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
42 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
43 | },
44 | {
45 | id: "bdcba306-57fa-4722-82e3-c4933b09e69b",
46 | userName: "Marie Dubois",
47 | phone: "+33-1-4533-0012",
48 | email: "marie.dubois@example.fr",
49 | role: "client",
50 | status: "active",
51 | location: "14 Rue de Rivoli, 75004 Paris",
52 | image: "marie.dubois.jpg",
53 | rtn: "FR21340987201",
54 | otherInformation: "Marie Dubois works in a fashion house in Paris.",
55 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
56 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
57 | },
58 | {
59 | id: "e643dbea-0ab2-4d3d-8bb8-63aedf027a66",
60 | userName: "Wang Wei",
61 | phone: "+86-20-8221-1234",
62 | email: "wang.wei@example.com.cn",
63 | role: "client",
64 | status: "inactive",
65 | location: "206 Huanshi E Rd, Yuexiu District, Guangzhou, Guangdong",
66 | image: "wang.wei.jpg",
67 | rtn: "CN9988321221",
68 | otherInformation: "Wang Wei works for an electronics manufacturing company in Guangzhou.",
69 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
70 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
71 | },
72 | {
73 | id: "94093200-c89f-410f-ba96-046f33fabb3e",
74 | userName: "Conor Murphy",
75 | phone: "+353-1-242-1000",
76 | email: "conor.murphy@example.ie",
77 | role: "provider",
78 | status: "active",
79 | location: "17 O'Connell Street, Dublin, D01 T9C2",
80 | image: "conor.murphy.jpg",
81 | rtn: "IE65432108701",
82 | otherInformation: "Conor Murphy works in a pharmaceutical company in Dublin.",
83 | createdAt: new Date("2024-02-07T23:35:52.087Z"),
84 | updatedAt: new Date("2024-02-07T23:38:03.259Z"),
85 | },
86 | {
87 | id: "4174f655-5cb2-4bd9-a785-ce11f16cebb0",
88 | userName: "Emma Tremblay",
89 | phone: "+1 604-555-0122",
90 | email: "emma.tremblay@example.com",
91 | role: "client",
92 | status: "inactive",
93 | location: "1020 Mainland Street, Vancouver, BC V6B 2T4",
94 | image: "emma.tremblay.jpg",
95 | rtn: "07081999021280",
96 | otherInformation: "Emma Tremblay is engaged in the environmental sector in Canada.",
97 | createdAt: new Date("2024-02-13T15:35:02.010Z"),
98 | updatedAt: new Date("2024-02-13T15:37:03.020Z"),
99 | },
100 | {
101 | id: "38d5126b-4473-40d2-8142-2e7049c07346",
102 | userName: "Maximilian Bauer",
103 | phone: "+49 30 567890",
104 | email: "maximilian.bauer@example.com",
105 | role: "client",
106 | status: "active",
107 | location: "Hauptstraße 5, 10178 Berlin",
108 | image: "maximilian.bauer.jpg",
109 | rtn: "08081999021280",
110 | otherInformation: "Maximilian Bauer works for an automobile company in Germany.",
111 | createdAt: new Date("2024-02-14T16:39:04.030Z"),
112 | updatedAt: new Date("2024-02-14T16:40:05.040Z"),
113 | },
114 | {
115 | id: "cb3ae8be-e376-4d26-9cfc-5884348c22ec",
116 | userName: "Sofia Ricci",
117 | phone: "+39 06 12345678",
118 | email: "sofia.ricci@example.com",
119 | role: "provider",
120 | status: "inactive",
121 | location: "Via Roma 15, 00184 Rome",
122 | image: "sofia.ricci.jpg",
123 | rtn: "09081999021280",
124 | otherInformation: "Sofia Ricci is part of the culinary field in Italy.",
125 | createdAt: new Date("2024-02-15T17:41:06.050Z"),
126 | updatedAt: new Date("2024-02-15T17:42:07.060Z"),
127 | },
128 | {
129 | id: "fa47c0f4-620c-40b3-a16a-b9afa9a88215",
130 | userName: "Arjun Patel",
131 | phone: "+91 22 2771 1234",
132 | email: "arjun.patel@example.com",
133 | role: "client",
134 | status: "active",
135 | location: "142 M.G. Road, Mumbai, Maharashtra 400001",
136 | image: "arjun.patel.jpg",
137 | rtn: "10081999021280",
138 | otherInformation: "Arjun Patel is active in the software industry in India.",
139 | createdAt: new Date("2024-02-16T18:43:08.070Z"),
140 | updatedAt: new Date("2024-02-16T18:44:09.080Z"),
141 | },
142 | {
143 | id: "8ce5b4d9-5182-4cbf-9d48-f187b377e931",
144 | userName: "Sato Yuki",
145 | phone: "+81 3 3541 1234",
146 | email: "sato.yuki@example.com",
147 | role: "client",
148 | status: "inactive",
149 | location: "2-11-3 Meguro, Tokyo 153-0063",
150 | image: "sato.yuki.jpg",
151 | rtn: "11081999021280",
152 | otherInformation: "Sato Yuki is engaged in the electronics sector in Japan.",
153 | createdAt: new Date("2024-02-17T19:45:10.090Z"),
154 | updatedAt: new Date("2024-02-17T19:46:11.100Z"),
155 | },
156 | {
157 | id: "cb2c15c3-7fc9-4d51-8b7b-3e636ac6195b",
158 | userName: "Lucas Silva",
159 | phone: "+55 11 9988-7766",
160 | email: "lucas.silva@example.com",
161 | role: "provider",
162 | status: "active",
163 | location: "Rua Oscar Freire, 379, São Paulo, SP 01426-001",
164 | image: "lucas.silva.jpg",
165 | rtn: "12081999021280",
166 | otherInformation: "Lucas Silva works in the agricultural business in Brazil.",
167 | createdAt: new Date("2024-02-18T20:47:12.110Z"),
168 | updatedAt: new Date("2024-02-18T20:48:13.120Z"),
169 | },
170 | ];
171 |
--------------------------------------------------------------------------------
/components/ui/dropdown-menu.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
5 | import { Check, ChevronRight, Circle } from "lucide-react"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const DropdownMenu = DropdownMenuPrimitive.Root
10 |
11 | const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
12 |
13 | const DropdownMenuGroup = DropdownMenuPrimitive.Group
14 |
15 | const DropdownMenuPortal = DropdownMenuPrimitive.Portal
16 |
17 | const DropdownMenuSub = DropdownMenuPrimitive.Sub
18 |
19 | const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
20 |
21 | const DropdownMenuSubTrigger = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef & {
24 | inset?: boolean
25 | }
26 | >(({ className, inset, children, ...props }, ref) => (
27 |
36 | {children}
37 |
38 |
39 | ))
40 | DropdownMenuSubTrigger.displayName =
41 | DropdownMenuPrimitive.SubTrigger.displayName
42 |
43 | const DropdownMenuSubContent = React.forwardRef<
44 | React.ElementRef,
45 | React.ComponentPropsWithoutRef
46 | >(({ className, ...props }, ref) => (
47 |
55 | ))
56 | DropdownMenuSubContent.displayName =
57 | DropdownMenuPrimitive.SubContent.displayName
58 |
59 | const DropdownMenuContent = React.forwardRef<
60 | React.ElementRef,
61 | React.ComponentPropsWithoutRef
62 | >(({ className, sideOffset = 4, ...props }, ref) => (
63 |
64 |
73 |
74 | ))
75 | DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
76 |
77 | const DropdownMenuItem = React.forwardRef<
78 | React.ElementRef,
79 | React.ComponentPropsWithoutRef & {
80 | inset?: boolean
81 | }
82 | >(({ className, inset, ...props }, ref) => (
83 |
92 | ))
93 | DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
94 |
95 | const DropdownMenuCheckboxItem = React.forwardRef<
96 | React.ElementRef,
97 | React.ComponentPropsWithoutRef
98 | >(({ className, children, checked, ...props }, ref) => (
99 |
108 |
109 |
110 |
111 |
112 |
113 | {children}
114 |
115 | ))
116 | DropdownMenuCheckboxItem.displayName =
117 | DropdownMenuPrimitive.CheckboxItem.displayName
118 |
119 | const DropdownMenuRadioItem = React.forwardRef<
120 | React.ElementRef,
121 | React.ComponentPropsWithoutRef
122 | >(({ className, children, ...props }, ref) => (
123 |
131 |
132 |
133 |
134 |
135 |
136 | {children}
137 |
138 | ))
139 | DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
140 |
141 | const DropdownMenuLabel = React.forwardRef<
142 | React.ElementRef,
143 | React.ComponentPropsWithoutRef & {
144 | inset?: boolean
145 | }
146 | >(({ className, inset, ...props }, ref) => (
147 |
156 | ))
157 | DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
158 |
159 | const DropdownMenuSeparator = React.forwardRef<
160 | React.ElementRef,
161 | React.ComponentPropsWithoutRef
162 | >(({ className, ...props }, ref) => (
163 |
168 | ))
169 | DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
170 |
171 | const DropdownMenuShortcut = ({
172 | className,
173 | ...props
174 | }: React.HTMLAttributes) => {
175 | return (
176 |
180 | )
181 | }
182 | DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
183 |
184 | export {
185 | DropdownMenu,
186 | DropdownMenuTrigger,
187 | DropdownMenuContent,
188 | DropdownMenuItem,
189 | DropdownMenuCheckboxItem,
190 | DropdownMenuRadioItem,
191 | DropdownMenuLabel,
192 | DropdownMenuSeparator,
193 | DropdownMenuShortcut,
194 | DropdownMenuGroup,
195 | DropdownMenuPortal,
196 | DropdownMenuSub,
197 | DropdownMenuSubContent,
198 | DropdownMenuSubTrigger,
199 | DropdownMenuRadioGroup,
200 | }
201 |
--------------------------------------------------------------------------------