From 5b7084476502c688766bc6eb2f9e878a1875dd83 Mon Sep 17 00:00:00 2001 From: Giorgi Gordiashvili Date: Mon, 13 Apr 2026 15:14:13 +0400 Subject: [PATCH] feat: implement Customers List and Customer Details pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two pages under Pages > Customers: - Customers List: data table with 20 customers, avatar + name + email column, phone, status filter (Active/VIP/Inactive), total orders, total spent, join date, search, sort, pagination, delete action - Customer Details: dynamic [id] route with profile-style layout — header card with avatar and status badge, info card with contact details, stats cards (total orders, total spent, avg order value), and recent orders table with payment status badges Follows established patterns (TanStack Table, localized Links, ScrollArea for mobile, ARIA labels, logical CSS for RTL). --- .../[id]/_components/customer-details.tsx | 47 ++ .../[id]/_components/customer-header-card.tsx | 43 ++ .../[id]/_components/customer-info-card.tsx | 41 ++ .../[id]/_components/customer-not-found.tsx | 31 + .../[id]/_components/customer-orders-card.tsx | 83 +++ .../[id]/_components/customer-stats-card.tsx | 54 ++ .../pages/customers/[id]/page.tsx | 33 + .../_components/customers-table-columns.tsx | 143 +++++ .../customers-table-row-actions.tsx | 62 ++ .../_components/customers-table-toolbar.tsx | 64 ++ .../list/_components/customers-table.tsx | 148 +++++ .../pages/customers/list/_data/customers.ts | 579 ++++++++++++++++++ .../pages/customers/list/page.tsx | 17 + .../pages/customers/types.ts | 27 + full-kit/src/data/navigations.ts | 6 +- 15 files changed, 1374 insertions(+), 4 deletions(-) create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-details.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-header-card.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-info-card.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-not-found.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-orders-card.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-stats-card.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/page.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-columns.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-row-actions.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-toolbar.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_data/customers.ts create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/page.tsx create mode 100644 full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/types.ts diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-details.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-details.tsx new file mode 100644 index 00000000..263e2842 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-details.tsx @@ -0,0 +1,47 @@ +"use client" + +import Link from "next/link" +import { useParams } from "next/navigation" +import { ChevronLeft } from "lucide-react" + +import type { LocaleType } from "@/types" +import type { CustomerType } from "../../types" + +import { ensureLocalizedPathname } from "@/lib/i18n" + +import { Button } from "@/components/ui/button" +import { CustomerHeaderCard } from "./customer-header-card" +import { CustomerInfoCard } from "./customer-info-card" +import { CustomerOrdersCard } from "./customer-orders-card" +import { CustomerStatsCard } from "./customer-stats-card" + +interface CustomerDetailsProps { + customer: CustomerType +} + +export function CustomerDetails({ customer }: CustomerDetailsProps) { + const params = useParams() + const locale = params.lang as LocaleType + + return ( +
+ + +
+
+ + +
+
+ + +
+
+
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-header-card.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-header-card.tsx new file mode 100644 index 00000000..69c2a9c6 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-header-card.tsx @@ -0,0 +1,43 @@ +import type { CustomerType } from "../../types" + +import { formatDate, getInitials } from "@/lib/utils" + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Badge } from "@/components/ui/badge" +import { Card, CardContent } from "@/components/ui/card" + +interface CustomerHeaderCardProps { + customer: CustomerType +} + +export function CustomerHeaderCard({ customer }: CustomerHeaderCardProps) { + const statusVariant = + customer.status === "VIP" + ? "secondary" + : customer.status === "Inactive" + ? "outline" + : "default" + + return ( + + + + + + {getInitials(customer.name)} + + +
+

{customer.name}

+

{customer.email}

+
+
+ {customer.status} + + Joined {formatDate(customer.joinDate)} + +
+
+
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-info-card.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-info-card.tsx new file mode 100644 index 00000000..6a2fdf4c --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-info-card.tsx @@ -0,0 +1,41 @@ +import { Building2, Globe, MapPin, Phone } from "lucide-react" + +import type { CustomerType } from "../../types" + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" + +interface CustomerInfoCardProps { + customer: CustomerType +} + +export function CustomerInfoCard({ customer }: CustomerInfoCardProps) { + const items = [ + { icon: Phone, label: "Phone", value: customer.phone }, + { + icon: MapPin, + label: "Address", + value: `${customer.address}, ${customer.city}, ${customer.state} ${customer.zipCode}`, + }, + { icon: Globe, label: "Country", value: customer.country }, + { icon: Building2, label: "Organization", value: customer.organization }, + ] + + return ( + + + Information + + + {items.map((item) => ( +
+ +
+

{item.label}

+

{item.value}

+
+
+ ))} +
+
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-not-found.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-not-found.tsx new file mode 100644 index 00000000..36a544ca --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-not-found.tsx @@ -0,0 +1,31 @@ +"use client" + +import Link from "next/link" +import { useParams } from "next/navigation" +import { UserX } from "lucide-react" + +import type { LocaleType } from "@/types" + +import { ensureLocalizedPathname } from "@/lib/i18n" + +import { Button } from "@/components/ui/button" + +export function CustomerNotFound() { + const params = useParams() + const locale = params.lang as LocaleType + + return ( +
+ +

Customer Not Found

+

+ The customer you are looking for does not exist or has been removed. +

+ +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-orders-card.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-orders-card.tsx new file mode 100644 index 00000000..e8b3f348 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-orders-card.tsx @@ -0,0 +1,83 @@ +import type { CustomerType } from "../../types" + +import { formatCurrency, formatDate } from "@/lib/utils" + +import { Badge } from "@/components/ui/badge" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { ScrollArea } from "@/components/ui/scroll-area" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" + +interface CustomerOrdersCardProps { + customer: CustomerType +} + +export function CustomerOrdersCard({ customer }: CustomerOrdersCardProps) { + const { recentOrders } = customer + + const paymentVariant = (status: string) => + status === "Paid" + ? "default" + : status === "Pending" + ? "secondary" + : status === "Failed" + ? "destructive" + : "outline" + + return ( + + + Recent Orders + + + + + + + Order ID + Date + Amount + Status + + + + {recentOrders.length > 0 ? ( + recentOrders.map((order) => ( + + + #{order.orderId} + + {formatDate(order.date)} + + {formatCurrency(order.amount)} + + + + {order.status} + + + + )) + ) : ( + + + No recent orders. + + + )} + +
+
+
+
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-stats-card.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-stats-card.tsx new file mode 100644 index 00000000..f78768e1 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/_components/customer-stats-card.tsx @@ -0,0 +1,54 @@ +import { DollarSign, ShoppingCart, TrendingUp } from "lucide-react" + +import type { CustomerType } from "../../types" + +import { formatCurrency } from "@/lib/utils" + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" + +interface CustomerStatsCardProps { + customer: CustomerType +} + +export function CustomerStatsCard({ customer }: CustomerStatsCardProps) { + const avgOrderValue = + customer.totalOrders > 0 + ? Math.round(customer.totalSpent / customer.totalOrders) + : 0 + + const stats = [ + { + icon: ShoppingCart, + label: "Total Orders", + value: customer.totalOrders.toString(), + }, + { + icon: DollarSign, + label: "Total Spent", + value: formatCurrency(customer.totalSpent), + }, + { + icon: TrendingUp, + label: "Avg. Order Value", + value: formatCurrency(avgOrderValue), + }, + ] + + return ( +
+ {stats.map((stat) => ( + + + + {stat.label} + + + + +

{stat.value}

+
+
+ ))} +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/page.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/page.tsx new file mode 100644 index 00000000..2a1abe88 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/[id]/page.tsx @@ -0,0 +1,33 @@ +import type { LocaleType } from "@/types" +import type { Metadata } from "next" + +import { customersData } from "../list/_data/customers" + +import { CustomerDetails } from "./_components/customer-details" +import { CustomerNotFound } from "./_components/customer-not-found" + +export const metadata: Metadata = { + title: "Customer Details", +} + +export default async function CustomerDetailsPage(props: { + params: Promise<{ lang: LocaleType; id: string }> +}) { + const params = await props.params + + const customer = customersData.find((c) => c.id === params.id) + + if (!customer) { + return ( +
+ +
+ ) + } + + return ( +
+ +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-columns.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-columns.tsx new file mode 100644 index 00000000..f79849cf --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-columns.tsx @@ -0,0 +1,143 @@ +"use client" + +import Image from "next/image" +import Link from "next/link" + +import type { LocaleType } from "@/types" +import type { ColumnDef } from "@tanstack/react-table" +import type { CustomerType } from "../../types" + +import { ensureLocalizedPathname } from "@/lib/i18n" +import { formatCurrency, formatDate } from "@/lib/utils" + +import { Badge } from "@/components/ui/badge" +import { Checkbox } from "@/components/ui/checkbox" +import { DataTableColumnHeader } from "@/components/ui/data-table/data-table-column-header" +import { CustomersTableRowActions } from "./customers-table-row-actions" + +export function getCustomersTableColumns( + onDelete: (id: string) => void, + locale: LocaleType +): ColumnDef[] { + return [ + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + className="ms-4" + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + className="ms-4" + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "name", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const customer = row.original + + return ( + + {customer.name} +
+ + {customer.name} + + + {customer.email} + +
+ + ) + }, + }, + { + accessorKey: "phone", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + {row.getValue("phone")} + ), + }, + { + accessorKey: "status", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const status = row.getValue("status") as string + const variant = + status === "VIP" + ? "secondary" + : status === "Inactive" + ? "outline" + : "default" + + return {status} + }, + filterFn: "equals", + }, + { + accessorKey: "totalOrders", + header: ({ column }) => ( + + ), + }, + { + accessorKey: "totalSpent", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( + {formatCurrency(row.getValue("totalSpent"))} + ), + }, + { + accessorKey: "joinDate", + header: ({ column }) => ( + + ), + cell: ({ row }) => formatDate(row.getValue("joinDate")), + }, + { + id: "actions", + header: () => Actions, + cell: ({ row }) => ( + + ), + }, + ] +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-row-actions.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-row-actions.tsx new file mode 100644 index 00000000..73cfd238 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-row-actions.tsx @@ -0,0 +1,62 @@ +"use client" + +import Link from "next/link" +import { Eye, MoreHorizontal, Trash2 } from "lucide-react" + +import type { LocaleType } from "@/types" +import type { CustomerType } from "../../types" + +import { ensureLocalizedPathname } from "@/lib/i18n" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +interface CustomersTableRowActionsProps { + customer: CustomerType + locale: LocaleType + onDelete: (id: string) => void +} + +export function CustomersTableRowActions({ + customer, + locale, + onDelete, +}: CustomersTableRowActionsProps) { + return ( + + + + + + + + + View Details + + + + onDelete(customer.id)} + > + + Delete + + + + ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-toolbar.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-toolbar.tsx new file mode 100644 index 00000000..09a7c39e --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table-toolbar.tsx @@ -0,0 +1,64 @@ +"use client" + +import { Search } from "lucide-react" + +import type { Table } from "@tanstack/react-table" +import type { CustomerType } from "../../types" + +import { customerStatusesData } from "../_data/customers" + +import { DataTableViewOptions } from "@/components/ui/data-table/data-table-column-toggle" +import { Input } from "@/components/ui/input" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" + +interface CustomersTableToolbarProps { + table: Table +} + +export function CustomersTableToolbar({ table }: CustomersTableToolbarProps) { + return ( +
+
+ + + table.getColumn("name")?.setFilterValue(event.target.value) + } + className="h-9 w-40 ps-8 md:w-60" + aria-label="Search customers by name" + /> +
+ + +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table.tsx new file mode 100644 index 00000000..632d12ff --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_components/customers-table.tsx @@ -0,0 +1,148 @@ +"use client" + +import { useCallback, useMemo, useState } from "react" +import { useParams } from "next/navigation" +import { + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" + +import type { LocaleType } from "@/types" +import type { + ColumnFiltersState, + SortingState, + VisibilityState, +} from "@tanstack/react-table" +import type { CustomerType } from "../../types" + +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { DataTablePagination } from "@/components/ui/data-table/data-table-pagination" +import { ScrollArea } from "@/components/ui/scroll-area" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { getCustomersTableColumns } from "./customers-table-columns" +import { CustomersTableToolbar } from "./customers-table-toolbar" + +interface CustomersTableProps { + data: CustomerType[] +} + +export function CustomersTable({ data: initialData }: CustomersTableProps) { + const params = useParams() + const locale = params.lang as LocaleType + + const [customers, setCustomers] = useState(initialData) + const [sorting, setSorting] = useState([]) + const [columnFilters, setColumnFilters] = useState([]) + const [columnVisibility, setColumnVisibility] = useState({}) + const [rowSelection, setRowSelection] = useState({}) + + const handleDelete = useCallback((id: string) => { + setCustomers((prev) => prev.filter((c) => c.id !== id)) + }, []) + + const columns = useMemo( + () => getCustomersTableColumns(handleDelete, locale), + [handleDelete, locale] + ) + + const table = useReactTable({ + data: customers, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + return ( + + + Customers + + + + + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+ + + +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_data/customers.ts b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_data/customers.ts new file mode 100644 index 00000000..285c6e35 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/_data/customers.ts @@ -0,0 +1,579 @@ +import type { CustomerType } from "../../types" + +export const customerStatusesData = [ + { label: "All", value: "all" }, + { label: "Active", value: "Active" }, + { label: "VIP", value: "VIP" }, + { label: "Inactive", value: "Inactive" }, +] + +const avatars = [ + "/images/avatars/male-01.svg", + "/images/avatars/female-01.svg", + "/images/avatars/male-02.svg", + "/images/avatars/female-02.svg", + "/images/avatars/female-03.svg", +] + +export const customersData: CustomerType[] = [ + { + id: "CUS-1001", + name: "John Doe", + email: "john.doe@email.com", + avatar: avatars[0], + phone: "+1 (555) 123-4567", + address: "123 Main St", + city: "New York", + state: "NY", + country: "United States", + zipCode: "10001", + organization: "Acme Corp", + status: "VIP", + totalOrders: 47, + totalSpent: 42500, + joinDate: "2023-01-15T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1001", + date: "2024-11-01T10:00:00Z", + amount: 270, + status: "Paid", + }, + { + orderId: "ORD-1016", + date: "2024-11-27T09:00:00Z", + amount: 2862, + status: "Paid", + }, + { + orderId: "ORD-1020", + date: "2024-12-05T14:00:00Z", + amount: 486, + status: "Pending", + }, + ], + }, + { + id: "CUS-1002", + name: "Emily Smith", + email: "emily.smith@email.com", + avatar: avatars[1], + phone: "+1 (555) 234-5678", + address: "456 Oak Ave", + city: "Los Angeles", + state: "CA", + country: "United States", + zipCode: "90001", + organization: "TechStart Inc", + status: "Active", + totalOrders: 23, + totalSpent: 18900, + joinDate: "2023-03-22T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1002", + date: "2024-11-03T14:30:00Z", + amount: 8640, + status: "Paid", + }, + { + orderId: "ORD-1008", + date: "2024-11-14T15:00:00Z", + amount: 1188, + status: "Paid", + }, + ], + }, + { + id: "CUS-1003", + name: "Michael Brown", + email: "m.brown@email.com", + avatar: avatars[2], + phone: "+1 (555) 345-6789", + address: "789 Pine Rd", + city: "Chicago", + state: "IL", + country: "United States", + zipCode: "60601", + organization: "Brown & Associates", + status: "Active", + totalOrders: 12, + totalSpent: 9450, + joinDate: "2023-05-10T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1003", + date: "2024-11-05T09:00:00Z", + amount: 3240, + status: "Pending", + }, + { + orderId: "ORD-1013", + date: "2024-11-22T16:00:00Z", + amount: 972, + status: "Paid", + }, + ], + }, + { + id: "CUS-1004", + name: "Sarah Johnson", + email: "sarah.j@email.com", + avatar: avatars[3], + phone: "+1 (555) 456-7890", + address: "321 Elm St", + city: "Houston", + state: "TX", + country: "United States", + zipCode: "77001", + organization: "Johnson Media", + status: "VIP", + totalOrders: 38, + totalSpent: 35200, + joinDate: "2023-02-08T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1004", + date: "2024-11-07T11:00:00Z", + amount: 2160, + status: "Paid", + }, + { + orderId: "ORD-1011", + date: "2024-11-19T14:00:00Z", + amount: 6480, + status: "Paid", + }, + { + orderId: "ORD-1018", + date: "2024-12-01T10:00:00Z", + amount: 4320, + status: "Paid", + }, + ], + }, + { + id: "CUS-1005", + name: "David Wilson", + email: "d.wilson@email.com", + avatar: avatars[4], + phone: "+1 (555) 567-8901", + address: "654 Maple Dr", + city: "Phoenix", + state: "AZ", + country: "United States", + zipCode: "85001", + organization: "Wilson Design", + status: "Inactive", + totalOrders: 3, + totalSpent: 1250, + joinDate: "2024-01-20T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1005", + date: "2024-11-08T16:00:00Z", + amount: 540, + status: "Failed", + }, + ], + }, + { + id: "CUS-1006", + name: "Olivia Martinez", + email: "olivia.m@email.com", + avatar: avatars[1], + phone: "+1 (555) 678-9012", + address: "987 Cedar Ln", + city: "Philadelphia", + state: "PA", + country: "United States", + zipCode: "19101", + organization: "Martinez Solutions", + status: "Active", + totalOrders: 19, + totalSpent: 15700, + joinDate: "2023-06-15T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1006", + date: "2024-11-10T13:00:00Z", + amount: 1944, + status: "Paid", + }, + { + orderId: "ORD-1014", + date: "2024-11-24T10:00:00Z", + amount: 756, + status: "Paid", + }, + ], + }, + { + id: "CUS-1007", + name: "James Anderson", + email: "james.a@email.com", + avatar: avatars[0], + phone: "+1 (555) 789-0123", + address: "147 Birch St", + city: "San Antonio", + state: "TX", + country: "United States", + zipCode: "78201", + organization: "Anderson Tech", + status: "Active", + totalOrders: 8, + totalSpent: 6300, + joinDate: "2023-09-01T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1007", + date: "2024-11-12T10:00:00Z", + amount: 1620, + status: "Refunded", + }, + ], + }, + { + id: "CUS-1008", + name: "Sophia Taylor", + email: "sophia.t@email.com", + avatar: avatars[3], + phone: "+1 (555) 890-1234", + address: "258 Walnut Ave", + city: "San Diego", + state: "CA", + country: "United States", + zipCode: "92101", + organization: "Taylor & Co", + status: "VIP", + totalOrders: 41, + totalSpent: 38900, + joinDate: "2023-01-28T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1008", + date: "2024-11-14T15:00:00Z", + amount: 1188, + status: "Paid", + }, + { + orderId: "ORD-1015", + date: "2024-11-25T13:00:00Z", + amount: 1944, + status: "Refunded", + }, + { + orderId: "ORD-1019", + date: "2024-12-03T12:00:00Z", + amount: 864, + status: "Failed", + }, + ], + }, + { + id: "CUS-1009", + name: "Daniel Thomas", + email: "daniel.t@email.com", + avatar: avatars[2], + phone: "+1 (555) 901-2345", + address: "369 Spruce Ct", + city: "Dallas", + state: "TX", + country: "United States", + zipCode: "75201", + organization: "Thomas Group", + status: "Active", + totalOrders: 15, + totalSpent: 12800, + joinDate: "2023-07-12T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1009", + date: "2024-11-16T12:00:00Z", + amount: 4860, + status: "Paid", + }, + ], + }, + { + id: "CUS-1010", + name: "Isabella Garcia", + email: "isabella.g@email.com", + avatar: avatars[4], + phone: "+1 (555) 012-3456", + address: "480 Ash Blvd", + city: "San Jose", + state: "CA", + country: "United States", + zipCode: "95101", + organization: "Garcia Ventures", + status: "Active", + totalOrders: 7, + totalSpent: 4200, + joinDate: "2024-02-14T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1010", + date: "2024-11-18T09:00:00Z", + amount: 378, + status: "Pending", + }, + ], + }, + { + id: "CUS-1011", + name: "William Lee", + email: "w.lee@email.com", + avatar: avatars[0], + phone: "+1 (555) 111-2222", + address: "591 Willow Way", + city: "Austin", + state: "TX", + country: "United States", + zipCode: "73301", + organization: "Lee Industries", + status: "Active", + totalOrders: 22, + totalSpent: 19600, + joinDate: "2023-04-18T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1011", + date: "2024-11-19T14:00:00Z", + amount: 6480, + status: "Paid", + }, + ], + }, + { + id: "CUS-1012", + name: "Mia Harris", + email: "mia.h@email.com", + avatar: avatars[1], + phone: "+1 (555) 222-3333", + address: "702 Poplar Dr", + city: "Jacksonville", + state: "FL", + country: "United States", + zipCode: "32099", + organization: "Harris Consulting", + status: "Inactive", + totalOrders: 2, + totalSpent: 890, + joinDate: "2024-04-05T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1012", + date: "2024-11-20T11:00:00Z", + amount: 2700, + status: "Failed", + }, + ], + }, + { + id: "CUS-1013", + name: "Ethan Clark", + email: "ethan.c@email.com", + avatar: avatars[2], + phone: "+1 (555) 333-4444", + address: "813 Aspen Rd", + city: "Columbus", + state: "OH", + country: "United States", + zipCode: "43004", + organization: "Clark Engineering", + status: "Active", + totalOrders: 11, + totalSpent: 8750, + joinDate: "2023-08-22T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1013", + date: "2024-11-22T16:00:00Z", + amount: 972, + status: "Paid", + }, + ], + }, + { + id: "CUS-1014", + name: "Charlotte Lewis", + email: "charlotte.l@email.com", + avatar: avatars[3], + phone: "+1 (555) 444-5555", + address: "924 Chestnut Pl", + city: "Fort Worth", + state: "TX", + country: "United States", + zipCode: "76101", + organization: "Lewis Creative", + status: "VIP", + totalOrders: 35, + totalSpent: 29800, + joinDate: "2023-03-01T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1014", + date: "2024-11-24T10:00:00Z", + amount: 756, + status: "Paid", + }, + { + orderId: "ORD-1017", + date: "2024-11-29T15:00:00Z", + amount: 540, + status: "Pending", + }, + ], + }, + { + id: "CUS-1015", + name: "Alexander Walker", + email: "alex.w@email.com", + avatar: avatars[4], + phone: "+1 (555) 555-6666", + address: "135 Magnolia Ln", + city: "Charlotte", + state: "NC", + country: "United States", + zipCode: "28201", + organization: "Walker Digital", + status: "Active", + totalOrders: 9, + totalSpent: 7100, + joinDate: "2023-11-10T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1015", + date: "2024-11-25T13:00:00Z", + amount: 1944, + status: "Refunded", + }, + ], + }, + { + id: "CUS-1016", + name: "Amelia Young", + email: "amelia.y@email.com", + avatar: avatars[1], + phone: "+1 (555) 666-7777", + address: "246 Dogwood St", + city: "Indianapolis", + state: "IN", + country: "United States", + zipCode: "46201", + organization: "Young Studios", + status: "Active", + totalOrders: 16, + totalSpent: 13400, + joinDate: "2023-06-28T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1016", + date: "2024-11-27T09:00:00Z", + amount: 2862, + status: "Paid", + }, + ], + }, + { + id: "CUS-1017", + name: "Benjamin King", + email: "ben.k@email.com", + avatar: avatars[0], + phone: "+1 (555) 777-8888", + address: "357 Juniper Ave", + city: "San Francisco", + state: "CA", + country: "United States", + zipCode: "94101", + organization: "King Software", + status: "VIP", + totalOrders: 44, + totalSpent: 47200, + joinDate: "2023-01-05T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1017", + date: "2024-11-29T15:00:00Z", + amount: 540, + status: "Pending", + }, + ], + }, + { + id: "CUS-1018", + name: "Harper Wright", + email: "harper.w@email.com", + avatar: avatars[3], + phone: "+1 (555) 888-9999", + address: "468 Cypress Rd", + city: "Seattle", + state: "WA", + country: "United States", + zipCode: "98101", + organization: "Wright Photography", + status: "Active", + totalOrders: 14, + totalSpent: 11200, + joinDate: "2023-10-15T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1018", + date: "2024-12-01T10:00:00Z", + amount: 4320, + status: "Paid", + }, + ], + }, + { + id: "CUS-1019", + name: "Lucas Scott", + email: "lucas.s@email.com", + avatar: avatars[2], + phone: "+1 (555) 999-0000", + address: "579 Redwood Blvd", + city: "Denver", + state: "CO", + country: "United States", + zipCode: "80201", + organization: "Scott Labs", + status: "Inactive", + totalOrders: 1, + totalSpent: 350, + joinDate: "2024-06-01T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1019", + date: "2024-12-03T12:00:00Z", + amount: 864, + status: "Failed", + }, + ], + }, + { + id: "CUS-1020", + name: "Ella Adams", + email: "ella.a@email.com", + avatar: avatars[4], + phone: "+1 (555) 000-1111", + address: "690 Sycamore Dr", + city: "Nashville", + state: "TN", + country: "United States", + zipCode: "37201", + organization: "Adams Marketing", + status: "Active", + totalOrders: 6, + totalSpent: 3800, + joinDate: "2024-03-12T00:00:00Z", + recentOrders: [ + { + orderId: "ORD-1020", + date: "2024-12-05T14:00:00Z", + amount: 486, + status: "Pending", + }, + ], + }, +] diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/page.tsx b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/page.tsx new file mode 100644 index 00000000..ad1e88b4 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/list/page.tsx @@ -0,0 +1,17 @@ +import type { Metadata } from "next" + +import { customersData } from "./_data/customers" + +import { CustomersTable } from "./_components/customers-table" + +export const metadata: Metadata = { + title: "Customers List", +} + +export default function CustomersListPage() { + return ( +
+ +
+ ) +} diff --git a/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/types.ts b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/types.ts new file mode 100644 index 00000000..da92d154 --- /dev/null +++ b/full-kit/src/app/[lang]/(dashboard-layout)/pages/customers/types.ts @@ -0,0 +1,27 @@ +export type CustomerStatusType = "Active" | "Inactive" | "VIP" + +export interface CustomerOrderType { + orderId: string + date: string + amount: number + status: "Paid" | "Pending" | "Failed" | "Refunded" +} + +export interface CustomerType { + id: string + name: string + email: string + avatar: string + phone: string + address: string + city: string + state: string + country: string + zipCode: string + organization: string + status: CustomerStatusType + totalOrders: number + totalSpent: number + joinDate: string + recentOrders: CustomerOrderType[] +} diff --git a/full-kit/src/data/navigations.ts b/full-kit/src/data/navigations.ts index b851209c..3c77511e 100644 --- a/full-kit/src/data/navigations.ts +++ b/full-kit/src/data/navigations.ts @@ -147,13 +147,11 @@ export const navigationsData: NavigationType[] = [ items: [ { title: "List", - href: "/", - label: "Soon", + href: "/pages/customers/list", }, { title: "Details", - href: "/", - label: "Soon", + href: "/pages/customers/CUS-1001", }, ], },