diff --git a/apps/edr-freight-web/portal/index.css b/apps/edr-freight-web/portal/index.css index 22fe63dad..f1d8c73cd 100644 --- a/apps/edr-freight-web/portal/index.css +++ b/apps/edr-freight-web/portal/index.css @@ -1,42 +1 @@ @import "tailwindcss"; - -@custom-variant dark (&:where(.dark, .dark *)); - -* { - scrollbar-width: thin; - scrollbar-color: rgb(203 213 225 / 0.6) transparent; -} - -*::-webkit-scrollbar { - width: 8px; - height: 10px; -} - -*::-webkit-scrollbar-track { - background: transparent; -} - -*::-webkit-scrollbar-thumb { - background-color: rgb(203 213 225 / 0.7); - border-radius: 9999px; -} - -*::-webkit-scrollbar-thumb:hover { - background-color: rgb(16 185 129 / 0.5); -} - -*::-webkit-scrollbar-corner { - background: transparent; -} - -.dark * { - scrollbar-color: rgb(71 85 105 / 0.6) transparent; -} - -.dark *::-webkit-scrollbar-thumb { - background-color: rgb(71 85 105 / 0.6); -} - -.dark *::-webkit-scrollbar-thumb:hover { - background-color: rgb(16 185 129 / 0.7); -} diff --git a/apps/edr-freight-web/portal/index.html b/apps/edr-freight-web/portal/index.html index 09f11f8dc..2233dc861 100644 --- a/apps/edr-freight-web/portal/index.html +++ b/apps/edr-freight-web/portal/index.html @@ -1,13 +1,15 @@ - - - - EDR Freight Portal - - -
- - - + + + + + EDR Freight Portal + + + +
+ + + diff --git a/apps/edr-freight-web/portal/src/main.tsx b/apps/edr-freight-web/portal/src/main.tsx index d0a07ba14..1437f9d00 100644 --- a/apps/edr-freight-web/portal/src/main.tsx +++ b/apps/edr-freight-web/portal/src/main.tsx @@ -2,12 +2,13 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import "../index.css"; import "@tria-plc/iamui-common/styles.css"; +import "@edr/ui-common/styles.css"; import App from "./App"; import { AuthProvider, - BrandingProvider, configureIam, UserProvider, axiosInstance, @@ -67,15 +68,13 @@ if (!rootElement) { createRoot(document.getElementById("root")!).render( - - + - + - - + , ); diff --git a/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx b/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx index 1a3e91f82..e912f8b4f 100644 --- a/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx +++ b/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx @@ -1,8 +1,6 @@ -import { useMemo, useState } from "react"; +import { useMemo } from "react"; import { Link } from "react-router-dom"; import { - ChevronLeft, - ChevronRight, Clock3, Eye, Filter, @@ -18,63 +16,155 @@ import { import Breadcrumbs from "@/components/Breadcrumbs"; import NewCustomerPage from "./NewCustomerPage"; import DeleteCustomerDialog from "./DeleteCustomerDialog"; -import { customers, type CustomerStatus } from "./customers.mock"; - -const PAGE_SIZE_OPTIONS = [5, 10, 25, 50]; +import { + customers, + type CustomerStatus, + type Customer, +} from "./customers.mock"; +import { + DataTable, + DataTableFooter, + type ColumnDef, + usePagination, + Button, + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + Input, +} from "@edr/ui-common"; export default function CustomerPage() { - const [pageSize, setPageSize] = useState(10); - const [page, setPage] = useState(1); + const { pagination, setPagination } = usePagination({ pageSize: 10 }); const total = customers.length; - const totalPages = Math.max(1, Math.ceil(total / pageSize)); - const safePage = Math.min(page, totalPages); - const start = (safePage - 1) * pageSize; - const end = Math.min(start + pageSize, total); - const paginated = useMemo( + const pageCount = Math.ceil(total / pagination.pageSize); + const start = pagination.pageIndex * pagination.pageSize; + const end = Math.min(start + pagination.pageSize, total); + + const paginatedData = useMemo( () => customers.slice(start, end), [start, end], ); + const columns: ColumnDef[] = [ + { + accessorKey: "name", + header: "Customer", + cell: ({ row }) => { + const customer = row.original; + return ( +
+
+ +
+
+

{customer.name}

+

ID #{customer.id}

+
+
+ ); + }, + }, + { + accessorKey: "company", + header: "Company", + }, + { + accessorKey: "email", + header: "Email", + cell: ({ row }) => ( + {row.original.email} + ), + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { + id: "actions", + header: () =>
Actions
, + cell: ({ row }) => { + const customer = row.original; + return ( +
+ + + + + + + + + + + +
+ ); + }, + }, + ]; + return ( -
-
+
+
- {/* Header */} -
+

Customers

-

+

Manage and monitor your customer records.

- - +
- +
-
+ - {/* Stats */}
- {/* Customer Table */} -
-
+ +
-

- Customer List -

-

+ Customer List + Recent customer activities and records. -

+
- -
+ + -
- - - - - - - - - - - - - {paginated.map((customer) => ( - - - - - - - - - - - - ))} - -
CustomerCompanyEmailStatusActions
-
-
- -
- -
-

- {customer.name} -

-

- ID #{customer.id} -

-
-
-
- {customer.company} - - {customer.email} - - - -
- - - - - - - - - - - -
-
-
- - { - setPageSize(size); - setPage(1); - }} - /> -
-
-
- ); -} - -function Pagination({ - page, - pageSize, - total, - totalPages, - start, - end, - onPageChange, - onPageSizeChange, -}: { - page: number; - pageSize: number; - total: number; - totalPages: number; - start: number; - end: number; - onPageChange: (page: number) => void; - onPageSizeChange: (size: number) => void; -}) { - const showingFrom = total === 0 ? 0 : start + 1; - - return ( -
-
- - - - Showing {showingFrom}–{end} of {total} - -
- -
- - - {Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => { - const isActive = p === page; - return ( - - ); - })} - - + + { }} + pagination={{ + pageIndex: pagination.pageIndex, + pageSize: pagination.pageSize, + pageCount: pageCount, + totalCount: total, + }} + tableOptions={{ + state: { pagination }, + onPaginationChange: setPagination, + }} + containerClassName="border-b shadow-none" + footer={DataTableFooter} + /> + +
); @@ -325,8 +236,8 @@ function StatCard({ icon: React.ReactNode; }) { return ( -
-
+ +

{title}

{value}

@@ -335,8 +246,8 @@ function StatCard({
{icon}
-
-
+ + ); } diff --git a/apps/edr-freight-web/portal/src/pages/customers/DeleteCustomerDialog.tsx b/apps/edr-freight-web/portal/src/pages/customers/DeleteCustomerDialog.tsx index b75effc64..d0d766c0c 100644 --- a/apps/edr-freight-web/portal/src/pages/customers/DeleteCustomerDialog.tsx +++ b/apps/edr-freight-web/portal/src/pages/customers/DeleteCustomerDialog.tsx @@ -9,9 +9,9 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; +} from "@edr/ui-common"; -import { Button } from "@/components/ui/button"; +import { Button } from "@edr/ui-common"; export interface DeleteCustomerDialogProps { customerName: string; diff --git a/package.json b/package.json index 0c3b26cb8..e4d55e7e9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "scripts": { "dev": "turbo run dev", - "dev:freight": "turbo run dev --filter=@edr/freight-api... --filter=@edr/freight-portal... --filter=@edr/freight-backoffice...", + "dev:freight": "turbo run dev --filter=@edr/freight-api... --filter=@edr/freight-portal... --filter=@edr/freight-backoffice... --filter=@edr/ui-common...", "dev:passenger": "turbo run dev --filter=@edr/passenger-api... --filter=@edr/passenger-portal... --filter=@edr/passenger-backoffice...", "build": "turbo run build", "build:freight": "turbo run build --filter=@edr/freight-api... --filter=@edr/freight-portal... --filter=@edr/freight-backoffice...", diff --git a/packages/ui-common/package.json b/packages/ui-common/package.json index 388915423..9ffe547f6 100644 --- a/packages/ui-common/package.json +++ b/packages/ui-common/package.json @@ -6,9 +6,13 @@ "main": "./src/index.ts", "types": "./src/index.ts", "exports": { - ".": "./src/index.ts" + ".": "./src/index.ts", + "./styles.css": "./dist/index.css" }, "scripts": { + "build:styles": "tailwindcss -i ./src/styles/index.css -o ./dist/index.css", + "check-types": "tsc --noEmit", + "dev:styles": "tailwindcss -i ./src/styles/index.css -o ./dist/index.css --watch", "type-check": "tsc --noEmit", "lint": "eslint src" }, @@ -18,6 +22,7 @@ }, "dependencies": { "@edr/types": "workspace:*", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.14.0", @@ -29,10 +34,13 @@ "devDependencies": { "@edr/eslint-config": "workspace:*", "@edr/tsconfig": "workspace:*", + "@tailwindcss/cli": "^4.3.0", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", + "postcss": "^8.4.47", "react": "^18.3.1", "react-dom": "^18.3.1", + "tailwindcss": "^4.3.0", "typescript": "^5.5.4" }, "imports": { diff --git a/packages/ui-common/postcss.config.js b/packages/ui-common/postcss.config.js new file mode 100644 index 000000000..1e8e9dbf9 --- /dev/null +++ b/packages/ui-common/postcss.config.js @@ -0,0 +1,6 @@ +// Optional PostCSS configuration for applications that need it +export const postcssConfig = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; diff --git a/packages/ui-common/src/components/Button/Button.tsx b/packages/ui-common/src/components/Button/Button.tsx deleted file mode 100644 index 04ddd10ad..000000000 --- a/packages/ui-common/src/components/Button/Button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { ButtonHTMLAttributes, forwardRef } from "react"; -import clsx from "clsx"; - -export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger"; -export type ButtonSize = "sm" | "md" | "lg"; - -export interface ButtonProps extends ButtonHTMLAttributes { - variant?: ButtonVariant; - size?: ButtonSize; - isLoading?: boolean; -} - -const variantClasses: Record = { - primary: "bg-blue-600 text-white hover:bg-blue-700 disabled:bg-blue-300", - secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 disabled:bg-gray-50", - ghost: "bg-transparent text-gray-900 hover:bg-gray-100", - danger: "bg-red-600 text-white hover:bg-red-700 disabled:bg-red-300", -}; - -const sizeClasses: Record = { - sm: "px-3 py-1.5 text-sm", - md: "px-4 py-2 text-base", - lg: "px-6 py-3 text-lg", -}; - -const Button = forwardRef( - ( - { - variant = "primary", - size = "md", - isLoading, - disabled, - className, - children, - ...rest - }, - ref, - ) => ( - - ), -); - -Button.displayName = "Button"; - -export default Button; diff --git a/packages/ui-common/src/components/Button/index.ts b/packages/ui-common/src/components/Button/index.ts deleted file mode 100644 index 55968f63d..000000000 --- a/packages/ui-common/src/components/Button/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./Button"; -export type { ButtonProps, ButtonVariant, ButtonSize } from "./Button"; diff --git a/packages/ui-common/src/components/Layout/DashboardLayout.tsx b/packages/ui-common/src/components/Layout/DashboardLayout.tsx index 27d328162..f86ddd933 100644 --- a/packages/ui-common/src/components/Layout/DashboardLayout.tsx +++ b/packages/ui-common/src/components/Layout/DashboardLayout.tsx @@ -123,7 +123,7 @@ const DashboardLayout = ({ ) : null; return ( -
+
-
-
-
- {title} -
+
+
+
{title}
@@ -220,9 +217,7 @@ const DashboardLayout = ({
-
- {children} -
+
{children}
); diff --git a/packages/ui-common/src/components/Layout/Sidebar.tsx b/packages/ui-common/src/components/Layout/Sidebar.tsx index deaa39ac5..186f8bfd4 100644 --- a/packages/ui-common/src/components/Layout/Sidebar.tsx +++ b/packages/ui-common/src/components/Layout/Sidebar.tsx @@ -28,11 +28,11 @@ const Sidebar = ({ onNavigate, headerExtra, }: SidebarProps) => ( -