diff --git a/APPLAYOUT_IMPLEMENTATION.md b/APPLAYOUT_IMPLEMENTATION.md
deleted file mode 100644
index 562ed56..0000000
--- a/APPLAYOUT_IMPLEMENTATION.md
+++ /dev/null
@@ -1,339 +0,0 @@
-# Global Layout & Responsive Sidebar - Implementation Summary
-
-## Overview
-
-Implemented a global application shell (`AppLayout`) with a responsive sidebar system that adapts to both desktop and mobile viewports. The implementation follows the strict Component → Hook → Service layered architecture pattern.
-
-## Implementation Details
-
-### Architecture: Component → Hook → Service Pattern ✓
-
-#### 1. **Service Layer** (`services/layoutService.ts`)
-
-- **Responsibility**: Manages all layout-related API communication and configuration
-- **Key Features**:
- - Fetches layout configuration from backend API
- - Retrieves navigation items based on user context
- - Manages user layout preferences (sidebar collapsed state, theme)
- - Provides fallback default configuration when API fails
- - Type-safe interfaces for all data structures
-- **Key Methods**:
- - `getLayoutConfig()`: Fetches branding and theme config
- - `getNavigationItems()`: Retrieves personalized nav items
- - `getUserLayoutPreferences()`: Gets user-specific preferences
- - `saveUserLayoutPreferences()`: Persists user preferences
-
-#### 2. **Custom Hook** (`hooks/useAppLayout.ts`)
-
-- **Responsibility**: Manages React component state and lifecycle
-- **Key Features**:
- - Detects mobile vs desktop (breakpoint: lg = 1024px)
- - Manages sidebar visibility state
- - Manages sidebar collapse state (desktop)
- - Handles window resize events
- - Provides method to filter nav items by role
- - Automatically initializes on mount
-- **Exposed API**:
- - `state`: Layout state (isLoading, error, isMobile, sidebarOpen, etc.)
- - `toggleSidebar()`: Toggle sidebar visibility on mobile
- - `closeSidebar()`: Close sidebar
- - `openSidebar()`: Open sidebar
- - `toggleSidebarCollapse()`: Toggle collapse state on desktop
- - `getVisibleNavItems()`: Get filtered navigation items
-
-#### 3. **UI Component** (`components/layout/AppLayout.tsx`)
-
-- **Responsibility**: Renders the application shell with responsive behavior
-- **Structure**:
- - `DesktopSidebar`: Fixed left sidebar (hidden on mobile)
- - `MobileBottomSheet`: Bottom-sheet menu (mobile only)
- - `NavLink`: Reusable navigation link component
- - Main layout wrapper with responsive margins
-- **Key Features**:
- - Responsive breakpoint: lg (1024px)
- - Mobile first approach with progressive enhancement
- - Dark mode support throughout
- - Loading state with spinner
- - Smooth transitions and animations
- - Accessibility features (ARIA labels, semantic HTML)
-
-### Files Created
-
-| File | Purpose | Lines |
-| --------------------------------- | ------------------------ | ----- |
-| `services/layoutService.ts` | API integration & config | 186 |
-| `hooks/useAppLayout.ts` | State management & logic | 142 |
-| `components/layout/AppLayout.tsx` | UI rendering | 268 |
-
-## Responsive Design
-
-### Desktop (1024px+)
-
-- **Sidebar**: Fixed left sidebar, 256px wide (or 80px when collapsed)
-- **Layout**: Main content shifts right based on sidebar state
-- **Interaction**: Click toggle button to collapse/expand sidebar
-- **Features**:
- - Collapsible sidebar with smooth transition
- - Full navigation items visible
- - Descriptions shown under nav labels
-
-### Mobile (< 1024px, tested at 375px)
-
-- **Header**: Sticky top header with hamburger menu icon
-- **Navigation**: Bottom-sheet drawer (slides up from bottom)
-- **Layout**: Full width main content
-- **Interactions**:
- - Tap hamburger to open bottom-sheet
- - Tap X or backdrop to close
- - Auto-closes when navigating to a link
-- **Features**:
- - Non-blocking bottom-sheet (draggable area at top)
- - Smooth slide-in animation
- - Dark overlay backdrop
- - Full navigation items visible in sheet
-
-## Component Usage
-
-```tsx
-import AppLayout from '@/components/layout/AppLayout';
-
-export default function RootLayout({ children }) {
- return (
-
-
- {children}
-
-
- );
-}
-```
-
-## Data Flow
-
-```
-Backend API
- ↓
-layoutService (fetch & format)
- ↓
-useAppLayout Hook (state management)
- ↓
-AppLayout Component (render)
- ↓
-NavLink Components (interactive)
-```
-
-## API Integration
-
-### Expected Backend Endpoints
-
-1. **GET `/api/layout/config`**
-
- ```json
- {
- "success": true,
- "data": {
- "branding": {
- "appName": "SwiftChain",
- "logo": "/logo.svg",
- "logoDark": "/logo-dark.svg"
- },
- "navigation": [...],
- "theme": {
- "primaryColor": "#3b82f6",
- "sidebarCollapsible": true
- }
- }
- }
- ```
-
-2. **GET `/api/layout/navigation`**
-
- ```json
- {
- "success": true,
- "data": [
- {
- "id": "dashboard",
- "label": "Dashboard",
- "href": "/dashboard",
- "icon": "📊",
- "description": "Overview and stats",
- "roles": ["customer", "driver", "admin"]
- },
- ...
- ]
- }
- ```
-
-3. **GET `/api/layout/preferences`**
-
- ```json
- {
- "success": true,
- "data": {
- "sidebarCollapsed": false,
- "theme": "light",
- "sidebarWidth": 256
- }
- }
- ```
-
-4. **PATCH `/api/layout/preferences`**
- - Request: `{ "sidebarCollapsed": boolean, "theme": "light" | "dark" }`
- - Response: Same as GET
-
-### Fallback Strategy
-
-- If API calls fail, service returns default configuration
-- Navigation items still functional with default items
-- User preferences default to: sidebar expanded, light theme, 256px width
-- No breaking UI changes due to API failures
-
-## Responsive Breakpoints
-
-| Breakpoint | Width | Sidebar |
-| -------------- | -------------- | ------------- |
-| Mobile (xs-sm) | < 1024px | Bottom-sheet |
-| Tablet (md) | 768px - 1023px | Bottom-sheet |
-| Desktop (lg) | ≥ 1024px | Fixed sidebar |
-
-## Styling & Theme
-
-### Color Scheme
-
-- **Primary**: Uses Tailwind `primary` color (#3b82f6)
-- **Light Mode**: Slate-50 background, white sidebar
-- **Dark Mode**: Slate-950 background, slate-900 sidebar
-- **Hover States**: Slate-100/800 backgrounds
-- **Borders**: Slate-200/800 colors
-
-### Animations
-
-- **Sidebar Toggle**: 300ms ease transitions
-- **Bottom Sheet**: 300ms ease translate animations
-- **Nav Items**: 200ms ease color/background transitions
-- **Loading Spinner**: Continuous rotation animation
-
-### Accessibility
-
-- Semantic HTML (header, nav, main, aside)
-- ARIA labels on all interactive elements
-- Proper heading hierarchy
-- Keyboard navigation support
-- Color contrast compliance (WCAG AA)
-- Focus management
-
-## Key Features
-
-✅ **Responsive Design**
-
-- Tested at 375px (mobile) and 1024px (desktop)
-- Smooth transitions between breakpoints
-- Touch-friendly mobile interactions
-
-✅ **Dark Mode Support**
-
-- Full dark mode styling throughout
-- Automatic theme switching via Tailwind
-
-✅ **Accessibility**
-
-- ARIA labels and semantic HTML
-- Keyboard navigation
-- Proper focus states
-
-✅ **Performance**
-
-- Lazy loads navigation data
-- Efficient state management
-- Minimal re-renders
-
-✅ **Error Handling**
-
-- Graceful fallback to default config
-- Error state display
-- Network error recovery
-
-✅ **Backend Integration**
-
-- Real API data source (no mocks)
-- User preference persistence
-- Role-based navigation (ready for filtering)
-
-## Testing Recommendations
-
-### Mobile Testing (375px)
-
-1. ✓ Hamburger menu appears at top
-2. ✓ Tap hamburger opens bottom-sheet
-3. ✓ Bottom-sheet animates from bottom
-4. ✓ Navigation items visible and tappable
-5. ✓ Backdrop click closes bottom-sheet
-6. ✓ X button closes bottom-sheet
-7. ✓ Automatic close on navigation
-8. ✓ Responsive text sizing
-
-### Desktop Testing (1024px+)
-
-1. ✓ Fixed sidebar appears on left (256px)
-2. ✓ Main content shifts right (margin-left: 256px)
-3. ✓ Collapse button works
-4. ✓ Sidebar collapses to 80px
-5. ✓ Navigation items remain visible when collapsed
-6. ✓ Hover states work on nav items
-7. ✓ Active route highlighted correctly
-8. ✓ Smooth transitions on all state changes
-
-### API Integration Testing
-
-1. ✓ Verify API endpoints return proper format
-2. ✓ Test fallback when API is down
-3. ✓ Test preferences persistence
-4. ✓ Test user role-based filtering
-5. ✓ Test network error recovery
-
-### Cross-browser Testing
-
-- Chrome/Edge (Chromium)
-- Firefox
-- Safari
-- Mobile browsers (Chrome, Safari)
-
-## Future Enhancements
-
-- Add nested navigation support
-- Implement breadcrumb integration
-- Add keyboard shortcuts
-- Persistent sidebar state per device
-- Animation preferences (respects prefers-reduced-motion)
-- Multi-language support
-- Custom icon support (SVG components)
-- Search/filter navigation items
-
-## Code Quality
-
-✅ TypeScript strict mode compliant
-✅ ESLint formatted
-✅ Prettier compliant
-✅ No console warnings
-✅ Comprehensive JSDoc comments
-✅ Proper error handling and guards
-✅ Follows project conventions
-✅ Mobile-first responsive approach
-
-## Related Issues
-
-Closes #[issue_id]
-
----
-
-## PR Submission Checklist
-
-- [ ] All tests pass (mobile + desktop)
-- [ ] API endpoints verified
-- [ ] Screenshots included (mobile & desktop)
-- [ ] Documentation updated
-- [ ] No console errors or warnings
-- [ ] Dark mode tested
-- [ ] Accessibility verified
-- [ ] PR description includes this summary
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 4a656c9..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,98 +0,0 @@
-````markdown
-# Contributing to SwiftChain Frontend
-
-Thank you for your interest in contributing to the **SwiftChain Frontend**! We welcome contributions from the community to help build the user interface for our Blockchain-Powered Logistics & Escrow Delivery Platform.
-
-Whether you are building out new Next.js UI components, fixing bugs, or proposing new user features, your help is incredibly valuable.
-
-## Product Reference
-
-Before contributing, please review our comprehensive Product Requirements Document to understand our users, features, and rollout phases:
-📄 **[SwiftChain Frontend PRD](https://docs.google.com/document/d/1ShtWjf6i5D5SueeEZ8aH_A3VbnckpbEfPAue4hKwXJo/edit?usp=sharing)**
-
-## Getting Started
-
-1. **Fork the repository** on GitHub.
-2. **Clone your fork** locally:
- ```bash
- git clone [https://github.com/your-username/SwiftChain_Frontend.git](https://github.com/your-username/SwiftChain_Frontend.git)
- cd SwiftChain_Frontend
- ```
-3. **Create a branch** for your feature or bug fix:
- ```bash
- git checkout -b feature/my-new-feature
- ```
-
-## Development Workflow
-
-The frontend application is the customer and administrator-facing interface allowing participants to interact with the logistics network.
-
-- **Tech Stack**: Next.js App Router, TypeScript, TailwindCSS, React Hook Form, Zod, Axios, TanStack Query, Zustand, WebSocket client.
-- **Roles Supported**: Customer, Driver, and Admin.
-- **Prerequisites**: Node.js (v18 or higher) and your preferred package manager (npm, yarn, or pnpm).
-
-### Installation & Setup
-
-1. **Install dependencies:**
- ```bash
- pnpm install
- ```
-````
-
-2. **Setup environment variables:**
-
- ```bash
- cp .env.example .env.local
- ```
-
- _(Fill in the required local variables inside `.env.local`)_
-
-3. **Start the development server:**
- ```bash
- pnpm dev
- ```
- The app will be available at `http://localhost:3000`.
-
-## Testing & UI Guidelines
-
-1. **Component Reliability**: Ensure any UI components handle API failures gracefully, display correct loading skeletons, and match the target Acceptance Criteria defined in the PRD (e.g., empty states, toast notifications).
-2. **Responsive Design**: All new features must be fully responsive. Test your implementations on both mobile (375px) and desktop viewports.
-3. **Accessibility**: Ensure your components are accessible, maintain good color contrast, and include proper ARIA labels.
-
-## Feature Requests & Git Issues
-
-We believe the community should drive the project's priorities based on the phased rollout outlined in our PRD (Phase 1 MVP ➔ Escrow ➔ Scaling).
-
-### Tackling Existing Issues
-
-When looking for something to work on, please check the GitHub Issues tab. We recommend filtering by our standard priority tags (`high`, `medium`, `low`) or type tags (`frontend`, `ui`).
-
-### Requesting a New Feature
-
-1. **Check existing requests**: Browse existing Issues to avoid duplicates.
-2. **Open an Issue**: Include a descriptive title, the problem/use case in the logistics flow, your proposed solution, and link back to the PRD document if applicable.
-
-## Submitting a Pull Request
-
-1. **Ensure all checks pass**: Run frontend linters and ensure there are zero strict TypeScript errors before submitting.
-2. **Update documentation**: If you change the routing architecture or core component structure, update the relevant markdown files.
-3. **Format your code**: Run your Prettier/ESLint formatting scripts.
-4. **Submit your PR** to the `main` branch.
- - Provide a clear description of the visual and functional changes.
- - Upload a **screenshot** or video recording of the working UI.
- - Include `Closes #[issue_id]` in the description to automatically link the PR to the issue.
-
----
-
-## License & Copyright
-
-By contributing, you agree that your contributions will be licensed under the **MIT License**, same as the project.
-
-++++++++++++++++++++++++++++++++++
-© Copyright
-© 2026 SwiftChainn. All rights reserved.
-++++++++++++++++++++++++++++++++++
-
-```
-
-```
diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md
deleted file mode 100644
index 6815ccc..0000000
--- a/IMPLEMENTATION_SUMMARY.md
+++ /dev/null
@@ -1,386 +0,0 @@
-# Login Interface Implementation - Summary
-
-## Overview
-
-Successfully implemented a complete login interface for SwiftChain Frontend following the Component → Hook → Service architecture pattern as specified in the requirements.
-
-## Acceptance Criteria - ALL MET ✅
-
-### ✅ Form Validation
-
-- Email field validation (required, valid format)
-- Password field validation (required)
-- Real-time error clearing on input change
-- Client-side validation before submission
-
-### ✅ Required Features
-
-- Email/Password input fields with validation
-- "Remember Me" checkbox
-- "Forgot Password" link
-- Password visibility toggle
-- Submit button with loading state
-- Link to registration page
-
-### ✅ Strict Layered Architecture
-
-Implementation follows **Component → Hook → Service** pattern:
-
-```
-LoginForm (Component)
- ↓
-useLogin (Custom Hook)
- ↓
-authService (Service Layer)
- ↓
-Axios API Calls
-```
-
-### ✅ Backend API Integration
-
-- No inline mock objects
-- All data retrieved from backend API via `authService`
-- Response-based error handling
-- Token management and storage
-
-### ✅ Unit Tests
-
-- ✅ 54/54 tests passing
-- ✅ All test suites pass (9/9)
-- ✅ Comprehensive coverage of components, hooks, and services
-
----
-
-## Implementation Details
-
-### Files Created
-
-#### 1. **LoginForm Component**
-
-[components/forms/LoginForm.tsx](../components/forms/LoginForm.tsx)
-
-- Renders login UI with all required fields
-- Integrates useLogin hook
-- Displays validation errors
-- Shows/hides password with toggle button
-- Remember me checkbox
-- Responsive design with TailwindCSS
-
-#### 2. **useLogin Hook**
-
-[hooks/useLogin.ts](../hooks/useLogin.ts)
-
-- Manages form state (values, errors)
-- Email format validation with regex
-- Real-time error clearing
-- Form submission with async API calls
-- Token storage in localStorage
-- Automatic redirect to dashboard on success
-- Error handling and display
-
-#### 3. **Authentication Service**
-
-[services/authService.ts](../services/authService.ts)
-
-- Centralized API communication
-- `login()` - Main authentication endpoint
-- `logout()` - Clears session
-- `requestPasswordReset()` - Forgot password flow
-- `resetPassword()` - Password reset with token
-- `getCurrentUser()` - Fetch authenticated user
-- Proper error handling
-
-#### 4. **Login Page**
-
-[app/(auth)/login/page.tsx](<../app/(auth)/login/page.tsx>)
-
-- Route: `/login`
-- Server component wrapper
-- Centered layout with responsive styling
-
-#### 5. **Comprehensive Tests**
-
-- [hooks/**tests**/useLogin.test.ts](../hooks/__tests__/useLogin.test.ts) - 19 tests
-- [components/forms/**tests**/LoginForm.test.tsx](../components/forms/__tests__/LoginForm.test.tsx) - 12 tests
-- [services/**tests**/authService.test.ts](../services/__tests__/authService.test.ts) - 10 tests
-
----
-
-## API Endpoints Used
-
-```typescript
-POST /api/auth/login
-{
- email: string,
- password: string
-}
-
-// Response
-{
- success: boolean,
- message: string,
- data: {
- token: string,
- user: {
- id: string,
- email: string,
- name: string,
- role: 'customer' | 'driver' | 'admin'
- }
- }
-}
-```
-
----
-
-## Key Features
-
-### 1. **Email Validation**
-
-- Required field validation
-- Format validation: `user@domain.com`
-- Real-time validation on blur
-- Clear error messages
-
-### 2. **Password Management**
-
-- Required field validation
-- Show/hide password toggle
-- Secure input type
-
-### 3. **User Experience**
-
-- Loading state on submit button
-- Error messages display
-- Remember me checkbox
-- Forgot password link
-- Link to registration
-- Responsive mobile design
-
-### 4. **Security**
-
-- Token stored in localStorage
-- Client-side validation before API call
-- Proper error handling (no credential exposure)
-- Secure password input
-
----
-
-## Testing Summary
-
-### Test Results
-
-```
-Test Suites: 9 passed, 9 total
-Tests: 54 passed, 54 total
-Snapshots: 0 total
-Time: 6.65 s
-```
-
-### Test Coverage
-
-#### useLogin Hook Tests (19 tests)
-
-- ✅ Initial state validation
-- ✅ Email/password value updates
-- ✅ Email validation (empty, invalid format, valid)
-- ✅ Password validation
-- ✅ Error clearing on input
-- ✅ Form submission validation
-- ✅ API integration
-- ✅ Error handling
-
-#### LoginForm Component Tests (12 tests)
-
-- ✅ Render all form fields
-- ✅ Sign in button rendering
-- ✅ Registration link
-- ✅ Password visibility toggle
-- ✅ Remember me checkbox
-- ✅ Input field interactions
-- ✅ Form blur handling
-- ✅ Form submit handling
-
-#### authService Tests (10 tests)
-
-- ✅ Successful login
-- ✅ Error handling
-- ✅ API endpoint verification
-- ✅ Logout functionality
-- ✅ Password reset request
-- ✅ Password reset confirmation
-- ✅ Get current user
-
----
-
-## Type Safety
-
-- ✅ Full TypeScript support
-- ✅ Interfaces defined for API responses
-- ✅ Type-safe hook returns
-- ✅ No any types in implementation
-
----
-
-## Code Quality
-
-- ✅ ESLint compliant
-- ✅ Follows project conventions
-- ✅ Proper error handling
-- ✅ Clean, readable code
-- ✅ Comprehensive comments
-
----
-
-## Browser Support
-
-- ✅ Chrome/Edge (latest)
-- ✅ Firefox (latest)
-- ✅ Safari (latest)
-- ✅ Mobile browsers
-- ✅ Responsive: 375px - 2560px
-
----
-
-## Performance
-
-- ✅ No unnecessary re-renders
-- ✅ useCallback for handlers
-- ✅ Efficient state management
-- ✅ Minimal bundle impact
-
----
-
-## Compliance with Contributing.md
-
-✅ Screenshot capability (visual components ready for PR screenshots)
-✅ Component reliability (graceful error handling)
-✅ Responsive design (mobile and desktop tested)
-✅ Accessibility (ARIA labels, keyboard navigation)
-✅ Git branch ready: `feat/login-ui`
-✅ All unit tests passing
-✅ Clear PR description template ready
-
----
-
-## Next Steps for PR Submission
-
-1. Create branch: `git checkout -b feat/login-ui`
-2. Take screenshots of:
- - Login form rendering
- - Email validation error
- - Password validation error
- - Successful login flow
- - Test coverage output
-3. Commit changes: `git add .`
-4. Create pull request with:
- - Title: "feat: Implement login interface for customers and drivers"
- - Description:
-
- ```
- Closes #[issue_id]
-
- ## Summary of Work
- Implemented complete login interface with:
- - Email/password fields with real-time validation
- - Remember me checkbox
- - Forgot password link
- - Password visibility toggle
- - Strict Component → Hook → Service architecture
- - Backend API integration (no mock data)
- - 54 passing unit tests
- - Full TypeScript support
-
- ## Screenshots
- [Include screenshots here]
- ```
-
- - Include test coverage screenshot
- - Link issue with "Closes #[issue_id]"
-
----
-
-## Files Modified/Created
-
-### Created
-
-- ✅ `components/forms/LoginForm.tsx`
-- ✅ `hooks/useLogin.ts`
-- ✅ `services/authService.ts`
-- ✅ `hooks/__tests__/useLogin.test.ts`
-- ✅ `components/forms/__tests__/LoginForm.test.tsx`
-- ✅ `services/__tests__/authService.test.ts`
-
-### Modified
-
-- ✅ `app/(auth)/login/page.tsx` - Updated with LoginForm integration
-
----
-
-## Verification Commands
-
-```bash
-# Run all tests
-pnpm test
-
-# Type checking (login implementation has no errors)
-pnpm type-check
-
-# Development server
-pnpm dev
-# Navigate to http://localhost:3000/login
-```
-
----
-
-## Environment Variables Required
-
-```env
-NEXT_PUBLIC_API_URL=
-```
-
-Example: `NEXT_PUBLIC_API_URL=http://localhost:3001`
-
----
-
-## Architecture Diagram
-
-```
-┌─────────────────────────────────────────────────┐
-│ LoginForm Component │
-│ - Renders UI │
-│ - Calls useLogin hook │
-│ - Displays validation errors │
-└──────────────────┬──────────────────────────────┘
- │ uses
- ▼
-┌─────────────────────────────────────────────────┐
-│ useLogin Hook │
-│ - State management (values, errors) │
-│ - Form validation logic │
-│ - Calls authService.login() │
-│ - Handles token storage │
-└──────────────────┬──────────────────────────────┘
- │ calls
- ▼
-┌─────────────────────────────────────────────────┐
-│ authService (Service Layer) │
-│ - API communication with Axios │
-│ - POST /api/auth/login │
-│ - Returns token and user data │
-└──────────────────┬──────────────────────────────┘
- │ calls
- ▼
-┌─────────────────────────────────────────────────┐
-│ Backend API Endpoint │
-│ - Validates credentials │
-│ - Generates JWT token │
-│ - Returns user profile │
-└─────────────────────────────────────────────────┘
-```
-
----
-
-**Implementation Status:** ✅ COMPLETE - Ready for PR submission
-
-All acceptance criteria have been met. The implementation follows best practices, includes comprehensive testing, and maintains strict architecture patterns as specified in the requirements.
diff --git a/MODAL_IMPLEMENTATION.md b/MODAL_IMPLEMENTATION.md
deleted file mode 100644
index c93bf2c..0000000
--- a/MODAL_IMPLEMENTATION.md
+++ /dev/null
@@ -1,444 +0,0 @@
-# Global Modal Framework - Implementation Summary
-
-## Overview
-
-Implemented a reusable, accessible modal component framework with focus trapping, backdrop blur, and smooth animations. The system follows strict layered architecture (Component → Hook → Service) with backend API integration for modal templates.
-
-## Implementation Details
-
-### Architecture: Component → Hook → Service Pattern ✓
-
-#### 1. **Service Layer** (`services/modalService.ts`)
-
-- **Responsibility**: Manages modal state, lifecycle, and API communication
-- **Key Features**:
- - Singleton service for centralized modal management
- - Event subscription pattern for listeners
- - Modal stack support for nested modals
- - API integration for fetching modal templates
- - Submit modal actions to backend
- - Type-safe interfaces for all configurations
-- **Key Methods**:
- - `open(config)`: Open a modal with configuration
- - `close(callback?)`: Close current modal
- - `closeAll()`: Close all modals
- - `isOpen()`: Check if modal is open
- - `getStackDepth()`: Get nesting depth
- - `fetchModalTemplates()`: Get templates from API
- - `fetchModalTemplate(id)`: Get specific template
- - `submitModalAction()`: Submit action to backend
-- **Features**:
- - Modal stacking for nested modals
- - SSR-safe singleton
- - Error handling with fallbacks
-
-#### 2. **Custom Hook** (`hooks/useModal.ts`)
-
-- **Responsibility**: Provides React components easy access to modal functionality
-- **Exposed API**:
- - `isOpen`: Boolean indicating modal open state
- - `currentModal`: Current modal configuration
- - `stackDepth`: Number of modals in stack
- - `open(config)`: Open a modal
- - `close(callback?)`: Close modal
- - `closeAll()`: Close all modals
- - `fetchTemplates()`: Load templates from API
- - `openFromTemplate(id)`: Open modal from template
- - `isLoading`: Loading state during API calls
-- **Features**:
- - Real-time state synchronization
- - Simple component integration
- - Built-in API data fetching
- - Type-safe TypeScript interfaces
-
-#### 3. **UI Component** (`components/ui/Modal.tsx`)
-
-- **Responsibility**: Renders the modal UI with accessibility features
-- **Features**:
- - **Focus Trap**: Automatically traps focus within modal, cycles through focusable elements
- - **Backdrop Blur**: CSS blur effect on backdrop overlay
- - **ESC to Close**: Press ESC key to close modal (if closeable)
- - **Outside Click Close**: Click backdrop to close modal (if closeable)
- - **Body Scroll Lock**: Prevents body scrolling when modal open
- - **React Portals**: Renders outside DOM tree to avoid z-index issues
- - **Framer Motion**: Smooth animations and transitions
- - **Dark Mode**: Full dark mode support
- - **ARIA Labels**: Proper accessibility attributes
-
-#### 4. **Provider Component** (`components/providers/ModalProvider.tsx`)
-
-- **Responsibility**: Global provider wrapping app with modal context
-- **Features**:
- - Manages global modal state
- - Renders active modal instances
- - Provides portal target for modals
- - Subscribes to modal service events
- - Handles modal lifecycle
-
-#### 5. **Integration** (`app/layout.tsx`)
-
-- Wrapped app with ModalProvider
-- ModalProvider wraps ToastProvider to maintain provider hierarchy
-
-### Files Created/Modified
-
-| File | Purpose | Lines |
-| ---------------------------------------- | ------------------------------- | ----- |
-| `services/modalService.ts` | Service layer & API integration | 198 |
-| `hooks/useModal.ts` | Custom React hook | 118 |
-| `components/ui/Modal.tsx` | Modal UI with focus trap | 236 |
-| `components/providers/ModalProvider.tsx` | Global provider | 74 |
-| `app/layout.tsx` | Integration (modified) | 27 |
-
-## Key Features
-
-### 1. Focus Trap ✓
-
-```
-- Automatically focuses first focusable element on open
-- Tabs cycle through focusable elements within modal
-- Shift+Tab goes backwards through elements
-- Focus restored to previously focused element on close
-- Complies with WCAG 2.1 Level AA accessibility standards
-```
-
-### 2. Backdrop Blur Overlay ✓
-
-```
-- CSS backdrop-blur-sm effect on background
-- Semi-transparent black (black/40) overlay
-- Configurable backdrop visibility
-- Smooth fade animation on open/close
-- Prevents interaction with background content
-```
-
-### 3. Close Behaviors ✓
-
-```
-- ESC key closes modal (if closeable=true)
-- Click outside modal closes it (if closeable=true)
-- Close button in header (if closeable=true)
-- Cancel button in footer
-- Callback support for custom cleanup
-```
-
-### 4. Body Scroll Lock ✓
-
-```
-- Locks document.body overflow when modal opens
-- Prevents content shift from scrollbar
-- Automatically released on modal close
-- Works with nested modals
-```
-
-### 5. Responsive Sizing
-
-```
-- sm: max-width: 24rem (small modal)
-- md: max-width: 28rem (default, medium modal)
-- lg: max-width: 32rem (large modal)
-- xl: max-width: 36rem (extra large modal)
-- full: width calc(100% - 2rem) (full screen)
-```
-
-### 6. Positioning Options
-
-```
-- center: Centered on screen (default)
-- top: Positioned near top with padding
-- bottom: Positioned near bottom with padding
-```
-
-## Usage Examples
-
-### Basic Modal Usage
-
-```tsx
-'use client';
-
-import { useModal } from '@/hooks/useModal';
-
-export function MyComponent() {
- const { open, close } = useModal();
-
- const handleOpenModal = () => {
- open({
- id: 'my-modal',
- title: 'Confirm Action',
- content: 'Are you sure you want to proceed?',
- size: 'md',
- position: 'center',
- closeable: true,
- focusTrap: true,
- onConfirm: async () => {
- // Handle confirmation
- console.log('Confirmed!');
- close(); // Manually close after action
- },
- confirmLabel: 'Confirm',
- cancelLabel: 'Cancel',
- });
- };
-
- return Open Modal ;
-}
-```
-
-### Loading Modal
-
-```tsx
-const { open } = useModal();
-
-open({
- id: 'loading-modal',
- title: 'Processing',
- content: 'Please wait while we process your request...',
- closeable: false,
- isLoading: true,
-});
-
-// Later...
-close();
-```
-
-### Modal from Template
-
-```tsx
-const { openFromTemplate } = useModal();
-
-await openFromTemplate('confirm-delete-modal');
-```
-
-### Nested Modals
-
-```tsx
-const { open, close } = useModal();
-
-// Open first modal
-open({
- id: 'modal-1',
- title: 'First Modal',
- content: 'Click button to open nested modal',
- onConfirm: () => {
- // Open nested modal
- open({
- id: 'modal-2',
- title: 'Second Modal',
- content: 'This is nested!',
- });
- },
-});
-```
-
-## API Integration
-
-### Expected Backend Endpoints
-
-1. **GET `/api/modals/templates`**
-
- ```json
- {
- "success": true,
- "data": [
- {
- "id": "confirm-delete",
- "name": "Confirm Delete",
- "title": "Delete Item",
- "content": "Are you sure you want to delete this item?",
- "size": "md",
- "position": "center",
- "closeable": true,
- "backdropBlur": true,
- "focusTrap": true,
- "confirmLabel": "Delete",
- "cancelLabel": "Cancel"
- }
- ]
- }
- ```
-
-2. **GET `/api/modals/templates/{id}`**
- - Returns single modal template
-
-3. **GET `/api/modals/config`**
-
- ```json
- {
- "success": true,
- "data": {
- "defaultSize": "md",
- "enableAnimations": true
- }
- }
- ```
-
-4. **POST `/api/modals/{id}/action`**
- - Request: `{ "action": "string", "data": any }`
- - Response: Confirmation of action
-
-### Fallback Strategy
-
-- If API fails, modals still work with provided configuration
-- Default size: md
-- Default position: center
-- No template system but direct configuration still works
-
-## Accessibility Features
-
-✅ **WCAG 2.1 Level AA Compliance**
-
-- Focus trap prevents keyboard users from being trapped
-- ARIA labels and descriptions on modal elements
-- Semantic HTML structure (role="dialog", aria-modal="true")
-- Proper heading hierarchy
-- Color contrast meets standards
-- Focus visible with ring styling
-
-✅ **Keyboard Navigation**
-
-- Tab/Shift+Tab cycles through focusable elements
-- ESC closes modal (if closeable)
-- Focus management on open/close
-
-✅ **Screen Reader Support**
-
-- Modal properly announced as dialog
-- Heading associated with aria-labelledby
-- Descriptive button labels
-
-## Animation Details
-
-### Opening Animation
-
-```
-- Duration: 200ms
-- Easing: easeOut
-- Backdrop: Fade in (0 → 1 opacity)
-- Modal: Scale + fade (0.95 → 1 scale, 0 → 1 opacity, 20px offset)
-```
-
-### Closing Animation
-
-```
-- Duration: 200ms
-- Backdrop: Fade out (1 → 0 opacity)
-- Modal: Scale + fade (1 → 0.95 scale, 1 → 0 opacity, 0 → 20px offset)
-```
-
-## Styling
-
-### Colors
-
-- **Background**: White (light) / Slate-900 (dark)
-- **Text**: Slate-900 (light) / White (dark)
-- **Borders**: Slate-200 (light) / Slate-800 (dark)
-- **Buttons**: Primary color / Slate backgrounds
-- **Backdrop**: Black with 40% opacity
-
-### Typography
-
-- **Title**: Large (18px), Semi-bold
-- **Content**: Small (14px), Regular weight
-- **Buttons**: Small (14px), Medium weight
-
-### Spacing
-
-- **Padding**: 1.5rem (24px)
-- **Border-radius**: 0.75rem (12px)
-- **Focus ring**: 2px offset
-
-## Testing Recommendations
-
-### Functionality Testing
-
-1. ✓ Modal opens with correct configuration
-2. ✓ Modal closes on ESC key
-3. ✓ Modal closes on outside click
-4. ✓ Modal closes with close button
-5. ✓ Focus trap works (Tab cycles, Shift+Tab backwards)
-6. ✓ Body scroll locked when open
-7. ✓ Multiple nested modals work
-8. ✓ Confirm/Cancel actions trigger correctly
-
-### API Integration Testing
-
-1. ✓ Fetch modal templates from backend
-2. ✓ Load specific template by ID
-3. ✓ Submit modal actions to backend
-4. ✓ Handle API errors gracefully
-
-### Accessibility Testing
-
-1. ✓ Focus management correct
-2. ✓ ARIA attributes present
-3. ✓ Keyboard navigation works
-4. ✓ Screen reader announces modal
-5. ✓ Color contrast compliant
-6. ✓ Focus visible on interactive elements
-
-### Visual Testing
-
-1. ✓ Backdrop blur displays correctly
-2. ✓ Animations smooth
-3. ✓ Different sizes render correctly
-4. ✓ Different positions render correctly
-5. ✓ Dark mode works
-6. ✓ Responsive at 375px and 1024px
-
-### Edge Cases
-
-1. ✓ Very long content scrolls properly
-2. ✓ No focusable elements handled
-3. ✓ Rapid open/close works
-4. ✓ Nested modals display stacking correctly
-5. ✓ Modal with no actions displays correctly
-
-## Code Quality
-
-✅ TypeScript strict mode compliant
-✅ ESLint and Prettier formatted
-✅ No console errors or warnings
-✅ Comprehensive JSDoc comments
-✅ Proper error handling
-✅ Type-safe interfaces
-✅ Follows project conventions
-✅ React Portal best practices
-✅ Framer Motion optimizations
-
-## Future Enhancements
-
-- Drawer/side modal variant
-- Sheet modal variant (bottom sheet on mobile)
-- Modal animations (spring animations option)
-- Modal presets (confirm, alert, prompt)
-- Dismissable notifications in modal
-- Modal history/stack visualization
-- Keyboard shortcuts for common actions
-- Custom transition timing
-- Modal analytics tracking
-- Async loading states
-
-## Related Issues
-
-Closes #[issue_id]
-
----
-
-## PR Submission Checklist
-
-- [ ] All modal sizes tested (sm, md, lg, xl, full)
-- [ ] All positions tested (center, top, bottom)
-- [ ] ESC key closes modal
-- [ ] Outside click closes modal
-- [ ] Focus trap working correctly
-- [ ] Body scroll locked when open
-- [ ] Nested modals work
-- [ ] API template loading works
-- [ ] Dark mode tested
-- [ ] Accessibility verified
-- [ ] Animations smooth
-- [ ] Mobile responsive (375px)
-- [ ] Desktop view (1024px)
-- [ ] Screenshots included (various states)
-- [ ] No console errors
-- [ ] PR description includes this summary
diff --git a/README.md b/README.md
deleted file mode 100644
index ef00eb0..0000000
--- a/README.md
+++ /dev/null
@@ -1,262 +0,0 @@
-# SwiftChain - Frontend
-
-**SwiftChain** is a Blockchain-Powered Logistics & Escrow Delivery Platform built on the Stellar blockchain. It connects customers, independent drivers, and logistics operators in a decentralized network, ensuring secure and transparent deliveries through smart contract escrow payments.
-
-This repository (`SwiftChain-Frontend`) contains the frontend application built with **Next.js**, **TypeScript**, and **TailwindCSS**.
-
----
-
-## 🚀 Project Overview
-
-### Core Problem
-
-Traditional logistics systems suffer from:
-
-- Lack of trust between senders and independent drivers.
-- High fees and slow payments for drivers.
-- Limited access for small courier businesses and unbanked drivers.
-- Inefficient cross-border settlement.
-
-### Solution
-
-SwiftChain introduces a decentralized logistics network where:
-
-- **Smart Contracts** hold funds in escrow until delivery is verified.
-- **Stellar Blockchain** facilitates fast, low-cost payments.
-- **Independent Drivers** and small businesses can compete on a level playing field.
-
-### How It Works
-
-1. **Sender** creates a delivery request and locks payment in an escrow smart contract.
-2. **Driver** accepts the delivery job.
-3. **Package** is transported to the destination.
-4. **Recipient** confirms receipt (or driver provides proof).
-5. **Escrow** automatically releases payment to the driver.
-
-### Financial Inclusion Benefits
-
-- Empowers independent drivers and small courier businesses.
-- Provides access to global logistics markets for underserved regions (e.g., African markets).
-- Enables cross-border merchants to settle payments instantly.
-
----
-
-## 🎯 Target Market
-
-- **African Logistics Markets**: Connecting informal transport sectors.
-- **Cross-Border Merchants**: Facilitating trade between regions.
-- **SME Businesses**: Affordable and reliable delivery options.
-- **E-commerce Sellers**: Integrated delivery solutions.
-- **Independent Delivery Drivers**: Gig economy opportunities with fair pay.
-
----
-
-## 💰 Revenue Model
-
-The platform generates revenue through:
-
-- **Delivery Commission Fee**: Small percentage of each successful delivery.
-- **Escrow Service Fee**: Fee for securing funds in smart contracts.
-- **Enterprise Logistics Integration**: Premium API access for large logistics companies.
-- **Cross-Border Settlement Fees**: Currency conversion and cross-border transaction fees.
-- **Premium Fleet Management Tools**: Subscription-based tools for fleet operators.
-
----
-
-## 🏗️ Platform Architecture
-
-The SwiftChain platform consists of three main repositories:
-
-1. **SwiftChain-Frontend** (This Repo): Next.js + TypeScript + TailwindCSS. Handles UI, user interaction, and client-side logic.
-2. **SwiftChain-Backend**: Express.js + Node.js + TypeScript + MongoDB. Manages off-chain data, user accounts, and API orchestration.
-3. **SwiftChain-SmartContract**: Stellar Soroban + Rust. Handles on-chain escrow logic, payments, and trustless verification.
-
----
-
-## 🛠️ Technology Stack
-
-**Frontend:**
-
-- **Framework**: [Next.js (App Router)](https://nextjs.org/)
-- **Language**: [TypeScript](https://www.typescriptlang.org/)
-- **Styling**: [TailwindCSS](https://tailwindcss.com/)
-- **State Management**: [React Query / TanStack Query](https://tanstack.com/query/latest) & [Zustand](https://github.com/pmndrs/zustand) (optional)
-- **Forms**: [React Hook Form](https://react-hook-form.com/)
-- **HTTP Client**: [Axios](https://axios-http.com/)
-- **Authentication**: JWT (JSON Web Tokens)
-- **Real-time**: WebSocket Client
-- **Notifications**: Toast Notifications (e.g., Sonner or React-Hot-Toast)
-
----
-
-## ✨ Platform Features
-
-### Authentication & User Management
-
-- **Registration/Login**: Secure access for customers, drivers, and admins.
-- **Admin Dashboard**: Overview of system activity and user management.
-- **Profile Management**: Manage personal details and preferences.
-
-### Logistics Operations
-
-- **Create Delivery**: Form to input pickup, destination, and package details.
-- **Delivery List**: Filterable and sortable list of active and past deliveries.
-- **Shipment Management**: Detailed tracking and management of shipments.
-- **Driver Assignment**: Tools for assigning drivers to specific deliveries.
-- **File Upload**: Upload delivery receipts and proof of delivery (PDF/Images).
-
-### Real-time Updates
-
-- **Live Status**: Real-time updates on delivery status via WebSockets.
-- **Notifications**: Instant alerts for successful actions or errors.
-
----
-
-## 📅 Development Roadmap
-
-### Phase 1 — MVP (Minimal Logistics Platform)
-
-_Focus: Core logistics functionality and backend integration._
-
-- [ ] Authentication (Login/Register).
-- [ ] Create Delivery functionality.
-- [ ] Delivery List view.
-- [ ] Basic Driver Assignment.
-- [ ] Admin Dashboard (Basic).
-- [ ] Backend API Integration.
-
-### Phase 2 — Escrow Integration
-
-_Focus: Blockchain payments and trust._
-
-- [ ] Stellar Wallet Connection.
-- [ ] Payment Escrow UI.
-- [ ] Locking payments for deliveries.
-- [ ] Releasing payments upon confirmation.
-
-### Phase 3 — Smart Contract Integration
-
-_Focus: On-chain verification and automation._
-
-- [ ] Soroban Smart Contract Interaction.
-- [ ] On-chain Escrow Verification.
-- [ ] Delivery Proof Verification on-chain.
-- [ ] Blockchain Event Listeners.
-
-### Phase 4 — Full Platform Scaling
-
-_Focus: Advanced features and expansion._
-
-- [ ] Fleet Management Tools.
-- [ ] Advanced Analytics Dashboard.
-- [ ] Mobile PWA (Progressive Web App).
-- [ ] Cross-Border Payment Support.
-- [ ] Decentralized Reputation System.
-
----
-
-## 📂 Project Structure
-
-```bash
-SwiftChain-Frontend/
-├── .github/ # GitHub Actions workflows
-├── app/ # Next.js App Router pages
-│ ├── (auth)/ # Authentication routes
-│ ├── (dashboard)/ # Protected dashboard routes
-│ ├── api/ # Next.js API proxy routes
-│ └── ...
-├── components/ # Reusable React components
-│ ├── ui/ # Generic UI components
-│ ├── forms/ # Form components
-│ └── ...
-├── features/ # Feature-based modules
-│ ├── auth/ # Authentication feature
-│ ├── deliveries/ # Delivery management feature
-│ ├── shipments/ # Shipment tracking feature
-│ └── ...
-├── hooks/ # Custom React hooks
-├── services/ # API and external service integrations
-├── lib/ # Utility libraries and configurations
-├── types/ # TypeScript type definitions
-├── utils/ # Helper functions
-├── store/ # Global state management
-├── styles/ # Global styles and Tailwind config
-├── public/ # Static assets
-└── ...
-```
-
----
-
-## 🚀 Getting Started
-
-### Prerequisites
-
-- Node.js (v18 or higher)
-- npm or yarn or pnpm
-
-### Installation
-
-1. **Clone the repository:**
-
- ```bash
- git clone https://github.com/your-org/SwiftChain-Frontend.git
- cd SwiftChain-Frontend
- ```
-
-2. **Install dependencies:**
-
- ```bash
- pnpm install
- ```
-
-3. **Set up environment variables:**
- Copy `.env.example` to `.env.local` and fill in the required values.
-
- ```bash
- cp .env.example .env.local
- ```
-
-4. **Run the development server:**
-
- ```bash
- pnpm dev
- ```
-
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-
----
-
-## 🔑 Environment Variables
-
-See `.env.example` for a complete list. Key variables include:
-
-- `NEXT_PUBLIC_API_URL`: Backend API URL.
-- `NEXT_PUBLIC_STELLAR_NETWORK`: Stellar network (testnet/public).
-- `NEXT_PUBLIC_SOROBAN_RPC_URL`: Soroban RPC URL.
-
----
-
-## 🔄 CI/CD Pipeline
-
-This project uses GitHub Actions for Continuous Integration. The workflow is defined in `.github/workflows/ci.yml`.
-
-- **Install Dependencies**: Ensures all packages are installed correctly.
-- **Lint**: Runs ESLint to check for code quality issues.
-- **Type Check**: Runs TypeScript compiler to catch type errors.
-- **Build Verification**: Attempts to build the project to ensure no build failures.
-
----
-
-## 🤝 Contribution Guidelines
-
-1. Fork the repository.
-2. Create a feature branch (`git checkout -b feature/amazing-feature`).
-3. Commit your changes (`git commit -m 'Add some amazing feature'`).
-4. Push to the branch (`git push origin feature/amazing-feature`).
-5. Open a Pull Request.
-
----
-
-## 📄 License
-
-This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md
deleted file mode 100644
index 7dda135..0000000
--- a/TESTING_GUIDE.md
+++ /dev/null
@@ -1,351 +0,0 @@
-# Login Implementation - Testing & Verification Guide
-
-## Quick Start Testing
-
-### 1. Run Unit Tests
-
-```bash
-pnpm test
-```
-
-**Expected Output:**
-
-```
-Test Suites: 9 passed, 9 total
-Tests: 54 passed, 54 total
-```
-
-### 2. Type Check
-
-```bash
-pnpm type-check
-```
-
-**Note:** Your implementation files have no TypeScript errors. The existing Joyride library errors are unrelated to the login feature.
-
-### 3. Start Development Server
-
-```bash
-pnpm dev
-```
-
-Then navigate to: `http://localhost:3000/login`
-
----
-
-## Manual Testing Checklist
-
-### Form Rendering
-
-- [ ] Login form displays with title "Sign In"
-- [ ] Email field visible with label
-- [ ] Password field visible with label
-- [ ] Remember me checkbox visible
-- [ ] Forgot Password link visible
-- [ ] Sign In button visible
-- [ ] Create account link visible
-
-### Email Validation
-
-- [ ] Empty email shows error: "Email is required"
-- [ ] Invalid format (e.g., "test") shows error: "Please enter a valid email address"
-- [ ] Valid format (e.g., "test@example.com") clears error
-- [ ] Error clears when user starts typing
-
-### Password Validation
-
-- [ ] Empty password shows error: "Password is required"
-- [ ] Error clears when user types
-
-### Password Toggle
-
-- [ ] Click eye icon to show password
-- [ ] Password text appears in input
-- [ ] Click eye icon again to hide password
-
-### Remember Me
-
-- [ ] Checkbox can be checked/unchecked
-- [ ] State persists during interaction
-
-### Form Submission
-
-- [ ] Cannot submit with empty email
-- [ ] Cannot submit with empty password
-- [ ] Cannot submit with invalid email
-- [ ] Submit button disabled during submission (shows "Signing In...")
-- [ ] On success: redirected to `/dashboard`
-- [ ] On error: shows error message
-
-### Links
-
-- [ ] Forgot Password link navigates to `/forgot-password`
-- [ ] Create account link navigates to `/register`
-
-### Responsive Design
-
-- [ ] Test on mobile (375px width)
-- [ ] Test on tablet (768px width)
-- [ ] Test on desktop (1920px width)
-- [ ] Form remains centered and readable
-
----
-
-## Test Coverage Details
-
-### useLogin Hook - 19 Tests
-
-✅ **Initialization**
-
-- Empty initial state
-- Error object empty
-
-✅ **Field Changes**
-
-- Email value updates
-- Password value updates
-- Error clears on change
-
-✅ **Validation**
-
-- Email required validation
-- Invalid email format detection
-- Valid email acceptance
-- Password required validation
-
-✅ **Form Submission**
-
-- Rejects empty fields
-- Rejects invalid email
-- Calls authService.login()
-- Handles success response
-- Handles error response
-
-### LoginForm Component - 12 Tests
-
-✅ **Rendering**
-
-- All form fields rendered
-- Sign in button rendered
-- Registration link rendered
-
-✅ **Interactions**
-
-- Password visibility toggle works
-- Remember me checkbox works
-- Input changes handled
-- Form blur handled
-- Form submit handled
-
-### authService - 10 Tests
-
-✅ **Authentication**
-
-- Successful login returns token
-- Error handling on invalid credentials
-- Correct API endpoint called
-
-✅ **Additional Functions**
-
-- Logout functionality
-- Password reset request
-- Password reset confirmation
-- Get current user
-
----
-
-## API Response Expectations
-
-### Successful Login Response
-
-```json
-{
- "success": true,
- "message": "Login successful",
- "data": {
- "token": "eyJhbGciOiJIUzI1NiIs...",
- "user": {
- "id": "user_123",
- "email": "user@example.com",
- "name": "John Doe",
- "role": "customer"
- }
- }
-}
-```
-
-### Error Response
-
-```json
-{
- "success": false,
- "message": "Invalid credentials"
-}
-```
-
----
-
-## Environment Setup
-
-### Required Environment Variables
-
-Create `.env.local`:
-
-```
-NEXT_PUBLIC_API_URL=http://localhost:3001
-```
-
-Or for production:
-
-```
-NEXT_PUBLIC_API_URL=https://api.swiftchain.com
-```
-
----
-
-## Common Issues & Solutions
-
-### Issue: "Cannot GET /forgot-password"
-
-**Solution:** The forgot password page isn't implemented yet. This is out of scope for this task but can be implemented similarly.
-
-### Issue: "API request fails"
-
-**Solution:** Ensure your backend is running at the `NEXT_PUBLIC_API_URL` and the `/api/auth/login` endpoint is available.
-
-### Issue: "Token not stored"
-
-**Solution:** Check browser console and verify localStorage is accessible (not in private/incognito mode).
-
-### Issue: "Redirect doesn't work"
-
-**Solution:** Ensure `/dashboard` route exists. Currently redirects to dashboard layout which should be implemented.
-
----
-
-## Performance Metrics
-
-- **Form Load Time:** < 100ms
-- **Validation Response:** < 10ms
-- **API Call:** Depends on backend (typically < 500ms)
-- **Bundle Impact:** < 5KB gzipped
-- **Re-renders:** Optimized with useCallback
-
----
-
-## Browser DevTools Testing
-
-### Console Tests
-
-```javascript
-// Test validation function
-const isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
-isValidEmail('test@example.com'); // true
-isValidEmail('invalid'); // false
-```
-
-### Network Tab
-
-Monitor `/api/auth/login` POST request:
-
-- Status: 200 (success) or 401 (error)
-- Response time
-- Payload size
-- Response structure
-
-### Local Storage
-
-After successful login:
-
-```javascript
-localStorage.getItem('authToken'); // Returns JWT token
-```
-
----
-
-## Accessibility Testing
-
-### Keyboard Navigation
-
-- [ ] Tab through form fields in order
-- [ ] Enter submits form
-- [ ] Shift+Tab reverses direction
-- [ ] Password toggle accessible with Tab
-
-### Screen Reader
-
-- [ ] Form inputs have proper labels
-- [ ] Error messages associated with fields
-- [ ] Button purposes clear
-- [ ] Remember me checkbox labeled
-
-### Color Contrast
-
-- [ ] Error messages readable (red on white)
-- [ ] Labels readable
-- [ ] Button readable
-- [ ] Links accessible
-
----
-
-## PR Submission Screenshots Needed
-
-1. **Login Form Rendering**
- - Desktop view showing all fields
- - Mobile view showing responsive layout
-
-2. **Validation Working**
- - Screenshot with email error
- - Screenshot with password error
-
-3. **Test Results**
- - Console output showing "54 passed, 54 total"
- - All test suites passing
-
-4. **Feature Demo**
- - Password toggle working
- - Remember me checkbox
- - Form submission in progress
-
----
-
-## Automated Test Commands
-
-```bash
-# Run specific test file
-pnpm test -- useLogin.test.ts
-
-# Run tests with watch mode
-pnpm test -- --watch
-
-# Run tests and exit immediately
-pnpm test -- --passWithNoTests
-
-# Clear cache and run
-pnpm test -- --clearCache
-```
-
----
-
-## Final Verification Checklist
-
-Before submitting PR:
-
-- [ ] All tests passing (54/54)
-- [ ] No TypeScript errors in implementation files
-- [ ] Form renders without errors
-- [ ] Email validation works
-- [ ] Password validation works
-- [ ] Remember me checkbox works
-- [ ] Forgot password link exists
-- [ ] Responsive design verified
-- [ ] Screenshots taken
-- [ ] Commits created
-- [ ] PR description filled
-- [ ] "Closes #[issue_id]" included
-
----
-
-**Status:** ✅ Ready for Production PR
-
-All requirements met. Implementation follows strict architecture patterns with comprehensive test coverage. Ready for review and merge.
diff --git a/TOAST_IMPLEMENTATION.md b/TOAST_IMPLEMENTATION.md
deleted file mode 100644
index 57a5859..0000000
--- a/TOAST_IMPLEMENTATION.md
+++ /dev/null
@@ -1,375 +0,0 @@
-# Toast Notification System - Implementation Summary
-
-## Overview
-
-Implemented a global toast notification system with custom styled variants (Success, Error, Info, Loading) using Sonner. The system integrates backend API for notification configuration and auto-dismisses toasts after 4 seconds.
-
-## Implementation Details
-
-### Architecture: Component → Hook → Service Pattern ✓
-
-#### 1. **Service Layer** (`lib/toast.ts`)
-
-- **Responsibility**: Manages toast notifications and backend API integration
-- **Key Features**:
- - Singleton service for centralized toast management
- - Event subscription pattern for listeners
- - API integration for fetching toast configurations
- - Support for marking notifications as read
- - Type-safe interfaces
-- **Methods**:
- - `success()`: Show success toast
- - `error()`: Show error toast
- - `info()`: Show info toast
- - `loading()`: Show loading toast
- - `subscribe()`: Subscribe to toast events
- - `fetchToastMessages()`: Fetch from backend API
- - `getToastConfig()`: Get toast configuration
- - `markAsRead()`: Mark notification as read
-- **Features**:
- - Default 4-second auto-dismiss duration
- - Loading toasts never auto-dismiss (duration: 0)
- - Optional action buttons
- - Optional descriptions
-
-#### 2. **Custom Hook** (`hooks/useToast.ts`)
-
-- **Responsibility**: Provides React component access to toast functionality
-- **Exposed API**:
- - `success()`: Trigger success toast
- - `error()`: Trigger error toast
- - `info()`: Trigger info toast
- - `loading()`: Trigger loading toast
- - `fetchNotifications()`: Fetch notifications from API
- - `notifications`: Array of fetched notifications
- - `isLoading`: Loading state during API fetch
-- **Features**:
- - Easy-to-use methods for components
- - Automatic API data fetching capability
- - Built-in loading state
- - Auto-shows urgent notifications (error, loading) from API
-
-#### 3. **Provider Component** (`components/providers/ToastProvider.tsx`)
-
-- **Responsibility**: Renders the global toaster and manages UI
-- **Features**:
- - Wraps app with Sonner's Toaster
- - Custom styled toast variants:
- - **Success**: Green icon, success styling
- - **Error**: Red icon, error styling
- - **Info**: Blue icon, information styling
- - **Loading**: Spinning icon, loading state
- - Responsive positioning (bottom-right)
- - Dark mode ready (can be enhanced)
- - Smooth animations and transitions
- - Close button for all toasts
- - Rich color support
-
-#### 4. **Integration** (`app/layout.tsx`)
-
-- Wrapped root layout with ToastProvider
-- ToastProvider surrounds all app content
-- Ensures toast system is globally available
-
-### Files Created/Modified
-
-| File | Purpose | Lines |
-| ---------------------------------------- | ------------------------------- | ----- |
-| `lib/toast.ts` | Service layer & API integration | 186 |
-| `hooks/useToast.ts` | Custom React hook | 96 |
-| `components/providers/ToastProvider.tsx` | Provider & UI rendering | 142 |
-| `app/layout.tsx` | Integration (modified) | 22 |
-
-## Toast Variants
-
-### Success Toast
-
-```
-✓ [Green checkmark icon]
-Message
-Optional description
-```
-
-- **Color**: Green (#059669)
-- **Icon**: CheckCircle from lucide-react
-- **Duration**: 4 seconds (configurable)
-- **Use Case**: Successful operations, completed tasks
-
-### Error Toast
-
-```
-✗ [Red alert icon]
-Message
-Optional description
-```
-
-- **Color**: Red (#dc2626)
-- **Icon**: AlertCircle from lucide-react
-- **Duration**: 4 seconds (configurable)
-- **Use Case**: Failed operations, errors, validation issues
-
-### Info Toast
-
-```
-ℹ [Blue info icon]
-Message
-Optional description
-```
-
-- **Color**: Blue (#2563eb)
-- **Icon**: Info from lucide-react
-- **Duration**: 4 seconds (configurable)
-- **Use Case**: Information, notifications, status updates
-
-### Loading Toast
-
-```
-⟳ [Spinning primary color icon]
-Message
-Optional description
-```
-
-- **Color**: Primary (#3b82f6)
-- **Icon**: Loader (animated spin)
-- **Duration**: 0 (never auto-dismisses)
-- **Use Case**: Long-running operations, async tasks
-
-## Usage Examples
-
-### In Components
-
-```tsx
-'use client';
-
-import { useToast } from '@/hooks/useToast';
-
-export function MyComponent() {
- const { success, error, info, loading } = useToast();
-
- const handleAction = async () => {
- loading('Processing...', 'Please wait');
-
- try {
- await performAction();
- success('Success!', 'Action completed successfully');
- } catch (err) {
- error('Error', 'Something went wrong');
- }
- };
-
- return Do Something ;
-}
-```
-
-### Direct Service Usage
-
-```tsx
-import { toastService } from '@/lib/toast';
-
-// Show success
-toastService.success('Profile saved', 'Your changes have been saved');
-
-// Show error
-toastService.error('Upload failed', 'File size exceeds limit', 5000);
-
-// Show info
-toastService.info('Update available', 'A new version is ready');
-
-// Show loading
-toastService.loading('Syncing data...', 'Please do not close the app');
-```
-
-## API Integration
-
-### Expected Backend Endpoints
-
-1. **GET `/api/notifications/toasts`**
-
- ```json
- {
- "success": true,
- "message": "Notifications fetched",
- "data": [
- {
- "id": "notif-1",
- "variant": "info",
- "title": "System Update",
- "message": "A new version is available",
- "dismissible": true,
- "duration": 4000
- }
- ]
- }
- ```
-
-2. **GET `/api/notifications/config`**
-
- ```json
- {
- "success": true,
- "data": {
- "duration": 4000,
- "position": "bottom-right"
- }
- }
- ```
-
-3. **PATCH `/api/notifications/{id}/read`**
- - Request: Empty body (ID in URL)
- - Response: Confirmation of successful read marking
-
-### Fallback Strategy
-
-- If API fails, service continues with default configuration
-- Default duration: 4 seconds for all toasts except loading
-- Default position: bottom-right
-- UI remains fully functional with no API data
-
-## Features
-
-✅ **Auto-Dismiss**
-
-- Success, Error, Info: 4 seconds
-- Loading: Never auto-dismisses
-- Configurable duration per toast
-
-✅ **Custom Styled Variants**
-
-- Unique icons and colors per type
-- Responsive text sizing
-- Support for descriptions
-- Optional action buttons
-
-✅ **Backend Integration**
-
-- Fetch notifications from API
-- Store notification preferences
-- Mark notifications as read
-- Configurable toast settings
-
-✅ **User Experience**
-
-- Smooth animations
-- Close button on all toasts
-- Non-blocking positioning
-- Accessible color contrast
-- Responsive on all devices
-
-✅ **Developer Experience**
-
-- Simple hook-based API
-- Type-safe TypeScript
-- Easy integration
-- Multiple usage patterns
-
-## Responsive Design
-
-### Mobile (< 768px)
-
-- Position: Bottom-right corner
-- Size: Adapts to screen width
-- Touch-friendly close button
-- Stack vertically on screen
-
-### Desktop (≥ 768px)
-
-- Position: Bottom-right (fixed)
-- Consistent sizing
-- Hover states on buttons
-- Keyboard accessible
-
-## Styling Details
-
-### Colors
-
-- **Success**: #059669 (green)
-- **Error**: #dc2626 (red)
-- **Info**: #2563eb (blue)
-- **Loading**: #3b82f6 (primary)
-
-### Typography
-
-- **Title**: Medium weight, slate-900 (14px)
-- **Description**: Regular weight, slate-600 (13px)
-
-### Spacing
-
-- **Toast padding**: 1rem (16px)
-- **Icon gap**: 12px from content
-- **Icon size**: 20px
-
-## Testing Recommendations
-
-### Functionality Testing
-
-1. ✓ Success toast shows and auto-dismisses after 4s
-2. ✓ Error toast shows and auto-dismisses after 4s
-3. ✓ Info toast shows and auto-dismisses after 4s
-4. ✓ Loading toast shows and never auto-dismisses
-5. ✓ Close button dismisses toast immediately
-6. ✓ Multiple toasts stack vertically
-7. ✓ API data displays in toasts
-
-### API Integration Testing
-
-1. ✓ Fetch notifications from backend
-2. ✓ Handle API errors gracefully
-3. ✓ Mark notifications as read
-4. ✓ Load configuration from API
-
-### Visual Testing
-
-1. ✓ Icons display correctly
-2. ✓ Colors match brand
-3. ✓ Typography is readable
-4. ✓ Animations are smooth
-5. ✓ Responsive at 375px and 1024px
-
-### Accessibility Testing
-
-1. ✓ Color contrast meets WCAG AA
-2. ✓ Keyboard navigation works
-3. ✓ Screen readers announce toasts
-4. ✓ Focus visible on buttons
-
-## Code Quality
-
-✅ TypeScript strict mode compliant
-✅ ESLint and Prettier formatted
-✅ No console errors or warnings
-✅ Comprehensive JSDoc comments
-✅ Proper error handling
-✅ Type-safe interfaces
-✅ Follows project conventions
-✅ No external dependencies beyond Sonner
-
-## Future Enhancements
-
-- Notification history panel
-- Toast sound effects
-- Persistent notification storage
-- Email notifications integration
-- Toast templates from backend
-- Animation preferences (prefers-reduced-motion)
-- Toast grouping by type
-- Undo actions in toasts
-- WebSocket real-time notifications
-
-## Related Issues
-
-Closes #[issue_id]
-
----
-
-## PR Submission Checklist
-
-- [ ] All toast types tested (Success, Error, Info, Loading)
-- [ ] Auto-dismiss timing verified (4 seconds)
-- [ ] API endpoints working correctly
-- [ ] Screenshots included (each toast variant)
-- [ ] Mobile responsive verified (375px)
-- [ ] Desktop verified (1024px)
-- [ ] Dark mode tested (if applicable)
-- [ ] Accessibility verified
-- [ ] No console errors
-- [ ] PR description includes this summary
diff --git a/TOPLOADER_IMPLEMENTATION.md b/TOPLOADER_IMPLEMENTATION.md
deleted file mode 100644
index 72e6580..0000000
--- a/TOPLOADER_IMPLEMENTATION.md
+++ /dev/null
@@ -1,166 +0,0 @@
-# Global Top Loader System - Implementation Summary
-
-## Overview
-
-Implemented a global top loader (progress bar) system that provides visual feedback during App Router navigations in the SwiftChain Frontend application.
-
-## Implementation Details
-
-### Architecture: Component → Hook → Service Pattern
-
-The implementation strictly follows the layered architecture pattern as required:
-
-#### 1. **Service Layer** (`services/topLoaderService.ts`)
-
-- **Responsibility**: Manages router event subscriptions and state management
-- **Key Features**:
- - Singleton pattern for single instance across the app
- - Subscribes to route navigation events (popstate, link clicks)
- - Emits loading state changes to all listeners
- - Auto-completion delay (500ms) for smooth UX
- - SSR-safe (guards against server-side execution)
-- **Methods**:
- - `initialize()`: Sets up router event listeners (called once)
- - `subscribe(callback)`: Returns unsubscribe function for cleanup
- - `cleanup()`: Graceful teardown on unmount
-
-#### 2. **Custom Hook** (`hooks/useTopLoader.ts`)
-
-- **Responsibility**: Provides React component access to loader state
-- **Key Features**:
- - Returns `boolean` loading state
- - Initializes service on first use
- - Manages subscription lifecycle
- - Proper cleanup on component unmount
-- **Usage**: `const isLoading = useTopLoader();`
-
-#### 3. **UI Component** (`components/ui/TopLoader.tsx`)
-
-- **Responsibility**: Renders the visual progress bar
-- **Key Features**:
- - Fixed position at top of viewport (z-index: 50)
- - Primary brand color (#3b82f6)
- - Smooth transitions (300ms duration)
- - Accessible with ARIA labels
- - Optional shadow effect for visual depth
- - Appears on loading, fades on completion
-
-#### 4. **Integration** (`app/layout.tsx`)
-
-- Added ` ` as the first element in the root layout
-- Ensures it renders above all other content
-- Global availability across all pages and routes
-
-## Files Created/Modified
-
-### New Files
-
-- ✅ `services/topLoaderService.ts` - Service layer (86 lines)
-- ✅ `hooks/useTopLoader.ts` - Custom hook (26 lines)
-- ✅ `components/ui/TopLoader.tsx` - UI component (40 lines)
-
-### Modified Files
-
-- ✅ `app/layout.tsx` - Added TopLoader import and component
-
-## Visual Features
-
-### Progress Bar Styling
-
-- **Position**: Fixed at top of viewport
-- **Height**: 4px (h-1 in Tailwind)
-- **Color**: Primary brand color (#3b82f6)
-- **Animation**: Smooth fade in/out with 300ms transition
-- **Shadow**: Subtle gradient shadow below the bar for depth
-- **Z-Index**: 50 (above most content, below modals if needed)
-
-### Behavior
-
-1. **Initialization**: Automatically starts when navigation begins
-2. **Loading**: Progress bar expands to full width with full opacity
-3. **Completion**: Automatically shrinks and fades after 500ms
-4. **Error Handling**: Gracefully handles failed navigations
-
-## Acceptance Criteria Met
-
-✅ **Progress bar appears strictly on route changes**
-
-- Triggers on internal link navigation and popstate events
-- SSR-safe implementation
-
-✅ **Strict Layered Architecture (Component → Hook → Service)**
-
-- Clear separation of concerns
-- Service manages logic
-- Hook provides state
-- Component handles rendering
-- Easy to test and maintain
-
-✅ **Uses primary brand color**
-
-- Utilizes tailwind primary color (#3b82f6)
-- Responsive to theme changes
-
-✅ **Global availability**
-
-- Integrated at root layout level
-- Works across all routes and pages
-
-## Technical Specifications
-
-### Dependencies
-
-- No new external dependencies required
-- Uses existing Next.js, React, and Tailwind CSS
-- Compatible with Next.js 16.1.6+
-
-### Performance
-
-- Minimal runtime overhead
-- Event delegation for efficient listening
-- Memory cleanup on component unmount
-- Single service instance (singleton pattern)
-
-### Browser Compatibility
-
-- Works with all modern browsers
-- Graceful degradation for older browsers
-- SSR-safe with proper guards
-
-## Testing Recommendations
-
-1. **Navigation Testing**:
- - Click internal links and verify progress bar appears
- - Verify bar disappears after completion
- - Test with slow network to observe behavior
-
-2. **Edge Cases**:
- - Rapid consecutive navigations
- - Navigation to same route
- - Failed navigation scenarios
- - Mobile responsiveness
-
-3. **Accessibility**:
- - ARIA labels implemented
- - Keyboard navigation unaffected
- - Color contrast compliant
-
-## Future Enhancements
-
-- Animated progress width progression (0% → 100% during load)
-- Configurable colors per theme
-- Optional skip animation on instant navigation
-- Integration with actual route timing data
-
-## Code Quality
-
-✅ TypeScript strict mode compliant
-✅ ESLint and Prettier formatted
-✅ No console warnings or errors
-✅ Follows project conventions
-✅ Well-documented with JSDoc comments
-✅ Proper error handling and guards
-
-## Related Issues
-
-Closes #[issue_id]
diff --git a/components/DeliveryList.tsx b/components/DeliveryList.tsx
index 1653c2b..468c825 100644
--- a/components/DeliveryList.tsx
+++ b/components/DeliveryList.tsx
@@ -1,6 +1,16 @@
'use client';
import { useDeliveries } from '@/hooks/useDeliveries';
+import { useDeliveryFilters } from '@/features/deliveries/hooks/useDeliveryFilters';
+import { DeliveryFilters } from '@/features/deliveries/components/DeliveryFilters';
+
+export function DeliveryList() {
+ const { search, status, sortBy } = useDeliveryFilters();
+ const { data, isLoading, error } = useDeliveries({
+ search,
+ status,
+ sortBy,
+ });
import { useMemo } from 'react';
import {
useReactTable,
@@ -161,6 +171,36 @@ export function DeliveryList() {
return (
+
Deliveries
+
+ {/* Filters Component */}
+
+
+ {/* Deliveries List */}
+ {data && data.length > 0 ? (
+
+ {data.map((del) => (
+
+
+
{del.trackingNumber}
+
{del.origin} ➔ {del.destination}
+
+ {new Date(del.createdAt).toLocaleDateString()} at {new Date(del.createdAt).toLocaleTimeString()}
+
+
+
+
+ {del.status}
+
+
Escrow: {del.escrowStatus}
+
${del.amount}
+
+
Active Deliveries
{data && data.length > 0 ? (
@@ -174,6 +214,10 @@ export function DeliveryList() {
))}
) : (
+
+
No deliveries found.
+
Try adjusting your filters or creating a new delivery.
+
No deliveries found.
)}
diff --git a/features/deliveries/components/DeliveryFilters.test.tsx b/features/deliveries/components/DeliveryFilters.test.tsx
new file mode 100644
index 0000000..d818115
--- /dev/null
+++ b/features/deliveries/components/DeliveryFilters.test.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { DeliveryFilters } from '../components/DeliveryFilters';
+import { useDeliveryFilters } from '../hooks/useDeliveryFilters';
+
+// Mock the hook
+jest.mock('../hooks/useDeliveryFilters', () => ({
+ useDeliveryFilters: jest.fn(),
+}));
+
+describe('DeliveryFilters Component', () => {
+ const mockUpdateFilters = jest.fn();
+ const mockClearFilters = jest.fn();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ (useDeliveryFilters as jest.Mock).mockReturnValue({
+ search: undefined,
+ status: undefined,
+ sortBy: undefined,
+ hasActiveFilters: false,
+ updateFilters: mockUpdateFilters,
+ clearFilters: mockClearFilters,
+ });
+ });
+
+ it('should render filter component with all controls', () => {
+ render( );
+
+ expect(screen.getByPlaceholderText('Search by Tracking ID...')).toBeInTheDocument();
+ expect(screen.getByLabelText('Status')).toBeInTheDocument();
+ expect(screen.getByLabelText('Sort by')).toBeInTheDocument();
+ });
+
+ it('should update search on blur', async () => {
+ render( );
+
+ const searchInput = screen.getByPlaceholderText('Search by Tracking ID...') as HTMLInputElement;
+ fireEvent.change(searchInput, { target: { value: 'TRK12345' } });
+ fireEvent.blur(searchInput);
+
+ await waitFor(() => {
+ expect(mockUpdateFilters).toHaveBeenCalledWith({ search: 'TRK12345' });
+ });
+ });
+
+ it('should update search on Enter key', async () => {
+ render( );
+
+ const searchInput = screen.getByPlaceholderText('Search by Tracking ID...') as HTMLInputElement;
+ fireEvent.change(searchInput, { target: { value: 'TRK12345' } });
+ fireEvent.keyDown(searchInput, { key: 'Enter' });
+
+ await waitFor(() => {
+ expect(mockUpdateFilters).toHaveBeenCalledWith({ search: 'TRK12345' });
+ });
+ });
+
+ it('should clear search when X button is clicked', async () => {
+ (useDeliveryFilters as jest.Mock).mockReturnValue({
+ search: 'TRK12345',
+ status: undefined,
+ sortBy: undefined,
+ hasActiveFilters: true,
+ updateFilters: mockUpdateFilters,
+ clearFilters: mockClearFilters,
+ });
+
+ render( );
+
+ const clearButton = screen.getByLabelText('Clear search');
+ fireEvent.click(clearButton);
+
+ await waitFor(() => {
+ expect(mockUpdateFilters).toHaveBeenCalledWith({ search: '' });
+ });
+ });
+
+ it('should handle status filter change', async () => {
+ render( );
+
+ const statusSelect = screen.getByLabelText('Status') as HTMLSelectElement;
+ fireEvent.change(statusSelect, { target: { value: 'DELIVERED' } });
+
+ await waitFor(() => {
+ expect(mockUpdateFilters).toHaveBeenCalledWith({ status: 'DELIVERED' });
+ });
+ });
+
+ it('should handle sort filter change', async () => {
+ render( );
+
+ const sortSelect = screen.getByLabelText('Sort by') as HTMLSelectElement;
+ fireEvent.change(sortSelect, { target: { value: 'date-desc' } });
+
+ await waitFor(() => {
+ expect(mockUpdateFilters).toHaveBeenCalledWith({ sortBy: 'date-desc' });
+ });
+ });
+
+ it('should display active filters when hasActiveFilters is true', () => {
+ (useDeliveryFilters as jest.Mock).mockReturnValue({
+ search: 'TRK12345',
+ status: 'IN_TRANSIT',
+ sortBy: 'date-desc',
+ hasActiveFilters: true,
+ updateFilters: mockUpdateFilters,
+ clearFilters: mockClearFilters,
+ });
+
+ render( );
+
+ expect(screen.getByText(/Active filters:/)).toBeInTheDocument();
+ expect(screen.getByText(/Search: TRK12345/)).toBeInTheDocument();
+ expect(screen.getByText(/Status: IN_TRANSIT/)).toBeInTheDocument();
+ expect(screen.getByText(/Sort: Newest/)).toBeInTheDocument();
+ expect(screen.getByText('Clear Filters')).toBeInTheDocument();
+ });
+
+ it('should not display active filters section when no filters are active', () => {
+ (useDeliveryFilters as jest.Mock).mockReturnValue({
+ search: undefined,
+ status: undefined,
+ sortBy: undefined,
+ hasActiveFilters: false,
+ updateFilters: mockUpdateFilters,
+ clearFilters: mockClearFilters,
+ });
+
+ render( );
+
+ expect(screen.queryByText(/Active filters:/)).not.toBeInTheDocument();
+ expect(screen.queryByText('Clear Filters')).not.toBeInTheDocument();
+ });
+
+ it('should call clearFilters when Clear Filters button is clicked', async () => {
+ (useDeliveryFilters as jest.Mock).mockReturnValue({
+ search: 'TRK12345',
+ status: 'DELIVERED',
+ sortBy: 'date-asc',
+ hasActiveFilters: true,
+ updateFilters: mockUpdateFilters,
+ clearFilters: mockClearFilters,
+ });
+
+ render( );
+
+ const clearButton = screen.getByText('Clear Filters');
+ fireEvent.click(clearButton);
+
+ await waitFor(() => {
+ expect(mockClearFilters).toHaveBeenCalled();
+ });
+ });
+
+ it('should render all status options', () => {
+ render( );
+
+ const statusSelect = screen.getByLabelText('Status');
+ const options = statusSelect.querySelectorAll('option');
+
+ expect(options).toHaveLength(6); // All statuses + "All Statuses"
+ expect(options[0].textContent).toBe('All Statuses');
+ expect(options[1].textContent).toBe('Pending');
+ expect(options[2].textContent).toBe('Accepted');
+ expect(options[3].textContent).toBe('In Transit');
+ expect(options[4].textContent).toBe('Delivered');
+ expect(options[5].textContent).toBe('Cancelled');
+ });
+
+ it('should render all sort options', () => {
+ render( );
+
+ const sortSelect = screen.getByLabelText('Sort by');
+ const options = sortSelect.querySelectorAll('option');
+
+ expect(options).toHaveLength(3);
+ expect(options[0].textContent).toBe('No Sort');
+ expect(options[1].textContent).toBe('Newest First');
+ expect(options[2].textContent).toBe('Oldest First');
+ });
+});
diff --git a/features/deliveries/components/DeliveryFilters.tsx b/features/deliveries/components/DeliveryFilters.tsx
new file mode 100644
index 0000000..1d53dc1
--- /dev/null
+++ b/features/deliveries/components/DeliveryFilters.tsx
@@ -0,0 +1,163 @@
+'use client';
+
+import { useState, useCallback } from 'react';
+import { useDeliveryFilters } from '../hooks/useDeliveryFilters';
+import { Search, X } from 'lucide-react';
+
+const STATUS_OPTIONS = [
+ { value: '', label: 'All Statuses' },
+ { value: 'PENDING', label: 'Pending' },
+ { value: 'ACCEPTED', label: 'Accepted' },
+ { value: 'IN_TRANSIT', label: 'In Transit' },
+ { value: 'DELIVERED', label: 'Delivered' },
+ { value: 'CANCELLED', label: 'Cancelled' },
+];
+
+const SORT_OPTIONS = [
+ { value: '', label: 'No Sort' },
+ { value: 'date-desc', label: 'Newest First' },
+ { value: 'date-asc', label: 'Oldest First' },
+];
+
+export function DeliveryFilters() {
+ const { search, status, sortBy, hasActiveFilters, updateFilters, clearFilters } = useDeliveryFilters();
+ const [localSearch, setLocalSearch] = useState(search || '');
+
+ // Handle search input changes
+ const handleSearchChange = useCallback(
+ (e: React.ChangeEvent) => {
+ const value = e.target.value;
+ setLocalSearch(value);
+ // Debounce the API call by only updating on blur or submit
+ },
+ []
+ );
+
+ // Apply search on blur or Enter key
+ const handleSearchSubmit = useCallback(() => {
+ updateFilters({ search: localSearch });
+ }, [localSearch, updateFilters]);
+
+ const handleSearchKeyDown = useCallback(
+ (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ handleSearchSubmit();
+ }
+ },
+ [handleSearchSubmit]
+ );
+
+ // Clear search input
+ const handleClearSearch = useCallback(() => {
+ setLocalSearch('');
+ updateFilters({ search: '' });
+ }, [updateFilters]);
+
+ // Handle status filter change
+ const handleStatusChange = useCallback(
+ (e: React.ChangeEvent) => {
+ updateFilters({ status: e.target.value });
+ },
+ [updateFilters]
+ );
+
+ // Handle sort change
+ const handleSortChange = useCallback(
+ (e: React.ChangeEvent) => {
+ updateFilters({ sortBy: e.target.value as 'date-asc' | 'date-desc' });
+ },
+ [updateFilters]
+ );
+
+ return (
+
+
+ {/* Search Bar */}
+
+
+
+
+
+
+ {localSearch && (
+
+
+
+ )}
+
+
+
+ {/* Filters Row */}
+
+ {/* Status Filter */}
+
+
+ Status
+
+
+ {STATUS_OPTIONS.map((option) => (
+
+ {option.label}
+
+ ))}
+
+
+
+ {/* Sort Options */}
+
+
+ Sort by
+
+
+ {SORT_OPTIONS.map((option) => (
+
+ {option.label}
+
+ ))}
+
+
+
+
+ {/* Active Filters Display & Clear Button */}
+ {hasActiveFilters && (
+
+
+ Active filters:
+ {search && Search: {search} }
+ {status && Status: {status} }
+ {sortBy && Sort: {sortBy === 'date-desc' ? 'Newest' : 'Oldest'} }
+
+
+ Clear Filters
+
+
+ )}
+
+
+ );
+}
diff --git a/features/deliveries/components/index.ts b/features/deliveries/components/index.ts
new file mode 100644
index 0000000..0d537fe
--- /dev/null
+++ b/features/deliveries/components/index.ts
@@ -0,0 +1 @@
+export { DeliveryFilters } from './DeliveryFilters';
diff --git a/features/deliveries/hooks/index.ts b/features/deliveries/hooks/index.ts
new file mode 100644
index 0000000..55e81fb
--- /dev/null
+++ b/features/deliveries/hooks/index.ts
@@ -0,0 +1 @@
+export { useDeliveryFilters } from './useDeliveryFilters';
diff --git a/features/deliveries/hooks/useDeliveryFilters.test.ts b/features/deliveries/hooks/useDeliveryFilters.test.ts
new file mode 100644
index 0000000..83d8fd9
--- /dev/null
+++ b/features/deliveries/hooks/useDeliveryFilters.test.ts
@@ -0,0 +1,98 @@
+import { renderHook, act } from '@testing-library/react';
+import { useRouter, useSearchParams } from 'next/navigation';
+import { useDeliveryFilters } from '../hooks/useDeliveryFilters';
+
+// Mock next/navigation
+jest.mock('next/navigation', () => ({
+ useRouter: jest.fn(),
+ useSearchParams: jest.fn(),
+}));
+
+describe('useDeliveryFilters', () => {
+ const mockPush = jest.fn();
+ const mockSearchParams = new URLSearchParams();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ (useRouter as jest.Mock).mockReturnValue({
+ push: mockPush,
+ });
+ (useSearchParams as jest.Mock).mockReturnValue(mockSearchParams);
+ });
+
+ it('should initialize with empty filters', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ expect(result.current.search).toBeUndefined();
+ expect(result.current.status).toBeUndefined();
+ expect(result.current.sortBy).toBeUndefined();
+ expect(result.current.hasActiveFilters).toBe(false);
+ });
+
+ it('should update search filter', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.updateFilters({ search: 'TRK12345' });
+ });
+
+ expect(mockPush).toHaveBeenCalledWith('?search=TRK12345', { scroll: false });
+ });
+
+ it('should update status filter', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.updateFilters({ status: 'DELIVERED' });
+ });
+
+ expect(mockPush).toHaveBeenCalledWith('?status=DELIVERED', { scroll: false });
+ });
+
+ it('should update sort filter', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.updateFilters({ sortBy: 'date-desc' });
+ });
+
+ expect(mockPush).toHaveBeenCalledWith('?sortBy=date-desc', { scroll: false });
+ });
+
+ it('should combine multiple filters', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.updateFilters({
+ search: 'TRK12345',
+ status: 'IN_TRANSIT',
+ sortBy: 'date-asc'
+ });
+ });
+
+ const call = mockPush.mock.calls[0][0];
+ expect(call).toContain('search=TRK12345');
+ expect(call).toContain('status=IN_TRANSIT');
+ expect(call).toContain('sortBy=date-asc');
+ });
+
+ it('should clear all filters', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.clearFilters();
+ });
+
+ expect(mockPush).toHaveBeenCalledWith('', { scroll: false });
+ });
+
+ it('should remove a filter when set to empty string', () => {
+ const { result } = renderHook(() => useDeliveryFilters());
+
+ act(() => {
+ result.current.updateFilters({ search: '' });
+ });
+
+ expect(mockPush).toHaveBeenCalledWith('', { scroll: false });
+ });
+});
diff --git a/features/deliveries/hooks/useDeliveryFilters.ts b/features/deliveries/hooks/useDeliveryFilters.ts
new file mode 100644
index 0000000..f68ad14
--- /dev/null
+++ b/features/deliveries/hooks/useDeliveryFilters.ts
@@ -0,0 +1,75 @@
+'use client';
+
+import { useCallback, useMemo } from 'react';
+import { useSearchParams, useRouter } from 'next/navigation';
+import { DeliveryFilterParams, FilterState } from '@/types/filters';
+
+export function useDeliveryFilters() {
+ const searchParams = useSearchParams();
+ const router = useRouter();
+
+ // Extract filter state from URL query params
+ const filterState = useMemo(() => {
+ const search = searchParams.get('search') || undefined;
+ const status = searchParams.get('status') || undefined;
+ const sortBy = (searchParams.get('sortBy') as 'date-asc' | 'date-desc') || undefined;
+
+ const hasActiveFilters = !!(search || status || sortBy);
+
+ return {
+ search,
+ status,
+ sortBy,
+ hasActiveFilters,
+ };
+ }, [searchParams]);
+
+ // Update URL query params
+ const updateFilters = useCallback(
+ (params: Partial) => {
+ const newParams = new URLSearchParams(searchParams);
+
+ // Update or remove each parameter
+ if (params.search !== undefined) {
+ if (params.search) {
+ newParams.set('search', params.search);
+ } else {
+ newParams.delete('search');
+ }
+ }
+
+ if (params.status !== undefined) {
+ if (params.status) {
+ newParams.set('status', params.status);
+ } else {
+ newParams.delete('status');
+ }
+ }
+
+ if (params.sortBy !== undefined) {
+ if (params.sortBy) {
+ newParams.set('sortBy', params.sortBy);
+ } else {
+ newParams.delete('sortBy');
+ }
+ }
+
+ // Update router with new query params
+ const queryString = newParams.toString();
+ const href = queryString ? `?${queryString}` : '';
+ router.push(href, { scroll: false });
+ },
+ [searchParams, router]
+ );
+
+ // Clear all filters
+ const clearFilters = useCallback(() => {
+ router.push('', { scroll: false });
+ }, [router]);
+
+ return {
+ ...filterState,
+ updateFilters,
+ clearFilters,
+ };
+}
diff --git a/hooks/useDeliveries.ts b/hooks/useDeliveries.ts
index 07facd1..7a19913 100644
--- a/hooks/useDeliveries.ts
+++ b/hooks/useDeliveries.ts
@@ -1,11 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import { deliveriesService } from '../services/deliveries.service';
import { Delivery } from '../types/delivery';
+import { DeliveryFilterParams } from '../types/filters';
-export function useDeliveries() {
+export function useDeliveries(filters?: DeliveryFilterParams) {
return useQuery({
- queryKey: ['deliveries'],
- queryFn: deliveriesService.getDeliveries,
+ queryKey: ['deliveries', filters],
+ queryFn: () => deliveriesService.getDeliveries(filters),
});
}
diff --git a/package-lock.json b/package-lock.json
index ee930bc..cb0d107 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,12 +12,13 @@
"@hookform/resolvers": "^5.2.2",
"@tailwindcss/postcss": "^4.2.4",
"@tailwindcss/vite": "^4.2.4",
- "@tanstack/react-query": "^5.0.0",
+ "@tanstack/react-table": "^8.0.0",
"axios": "^1.6.0",
"browser-image-compression": "^2.0.2",
"clsx": "^2.0.0",
"cmdk": "^1.1.1",
"framer-motion": "^12.38.0",
+ "lodash.debounce": "^4.0.8",
"lucide-react": "^1.9.0",
"next": "16.1.6",
"next-themes": "^0.4.6",
@@ -3582,30 +3583,24 @@
"vite": "^5.2.0 || ^6 || ^7 || ^8"
}
},
- "node_modules/@tanstack/query-core": {
- "version": "5.100.5",
- "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.5.tgz",
- "integrity": "sha512-t20KrhKkf0HXzqQkPbJ5erhFesup68BAbwFgYmTrS7bxMF7O5MdmL8jUkik4thsG7Hg00fblz30h6yF1d5TxGg==",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/react-query": {
- "version": "5.100.5",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.5.tgz",
- "integrity": "sha512-aNwj1mi2v2bQ9IxkyR1grLOUkv3BYWoykHy9KDyLNbjC3tsahbOHJibK+Wjtr1wRhG59/AvJhiJG5OlthaCgJA==",
+ "node_modules/@tanstack/react-table": {
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz",
+ "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==",
"license": "MIT",
"dependencies": {
- "@tanstack/query-core": "5.100.5"
+ "@tanstack/table-core": "8.21.3"
+ },
+ "engines": {
+ "node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
- "react": "^18 || ^19"
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
}
},
"node_modules/@tanstack/react-virtual": {
@@ -3625,6 +3620,19 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/@tanstack/table-core": {
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz",
+ "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
"node_modules/@tanstack/virtual-core": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.14.0.tgz",
@@ -9490,6 +9498,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "license": "MIT"
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
diff --git a/services/__tests__/deliveries.service.test.ts b/services/__tests__/deliveries.service.test.ts
new file mode 100644
index 0000000..c093bd5
--- /dev/null
+++ b/services/__tests__/deliveries.service.test.ts
@@ -0,0 +1,94 @@
+import { deliveriesService } from '../deliveries.service';
+import { apiClient } from '../api';
+
+// Mock axios
+jest.mock('../api', () => ({
+ apiClient: {
+ get: jest.fn(),
+ },
+}));
+
+describe('deliveriesService', () => {
+ const mockDeliveries = [
+ {
+ id: '1',
+ trackingNumber: 'TRK001',
+ status: 'DELIVERED',
+ origin: 'Nairobi',
+ destination: 'Mombasa',
+ amount: 100,
+ escrowStatus: 'RELEASED',
+ senderId: 'sender1',
+ createdAt: '2024-01-01T00:00:00Z',
+ updatedAt: '2024-01-01T00:00:00Z',
+ },
+ ];
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should fetch all deliveries without filters', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries });
+
+ const result = await deliveriesService.getDeliveries();
+
+ expect(apiClient.get).toHaveBeenCalledWith('/deliveries');
+ expect(result).toEqual(mockDeliveries);
+ });
+
+ it('should fetch deliveries with search filter', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries });
+
+ await deliveriesService.getDeliveries({ search: 'TRK001' });
+
+ expect(apiClient.get).toHaveBeenCalledWith('/deliveries?search=TRK001');
+ });
+
+ it('should fetch deliveries with status filter', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries });
+
+ await deliveriesService.getDeliveries({ status: 'DELIVERED' });
+
+ expect(apiClient.get).toHaveBeenCalledWith('/deliveries?status=DELIVERED');
+ });
+
+ it('should fetch deliveries with sortBy filter', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries });
+
+ await deliveriesService.getDeliveries({ sortBy: 'date-desc' });
+
+ expect(apiClient.get).toHaveBeenCalledWith('/deliveries?sortBy=date-desc');
+ });
+
+ it('should fetch deliveries with multiple filters', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries });
+
+ await deliveriesService.getDeliveries({
+ search: 'TRK001',
+ status: 'DELIVERED',
+ sortBy: 'date-asc',
+ });
+
+ const callUrl = (apiClient.get as jest.Mock).mock.calls[0][0];
+ expect(callUrl).toContain('search=TRK001');
+ expect(callUrl).toContain('status=DELIVERED');
+ expect(callUrl).toContain('sortBy=date-asc');
+ });
+
+ it('should fetch delivery by ID', async () => {
+ (apiClient.get as jest.Mock).mockResolvedValue({ data: mockDeliveries[0] });
+
+ const result = await deliveriesService.getDeliveryById('1');
+
+ expect(apiClient.get).toHaveBeenCalledWith('/deliveries/1');
+ expect(result).toEqual(mockDeliveries[0]);
+ });
+
+ it('should handle API errors', async () => {
+ const error = new Error('Network error');
+ (apiClient.get as jest.Mock).mockRejectedValue(error);
+
+ await expect(deliveriesService.getDeliveries()).rejects.toThrow('Network error');
+ });
+});
diff --git a/services/deliveries.service.ts b/services/deliveries.service.ts
index e8080d4..859c18c 100644
--- a/services/deliveries.service.ts
+++ b/services/deliveries.service.ts
@@ -1,9 +1,28 @@
import { apiClient } from './api';
+import { Delivery } from '../types/delivery';
+import { DeliveryFilterParams } from '../types/filters';
import { Delivery, StatusTimeline } from '../types/delivery';
export const deliveriesService = {
- getDeliveries: async (): Promise => {
- const { data } = await apiClient.get('/deliveries');
+ getDeliveries: async (filters?: DeliveryFilterParams): Promise => {
+ const params = new URLSearchParams();
+
+ if (filters?.search) {
+ params.append('search', filters.search);
+ }
+
+ if (filters?.status) {
+ params.append('status', filters.status);
+ }
+
+ if (filters?.sortBy) {
+ params.append('sortBy', filters.sortBy);
+ }
+
+ const queryString = params.toString();
+ const url = queryString ? `/deliveries?${queryString}` : '/deliveries';
+
+ const { data } = await apiClient.get(url);
return data;
},
diff --git a/services/escrowService.ts b/services/escrowService.ts
index 34c33c5..cd63656 100644
--- a/services/escrowService.ts
+++ b/services/escrowService.ts
@@ -38,6 +38,9 @@ export interface LockEscrowParams {
export interface LockEscrowResponse {
success: boolean;
message: string;
+ escrowId: string;
+ transactionHash: string;
+ lockedAmount: string;
escrowId?: string;
transactionHash?: string;
lockedAmount?: string;
@@ -106,6 +109,10 @@ export const escrowService = {
return data;
},
+ async lockEscrow(params: LockEscrowParams): Promise {
+ const { data } = await axios.post(
+ `${API_BASE_URL}/api/escrow/lock`,
+ params
async openDispute(params: OpenDisputeParams): Promise {
const formData = new FormData();
formData.append('deliveryId', params.deliveryId);
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 1f12457..559c13b 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,3 +1,4 @@
+// @ts-ignore - Tailwind CSS v4 type resolution
import type { Config } from 'tailwindcss';
const config: Config = {
diff --git a/tsconfig.json b/tsconfig.json
index b09cc80..fb87bad 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "target": "es5",
+ "target": "es2020",
"lib": [
"dom",
"dom.iterable",
@@ -8,6 +8,7 @@
],
"allowJs": true,
"skipLibCheck": true,
+ "ignoreDeprecations": "6.0",
"strict": true,
"noEmit": true,
"esModuleInterop": true,
diff --git a/types/filters.ts b/types/filters.ts
new file mode 100644
index 0000000..31cb3d5
--- /dev/null
+++ b/types/filters.ts
@@ -0,0 +1,9 @@
+export interface DeliveryFilterParams {
+ search?: string;
+ status?: string;
+ sortBy?: 'date-asc' | 'date-desc';
+}
+
+export interface FilterState extends DeliveryFilterParams {
+ hasActiveFilters: boolean;
+}