update info

This commit is contained in:
Phuoc Nguyen
2025-11-20 10:12:24 +07:00
parent 54cb7d0fdd
commit 0708ed7d6f
17 changed files with 2144 additions and 161 deletions

View File

@@ -0,0 +1,200 @@
/// 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> userInfoRemoteDataSource(Ref ref) async {
final dioClient = await ref.watch(dioClientProvider.future);
return UserInfoRemoteDataSource(dioClient);
}
// ============================================================================
// REPOSITORY PROVIDERS
// ============================================================================
/// User Info Repository Provider
@riverpod
Future<UserInfoRepository> 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<GetUserInfo> 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<domain.UserInfo> 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<void> 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 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;
}