Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/app/(protected)/bookings-lite/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Suspense } from "react";
import { Container, Stack, Title } from "@mantine/core";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
import { getActiveShipments } from "@/lib/shipments/queries";
import { getCurrentSession } from "@/server/auth/utils/session";
import getQueryClient from "@/config/get-query-client";
import BookingsLiteTable from "./table";
import TableSkeleton from "./table-skeleton";

export default async function BookingsLitePage() {
const { user } = await getCurrentSession();
const queryClient = getQueryClient();

// Prefetch active shipments
await queryClient.prefetchQuery({
queryKey: ["shipmentData", "active"],
queryFn: () => getActiveShipments({ user }),
});

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<Container size="xl" py="xl">
<Stack gap="lg">
<Title order={1}>Bookings</Title>
<Suspense fallback={<TableSkeleton />}>
<BookingsLiteTable />
</Suspense>
</Stack>
</Container>
</HydrationBoundary>
);
}
108 changes: 108 additions & 0 deletions src/app/(protected)/bookings-lite/table-skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Paper, Skeleton, Stack, Group, Title } from "@mantine/core";

export default function TableSkeleton() {
return (
<Paper withBorder shadow="md" radius="md">
<Stack p="md" gap="md">
<Group justify="space-between">
<Title order={4}>Loading Bookings...</Title>
<Skeleton height={36} width={300} />
</Group>

{/* Table header skeleton */}
<Group justify="space-between" px="md" py="xs" gap="md">
<Skeleton height={20} width={140} />
<Skeleton height={20} width={140} />
<Skeleton height={20} width={180} />
<Skeleton height={20} width={180} />
<Skeleton height={20} width={150} />
<Skeleton height={20} width={250} />
</Group>

{/* Table rows skeleton */}
{Array.from({ length: 10 }).map((_, rowIndex) => (
<Group key={rowIndex} justify="space-between" px="md" py="md" gap="md" align="flex-start">
{/* Booking column */}
<Stack gap={8} style={{ width: 140 }}>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Skeleton height={16} width={120} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={60} />
<Skeleton height={16} width={120} />
</Stack>
</Stack>

{/* Shipper column */}
<Stack gap={8} style={{ width: 140 }}>
<Stack gap={4}>
<Skeleton height={12} width={70} />
<Skeleton height={16} width={100} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={80} />
<Skeleton height={16} width={120} />
</Stack>
</Stack>

{/* Origin column */}
<Stack gap={8} style={{ width: 180 }}>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Skeleton height={16} width={150} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Skeleton height={16} width={150} />
</Stack>
</Stack>

{/* Destination column */}
<Stack gap={8} style={{ width: 180 }}>
<Stack gap={4}>
<Skeleton height={12} width={60} />
<Skeleton height={16} width={150} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Skeleton height={16} width={150} />
</Stack>
</Stack>

{/* Dates column */}
<Stack gap={8} style={{ width: 150 }}>
<Stack gap={4}>
<Skeleton height={12} width={30} />
<Skeleton height={16} width={80} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={30} />
<Skeleton height={16} width={80} />
</Stack>
</Stack>

{/* Vessel & Status column */}
<Stack gap={8} style={{ width: 250 }}>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Skeleton height={16} width={200} />
</Stack>
<Stack gap={4}>
<Skeleton height={12} width={50} />
<Group gap="xs">
<Skeleton height={20} width={80} radius="xl" />
</Group>
</Stack>
</Stack>
</Group>
))}

{/* Pagination skeleton */}
<Group justify="flex-end" px="md" py="xs">
<Skeleton height={36} width={200} />
</Group>
</Stack>
</Paper>
);
}
72 changes: 72 additions & 0 deletions src/app/(protected)/bookings-lite/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"use client";

import {
MantineReactTable,
useMantineReactTable,
} from "mantine-react-table";

import { useRouter } from "next/navigation";
import { useBookingColumns } from "@/components/tables/bookings-columns";
import { Text } from "@mantine/core";
import { useUser } from "@/hooks/use-user";
import { useQuery } from "@tanstack/react-query";
import { getActiveShipments } from "@/lib/shipments/queries";

export default function BookingsLiteTable() {
const router = useRouter();
const { user } = useUser();
const columns = useBookingColumns();

// Fetch all active shipments
const { data, isLoading } = useQuery({
queryKey: ["shipmentData", "active"],
queryFn: () => getActiveShipments({ user }),
enabled: !!user,
});

const table = useMantineReactTable({
data: data ?? [],
state: { isLoading },
layoutMode: "grid",
columns: columns,
enableFullScreenToggle: false,
enableHiding: false,
enableColumnActions: false,
enableDensityToggle: false,
enableColumnFilters: false,
initialState: {
sorting: [{ id: "dates", desc: false }],
pagination: { pageIndex: 0, pageSize: 25 },
density: "xs",
showGlobalFilter: true,
},
defaultColumn: {
size: 160,
},
mantineTableProps: {
striped: true,
},
mantineTableHeadCellProps: {
style: { padding: "8px 12px" },
},
mantineTableBodyCellProps: {
style: { padding: "12px", verticalAlign: "top", textAlign: "left" },
},
mantineTableBodyRowProps: ({ row }) => ({
onClick: () => {
router.push(`/dashboard?bookingNumber=${row.original["_GMT#"]}`);
},
style: {
cursor: "pointer",
},
}),
renderTopToolbarCustomActions: () => (
<Text size="lg">
<strong>{user?.reportReferenceCustomer}</strong>
{" Active Shipments"}
</Text>
),
});

return <MantineReactTable table={table} />;
}