-
+
{
setQuery(e.target.value);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
placeholder="Search by code, label, description..."
className="pl-8!"
@@ -312,7 +339,7 @@ export default function DropdownSettingsPage() {
columns={columns}
data={paginatedData}
status="success"
- onRowClick={() => {}}
+ onRowClick={() => { }}
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
diff --git a/apps/edr-freight-web/portal/src/pages/billing/BillingPage.tsx b/apps/edr-freight-web/portal/src/pages/billing/BillingPage.tsx
index 49b314dd4..8b7ac4557 100644
--- a/apps/edr-freight-web/portal/src/pages/billing/BillingPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/billing/BillingPage.tsx
@@ -5,6 +5,7 @@ import {
DollarSign,
Download,
Filter,
+ MoreHorizontal,
Pencil,
Plus,
Receipt,
@@ -15,11 +16,7 @@ import {
import Breadcrumbs from "@/components/Breadcrumbs";
import NewInvoicePage from "./NewInvoicePage";
import DeleteInvoiceDialog from "./DeleteInvoiceDialog";
-import {
- formatCurrency,
- invoices,
- type InvoiceStatus,
-} from "./invoices.mock";
+import { formatCurrency, invoices, type InvoiceStatus } from "./invoices.mock";
import {
DataTable,
DataTableFooter,
@@ -32,6 +29,11 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
type FilterValue = "All" | InvoiceStatus;
@@ -83,7 +85,9 @@ export default function BillingPage() {
inv.currency === "USD",
)
.reduce((sum, inv) => sum + inv.amount, 0);
- const overdueCount = invoices.filter((inv) => inv.status === "Overdue").length;
+ const overdueCount = invoices.filter(
+ (inv) => inv.status === "Overdue",
+ ).length;
const columns: ColumnDef<(typeof invoices)[number]>[] = [
{
@@ -135,39 +139,56 @@ export default function BillingPage() {
},
{
id: "actions",
- header: () =>
Actions
,
+ size: 40,
cell: ({ row }) => {
const invoice = row.original;
return (
-
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+
+
+ Download
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Void
+
+
+
+
);
},
@@ -191,13 +212,16 @@ export default function BillingPage() {
-
+
{
setQuery(e.target.value);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
placeholder="Search invoices..."
className="pl-8!"
@@ -271,7 +295,10 @@ export default function BillingPage() {
type="button"
onClick={() => {
setFilter(f);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
className={
isActive
@@ -315,7 +342,7 @@ export default function BillingPage() {
columns={columns}
data={paginatedData}
status="success"
- onRowClick={() => {}}
+ onRowClick={() => { }}
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingsPage.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingsPage.tsx
index 3febdeff5..e755c174b 100644
--- a/apps/edr-freight-web/portal/src/pages/bookings/BookingsPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingsPage.tsx
@@ -1,10 +1,11 @@
import { useMemo } from "react";
-import { Link } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
import {
ArrowRight,
Clock,
Eye,
Filter,
+ MoreHorizontal,
Package,
Pencil,
Plus,
@@ -29,9 +30,15 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
export default function BookingsPage() {
+ const navigate = useNavigate();
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const total = bookings.length;
@@ -39,10 +46,7 @@ export default function BookingsPage() {
const start = pagination.pageIndex * pagination.pageSize;
const end = Math.min(start + pagination.pageSize, total);
- const paginatedData = useMemo(
- () => bookings.slice(start, end),
- [start, end],
- );
+ const paginatedData = useMemo(() => bookings.slice(start, end), [start, end]);
const columns: ColumnDef<(typeof bookings)[number]>[] = [
{
@@ -100,45 +104,62 @@ export default function BookingsPage() {
},
{
id: "actions",
- header: () =>
Actions
,
+ size: 40,
cell: ({ row }) => {
const booking = row.original;
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+ navigate(`/bookings/${booking.id}`)}
+ >
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Delete
+
+
+
+
);
},
@@ -162,7 +183,7 @@ export default function BookingsPage() {
-
+
{}}
+ onRowClick={(row) =>
+ navigate(`/bookings/${(row as (typeof bookings)[number]).id}`)
+ }
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
diff --git a/apps/edr-freight-web/portal/src/pages/consignments/ConsignmentsPage.tsx b/apps/edr-freight-web/portal/src/pages/consignments/ConsignmentsPage.tsx
index 93376c1e3..33a57a571 100644
--- a/apps/edr-freight-web/portal/src/pages/consignments/ConsignmentsPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/consignments/ConsignmentsPage.tsx
@@ -1,11 +1,12 @@
import { useMemo, useState } from "react";
-import { Link } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
import {
AlertTriangle,
ArrowRight,
CheckCircle2,
Eye,
Filter,
+ MoreHorizontal,
Package,
Pencil,
Plus,
@@ -17,10 +18,7 @@ import {
import Breadcrumbs from "@/components/Breadcrumbs";
import NewConsignmentPage from "./NewConsignmentPage";
import DeleteConsignmentDialog from "./DeleteConsignmentDialog";
-import {
- consignments,
- type ConsignmentStatus,
-} from "./consignments.mock";
+import { consignments, type ConsignmentStatus } from "./consignments.mock";
import {
DataTable,
DataTableFooter,
@@ -33,6 +31,11 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
type FilterValue = "All" | ConsignmentStatus;
@@ -47,6 +50,7 @@ const FILTERS: FilterValue[] = [
];
export default function ConsignmentsPage() {
+ const navigate = useNavigate();
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const [filter, setFilter] = useState
("All");
const [query, setQuery] = useState("");
@@ -143,7 +147,8 @@ export default function ConsignmentsPage() {
{c.cargoType}
- {c.pieces} pcs · {c.weightKg.toLocaleString()} kg · {c.volumeM3} m³
+ {c.pieces} pcs · {c.weightKg.toLocaleString()} kg · {c.volumeM3}{" "}
+ m³
);
@@ -156,46 +161,63 @@ export default function ConsignmentsPage() {
},
{
id: "actions",
- header: () => Actions
,
+ size: 40,
cell: ({ row }) => {
const consignment = row.original;
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+ navigate(`/consignments/${consignment.id}`)}
+ >
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Delete
+
+
+
+
);
},
@@ -219,13 +241,16 @@ export default function ConsignmentsPage() {
-
+
{
setQuery(e.target.value);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
placeholder="Search consignments..."
className="pl-8!"
@@ -313,7 +338,10 @@ export default function ConsignmentsPage() {
type="button"
onClick={() => {
setFilter(f);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
className={
isActive
@@ -357,7 +385,11 @@ export default function ConsignmentsPage() {
columns={columns}
data={paginatedData}
status="success"
- onRowClick={() => {}}
+ onRowClick={(row) =>
+ navigate(
+ `/consignments/${(row as (typeof consignments)[number]).id}`,
+ )
+ }
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
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 e0e1e807a..3a7714abf 100644
--- a/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/customers/CustomersPage.tsx
@@ -1,9 +1,10 @@
import { useMemo } from "react";
-import { Link } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
import {
Clock3,
Eye,
Filter,
+ MoreHorizontal,
Pencil,
Plus,
Search,
@@ -33,9 +34,15 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
export default function CustomerPage() {
+ const navigate = useNavigate();
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const total = customers.length;
@@ -85,42 +92,59 @@ export default function CustomerPage() {
},
{
id: "actions",
- header: () =>
Actions
,
+ size: 40,
cell: ({ row }) => {
const customer = row.original;
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+ navigate(`/customers/${customer.id}`)}
+ >
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Delete
+
+
+
+
);
},
@@ -201,7 +225,7 @@ export default function CustomerPage() {
columns={columns}
data={paginatedData}
status="success"
- onRowClick={() => { }}
+ onRowClick={(row) => navigate(`/customers/${row.id}`)}
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
@@ -232,7 +256,7 @@ function StatCard({
icon: React.ReactNode;
}) {
return (
-
+
{title}
diff --git a/apps/edr-freight-web/portal/src/pages/documents/DocumentsPage.tsx b/apps/edr-freight-web/portal/src/pages/documents/DocumentsPage.tsx
index bd7976499..25c1b1dbe 100644
--- a/apps/edr-freight-web/portal/src/pages/documents/DocumentsPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/documents/DocumentsPage.tsx
@@ -12,6 +12,7 @@ import {
HardDrive,
LayoutGrid,
List,
+ MoreHorizontal,
Pencil,
Plus,
Search,
@@ -40,6 +41,11 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
type FilterValue = "All" | DocumentStatus;
@@ -145,37 +151,58 @@ export default function DocumentsPage() {
},
{
id: "actions",
- header: () =>
Actions
,
+ size: 40,
cell: ({ row }) => {
const doc = row.original;
return (
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+
+
+ Preview
+
+
+
+ Download
+
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Delete
+
+
+
+
);
},
@@ -200,7 +227,7 @@ export default function DocumentsPage() {
-
+
By {doc.uploadedBy}
-
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+
+
+ Preview
+
+
+
+ Download
+
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Delete
+
+
+
+
diff --git a/apps/edr-freight-web/portal/src/pages/tracking/TrackingPage.tsx b/apps/edr-freight-web/portal/src/pages/tracking/TrackingPage.tsx
index ce277ff9c..144bc2bef 100644
--- a/apps/edr-freight-web/portal/src/pages/tracking/TrackingPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/tracking/TrackingPage.tsx
@@ -3,9 +3,11 @@ import {
ArrowRight,
Building2,
Clock,
+ Eye,
LayoutGrid,
List,
MapPin,
+ MoreHorizontal,
Pencil,
Plus,
Search,
@@ -31,6 +33,11 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
type FilterValue = "All" | ShipmentStatus;
@@ -77,7 +84,7 @@ export default function TrackingPage() {
-
+
-
-
-
-
-
-
-
-
+
e.stopPropagation()}>
+
+
+
+
+
+
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()} variant="destructive">
+
+ Remove
+
+
+
+
@@ -402,30 +423,45 @@ function ShipmentTable({ shipments: rows }: { shipments: Shipment[] }) {
-
-
-
-
-
-
-
-
+ e.stopPropagation()}>
+
+
+
+
+
+
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()} variant="destructive">
+
+ Remove
+
+
+
+
|
diff --git a/apps/edr-freight-web/portal/src/pages/trains/TrainsPage.tsx b/apps/edr-freight-web/portal/src/pages/trains/TrainsPage.tsx
index 42447f5b5..bfaa16d36 100644
--- a/apps/edr-freight-web/portal/src/pages/trains/TrainsPage.tsx
+++ b/apps/edr-freight-web/portal/src/pages/trains/TrainsPage.tsx
@@ -1,7 +1,9 @@
import { useMemo, useState } from "react";
import {
+ Eye,
Filter,
Gauge,
+ MoreHorizontal,
Pencil,
Plus,
Search,
@@ -26,6 +28,11 @@ import {
CardDescription,
CardContent,
Input,
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
} from "@edr/ui-common";
type FilterValue = "All" | TrainStatus;
@@ -120,38 +127,59 @@ export default function TrainsPage() {
},
{
id: "actions",
- header: () =>
Actions
,
+ size: 40,
cell: ({ row }) => {
const train = row.original;
return (
-
-
-
-
-
-
-
-
+
e.stopPropagation()}
+ >
+
+
+
+
+
+
+
+ View
+
+
+ e.preventDefault()}>
+
+ Edit
+
+
+
+
+ e.preventDefault()}
+ variant="destructive"
+ >
+
+ Retire
+
+
+
+
);
},
@@ -175,13 +203,16 @@ export default function TrainsPage() {
-
+
{
setQuery(e.target.value);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
placeholder="Search trains..."
className="pl-8!"
@@ -255,7 +286,10 @@ export default function TrainsPage() {
type="button"
onClick={() => {
setFilter(f);
- setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
+ setPagination({
+ pageIndex: 0,
+ pageSize: pagination.pageSize,
+ });
}}
className={
isActive
@@ -299,7 +333,7 @@ export default function TrainsPage() {
columns={columns}
data={paginatedData}
status="success"
- onRowClick={() => {}}
+ onRowClick={() => { }}
pagination={{
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
diff --git a/packages/ui-common/src/components/dropdown-menu.tsx b/packages/ui-common/src/components/dropdown-menu.tsx
new file mode 100644
index 000000000..102228c02
--- /dev/null
+++ b/packages/ui-common/src/components/dropdown-menu.tsx
@@ -0,0 +1,255 @@
+import * as React from "react"
+import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
+import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
+
+import { cn } from "../lib/utils"
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+ variant?: "default" | "destructive"
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+}
diff --git a/packages/ui-common/src/index.ts b/packages/ui-common/src/index.ts
index 6f047a6f2..39405a088 100644
--- a/packages/ui-common/src/index.ts
+++ b/packages/ui-common/src/index.ts
@@ -23,6 +23,6 @@ export * from "./components/input";
export * from "./components/textarea";
export * from "./components/label";
export * from "./components/card";
-
+export * from "./components/dropdown-menu";
export * from "./components/data-table";
export * from "./components/dialog";