diff --git a/web/__tests__/responsive-design.test.tsx b/web/__tests__/responsive-design.test.tsx
new file mode 100644
index 0000000..f64f519
--- /dev/null
+++ b/web/__tests__/responsive-design.test.tsx
@@ -0,0 +1,200 @@
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+// Mock next/navigation
+jest.mock('next/navigation', () => ({
+ useRouter: () => ({
+ push: jest.fn(),
+ replace: jest.fn(),
+ }),
+ usePathname: () => '/dashboard',
+}));
+
+// Mock auth store
+jest.mock('@/stores/authStore', () => ({
+ useAuthStore: () => ({
+ isAuthenticated: true,
+ user: { firstName: 'Test', lastName: 'User', email: 'test@example.com' },
+ logout: jest.fn(),
+ }),
+}));
+
+// Mock API
+jest.mock('@/lib/api', () => ({
+ __esModule: true,
+ default: {
+ getAllBeneficiaries: jest.fn().mockResolvedValue({ ok: true, data: [] }),
+ },
+}));
+
+import { Layout } from '@/components/Layout/Layout';
+import { Header } from '@/components/Layout/Header';
+import { Sidebar } from '@/components/Layout/Sidebar';
+
+describe('Responsive Design - Layout Components', () => {
+ describe('Layout Component', () => {
+ it('has responsive max-width classes for 4K screens', () => {
+ const { container } = render(
+
+ Test Content
+
+ );
+
+ // Find the main content container
+ const mainContent = container.querySelector('main > div');
+ expect(mainContent).toBeInTheDocument();
+
+ // Check for responsive max-width classes
+ const className = mainContent?.className || '';
+ expect(className).toContain('max-w-7xl');
+ expect(className).toContain('3xl:max-w-8xl');
+ expect(className).toContain('4xl:max-w-9xl');
+ });
+
+ it('has responsive padding for large screens', () => {
+ const { container } = render(
+
+ Test Content
+
+ );
+
+ const mainContent = container.querySelector('main > div');
+ const className = mainContent?.className || '';
+
+ // Check for responsive padding classes
+ expect(className).toContain('px-4');
+ expect(className).toContain('lg:px-8');
+ expect(className).toContain('xl:px-10');
+ expect(className).toContain('3xl:px-12');
+ expect(className).toContain('4xl:px-16');
+ });
+
+ it('has responsive sidebar offset', () => {
+ const { container } = render(
+
+ Test Content
+
+ );
+
+ // Find main content area (direct child of root container, contains pl- classes)
+ // The structure is: div.flex.min-h-screen > aside.sidebar + div.flex.flex-1.flex-col
+ const rootContainer = container.querySelector('.flex.min-h-screen');
+ const contentArea = rootContainer?.querySelector(':scope > div.flex-1');
+ const className = contentArea?.className || '';
+
+ expect(className).toContain('lg:pl-64');
+ expect(className).toContain('3xl:pl-72');
+ expect(className).toContain('4xl:pl-80');
+ });
+ });
+
+ describe('Header Component', () => {
+ it('has responsive container width for large screens', () => {
+ const { container } = render();
+
+ // Find header container
+ const headerContainer = container.querySelector('header > div');
+ const className = headerContainer?.className || '';
+
+ expect(className).toContain('max-w-7xl');
+ expect(className).toContain('3xl:max-w-8xl');
+ expect(className).toContain('4xl:max-w-9xl');
+ });
+
+ it('has responsive padding', () => {
+ const { container } = render();
+
+ const headerContainer = container.querySelector('header > div');
+ const className = headerContainer?.className || '';
+
+ expect(className).toContain('px-4');
+ expect(className).toContain('lg:px-8');
+ expect(className).toContain('xl:px-10');
+ expect(className).toContain('3xl:px-12');
+ expect(className).toContain('4xl:px-16');
+ });
+
+ it('hides mobile menu on md screens and above', () => {
+ render();
+
+ // Mobile menu button should have md:hidden class
+ const mobileMenuButton = screen.getByLabelText('Toggle menu');
+ expect(mobileMenuButton).toHaveClass('md:hidden');
+ });
+
+ it('shows desktop navigation on md screens and above', () => {
+ const { container } = render();
+
+ // Desktop nav should have hidden md:flex classes
+ const desktopNav = container.querySelector('nav.hidden.md\\:flex');
+ expect(desktopNav).toBeInTheDocument();
+ });
+ });
+
+ describe('Sidebar Component', () => {
+ it('has responsive width for large screens', () => {
+ const { container } = render();
+
+ const sidebar = container.querySelector('aside');
+ const className = sidebar?.className || '';
+
+ // Check responsive width classes
+ expect(className).toContain('lg:w-64');
+ expect(className).toContain('3xl:w-72');
+ expect(className).toContain('4xl:w-80');
+ });
+
+ it('is hidden on mobile and tablet, shown on lg+', () => {
+ const { container } = render();
+
+ const sidebar = container.querySelector('aside');
+ const className = sidebar?.className || '';
+
+ expect(className).toContain('hidden');
+ expect(className).toContain('lg:flex');
+ });
+ });
+});
+
+describe('Responsive Design - Breakpoint Coverage', () => {
+ it('defines required breakpoints in Tailwind config', async () => {
+ // This is a conceptual test - in practice, check the compiled CSS
+ // or use visual regression testing
+
+ const breakpoints = {
+ sm: '640px',
+ md: '768px',
+ lg: '1024px',
+ xl: '1280px',
+ '2xl': '1536px',
+ '3xl': '1920px', // Full HD
+ '4xl': '2560px', // QHD / 4K
+ };
+
+ // Verify we're targeting all key breakpoints
+ expect(Object.keys(breakpoints)).toContain('md'); // Tablet
+ expect(Object.keys(breakpoints)).toContain('lg'); // Desktop
+ expect(Object.keys(breakpoints)).toContain('3xl'); // Full HD
+ expect(Object.keys(breakpoints)).toContain('4xl'); // 4K
+ });
+
+ it('covers tablet range (768px-1023px)', () => {
+ // Tablet breakpoint is md (768px) to lg (1024px)
+ // Components should have specific behavior in this range
+
+ const mdBreakpoint = 768;
+ const lgBreakpoint = 1024;
+
+ expect(mdBreakpoint).toBeGreaterThanOrEqual(768);
+ expect(lgBreakpoint - mdBreakpoint).toBeGreaterThan(0);
+ });
+
+ it('covers large screen range (1920px-4K)', () => {
+ // Large screens from Full HD to 4K
+ const fullHD = 1920;
+ const fourK = 2560;
+
+ expect(fullHD).toBeGreaterThanOrEqual(1920);
+ expect(fourK).toBeGreaterThanOrEqual(2560);
+ });
+});
diff --git a/web/app/(main)/dashboard/page.tsx b/web/app/(main)/dashboard/page.tsx
index 1511b9e..265fbf1 100644
--- a/web/app/(main)/dashboard/page.tsx
+++ b/web/app/(main)/dashboard/page.tsx
@@ -69,7 +69,7 @@ export default function DashboardPage() {
if (isLoading) {
return (
-
+
);
}
@@ -86,17 +86,17 @@ export default function DashboardPage() {
return (
{/* Header */}
-
-
+
+
Welcome{user?.firstName ? `, ${user.firstName}` : ''}
-
+
Monitor your loved ones and manage their health sensors
{/* Summary Cards */}
-
+
-
-
Your Loved Ones
+
+
Your Loved Ones
) : (
-
+
{beneficiaries.map((beneficiary) => (
-
+
{/* Logo and brand */}
diff --git a/web/components/Layout/Layout.tsx b/web/components/Layout/Layout.tsx
index 0980b9c..ea3ec34 100644
--- a/web/components/Layout/Layout.tsx
+++ b/web/components/Layout/Layout.tsx
@@ -46,13 +46,14 @@ interface LayoutProps {
/**
* Max width classes mapping
+ * Responsive: scales up on larger screens for better use of space
*/
const maxWidthClasses = {
full: '',
- '7xl': 'max-w-7xl',
- '6xl': 'max-w-6xl',
- '5xl': 'max-w-5xl',
- '4xl': 'max-w-4xl',
+ '7xl': 'max-w-7xl 3xl:max-w-8xl 4xl:max-w-9xl',
+ '6xl': 'max-w-6xl 3xl:max-w-7xl 4xl:max-w-8xl',
+ '5xl': 'max-w-5xl 3xl:max-w-6xl 4xl:max-w-7xl',
+ '4xl': 'max-w-4xl 3xl:max-w-5xl 4xl:max-w-6xl',
};
/**
@@ -106,13 +107,13 @@ export function Layout({
{showSidebar &&
}
{/* Main content area */}
-
+
{/* Header */}
{showHeader &&
}
{/* Page content */}
-
+
{/* Breadcrumbs */}
{showBreadcrumbs && (
diff --git a/web/components/Layout/Sidebar.tsx b/web/components/Layout/Sidebar.tsx
index b95b5dc..618cfcc 100644
--- a/web/components/Layout/Sidebar.tsx
+++ b/web/components/Layout/Sidebar.tsx
@@ -77,7 +77,7 @@ export function Sidebar() {
: user?.email || 'User';
return (
-