Overview
The platform has inconsistent error handling across pages, no global error boundary, a missing 404 page, varying loading states, and multiple toast implementations. This issue standardizes error handling and loading UX across the entire application.
Technical Details
1. Global Error Boundary (frontend/app/error.tsx)
Create or update the Next.js root error boundary:
// app/error.tsx — auto-wired by Next.js App Router
'use client';
export default function ErrorBoundary({ error, reset }: { error: Error, reset: () => void }) {
// Log to console in dev, or to Sentry/observability tool in prod
return (
<div className="error-boundary-container">
<h2>Something went wrong</h2>
<p>{error.message || 'An unexpected error occurred'}</p>
<button onClick={reset}>Try again</button>
<a href="/dashboard">Go to dashboard</a>
</div>
);
}
Also create frontend/app/global-error.tsx for root layout errors (same pattern).
Create a frontend/app/(dashboard)/error.tsx specifically for the dashboard section that shows a friendlier "Dashboard failed to load" error with a retry button.
2. Custom 404 Page (frontend/app/not-found.tsx)
Create or update app/not-found.tsx:
- Illustration: a lost truck SVG or simple "404" large text with a truck icon
- Heading: "Page Not Found"
- Subtext: "The page you're looking for doesn't exist or has been moved."
- Two buttons: "Go to Dashboard" →
/dashboard and "Go to Home" → /
- Use
Link from next/link
3. Skeleton Loading Components
Create a set of reusable skeleton components in frontend/components/skeletons/:
ShipmentCardSkeleton — matches the shape of a shipment list card
TableRowSkeleton — one row of a data table (configurable number of columns)
KpiCardSkeleton — matches the KPI card shape from the dashboard
ProfileSkeleton — avatar circle + two lines of text
NotificationItemSkeleton — matches a notification row
Each skeleton uses a CSS shimmer animation (animate-pulse from Tailwind or a custom keyframe). Export all from frontend/components/skeletons/index.ts.
Audit all existing pages that show a blank or spinning loading state and replace with the appropriate skeleton component:
/shipments: use TableRowSkeleton × 5 while loading
/dashboard: use KpiCardSkeleton × 4 while loading
/notifications: use NotificationItemSkeleton × 5 while loading
/bids: use TableRowSkeleton × 3 while loading
4. Toast System Standardization
The project has sonner installed. Audit all existing toast() calls across the frontend and ensure they follow a consistent API:
// All success toasts:
toast.success('Action completed successfully');
// All error toasts:
toast.error('Something went wrong. Please try again.');
// All info toasts:
toast.info('Processing your request...');
- Remove any direct uses of
alert() or console.error() intended as user feedback
- Ensure the
Toaster component from sonner is rendered once in frontend/app/layout.tsx
- Set default:
position: 'top-right', duration: 4000
5. Empty States
Create a reusable <EmptyState /> component (frontend/components/ui/empty-state.tsx):
<EmptyState icon={<TruckIcon />} title="No shipments yet" description="Post your first shipment to get started." action={{ label: 'Post Shipment', href: '/shipments/new' }} />
Use it on all pages that currently show blank or missing content for empty data sets.
Acceptance Criteria
Overview
The platform has inconsistent error handling across pages, no global error boundary, a missing 404 page, varying loading states, and multiple toast implementations. This issue standardizes error handling and loading UX across the entire application.
Technical Details
1. Global Error Boundary (
frontend/app/error.tsx)Create or update the Next.js root error boundary:
Also create
frontend/app/global-error.tsxfor root layout errors (same pattern).Create a
frontend/app/(dashboard)/error.tsxspecifically for the dashboard section that shows a friendlier "Dashboard failed to load" error with a retry button.2. Custom 404 Page (
frontend/app/not-found.tsx)Create or update
app/not-found.tsx:/dashboardand "Go to Home" →/Linkfromnext/link3. Skeleton Loading Components
Create a set of reusable skeleton components in
frontend/components/skeletons/:ShipmentCardSkeleton— matches the shape of a shipment list cardTableRowSkeleton— one row of a data table (configurable number of columns)KpiCardSkeleton— matches the KPI card shape from the dashboardProfileSkeleton— avatar circle + two lines of textNotificationItemSkeleton— matches a notification rowEach skeleton uses a CSS shimmer animation (
animate-pulsefrom Tailwind or a custom keyframe). Export all fromfrontend/components/skeletons/index.ts.Audit all existing pages that show a blank or spinning loading state and replace with the appropriate skeleton component:
/shipments: useTableRowSkeleton× 5 while loading/dashboard: useKpiCardSkeleton× 4 while loading/notifications: useNotificationItemSkeleton× 5 while loading/bids: useTableRowSkeleton× 3 while loading4. Toast System Standardization
The project has
sonnerinstalled. Audit all existingtoast()calls across the frontend and ensure they follow a consistent API:alert()orconsole.error()intended as user feedbackToastercomponent fromsonneris rendered once infrontend/app/layout.tsxposition: 'top-right',duration: 40005. Empty States
Create a reusable
<EmptyState />component (frontend/components/ui/empty-state.tsx):Use it on all pages that currently show blank or missing content for empty data sets.
Acceptance Criteria
frontend/components/skeletons//shipments,/dashboard, and/notificationsuse skeletons while loadingalert()calls remain in the frontend codebase (verify withgrep -r 'alert(' frontend/)Toasteris mounted once in the root layouttoast.success()andtoast.error()consistently<EmptyState />is used on at least 3 pages (shipments, bids, notifications)