/// Provider: User Info Provider /// /// Manages the state of user information using Riverpod. /// Fetches data from API and provides it to the UI. library; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:worker/core/network/dio_client.dart'; import 'package:worker/features/account/data/datasources/user_info_remote_datasource.dart'; import 'package:worker/features/account/data/repositories/user_info_repository_impl.dart'; import 'package:worker/features/account/domain/entities/user_info.dart' as domain; import 'package:worker/features/account/domain/repositories/user_info_repository.dart'; import 'package:worker/features/account/domain/usecases/get_user_info.dart'; part 'user_info_provider.g.dart'; // ============================================================================ // DATA SOURCE PROVIDERS // ============================================================================ /// User Info Remote Data Source Provider @riverpod Future userInfoRemoteDataSource(Ref ref) async { final dioClient = await ref.watch(dioClientProvider.future); return UserInfoRemoteDataSource(dioClient); } // ============================================================================ // REPOSITORY PROVIDERS // ============================================================================ /// User Info Repository Provider @riverpod Future userInfoRepository(Ref ref) async { final remoteDataSource = await ref.watch( userInfoRemoteDataSourceProvider.future, ); return UserInfoRepositoryImpl(remoteDataSource: remoteDataSource); } // ============================================================================ // USE CASE PROVIDERS // ============================================================================ /// Get User Info Use Case Provider @riverpod Future getUserInfoUseCase(Ref ref) async { final repository = await ref.watch(userInfoRepositoryProvider.future); return GetUserInfo(repository); } // ============================================================================ // STATE PROVIDERS // ============================================================================ /// User Info Provider /// /// Fetches and manages user information state. /// Automatically loads user info on initialization. /// Provides refresh functionality for manual updates. /// /// Usage: /// ```dart /// // In a widget /// final userInfoAsync = ref.watch(userInfoProvider); /// /// userInfoAsync.when( /// data: (userInfo) => Text(userInfo.fullName), /// loading: () => CircularProgressIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// /// // To refresh /// ref.read(userInfoProvider.notifier).refresh(); /// ``` @riverpod class UserInfo extends _$UserInfo { @override Future build() async { // Fetch user info on initialization final useCase = await ref.watch(getUserInfoUseCaseProvider.future); return await useCase(); } /// Refresh user information /// /// Forces a fresh fetch from the API. /// Updates the state with new data. /// /// Usage: /// ```dart /// await ref.read(userInfoProvider.notifier).refresh(); /// ``` Future refresh() async { // Set loading state state = const AsyncValue.loading(); // Fetch fresh data state = await AsyncValue.guard(() async { final useCase = await ref.read(getUserInfoUseCaseProvider.future); return await useCase.refresh(); }); } /// Update user information /// /// Sends updated user data to the API and refreshes the state. /// /// [data] should contain: /// - full_name: String /// - date_of_birth: String (YYYY-MM-DD) /// - gender: String /// - company_name: String? /// - tax_code: String? /// - avatar_base64: String? (base64 encoded) /// - id_card_front_base64: String? (base64 encoded) /// - id_card_back_base64: String? (base64 encoded) /// - certificates_base64: List (base64 encoded) /// /// Usage: /// ```dart /// await ref.read(userInfoProvider.notifier).updateUserInfo(updateData); /// ``` Future updateUserInfo(Map data) async { // Set loading state state = const AsyncValue.loading(); // Update via repository and fetch fresh data state = await AsyncValue.guard(() async { final repository = await ref.read(userInfoRepositoryProvider.future); return await repository.updateUserInfo(data); }); } /// Update user info locally /// /// Updates the cached state without fetching from API. /// Useful after local profile updates. /// /// Usage: /// ```dart /// ref.read(userInfoProvider.notifier).updateLocal(updatedUserInfo); /// ``` void updateLocal(domain.UserInfo updatedInfo) { state = AsyncValue.data(updatedInfo); } /// Clear user info /// /// Resets the state to loading. /// Useful on logout or session expiry. void clear() { state = const AsyncValue.loading(); } } // ============================================================================ // COMPUTED PROVIDERS // ============================================================================ /// User Display Name Provider /// /// Provides the user's display name (full name). /// Returns null if user info is not loaded. @riverpod String? userDisplayName(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.fullName; } /// User Loyalty Tier Provider /// /// Provides the user's current loyalty tier. /// Returns null if user info is not loaded. @riverpod String? userLoyaltyTier(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.tierDisplayName; } /// User Total Points Provider /// /// Provides the user's total loyalty points. /// Returns 0 if user info is not loaded. @riverpod int userTotalPoints(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.totalPoints ?? 0; } /// User Available Points Provider /// /// Provides the user's available points for redemption. /// Returns 0 if user info is not loaded. @riverpod int userAvailablePoints(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.availablePoints ?? 0; } /// User Avatar URL Provider /// /// Provides the user's avatar URL. /// Returns null if user info is not loaded or no avatar set. @riverpod String? userAvatarUrl(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.avatarUrl; } /// User Has Company Info Provider /// /// Checks if the user has company information. /// Returns false if user info is not loaded. @riverpod bool userHasCompanyInfo(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.hasCompanyInfo ?? false; } /// User Is Active Provider /// /// Checks if the user's account is active. /// Returns false if user info is not loaded. @riverpod bool userIsActive(Ref ref) { final userInfoAsync = ref.watch(userInfoProvider); return userInfoAsync.value?.isActive ?? false; }