diff --git a/apps/edr-freight-web/portal/src/pages/admin/DropdownSettingsPage.tsx b/apps/edr-freight-web/portal/src/pages/admin/DropdownSettingsPage.tsx index 93d466006..44cfaa8b0 100644 --- a/apps/edr-freight-web/portal/src/pages/admin/DropdownSettingsPage.tsx +++ b/apps/edr-freight-web/portal/src/pages/admin/DropdownSettingsPage.tsx @@ -2,8 +2,10 @@ import { useMemo, useState } from "react"; import { Boxes, CheckCircle2, + Eye, Filter, ListOrdered, + MoreHorizontal, Pencil, Plus, Search, @@ -30,6 +32,11 @@ import { CardDescription, CardContent, Input, + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, } from "@edr/ui-common"; export default function DropdownSettingsPage() { @@ -121,12 +128,8 @@ export default function DropdownSettingsPage() { ) : ( )} - {s.meta?.searchable ? ( - - ) : null} - {s.meta?.clearable ? ( - - ) : null} + {s.meta?.searchable ? : null} + {s.meta?.clearable ? : null} ); }, @@ -157,32 +160,53 @@ export default function DropdownSettingsPage() { }, { id: "actions", - header: () =>
Actions
, + size: 40, cell: ({ row }) => { const setting = row.original; return ( -
- - - - - - - - - - - +
e.stopPropagation()} + > + + + + + + + + View + + + e.preventDefault()}> + + Options + + + + + e.preventDefault()}> + + Edit + + + + + e.preventDefault()} + variant="destructive" + > + + Delete + + + +
); }, @@ -212,13 +236,16 @@ export default function DropdownSettingsPage() {
- + { 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";