/// Address Provider /// /// Riverpod providers for address management. library; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:worker/core/network/dio_client.dart'; import 'package:worker/features/account/data/datasources/address_remote_datasource.dart'; import 'package:worker/features/account/data/repositories/address_repository_impl.dart'; import 'package:worker/features/account/domain/entities/address.dart'; import 'package:worker/features/account/domain/repositories/address_repository.dart'; part 'address_provider.g.dart'; // ============================================================================ // DATASOURCE PROVIDER // ============================================================================ /// Provides instance of AddressRemoteDataSource @riverpod Future addressRemoteDataSource(Ref ref) async { final dioClient = await ref.watch(dioClientProvider.future); return AddressRemoteDataSource(dioClient.dio); } // ============================================================================ // REPOSITORY PROVIDER // ============================================================================ /// Provides instance of AddressRepository @riverpod Future addressRepository(Ref ref) async { final remoteDataSource = await ref.watch(addressRemoteDataSourceProvider.future); return AddressRepositoryImpl( remoteDataSource: remoteDataSource, ); } // ============================================================================ // ADDRESSES LIST PROVIDER // ============================================================================ /// Manages list of addresses with online-only approach /// /// This is the MAIN provider for the addresses feature. /// Returns list of Address entities from the API. /// /// Online-only: Always fetches from API, no offline caching. /// Uses keepAlive to prevent unnecessary reloads. /// Provides refresh() method for pull-to-refresh functionality. @Riverpod(keepAlive: true) class Addresses extends _$Addresses { late AddressRepository _repository; @override Future> build() async { _repository = await ref.read(addressRepositoryProvider.future); return await _loadAddresses(); } // ========================================================================== // PRIVATE METHODS // ========================================================================== /// Load addresses from repository /// /// Online-only: Fetches from API Future> _loadAddresses() async { try { final addresses = await _repository.getAddresses(); _debugPrint('Loaded ${addresses.length} addresses'); return addresses; } catch (e) { _debugPrint('Error loading addresses: $e'); rethrow; } } // ========================================================================== // PUBLIC METHODS // ========================================================================== /// Create new address /// /// Calls API to create address, then refreshes the list. Future createAddress(Address address) async { try { _debugPrint('Creating address: ${address.addressTitle}'); await _repository.createAddress(address); // Refresh the list after successful creation await refresh(); _debugPrint('Successfully created address'); } catch (e) { _debugPrint('Error creating address: $e'); rethrow; } } /// Update existing address /// /// Calls API to update address, then refreshes the list. Future updateAddress(Address address) async { try { _debugPrint('Updating address: ${address.name}'); await _repository.updateAddress(address); // Refresh the list after successful update await refresh(); _debugPrint('Successfully updated address'); } catch (e) { _debugPrint('Error updating address: $e'); rethrow; } } /// Delete address /// /// Calls API to delete address, then refreshes the list. Future deleteAddress(String name) async { try { _debugPrint('Deleting address: $name'); await _repository.deleteAddress(name); // Refresh the list after successful deletion await refresh(); _debugPrint('Successfully deleted address'); } catch (e) { _debugPrint('Error deleting address: $e'); rethrow; } } /// Set address as default /// /// Calls API to set address as default, then refreshes the list. Future setDefaultAddress(String name) async { try { _debugPrint('Setting default address: $name'); await _repository.setDefaultAddress(name); // Refresh the list after successful update await refresh(); _debugPrint('Successfully set default address'); } catch (e) { _debugPrint('Error setting default address: $e'); rethrow; } } /// Refresh addresses from API /// /// Used for pull-to-refresh functionality. /// Fetches latest data from API. Future refresh() async { state = const AsyncValue.loading(); state = await AsyncValue.guard(() async { return await _loadAddresses(); }); } } // ============================================================================ // HELPER PROVIDERS // ============================================================================ /// Get the default address /// /// Derived from the addresses list. /// Returns the address marked as default, or null if none. @riverpod Address? defaultAddress(Ref ref) { final addressesAsync = ref.watch(addressesProvider); return addressesAsync.when( data: (addresses) { try { return addresses.firstWhere((addr) => addr.isDefault); } catch (e) { return null; } }, loading: () => null, error: (_, __) => null, ); } /// Get address count /// /// Derived from the addresses list. /// Returns the number of addresses. @riverpod int addressCount(Ref ref) { final addressesAsync = ref.watch(addressesProvider); return addressesAsync.when( data: (addresses) => addresses.length, loading: () => 0, error: (_, __) => 0, ); } // ============================================================================ // DEBUG UTILITIES // ============================================================================ /// Debug print helper void _debugPrint(String message) { // ignore: avoid_print print('[AddressProvider] $message'); }