A production-ready React TypeScript application for creating and managing SOAP (Subjective, Objective, Assessment, Plan) medical notes with offline-first capabilities and automatic synchronization.
- Offline-First Architecture: Fully functional without internet connectivity
- Real-time Validation: Form validation with helpful error messages
- IndexedDB Storage: Robust offline data persistence
- Automatic Sync: Background synchronization when connection is restored
- Retry Logic: Exponential backoff for failed sync attempts
- Material-UI: Clean, accessible, and responsive design
- TypeScript: Full type safety throughout the application
- Frontend: Next.js 15 + React 19 + TypeScript
- UI Library: Material-UI (MUI) v7
- Validation: Zod schema validation
- Storage: IndexedDB for offline persistence
- API: json-server for mock backend
- Build Tool: Turbopack for fast development
- Node.js 18+ and yarn
- Modern browser with IndexedDB support
# Clone the repository
git clone <repository-url>
cd soap
# Install dependencies
yarn install
# Start development servers (app + mock API)
yarn dev:allThe application will be available at:
- App: http://localhost:3000
- Mock API: http://localhost:4000
# Start only the Next.js app
yarn dev
# Start only the mock API server
yarn api
# Build for production
yarn build
# Start production server
yarn startsrc/
├── components/ # React components
│ ├── forms/ # Form components
│ └── ui/ # UI components (status, queue)
├── hooks/ # Custom React hooks
├── lib/ # Core utilities and services
│ ├── api.ts # API client with error handling
│ ├── storage.ts # IndexedDB wrapper
│ ├── sync.ts # Sync orchestrator
│ ├── utils.ts # Utility functions
│ ├── validation.ts # Zod schemas
│ └── theme.ts # Material-UI theme
├── stores/ # State management
│ └── AppContext.tsx # React Context for global state
└── types/ # TypeScript type definitions
└── soap.ts # SOAP note interfaces
Data Flow:
- User creates SOAP note → Saved to IndexedDB with 'pending' status
- Sync orchestrator detects pending notes → Attempts API sync
- Success: Note marked as 'synced' | Failure: Note marked as 'error' with retry logic
Offline Strategy:
- All notes stored locally in IndexedDB
- App fully functional offline
- Automatic sync when connection restored
- Failed syncs queued with exponential backoff retry
Error Handling:
- Graceful degradation for network failures
- User-friendly error messages
- Retry mechanisms with visual feedback
- Partial sync failure handling
The SOAP note form includes comprehensive validation:
- Patient Name: Required, non-empty string
- Patient ID: Required, positive integer
- Date: Required, valid ISO date format
- Weight: Required, positive number with unit selection (kg/lb)
- Heart Rate: Required, integer between 20-300 bpm
- History/Assessment/Plan: Required, non-empty text fields
- Primary Storage: IndexedDB for structured data and reliability
- Data Structure: Notes stored with sync status and metadata
- Persistence: Data survives browser restarts and updates
- Connection Detection: Uses
navigator.onLine+ API health checks - Queue Management: Failed syncs remain in queue with error details
- Retry Logic: Exponential backoff (1s, 2s, 4s, 8s, 16s, 30s max)
- Partial Failures: Individual note failures don't block other syncs
- Status Indicators: Clear sync status (Offline, Pending, Synced, Error)
- Queue Visibility: Expandable sync queue with retry actions
- Manual Sync: "Sync Now" button for user-initiated sync
- Error Recovery: Individual retry buttons for failed items
The application expects a REST API with these endpoints:
POST /notes - Create new note (returns note with server-assigned ID)
GET /notes - List all notes
PUT /notes/:id - Update existing note
DELETE /notes/:id - Delete note
{
"id": "2a46",
"patientName": "John Doe",
"patientId": 12345,
"date": "2024-01-15",
"history": "Patient reports headache...",
"weightValue": 70.5,
"weightUnit": "kg",
"heartRate": 72,
"assessment": "Mild tension headache...",
"plan": "Rest and hydration...",
"createdAt": "2024-01-15T10:30:00.000Z",
"syncedAt": "2024-01-15T10:30:05.000Z"
}- Open browser developer tools
- Go to Network tab → Check "Offline"
- Create SOAP notes (should work normally)
- Check sync queue shows pending items
- Uncheck "Offline" → Notes should sync automatically
- Stop the json-server (
Ctrl+C) - Try to sync notes → Should show error status
- Restart json-server → Retry should work
- Full TypeScript coverage with strict mode
- Runtime validation with Zod schemas
- Type-safe API client with error handling
- IndexedDB for efficient offline storage
- Debounced validation to reduce re-renders
- Lazy imports for utility functions
- Background sync to avoid blocking UI
- Semantic HTML structure
- Proper form labels and ARIA attributes
- Keyboard navigation support
- Screen reader friendly error messages
With more time, I would implement:
- Service Worker: Background sync for true offline-first experience
- Batch Sync: Sync multiple notes in single API call
- Conflict Resolution: Handle concurrent edits from multiple devices
- Diagnostics Panel: Sync statistics and debugging information
- Data Export: Export notes to various formats (PDF, CSV)
- Search & Filter: Find notes by patient, date, or content
- Authentication: User login and access control
- Real Database: Replace json-server with production backend
- Error Monitoring: Sentry or similar error tracking
- Analytics: Usage tracking and performance monitoring
- Caching Strategy: Implement proper HTTP caching
- Progressive Enhancement: Enhanced features for modern browsers
Build Errors: Ensure all dependencies are installed with yarn install
Sync Not Working: Check that json-server is running on port 4000
IndexedDB Issues: Try clearing browser data or test in incognito mode
Form Validation: Check browser console for detailed validation errors
- Modern browsers with ES2017+ support
- IndexedDB support required for offline functionality
- Tested on Chrome 90+, Firefox 88+, Safari 14+
- Testing, testing, testing!
- Get eslint working
- Fine tune server sync
- Better testing of error states
- Integrate react-query for more terse and declarative server sync and state mgmt code
- Make the UI less ugly (tighter spacing, colors, fonts)