Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use client';

import type { Shipment } from '@/types/shipment.types';

interface Props {
shipments: Shipment[];
onViewDetails?: (id: string) => void;
}

export function ResponsiveShipmentList({ shipments, onViewDetails }: Props) {
if (shipments.length === 0) {
return <p className="py-8 text-center text-sm text-gray-500">No shipments found.</p>;
}

return (
<>
{/* Desktop table */}
<div className="hidden md:block overflow-x-auto">
<table className="min-w-full text-sm">
<thead className="bg-gray-50 text-left text-xs font-semibold uppercase text-gray-500">
<tr>
{['ID', 'Origin', 'Destination', 'Status', 'Weight'].map((h) => (
<th key={h} className="px-4 py-3">{h}</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
{shipments.map((s) => (
<tr key={s.id} className="hover:bg-gray-50 cursor-pointer" onClick={() => onViewDetails?.(s.id)}>
<td className="px-4 py-3 font-mono text-xs">{s.id.slice(0, 8)}</td>
<td className="px-4 py-3">{s.origin}</td>
<td className="px-4 py-3">{s.destination}</td>
<td className="px-4 py-3 capitalize">{s.status}</td>
<td className="px-4 py-3">{s.weight} kg</td>
</tr>
))}
</tbody>
</table>
</div>

{/* Mobile cards */}
<div className="flex flex-col gap-3 md:hidden">
{shipments.map((s) => (
<div key={s.id} className="rounded-lg border bg-white p-4 shadow-sm" onClick={() => onViewDetails?.(s.id)}>
<p className="text-xs font-mono text-gray-400">{s.id.slice(0, 8)}</p>
<p className="mt-1 font-medium">{s.origin} → {s.destination}</p>
<div className="mt-2 flex items-center justify-between text-sm text-gray-600">
<span className="capitalize">{s.status}</span>
<span>{s.weight} kg</span>
</div>
</div>
))}
</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ResponsiveShipmentList } from './ResponsiveShipmentList';
64 changes: 64 additions & 0 deletions frontend/package/components/Skeletons/Skeletons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const base = 'animate-pulse rounded bg-gray-200';

export function SkeletonText({ className = '' }: { className?: string }) {
return <div className={`${base} h-4 w-full ${className}`} />;
}

export function SkeletonBox({ className = '' }: { className?: string }) {
return <div className={`${base} ${className}`} />;
}

export function SkeletonAvatar({ size = 40 }: { size?: number }) {
return <div className={`${base} rounded-full`} style={{ width: size, height: size }} />;
}

export function SkeletonCard() {
return (
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="flex items-center gap-3">
<SkeletonAvatar />
<div className="flex-1 space-y-2">
<SkeletonText className="w-3/4" />
<SkeletonText className="w-1/2" />
</div>
</div>
<div className="mt-4 space-y-2">
<SkeletonText />
<SkeletonText className="w-5/6" />
<SkeletonText className="w-4/6" />
</div>
</div>
);
}

export function SkeletonTable({ rows = 5, cols = 4 }: { rows?: number; cols?: number }) {
return (
<div className="space-y-2">
<div className={`grid gap-4`} style={{ gridTemplateColumns: `repeat(${cols}, 1fr)` }}>
{Array.from({ length: cols }).map((_, i) => (
<SkeletonText key={i} className="h-3 w-3/4" />
))}
</div>
{Array.from({ length: rows }).map((_, r) => (
<div key={r} className={`grid gap-4`} style={{ gridTemplateColumns: `repeat(${cols}, 1fr)` }}>
{Array.from({ length: cols }).map((_, c) => (
<SkeletonText key={c} />
))}
</div>
))}
</div>
);
}

export function SkeletonShipmentCard() {
return (
<div className="rounded-lg border bg-white p-4 shadow-sm space-y-3">
<SkeletonText className="w-1/3 h-3" />
<SkeletonText className="w-2/3" />
<div className="flex justify-between">
<SkeletonText className="w-1/4" />
<SkeletonText className="w-1/5" />
</div>
</div>
);
}
1 change: 1 addition & 0 deletions frontend/package/components/Skeletons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SkeletonText, SkeletonBox, SkeletonAvatar, SkeletonCard, SkeletonTable, SkeletonShipmentCard } from './Skeletons';
Loading