update md
This commit is contained in:
238
docs/md/CART_INITIALIZATION.md
Normal file
238
docs/md/CART_INITIALIZATION.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# Cart Initialization & Keep Alive Implementation
|
||||
|
||||
## Overview
|
||||
The cart is now initialized when the app starts (on HomePage mount) and kept alive throughout the entire app session. This ensures:
|
||||
- Cart data is loaded from API once on startup
|
||||
- Cart state persists across all navigation
|
||||
- No unnecessary re-fetching when navigating between pages
|
||||
- Real-time cart badge updates across all screens
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Cart Provider with Keep Alive
|
||||
**File**: `lib/features/cart/presentation/providers/cart_provider.dart`
|
||||
|
||||
```dart
|
||||
@Riverpod(keepAlive: true) // ✅ Keep alive throughout app session
|
||||
class Cart extends _$Cart {
|
||||
@override
|
||||
CartState build() {
|
||||
return CartState.initial().copyWith(
|
||||
memberTier: 'Diamond',
|
||||
memberDiscountPercent: 15.0,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
// Load cart from API with Hive fallback
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// Dependent providers also need keepAlive
|
||||
@Riverpod(keepAlive: true)
|
||||
int cartItemCount(Ref ref) {
|
||||
final cartState = ref.watch(cartProvider);
|
||||
return cartState.items.length;
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
double cartTotal(Ref ref) {
|
||||
final cartState = ref.watch(cartProvider);
|
||||
return cartState.total;
|
||||
}
|
||||
```
|
||||
|
||||
### 1.1 Cart Data Providers with Keep Alive
|
||||
**File**: `lib/features/cart/data/providers/cart_data_providers.dart`
|
||||
|
||||
**CRITICAL**: All cart data layer providers must also use `keepAlive: true` to prevent disposal errors:
|
||||
|
||||
```dart
|
||||
@Riverpod(keepAlive: true)
|
||||
CartLocalDataSource cartLocalDataSource(Ref ref) {
|
||||
final hiveService = HiveService();
|
||||
return CartLocalDataSourceImpl(hiveService);
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<CartRemoteDataSource> cartRemoteDataSource(Ref ref) async {
|
||||
final dioClient = await ref.watch(dioClientProvider.future);
|
||||
return CartRemoteDataSourceImpl(dioClient);
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<CartRepository> cartRepository(Ref ref) async {
|
||||
final remoteDataSource = await ref.watch(cartRemoteDataSourceProvider.future);
|
||||
final localDataSource = ref.watch(cartLocalDataSourceProvider);
|
||||
return CartRepositoryImpl(
|
||||
remoteDataSource: remoteDataSource,
|
||||
localDataSource: localDataSource,
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Why all providers need keepAlive:**
|
||||
- Cart provider depends on cartRepository
|
||||
- If repository is disposed, cart operations fail with "Ref disposed" error
|
||||
- All dependencies in the chain must persist together
|
||||
- Ensures consistent lifecycle management
|
||||
|
||||
**Benefits of `keepAlive: true`:**
|
||||
- Provider state is never disposed
|
||||
- Cart data persists when navigating away and back
|
||||
- No re-initialization needed on subsequent visits
|
||||
- Consistent cart count across all app screens
|
||||
- No "Ref disposed" errors during async operations
|
||||
|
||||
### 2. HomePage Initialization
|
||||
**File**: `lib/features/home/presentation/pages/home_page.dart`
|
||||
|
||||
```dart
|
||||
class HomePage extends ConsumerStatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends ConsumerState<HomePage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Initialize cart from API on app startup
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(cartProvider.notifier).initialize();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Watch cart item count for badge
|
||||
final cartItemCount = ref.watch(cartItemCountProvider);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why in HomePage?**
|
||||
- HomePage is the first screen after login
|
||||
- Ensures cart is loaded early in app lifecycle
|
||||
- Provides immediate cart count for navigation badge
|
||||
|
||||
### 3. Cart Badge Integration
|
||||
**Location**: All pages with cart icon/badge
|
||||
|
||||
```dart
|
||||
// Any page can watch cart count - it's always available
|
||||
final cartItemCount = ref.watch(cartItemCountProvider);
|
||||
|
||||
// Display badge
|
||||
if (cartItemCount > 0)
|
||||
Badge(
|
||||
label: Text('$cartItemCount'),
|
||||
child: Icon(Icons.shopping_cart),
|
||||
)
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
App Start
|
||||
↓
|
||||
HomePage mounts
|
||||
↓
|
||||
initState() calls cart.initialize()
|
||||
↓
|
||||
Cart loads from API → Syncs to Hive
|
||||
↓
|
||||
Cart state updates with items
|
||||
↓
|
||||
cartItemCountProvider updates
|
||||
↓
|
||||
All badges across app update reactively
|
||||
↓
|
||||
[keepAlive ensures state persists during navigation]
|
||||
```
|
||||
|
||||
## API & Local Storage Integration
|
||||
|
||||
### Initialize Flow
|
||||
1. **API First**: Fetch cart items from ERPNext API
|
||||
2. **Product Details**: For each cart item, fetch full product data
|
||||
3. **Calculate Conversions**: Apply business rules (boxes, m², etc.)
|
||||
4. **Update State**: Set cart items with full product info
|
||||
5. **Local Sync**: Automatically synced to Hive by repository
|
||||
|
||||
### Offline Fallback
|
||||
- If API fails, cart loads from Hive cache
|
||||
- All mutations queue for sync when online
|
||||
- See `cart_repository_impl.dart` for sync logic
|
||||
|
||||
## Cart Operations
|
||||
|
||||
All cart operations work seamlessly after initialization:
|
||||
|
||||
```dart
|
||||
// Add to cart (from any page)
|
||||
await ref.read(cartProvider.notifier).addToCart(product, quantity: 2.0);
|
||||
|
||||
// Remove from cart
|
||||
await ref.read(cartProvider.notifier).removeFromCart(productId);
|
||||
|
||||
// Update quantity
|
||||
await ref.read(cartProvider.notifier).updateQuantity(productId, 5.0);
|
||||
|
||||
// Clear cart
|
||||
await ref.read(cartProvider.notifier).clearCart();
|
||||
```
|
||||
|
||||
All operations:
|
||||
- Sync to API first
|
||||
- Fallback to local on failure
|
||||
- Queue for sync when offline
|
||||
- Update UI reactively
|
||||
|
||||
## Testing Keep Alive
|
||||
|
||||
To verify keepAlive works:
|
||||
|
||||
1. **Navigate to HomePage** → Cart initializes
|
||||
2. **Add items to cart** → Badge shows count
|
||||
3. **Navigate to Products page** → Badge still shows count
|
||||
4. **Navigate back to HomePage** → Cart state preserved, no re-fetch
|
||||
5. **Navigate to Cart page** → Same items, no loading
|
||||
6. **Hot restart app** → Cart reloads from API
|
||||
|
||||
## Performance Benefits
|
||||
|
||||
- **One-time API call**: Cart loads once on startup
|
||||
- **No re-fetching**: Navigation doesn't trigger reloads
|
||||
- **Instant updates**: All cart operations update state immediately
|
||||
- **Offline support**: Hive cache provides instant fallback
|
||||
- **Memory efficient**: Single provider instance for entire app
|
||||
|
||||
## Error Handling
|
||||
|
||||
If cart initialization fails:
|
||||
- Error stored in `cartState.errorMessage`
|
||||
- Can retry via `ref.read(cartProvider.notifier).initialize()`
|
||||
- Cart page shows error state with retry button
|
||||
- Local Hive cache used if available
|
||||
|
||||
## Related Files
|
||||
|
||||
- **Cart Provider**: `lib/features/cart/presentation/providers/cart_provider.dart`
|
||||
- **Cart State**: `lib/features/cart/presentation/providers/cart_state.dart`
|
||||
- **Data Providers**: `lib/features/cart/data/providers/cart_data_providers.dart`
|
||||
- **Repository**: `lib/features/cart/data/repositories/cart_repository_impl.dart`
|
||||
- **HomePage**: `lib/features/home/presentation/pages/home_page.dart`
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements:
|
||||
- Add periodic background sync (every 5 minutes)
|
||||
- Implement optimistic updates for faster UI
|
||||
- Add cart merge logic when switching accounts
|
||||
- Implement cart expiry (clear after 30 days)
|
||||
- Add analytics tracking for cart events
|
||||
Reference in New Issue
Block a user