231 lines
7.0 KiB
Dart
231 lines
7.0 KiB
Dart
/// 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 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<String> (base64 encoded)
|
|
///
|
|
/// Usage:
|
|
/// ```dart
|
|
/// await ref.read(userInfoProvider.notifier).updateUserInfo(updateData);
|
|
/// ```
|
|
Future<void> updateUserInfo(Map<String, dynamic> 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;
|
|
}
|