diff --git a/components/__tests__/DashboardOverview.test.tsx b/components/__tests__/DashboardOverview.test.tsx index a7a82daa..cb7e7eea 100644 --- a/components/__tests__/DashboardOverview.test.tsx +++ b/components/__tests__/DashboardOverview.test.tsx @@ -1,20 +1,16 @@ -// __tests__/components/DashboardOverview.test.tsx - import React from 'react'; import { render, screen } from '@testing-library/react'; -import DashboardOverview from '@/components/dashboard/DashboardOverview'; // Adjust path as needed -import { useDashboardData } from '@/hooks/useDashboardData'; // Adjust path to your data hook +import DashboardOverview from '@/components/dashboard/DashboardOverview'; +import { useDashboardData } from '@/hooks/useDashboardData'; -// Mock the data fetching hook to control loading states jest.mock('@/hooks/useDashboardData'); -describe('Component: Skeleton Loading States for Dashboard', () => { +describe('DashboardOverview', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('renders skeleton UI placeholders when data is loading', () => { - // Force the loading state to true + it('renders skeleton placeholders while loading', () => { (useDashboardData as jest.Mock).mockReturnValue({ data: null, isLoading: true, @@ -23,20 +19,28 @@ describe('Component: Skeleton Loading States for Dashboard', () => { render(); - // Assert that skeleton elements are rendered - const skeletons = screen.getAllByTestId('skeleton-loader'); - expect(skeletons.length).toBeGreaterThan(0); - - // Assert that actual data content is not present - expect(screen.queryByText(/total deliveries/i)).not.toBeInTheDocument(); + expect(screen.getAllByTestId('skeleton-loader').length).toBeGreaterThan(0); + expect(screen.queryByText(/dashboard overview/i)).not.toBeInTheDocument(); }); - it('removes skeleton loaders and renders actual data when loading completes', () => { - // Simulate a successful data fetch + it('renders metrics, active shipments, and quick actions when data loads', () => { (useDashboardData as jest.Mock).mockReturnValue({ data: { totalDeliveries: 1450, activeDrivers: 32, + metrics: [ + { label: 'Completed', value: '1284' }, + { label: 'Escrowed', value: '$245k' }, + ], + shipments: [ + { + id: 'SC-1048', + route: 'Lagos → Abuja', + status: 'In transit', + eta: '18 min', + }, + ], + quickActions: ['Create delivery', 'Assign driver'], }, isLoading: false, error: null, @@ -44,15 +48,18 @@ describe('Component: Skeleton Loading States for Dashboard', () => { render(); - // Assert that skeletons are removed - expect(screen.queryByTestId('skeleton-loader')).not.toBeInTheDocument(); - - // Assert that real data is rendered + expect( + screen.getByRole('heading', { name: /dashboard overview/i }) + ).toBeInTheDocument(); expect(screen.getByText('1450')).toBeInTheDocument(); expect(screen.getByText('32')).toBeInTheDocument(); + expect(screen.getByText(/active shipments/i)).toBeInTheDocument(); + expect(screen.getByText(/quick actions/i)).toBeInTheDocument(); + expect(screen.getByText('SC-1048')).toBeInTheDocument(); + expect(screen.getByText('Create delivery')).toBeInTheDocument(); }); - it('renders an error boundary or state if data fetching fails', () => { + it('renders an error state if data fetching fails', () => { (useDashboardData as jest.Mock).mockReturnValue({ data: null, isLoading: false, @@ -62,6 +69,8 @@ describe('Component: Skeleton Loading States for Dashboard', () => { render(); expect(screen.queryByTestId('skeleton-loader')).not.toBeInTheDocument(); - expect(screen.getByText(/failed to fetch dashboard metrics/i)).toBeInTheDocument(); + expect( + screen.getByText(/failed to fetch dashboard metrics/i) + ).toBeInTheDocument(); }); -}); \ No newline at end of file +}); diff --git a/components/dashboard/DashboardOverview.tsx b/components/dashboard/DashboardOverview.tsx new file mode 100644 index 00000000..c92bee95 --- /dev/null +++ b/components/dashboard/DashboardOverview.tsx @@ -0,0 +1,151 @@ +'use client'; + +import { useDashboardData } from '@/hooks/useDashboardData'; + +export default function DashboardOverview() { + const { data, isLoading, error } = useDashboardData(); + + if (isLoading) { + return ( +
+
+
+
+
+
+
+ +
+ {Array.from({ length: 3 }).map((_, index) => ( +
+ ))} +
+
+ ); + } + + if (error) { + return ( +
+
+ Failed to fetch dashboard metrics +
+
+ ); + } + + if (!data) { + return ( +
+

No dashboard data available.

+
+ ); + } + + return ( +
+
+

+ Dashboard Overview +

+

+ Live logistics performance and shipment activity +

+
+ +
+ {data.metrics.map((metric) => ( +
+

+ {metric.label} +

+

+ {metric.value} +

+
+ ))} +
+

+ Total Deliveries +

+

+ {data.totalDeliveries} +

+
+
+

+ Active Drivers +

+

+ {data.activeDrivers} +

+
+
+ +
+
+

+ Active shipments +

+
    + {data.shipments.map((shipment) => ( +
  • +
    +

    + {shipment.id} +

    +

    + {shipment.route} +

    +
    +
    +

    + {shipment.status} +

    +

    + {shipment.eta} +

    +
    +
  • + ))} +
+
+ +
+

+ Quick actions +

+
    + {data.quickActions.map((action) => ( +
  • + {action} +
  • + ))} +
+
+
+
+ ); +} diff --git a/hooks/useDashboardData.ts b/hooks/useDashboardData.ts new file mode 100644 index 00000000..1a6f84e9 --- /dev/null +++ b/hooks/useDashboardData.ts @@ -0,0 +1,58 @@ +export interface DashboardShipment { + id: string; + route: string; + status: string; + eta: string; +} + +export interface DashboardOverviewData { + totalDeliveries: number; + activeDrivers: number; + metrics: Array<{ label: string; value: string | number }>; + shipments: DashboardShipment[]; + quickActions: string[]; +} + +export function useDashboardData() { + const data: DashboardOverviewData = { + totalDeliveries: 1450, + activeDrivers: 32, + metrics: [ + { label: 'Completed', value: '1284' }, + { label: 'Pending', value: '96' }, + { label: 'Escrowed', value: '$245k' }, + ], + shipments: [ + { + id: 'SC-1048', + route: 'Lagos → Abuja', + status: 'In transit', + eta: '18 min', + }, + { + id: 'SC-1021', + route: 'Accra → Kumasi', + status: 'Assigned', + eta: '32 min', + }, + { + id: 'SC-1007', + route: 'Nairobi → Mombasa', + status: 'Delayed', + eta: 'Requires review', + }, + ], + quickActions: [ + 'Create delivery', + 'Assign driver', + 'View analytics', + 'Review escrow', + ], + }; + + return { + data, + isLoading: false, + error: null, + }; +}