# Riverpod Providers Quick Reference

## Essential Providers at a Glance

### Authentication
```dart
// Check if user is logged in
final isAuth = ref.watch(isAuthenticatedProvider);

// Get current user
final user = ref.watch(currentUserProvider);

// Login
ref.read(authProvider.notifier).login(username, password);

// Logout
ref.read(authProvider.notifier).logout();

// Check auth on app start
ref.read(authProvider.notifier).checkAuthStatus();

// Listen to auth changes
ref.listen<AuthState>(authProvider, (previous, next) {
  if (next.isAuthenticated) {
    // Navigate to home
  }
  if (next.error != null) {
    // Show error
  }
});
```

### Warehouse
```dart
// Load warehouses
ref.read(warehouseProvider.notifier).loadWarehouses();

// Get warehouses list
final warehouses = ref.watch(warehousesListProvider);

// Get selected warehouse
final selected = ref.watch(selectedWarehouseProvider);

// Select a warehouse
ref.read(warehouseProvider.notifier).selectWarehouse(warehouse);

// Clear selection
ref.read(warehouseProvider.notifier).clearSelection();

// Check loading state
final isLoading = ref.watch(isWarehouseLoadingProvider);

// Get error
final error = ref.watch(warehouseErrorProvider);
```

### Products
```dart
// Load products
ref.read(productsProvider.notifier).loadProducts(
  warehouseId,
  warehouseName,
  'import', // or 'export'
);

// Get products list
final products = ref.watch(productsListProvider);

// Refresh products
ref.read(productsProvider.notifier).refreshProducts();

// Clear products
ref.read(productsProvider.notifier).clearProducts();

// Check loading state
final isLoading = ref.watch(isProductsLoadingProvider);

// Get products count
final count = ref.watch(productsCountProvider);

// Get operation type
final type = ref.watch(operationTypeProvider);

// Get error
final error = ref.watch(productsErrorProvider);
```

## Widget Setup

### ConsumerWidget (Stateless)
```dart
class MyPage extends ConsumerWidget {
  const MyPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final data = ref.watch(someProvider);
    return Widget();
  }
}
```

### ConsumerStatefulWidget (Stateful)
```dart
class MyPage extends ConsumerStatefulWidget {
  const MyPage({Key? key}) : super(key: key);

  @override
  ConsumerState<MyPage> createState() => _MyPageState();
}

class _MyPageState extends ConsumerState<MyPage> {
  @override
  void initState() {
    super.initState();
    // Load data on init
    Future.microtask(() {
      ref.read(someProvider.notifier).loadData();
    });
  }

  @override
  Widget build(BuildContext context) {
    final data = ref.watch(someProvider);
    return Widget();
  }
}
```

## Common Patterns

### Pattern 1: Display Loading State
```dart
final isLoading = ref.watch(isAuthLoadingProvider);

return isLoading
    ? CircularProgressIndicator()
    : YourContent();
```

### Pattern 2: Handle Errors
```dart
final error = ref.watch(authErrorProvider);

return Column(
  children: [
    if (error != null)
      Text(error, style: TextStyle(color: Colors.red)),
    YourContent(),
  ],
);
```

### Pattern 3: Conditional Navigation
```dart
ref.listen<AuthState>(authProvider, (previous, next) {
  if (next.isAuthenticated) {
    Navigator.pushReplacementNamed(context, '/home');
  }
});
```

### Pattern 4: Pull to Refresh
```dart
RefreshIndicator(
  onRefresh: () async {
    await ref.read(warehouseProvider.notifier).refresh();
  },
  child: ListView(...),
)
```

### Pattern 5: Load Data on Page Open
```dart
@override
void initState() {
  super.initState();
  Future.microtask(() {
    ref.read(warehouseProvider.notifier).loadWarehouses();
  });
}
```

## Key Methods by Feature

### Auth Methods
- `login(username, password)` - Authenticate user
- `logout()` - Sign out user
- `checkAuthStatus()` - Check if token exists
- `clearError()` - Clear error message
- `reset()` - Reset to initial state

### Warehouse Methods
- `loadWarehouses()` - Fetch all warehouses
- `selectWarehouse(warehouse)` - Select a warehouse
- `clearSelection()` - Clear selected warehouse
- `refresh()` - Reload warehouses
- `clearError()` - Clear error message
- `reset()` - Reset to initial state

### Products Methods
- `loadProducts(warehouseId, name, type)` - Fetch products
- `refreshProducts()` - Reload current products
- `clearProducts()` - Clear products list

## Provider Types Explained

### Provider (Read-only)
```dart
// For services, repositories, use cases
final myServiceProvider = Provider<MyService>((ref) {
  return MyService();
});

// Usage
final service = ref.watch(myServiceProvider);
```

### StateNotifierProvider (Mutable State)
```dart
// For managing mutable state
final myStateProvider = StateNotifierProvider<MyNotifier, MyState>((ref) {
  return MyNotifier();
});

// Usage - watch state
final state = ref.watch(myStateProvider);

// Usage - call methods
ref.read(myStateProvider.notifier).doSomething();
```

## Ref Methods

### ref.watch()
- Use in `build()` method
- Rebuilds widget when provider changes
- Reactive to state updates

```dart
final data = ref.watch(someProvider);
```

### ref.read()
- Use in event handlers, callbacks
- One-time read, no rebuild
- For calling methods

```dart
onPressed: () {
  ref.read(authProvider.notifier).login(user, pass);
}
```

### ref.listen()
- Use for side effects
- Navigation, dialogs, snackbars
- Doesn't rebuild widget

```dart
ref.listen<AuthState>(authProvider, (previous, next) {
  if (next.error != null) {
    showDialog(...);
  }
});
```

## App Initialization

```dart
void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends ConsumerStatefulWidget {
  @override
  ConsumerState<MyApp> createState() => _MyAppState();
}

class _MyAppState extends ConsumerState<MyApp> {
  @override
  void initState() {
    super.initState();
    // Check auth on app start
    Future.microtask(() {
      ref.read(authProvider.notifier).checkAuthStatus();
    });
  }

  @override
  Widget build(BuildContext context) {
    final isAuthenticated = ref.watch(isAuthenticatedProvider);

    return MaterialApp(
      home: isAuthenticated
          ? WarehouseSelectionPage()
          : LoginPage(),
    );
  }
}
```

## Complete Example Flow

### 1. Login Page
```dart
class LoginPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isLoading = ref.watch(isAuthLoadingProvider);
    final error = ref.watch(authErrorProvider);

    ref.listen<AuthState>(authProvider, (previous, next) {
      if (next.isAuthenticated) {
        Navigator.pushReplacementNamed(context, '/warehouses');
      }
    });

    return Scaffold(
      body: Column(
        children: [
          if (error != null)
            Text(error, style: TextStyle(color: Colors.red)),
          TextField(controller: usernameController),
          TextField(controller: passwordController, obscureText: true),
          ElevatedButton(
            onPressed: isLoading ? null : () {
              ref.read(authProvider.notifier).login(
                usernameController.text,
                passwordController.text,
              );
            },
            child: isLoading
                ? CircularProgressIndicator()
                : Text('Login'),
          ),
        ],
      ),
    );
  }
}
```

### 2. Warehouse Selection Page
```dart
class WarehouseSelectionPage extends ConsumerStatefulWidget {
  @override
  ConsumerState<WarehouseSelectionPage> createState() => _State();
}

class _State extends ConsumerState<WarehouseSelectionPage> {
  @override
  void initState() {
    super.initState();
    Future.microtask(() {
      ref.read(warehouseProvider.notifier).loadWarehouses();
    });
  }

  @override
  Widget build(BuildContext context) {
    final warehouses = ref.watch(warehousesListProvider);
    final isLoading = ref.watch(isWarehouseLoadingProvider);

    return Scaffold(
      appBar: AppBar(
        title: Text('Select Warehouse'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () {
              ref.read(authProvider.notifier).logout();
            },
          ),
        ],
      ),
      body: isLoading
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: warehouses.length,
              itemBuilder: (context, index) {
                final warehouse = warehouses[index];
                return ListTile(
                  title: Text(warehouse.name),
                  subtitle: Text(warehouse.code),
                  onTap: () {
                    ref.read(warehouseProvider.notifier)
                        .selectWarehouse(warehouse);
                    Navigator.pushNamed(context, '/operations');
                  },
                );
              },
            ),
    );
  }
}
```

### 3. Products Page
```dart
class ProductsPage extends ConsumerStatefulWidget {
  final int warehouseId;
  final String warehouseName;
  final String operationType;

  const ProductsPage({
    required this.warehouseId,
    required this.warehouseName,
    required this.operationType,
  });

  @override
  ConsumerState<ProductsPage> createState() => _ProductsPageState();
}

class _ProductsPageState extends ConsumerState<ProductsPage> {
  @override
  void initState() {
    super.initState();
    Future.microtask(() {
      ref.read(productsProvider.notifier).loadProducts(
        widget.warehouseId,
        widget.warehouseName,
        widget.operationType,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    final products = ref.watch(productsListProvider);
    final isLoading = ref.watch(isProductsLoadingProvider);
    final error = ref.watch(productsErrorProvider);

    return Scaffold(
      appBar: AppBar(
        title: Text('${widget.warehouseName} - ${widget.operationType}'),
        actions: [
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: () {
              ref.read(productsProvider.notifier).refreshProducts();
            },
          ),
        ],
      ),
      body: isLoading
          ? Center(child: CircularProgressIndicator())
          : error != null
              ? Center(child: Text(error))
              : RefreshIndicator(
                  onRefresh: () async {
                    await ref.read(productsProvider.notifier)
                        .refreshProducts();
                  },
                  child: ListView.builder(
                    itemCount: products.length,
                    itemBuilder: (context, index) {
                      final product = products[index];
                      return ListTile(
                        title: Text(product.name),
                        subtitle: Text(product.code),
                        trailing: Text('${product.piecesInStock} pcs'),
                      );
                    },
                  ),
                ),
    );
  }
}
```

## Troubleshooting

### Provider Not Found
- Ensure `ProviderScope` wraps your app in `main.dart`
- Check that you're using `ConsumerWidget` or `ConsumerStatefulWidget`

### State Not Updating
- Use `ref.watch()` not `ref.read()` in build method
- Verify the provider is actually updating its state

### Null Value
- Check if data is loaded before accessing
- Use null-safe operators `?.` and `??`

### Infinite Loop
- Don't call `ref.read(provider.notifier).method()` directly in build
- Use `Future.microtask()` in initState or callbacks

## Cheat Sheet

| Task | Code |
|------|------|
| Watch state | `ref.watch(provider)` |
| Read once | `ref.read(provider)` |
| Call method | `ref.read(provider.notifier).method()` |
| Listen for changes | `ref.listen(provider, callback)` |
| Get loading | `ref.watch(isXxxLoadingProvider)` |
| Get error | `ref.watch(xxxErrorProvider)` |
| Check auth | `ref.watch(isAuthenticatedProvider)` |
| Get user | `ref.watch(currentUserProvider)` |
| Get warehouses | `ref.watch(warehousesListProvider)` |
| Get products | `ref.watch(productsListProvider)` |
