- Extract NotificationItem/NotificationType to Models/Notification.swift - Create NotificationsServiceProtocol with testable service layer - Implement markAsRead(id:) and markAllAsRead() with HTTP calls - Add NotificationError enum with localized descriptions - Update NotificationsViewModel to use protocol-based service - Add 18 unit tests (12 ViewModel + 6 Model) with mock service - Update README with architecture documentation
110 lines
4.1 KiB
Markdown
110 lines
4.1 KiB
Markdown
# Lendair iOS Notifications
|
|
|
|
## Overview
|
|
SwiftUI implementation of the notifications feature for the Lendair iOS app.
|
|
|
|
## Architecture
|
|
|
|
### MVVM Pattern
|
|
- **View**: `Views/` - SwiftUI views for notification display
|
|
- **ViewModel**: `ViewModels/` - State management and business logic
|
|
- **Service**: `Services/` - Data layer with API communication
|
|
- **Model**: `Models/` - Data structures and type definitions
|
|
|
|
### File Structure
|
|
```
|
|
Lendair/
|
|
├── Models/
|
|
│ └── Notification.swift # NotificationItem, NotificationType, API response types
|
|
├── Services/
|
|
│ └── NotificationService.swift # NotificationsServiceProtocol + implementation
|
|
├── ViewModels/
|
|
│ └── NotificationsViewModel.swift # State management, mark-as-read actions
|
|
├── Views/
|
|
│ ├── NotificationsView.swift # Main notifications list screen
|
|
│ └── NotificationRowView.swift # Individual notification row
|
|
└── README.md
|
|
```
|
|
|
|
## Components
|
|
|
|
### NotificationsView (`Views/NotificationsView.swift`)
|
|
- Main navigation container for the notifications screen
|
|
- Pull-to-refresh via `.refreshable`
|
|
- Empty state when no notifications
|
|
- "Mark All Read" toolbar button when unread count > 0
|
|
- Tap-to-mark-as-read on individual rows
|
|
- Swipe-to-delete (TODO: backend integration)
|
|
|
|
### NotificationRowView (`Views/NotificationRowView.swift`)
|
|
- Individual notification list item
|
|
- Type-specific SF Symbol icon with color coding
|
|
- Read/unread indicator (blue dot)
|
|
- Relative timestamp display
|
|
|
|
### NotificationsViewModel (`ViewModels/NotificationsViewModel.swift`)
|
|
- `@Published notifications` — sorted by createdAt descending
|
|
- `@Published isLoading` — loading state for UI feedback
|
|
- `@Published error` — typed error state (NotificationError)
|
|
- `fetchNotifications()` — loads from service
|
|
- `markAsRead(id:)` — marks single notification, updates local state
|
|
- `markAllAsRead()` — marks all unread, updates local state
|
|
- `unreadCount` — computed property for badge display
|
|
|
|
### NotificationsService (`Services/NotificationService.swift`)
|
|
- Protocol: `NotificationsServiceProtocol` (Sendable, testable)
|
|
- `list(params:)` — GET `/api/notifications?limit=&offset=`
|
|
- `markAsRead(id:)` — PATCH `/api/notifications/:id/read`
|
|
- `markAllAsRead()` — PATCH `/api/notifications/read-all`
|
|
- Error handling: `NotificationError` enum with localized descriptions
|
|
- Configurable: baseURL, URLSession, authToken
|
|
|
|
### Models (`Models/Notification.swift`)
|
|
- `NotificationItem` — Identifiable, Equatable, Codable
|
|
- `NotificationType` — 6 cases with icon/color mappings
|
|
- `NotificationListParams` — pagination parameters
|
|
- `NotificationListResponse`, `NotificationMarkAsReadResponse`, `NotificationMarkAllReadResponse` — API response types
|
|
|
|
## Notification Types
|
|
|
|
| Type | Icon | Color |
|
|
|------|------|-------|
|
|
| `LOAN_APPROVED` | checkmark.circle.fill | Green |
|
|
| `LOAN_REJECTED` | xmark.circle.fill | Red |
|
|
| `PAYMENT_RECEIVED` | arrow.down.circle.fill | Green |
|
|
| `PAYMENT_DUE` | exclamationmark.circle.fill | Orange |
|
|
| `NEW_LENDER` | person.circle.fill | Blue |
|
|
| `SYSTEM_UPDATE` | info.circle.fill | Gray |
|
|
|
|
## API Endpoints
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/api/notifications?limit=&offset=` | List notifications |
|
|
| PATCH | `/api/notifications/:id/read` | Mark single as read |
|
|
| PATCH | `/api/notifications/read-all` | Mark all as read |
|
|
|
|
## Testing
|
|
|
|
Tests are in `LendairTests/NotificationServiceTests.swift`:
|
|
- 12 ViewModel tests (fetch, mark-as-read, mark-all-read, unread count, refresh, error handling)
|
|
- 6 Model tests (icons, colors, equality, raw values, params)
|
|
- Uses `MockNotificationsService` conforming to `NotificationsServiceProtocol`
|
|
|
|
## Usage
|
|
|
|
```swift
|
|
// In your MainTabView or navigation stack
|
|
NavigationStack {
|
|
NotificationsView()
|
|
}
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Push Notifications**: Integrate with UNUserNotificationCenter
|
|
2. **Notification Preferences**: Allow users to customize notification types
|
|
3. **Deep Linking**: Navigate to relevant screens when tapping notifications
|
|
4. **Offline Support**: Cache notifications locally with Core Data
|
|
5. **Analytics**: Track notification engagement metrics
|