add auth, format
This commit is contained in:
279
lib/features/auth/presentation/providers/auth_provider.dart
Normal file
279
lib/features/auth/presentation/providers/auth_provider.dart
Normal file
@@ -0,0 +1,279 @@
|
||||
/// Authentication State Provider
|
||||
///
|
||||
/// Manages authentication state for the Worker application.
|
||||
/// Handles login, logout, and user session management.
|
||||
///
|
||||
/// Uses Riverpod 3.0 with code generation for type-safe state management.
|
||||
library;
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:worker/features/auth/data/datasources/auth_local_datasource.dart';
|
||||
import 'package:worker/features/auth/data/models/auth_session_model.dart';
|
||||
import 'package:worker/features/auth/domain/entities/user.dart';
|
||||
|
||||
part 'auth_provider.g.dart';
|
||||
|
||||
/// Provide FlutterSecureStorage instance
|
||||
@riverpod
|
||||
FlutterSecureStorage secureStorage(Ref ref) {
|
||||
return const FlutterSecureStorage(
|
||||
aOptions: AndroidOptions(encryptedSharedPreferences: true),
|
||||
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
|
||||
);
|
||||
}
|
||||
|
||||
/// Provide AuthLocalDataSource instance
|
||||
@riverpod
|
||||
AuthLocalDataSource authLocalDataSource(Ref ref) {
|
||||
final secureStorage = ref.watch(secureStorageProvider);
|
||||
return AuthLocalDataSource(secureStorage);
|
||||
}
|
||||
|
||||
/// Authentication state result
|
||||
///
|
||||
/// Represents the result of authentication operations.
|
||||
/// Contains either the authenticated user or null if logged out.
|
||||
typedef AuthState = AsyncValue<User?>;
|
||||
|
||||
/// Authentication Provider
|
||||
///
|
||||
/// Main provider for authentication state management.
|
||||
/// Provides login and logout functionality with async state handling.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final authState = ref.watch(authProvider);
|
||||
/// authState.when(
|
||||
/// data: (user) => user != null ? HomeScreen() : LoginScreen(),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
@riverpod
|
||||
class Auth extends _$Auth {
|
||||
/// Get auth local data source
|
||||
AuthLocalDataSource get _localDataSource =>
|
||||
ref.read(authLocalDataSourceProvider);
|
||||
|
||||
/// Initialize with saved session if available
|
||||
@override
|
||||
Future<User?> build() async {
|
||||
// Check for saved session in secure storage
|
||||
final session = await _localDataSource.getSession();
|
||||
if (session != null) {
|
||||
// User has saved session, create User entity
|
||||
final now = DateTime.now();
|
||||
return User(
|
||||
userId: 'user_saved', // TODO: Get from API
|
||||
phoneNumber: '', // TODO: Get from saved user data
|
||||
fullName: session.fullName,
|
||||
email: '', // TODO: Get from saved user data
|
||||
role: UserRole.customer,
|
||||
status: UserStatus.active,
|
||||
loyaltyTier: LoyaltyTier.gold,
|
||||
totalPoints: 0,
|
||||
companyInfo: null,
|
||||
cccd: null,
|
||||
attachments: [],
|
||||
address: null,
|
||||
avatarUrl: null,
|
||||
referralCode: null,
|
||||
referredBy: null,
|
||||
erpnextCustomerId: null,
|
||||
createdAt: session.createdAt,
|
||||
updatedAt: now,
|
||||
lastLoginAt: now,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Login with phone number and password
|
||||
///
|
||||
/// Simulates ERPNext API authentication with mock response.
|
||||
/// Stores session data (SID, CSRF token) in Hive.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [phoneNumber]: User's phone number (Vietnamese format)
|
||||
/// - [password]: User's password
|
||||
///
|
||||
/// Returns: Authenticated User object on success
|
||||
///
|
||||
/// Throws: Exception on authentication failure
|
||||
Future<void> login({
|
||||
required String phoneNumber,
|
||||
required String password,
|
||||
}) async {
|
||||
// Set loading state
|
||||
state = const AsyncValue.loading();
|
||||
|
||||
// Simulate API call delay
|
||||
state = await AsyncValue.guard(() async {
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
|
||||
// Mock validation
|
||||
if (phoneNumber.isEmpty || password.isEmpty) {
|
||||
throw Exception('Số điện thoại và mật khẩu không được để trống');
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
throw Exception('Mật khẩu phải có ít nhất 6 ký tự');
|
||||
}
|
||||
|
||||
// Simulate API response matching ERPNext format
|
||||
final mockApiResponse = AuthSessionResponse(
|
||||
sessionExpired: 1,
|
||||
message: const LoginMessage(
|
||||
success: true,
|
||||
message: 'Login successful',
|
||||
sid: 'df7fd4e7ef1041aa3422b0ee861315ba8c28d4fe008a7d7e0e7e0e01',
|
||||
csrfToken: '6b6e37563854e951c36a7af4177956bb15ca469ca4f498b742648d70',
|
||||
apps: [
|
||||
AppInfo(
|
||||
appTitle: 'App nhân viên kinh doanh',
|
||||
appEndpoint: '/ecommerce/app-sales',
|
||||
appLogo:
|
||||
'https://assets.digitalbiz.com.vn/DBIZ_Internal/Logo/logo_app_sales.png',
|
||||
),
|
||||
],
|
||||
),
|
||||
homePage: '/apps',
|
||||
fullName: 'Tân Duy Nguyễn',
|
||||
);
|
||||
|
||||
// Save session data to Hive
|
||||
final sessionData = SessionData.fromAuthResponse(mockApiResponse);
|
||||
await _localDataSource.saveSession(sessionData);
|
||||
|
||||
// Create and return User entity
|
||||
final now = DateTime.now();
|
||||
return User(
|
||||
userId: 'user_${phoneNumber.replaceAll('+84', '')}',
|
||||
phoneNumber: phoneNumber,
|
||||
fullName: mockApiResponse.fullName,
|
||||
email: 'user@eurotile.vn',
|
||||
role: UserRole.customer,
|
||||
status: UserStatus.active,
|
||||
loyaltyTier: LoyaltyTier.gold,
|
||||
totalPoints: 1500,
|
||||
companyInfo: const CompanyInfo(
|
||||
name: 'Công ty TNHH XYZ',
|
||||
taxId: '0123456789',
|
||||
businessType: 'Xây dựng',
|
||||
),
|
||||
cccd: '001234567890',
|
||||
attachments: [],
|
||||
address: '123 Đường ABC, Quận 1, TP.HCM',
|
||||
avatarUrl: null,
|
||||
referralCode: 'REF${phoneNumber.replaceAll('+84', '').substring(0, 6)}',
|
||||
referredBy: null,
|
||||
erpnextCustomerId: null,
|
||||
createdAt: now.subtract(const Duration(days: 30)),
|
||||
updatedAt: now,
|
||||
lastLoginAt: now,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Logout current user
|
||||
///
|
||||
/// Clears authentication state and removes saved session from Hive.
|
||||
Future<void> logout() async {
|
||||
state = const AsyncValue.loading();
|
||||
|
||||
state = await AsyncValue.guard(() async {
|
||||
// Clear saved session from Hive
|
||||
await _localDataSource.clearSession();
|
||||
|
||||
// TODO: Call logout API to invalidate token on server
|
||||
|
||||
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// Return null to indicate logged out
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/// Get current authenticated user
|
||||
///
|
||||
/// Returns the current user if logged in, null otherwise.
|
||||
User? get currentUser => state.value;
|
||||
|
||||
/// Check if user is authenticated
|
||||
///
|
||||
/// Returns true if there is a logged-in user.
|
||||
bool get isAuthenticated => currentUser != null;
|
||||
|
||||
/// Check if authentication is in progress
|
||||
///
|
||||
/// Returns true during login/logout operations.
|
||||
bool get isLoading => state.isLoading;
|
||||
|
||||
/// Get authentication error if any
|
||||
///
|
||||
/// Returns error message or null if no error.
|
||||
Object? get error => state.error;
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if user is authenticated
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isLoggedIn = ref.watch(isAuthenticatedProvider);
|
||||
/// if (isLoggedIn) {
|
||||
/// // Show home screen
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
bool isAuthenticated(Ref ref) {
|
||||
final authState = ref.watch(authProvider);
|
||||
return authState.value != null;
|
||||
}
|
||||
|
||||
/// Convenience provider for getting current user
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final user = ref.watch(currentUserProvider);
|
||||
/// if (user != null) {
|
||||
/// Text('Welcome ${user.fullName}');
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
User? currentUser(Ref ref) {
|
||||
final authState = ref.watch(authProvider);
|
||||
return authState.value;
|
||||
}
|
||||
|
||||
/// Convenience provider for user's loyalty tier
|
||||
///
|
||||
/// Returns the current user's loyalty tier or null if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final tier = ref.watch(userLoyaltyTierProvider);
|
||||
/// if (tier != null) {
|
||||
/// Text('Tier: ${tier.displayName}');
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
LoyaltyTier? userLoyaltyTier(Ref ref) {
|
||||
final user = ref.watch(currentUserProvider);
|
||||
return user?.loyaltyTier;
|
||||
}
|
||||
|
||||
/// Convenience provider for user's total points
|
||||
///
|
||||
/// Returns the current user's total loyalty points or 0 if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final points = ref.watch(userTotalPointsProvider);
|
||||
/// Text('Points: $points');
|
||||
/// ```
|
||||
@riverpod
|
||||
int userTotalPoints(Ref ref) {
|
||||
final user = ref.watch(currentUserProvider);
|
||||
return user?.totalPoints ?? 0;
|
||||
}
|
||||
500
lib/features/auth/presentation/providers/auth_provider.g.dart
Normal file
500
lib/features/auth/presentation/providers/auth_provider.g.dart
Normal file
@@ -0,0 +1,500 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Provide FlutterSecureStorage instance
|
||||
|
||||
@ProviderFor(secureStorage)
|
||||
const secureStorageProvider = SecureStorageProvider._();
|
||||
|
||||
/// Provide FlutterSecureStorage instance
|
||||
|
||||
final class SecureStorageProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
FlutterSecureStorage,
|
||||
FlutterSecureStorage,
|
||||
FlutterSecureStorage
|
||||
>
|
||||
with $Provider<FlutterSecureStorage> {
|
||||
/// Provide FlutterSecureStorage instance
|
||||
const SecureStorageProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'secureStorageProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$secureStorageHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<FlutterSecureStorage> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FlutterSecureStorage create(Ref ref) {
|
||||
return secureStorage(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(FlutterSecureStorage value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<FlutterSecureStorage>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$secureStorageHash() => r'c3d90388f6d1bb7c95a29ceeda2e56c57deb1ecb';
|
||||
|
||||
/// Provide AuthLocalDataSource instance
|
||||
|
||||
@ProviderFor(authLocalDataSource)
|
||||
const authLocalDataSourceProvider = AuthLocalDataSourceProvider._();
|
||||
|
||||
/// Provide AuthLocalDataSource instance
|
||||
|
||||
final class AuthLocalDataSourceProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AuthLocalDataSource,
|
||||
AuthLocalDataSource,
|
||||
AuthLocalDataSource
|
||||
>
|
||||
with $Provider<AuthLocalDataSource> {
|
||||
/// Provide AuthLocalDataSource instance
|
||||
const AuthLocalDataSourceProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'authLocalDataSourceProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$authLocalDataSourceHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<AuthLocalDataSource> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
AuthLocalDataSource create(Ref ref) {
|
||||
return authLocalDataSource(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AuthLocalDataSource value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<AuthLocalDataSource>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$authLocalDataSourceHash() =>
|
||||
r'f104de00a8ab431f6736387fb499c2b6e0ab4924';
|
||||
|
||||
/// Authentication Provider
|
||||
///
|
||||
/// Main provider for authentication state management.
|
||||
/// Provides login and logout functionality with async state handling.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final authState = ref.watch(authProvider);
|
||||
/// authState.when(
|
||||
/// data: (user) => user != null ? HomeScreen() : LoginScreen(),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
@ProviderFor(Auth)
|
||||
const authProvider = AuthProvider._();
|
||||
|
||||
/// Authentication Provider
|
||||
///
|
||||
/// Main provider for authentication state management.
|
||||
/// Provides login and logout functionality with async state handling.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final authState = ref.watch(authProvider);
|
||||
/// authState.when(
|
||||
/// data: (user) => user != null ? HomeScreen() : LoginScreen(),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
final class AuthProvider extends $AsyncNotifierProvider<Auth, User?> {
|
||||
/// Authentication Provider
|
||||
///
|
||||
/// Main provider for authentication state management.
|
||||
/// Provides login and logout functionality with async state handling.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final authState = ref.watch(authProvider);
|
||||
/// authState.when(
|
||||
/// data: (user) => user != null ? HomeScreen() : LoginScreen(),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
const AuthProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'authProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$authHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
Auth create() => Auth();
|
||||
}
|
||||
|
||||
String _$authHash() => r'6f410d1abe6c53a6cbfa52fde7ea7a2d22a7f78d';
|
||||
|
||||
/// Authentication Provider
|
||||
///
|
||||
/// Main provider for authentication state management.
|
||||
/// Provides login and logout functionality with async state handling.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final authState = ref.watch(authProvider);
|
||||
/// authState.when(
|
||||
/// data: (user) => user != null ? HomeScreen() : LoginScreen(),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
abstract class _$Auth extends $AsyncNotifier<User?> {
|
||||
FutureOr<User?> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AsyncValue<User?>, User?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<User?>, User?>,
|
||||
AsyncValue<User?>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if user is authenticated
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isLoggedIn = ref.watch(isAuthenticatedProvider);
|
||||
/// if (isLoggedIn) {
|
||||
/// // Show home screen
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(isAuthenticated)
|
||||
const isAuthenticatedProvider = IsAuthenticatedProvider._();
|
||||
|
||||
/// Convenience provider for checking if user is authenticated
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isLoggedIn = ref.watch(isAuthenticatedProvider);
|
||||
/// if (isLoggedIn) {
|
||||
/// // Show home screen
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class IsAuthenticatedProvider
|
||||
extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
/// Convenience provider for checking if user is authenticated
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isLoggedIn = ref.watch(isAuthenticatedProvider);
|
||||
/// if (isLoggedIn) {
|
||||
/// // Show home screen
|
||||
/// }
|
||||
/// ```
|
||||
const IsAuthenticatedProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'isAuthenticatedProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$isAuthenticatedHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<bool> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
bool create(Ref ref) {
|
||||
return isAuthenticated(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$isAuthenticatedHash() => r'dc783f052ad2ddb7fa18c58e5dc6d212e6c32a96';
|
||||
|
||||
/// Convenience provider for getting current user
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final user = ref.watch(currentUserProvider);
|
||||
/// if (user != null) {
|
||||
/// Text('Welcome ${user.fullName}');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(currentUser)
|
||||
const currentUserProvider = CurrentUserProvider._();
|
||||
|
||||
/// Convenience provider for getting current user
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final user = ref.watch(currentUserProvider);
|
||||
/// if (user != null) {
|
||||
/// Text('Welcome ${user.fullName}');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class CurrentUserProvider extends $FunctionalProvider<User?, User?, User?>
|
||||
with $Provider<User?> {
|
||||
/// Convenience provider for getting current user
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final user = ref.watch(currentUserProvider);
|
||||
/// if (user != null) {
|
||||
/// Text('Welcome ${user.fullName}');
|
||||
/// }
|
||||
/// ```
|
||||
const CurrentUserProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'currentUserProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$currentUserHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<User?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
User? create(Ref ref) {
|
||||
return currentUser(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(User? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<User?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$currentUserHash() => r'f3c1da551f4a4c2bf158782ea37a4749a718128a';
|
||||
|
||||
/// Convenience provider for user's loyalty tier
|
||||
///
|
||||
/// Returns the current user's loyalty tier or null if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final tier = ref.watch(userLoyaltyTierProvider);
|
||||
/// if (tier != null) {
|
||||
/// Text('Tier: ${tier.displayName}');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(userLoyaltyTier)
|
||||
const userLoyaltyTierProvider = UserLoyaltyTierProvider._();
|
||||
|
||||
/// Convenience provider for user's loyalty tier
|
||||
///
|
||||
/// Returns the current user's loyalty tier or null if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final tier = ref.watch(userLoyaltyTierProvider);
|
||||
/// if (tier != null) {
|
||||
/// Text('Tier: ${tier.displayName}');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class UserLoyaltyTierProvider
|
||||
extends $FunctionalProvider<LoyaltyTier?, LoyaltyTier?, LoyaltyTier?>
|
||||
with $Provider<LoyaltyTier?> {
|
||||
/// Convenience provider for user's loyalty tier
|
||||
///
|
||||
/// Returns the current user's loyalty tier or null if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final tier = ref.watch(userLoyaltyTierProvider);
|
||||
/// if (tier != null) {
|
||||
/// Text('Tier: ${tier.displayName}');
|
||||
/// }
|
||||
/// ```
|
||||
const UserLoyaltyTierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'userLoyaltyTierProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$userLoyaltyTierHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<LoyaltyTier?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
LoyaltyTier? create(Ref ref) {
|
||||
return userLoyaltyTier(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(LoyaltyTier? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<LoyaltyTier?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$userLoyaltyTierHash() => r'f1a157486b8bdd2cf64bc2201207f2ac71ea6a69';
|
||||
|
||||
/// Convenience provider for user's total points
|
||||
///
|
||||
/// Returns the current user's total loyalty points or 0 if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final points = ref.watch(userTotalPointsProvider);
|
||||
/// Text('Points: $points');
|
||||
/// ```
|
||||
|
||||
@ProviderFor(userTotalPoints)
|
||||
const userTotalPointsProvider = UserTotalPointsProvider._();
|
||||
|
||||
/// Convenience provider for user's total points
|
||||
///
|
||||
/// Returns the current user's total loyalty points or 0 if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final points = ref.watch(userTotalPointsProvider);
|
||||
/// Text('Points: $points');
|
||||
/// ```
|
||||
|
||||
final class UserTotalPointsProvider extends $FunctionalProvider<int, int, int>
|
||||
with $Provider<int> {
|
||||
/// Convenience provider for user's total points
|
||||
///
|
||||
/// Returns the current user's total loyalty points or 0 if not logged in.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final points = ref.watch(userTotalPointsProvider);
|
||||
/// Text('Points: $points');
|
||||
/// ```
|
||||
const UserTotalPointsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'userTotalPointsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$userTotalPointsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<int> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
int create(Ref ref) {
|
||||
return userTotalPoints(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(int value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<int>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$userTotalPointsHash() => r'9ccebb48a8641c3c0624b1649303b436e82602bd';
|
||||
@@ -0,0 +1,112 @@
|
||||
/// Password Visibility Provider
|
||||
///
|
||||
/// Simple state provider for toggling password visibility in login/register forms.
|
||||
///
|
||||
/// Uses Riverpod 3.0 with code generation for type-safe state management.
|
||||
library;
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'password_visibility_provider.g.dart';
|
||||
|
||||
/// Password Visibility State Provider
|
||||
///
|
||||
/// Manages the visibility state of password input fields.
|
||||
/// Default state is false (password hidden).
|
||||
///
|
||||
/// Usage in login/register pages:
|
||||
/// ```dart
|
||||
/// class LoginPage extends ConsumerWidget {
|
||||
/// @override
|
||||
/// Widget build(BuildContext context, WidgetRef ref) {
|
||||
/// final isPasswordVisible = ref.watch(passwordVisibilityProvider);
|
||||
///
|
||||
/// return TextField(
|
||||
/// obscureText: !isPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(passwordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
class PasswordVisibility extends _$PasswordVisibility {
|
||||
/// Initialize with password hidden (false)
|
||||
@override
|
||||
bool build() => false;
|
||||
|
||||
/// Toggle password visibility
|
||||
///
|
||||
/// Switches between showing and hiding the password.
|
||||
void toggle() {
|
||||
state = !state;
|
||||
}
|
||||
|
||||
/// Show password
|
||||
///
|
||||
/// Sets visibility to true (password visible).
|
||||
void show() {
|
||||
state = true;
|
||||
}
|
||||
|
||||
/// Hide password
|
||||
///
|
||||
/// Sets visibility to false (password hidden).
|
||||
void hide() {
|
||||
state = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Confirm Password Visibility State Provider
|
||||
///
|
||||
/// Separate provider for confirm password field in registration forms.
|
||||
/// This allows independent control of password and confirm password visibility.
|
||||
///
|
||||
/// Usage in registration page:
|
||||
/// ```dart
|
||||
/// final isConfirmPasswordVisible = ref.watch(confirmPasswordVisibilityProvider);
|
||||
///
|
||||
/// TextField(
|
||||
/// obscureText: !isConfirmPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// labelText: 'Xác nhận mật khẩu',
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(confirmPasswordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
@riverpod
|
||||
class ConfirmPasswordVisibility extends _$ConfirmPasswordVisibility {
|
||||
/// Initialize with password hidden (false)
|
||||
@override
|
||||
bool build() => false;
|
||||
|
||||
/// Toggle confirm password visibility
|
||||
void toggle() {
|
||||
state = !state;
|
||||
}
|
||||
|
||||
/// Show confirm password
|
||||
void show() {
|
||||
state = true;
|
||||
}
|
||||
|
||||
/// Hide confirm password
|
||||
void hide() {
|
||||
state = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'password_visibility_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Password Visibility State Provider
|
||||
///
|
||||
/// Manages the visibility state of password input fields.
|
||||
/// Default state is false (password hidden).
|
||||
///
|
||||
/// Usage in login/register pages:
|
||||
/// ```dart
|
||||
/// class LoginPage extends ConsumerWidget {
|
||||
/// @override
|
||||
/// Widget build(BuildContext context, WidgetRef ref) {
|
||||
/// final isPasswordVisible = ref.watch(passwordVisibilityProvider);
|
||||
///
|
||||
/// return TextField(
|
||||
/// obscureText: !isPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(passwordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(PasswordVisibility)
|
||||
const passwordVisibilityProvider = PasswordVisibilityProvider._();
|
||||
|
||||
/// Password Visibility State Provider
|
||||
///
|
||||
/// Manages the visibility state of password input fields.
|
||||
/// Default state is false (password hidden).
|
||||
///
|
||||
/// Usage in login/register pages:
|
||||
/// ```dart
|
||||
/// class LoginPage extends ConsumerWidget {
|
||||
/// @override
|
||||
/// Widget build(BuildContext context, WidgetRef ref) {
|
||||
/// final isPasswordVisible = ref.watch(passwordVisibilityProvider);
|
||||
///
|
||||
/// return TextField(
|
||||
/// obscureText: !isPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(passwordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
final class PasswordVisibilityProvider
|
||||
extends $NotifierProvider<PasswordVisibility, bool> {
|
||||
/// Password Visibility State Provider
|
||||
///
|
||||
/// Manages the visibility state of password input fields.
|
||||
/// Default state is false (password hidden).
|
||||
///
|
||||
/// Usage in login/register pages:
|
||||
/// ```dart
|
||||
/// class LoginPage extends ConsumerWidget {
|
||||
/// @override
|
||||
/// Widget build(BuildContext context, WidgetRef ref) {
|
||||
/// final isPasswordVisible = ref.watch(passwordVisibilityProvider);
|
||||
///
|
||||
/// return TextField(
|
||||
/// obscureText: !isPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(passwordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
const PasswordVisibilityProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'passwordVisibilityProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$passwordVisibilityHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
PasswordVisibility create() => PasswordVisibility();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$passwordVisibilityHash() =>
|
||||
r'25b6fa914e42dd83c8443aecbeb1d608cccd00ab';
|
||||
|
||||
/// Password Visibility State Provider
|
||||
///
|
||||
/// Manages the visibility state of password input fields.
|
||||
/// Default state is false (password hidden).
|
||||
///
|
||||
/// Usage in login/register pages:
|
||||
/// ```dart
|
||||
/// class LoginPage extends ConsumerWidget {
|
||||
/// @override
|
||||
/// Widget build(BuildContext context, WidgetRef ref) {
|
||||
/// final isPasswordVisible = ref.watch(passwordVisibilityProvider);
|
||||
///
|
||||
/// return TextField(
|
||||
/// obscureText: !isPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(passwordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
abstract class _$PasswordVisibility extends $Notifier<bool> {
|
||||
bool build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<bool, bool>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<bool, bool>,
|
||||
bool,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Confirm Password Visibility State Provider
|
||||
///
|
||||
/// Separate provider for confirm password field in registration forms.
|
||||
/// This allows independent control of password and confirm password visibility.
|
||||
///
|
||||
/// Usage in registration page:
|
||||
/// ```dart
|
||||
/// final isConfirmPasswordVisible = ref.watch(confirmPasswordVisibilityProvider);
|
||||
///
|
||||
/// TextField(
|
||||
/// obscureText: !isConfirmPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// labelText: 'Xác nhận mật khẩu',
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(confirmPasswordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
@ProviderFor(ConfirmPasswordVisibility)
|
||||
const confirmPasswordVisibilityProvider = ConfirmPasswordVisibilityProvider._();
|
||||
|
||||
/// Confirm Password Visibility State Provider
|
||||
///
|
||||
/// Separate provider for confirm password field in registration forms.
|
||||
/// This allows independent control of password and confirm password visibility.
|
||||
///
|
||||
/// Usage in registration page:
|
||||
/// ```dart
|
||||
/// final isConfirmPasswordVisible = ref.watch(confirmPasswordVisibilityProvider);
|
||||
///
|
||||
/// TextField(
|
||||
/// obscureText: !isConfirmPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// labelText: 'Xác nhận mật khẩu',
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(confirmPasswordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
final class ConfirmPasswordVisibilityProvider
|
||||
extends $NotifierProvider<ConfirmPasswordVisibility, bool> {
|
||||
/// Confirm Password Visibility State Provider
|
||||
///
|
||||
/// Separate provider for confirm password field in registration forms.
|
||||
/// This allows independent control of password and confirm password visibility.
|
||||
///
|
||||
/// Usage in registration page:
|
||||
/// ```dart
|
||||
/// final isConfirmPasswordVisible = ref.watch(confirmPasswordVisibilityProvider);
|
||||
///
|
||||
/// TextField(
|
||||
/// obscureText: !isConfirmPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// labelText: 'Xác nhận mật khẩu',
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(confirmPasswordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
const ConfirmPasswordVisibilityProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'confirmPasswordVisibilityProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$confirmPasswordVisibilityHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ConfirmPasswordVisibility create() => ConfirmPasswordVisibility();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$confirmPasswordVisibilityHash() =>
|
||||
r'8408bba9db1e8deba425f98015a4e2fa76d75eb8';
|
||||
|
||||
/// Confirm Password Visibility State Provider
|
||||
///
|
||||
/// Separate provider for confirm password field in registration forms.
|
||||
/// This allows independent control of password and confirm password visibility.
|
||||
///
|
||||
/// Usage in registration page:
|
||||
/// ```dart
|
||||
/// final isConfirmPasswordVisible = ref.watch(confirmPasswordVisibilityProvider);
|
||||
///
|
||||
/// TextField(
|
||||
/// obscureText: !isConfirmPasswordVisible,
|
||||
/// decoration: InputDecoration(
|
||||
/// labelText: 'Xác nhận mật khẩu',
|
||||
/// suffixIcon: IconButton(
|
||||
/// icon: Icon(
|
||||
/// isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
/// ),
|
||||
/// onPressed: () {
|
||||
/// ref.read(confirmPasswordVisibilityProvider.notifier).toggle();
|
||||
/// },
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
abstract class _$ConfirmPasswordVisibility extends $Notifier<bool> {
|
||||
bool build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<bool, bool>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<bool, bool>,
|
||||
bool,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
305
lib/features/auth/presentation/providers/register_provider.dart
Normal file
305
lib/features/auth/presentation/providers/register_provider.dart
Normal file
@@ -0,0 +1,305 @@
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Manages registration state for the Worker application.
|
||||
/// Handles user registration with role-based validation and verification.
|
||||
///
|
||||
/// Uses Riverpod 3.0 with code generation for type-safe state management.
|
||||
library;
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:worker/features/auth/domain/entities/user.dart';
|
||||
|
||||
part 'register_provider.g.dart';
|
||||
|
||||
/// Registration Form Data
|
||||
///
|
||||
/// Contains all data needed for user registration.
|
||||
/// Optional fields are used based on selected role.
|
||||
class RegistrationData {
|
||||
/// Required: Full name of the user
|
||||
final String fullName;
|
||||
|
||||
/// Required: Phone number (Vietnamese format)
|
||||
final String phoneNumber;
|
||||
|
||||
/// Required: Email address
|
||||
final String email;
|
||||
|
||||
/// Required: Password (minimum 6 characters)
|
||||
final String password;
|
||||
|
||||
/// Required: User role
|
||||
final UserRole role;
|
||||
|
||||
/// Optional: CCCD/ID card number (required for dealer/worker roles)
|
||||
final String? cccd;
|
||||
|
||||
/// Optional: Tax code (personal or company)
|
||||
final String? taxCode;
|
||||
|
||||
/// Optional: Company/store name
|
||||
final String? companyName;
|
||||
|
||||
/// Required: Province/city
|
||||
final String? city;
|
||||
|
||||
/// Optional: Attachment file paths (ID card, certificate, license)
|
||||
final List<String>? attachments;
|
||||
|
||||
const RegistrationData({
|
||||
required this.fullName,
|
||||
required this.phoneNumber,
|
||||
required this.email,
|
||||
required this.password,
|
||||
required this.role,
|
||||
this.cccd,
|
||||
this.taxCode,
|
||||
this.companyName,
|
||||
this.city,
|
||||
this.attachments,
|
||||
});
|
||||
|
||||
/// Copy with method for immutability
|
||||
RegistrationData copyWith({
|
||||
String? fullName,
|
||||
String? phoneNumber,
|
||||
String? email,
|
||||
String? password,
|
||||
UserRole? role,
|
||||
String? cccd,
|
||||
String? taxCode,
|
||||
String? companyName,
|
||||
String? city,
|
||||
List<String>? attachments,
|
||||
}) {
|
||||
return RegistrationData(
|
||||
fullName: fullName ?? this.fullName,
|
||||
phoneNumber: phoneNumber ?? this.phoneNumber,
|
||||
email: email ?? this.email,
|
||||
password: password ?? this.password,
|
||||
role: role ?? this.role,
|
||||
cccd: cccd ?? this.cccd,
|
||||
taxCode: taxCode ?? this.taxCode,
|
||||
companyName: companyName ?? this.companyName,
|
||||
city: city ?? this.city,
|
||||
attachments: attachments ?? this.attachments,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Main provider for user registration state management.
|
||||
/// Handles registration process with role-based validation.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final registerState = ref.watch(registerProvider);
|
||||
/// registerState.when(
|
||||
/// data: (user) => SuccessScreen(user),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
@riverpod
|
||||
class Register extends _$Register {
|
||||
/// Initialize with no registration result
|
||||
@override
|
||||
Future<User?> build() async {
|
||||
// No initial registration
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Register a new user
|
||||
///
|
||||
/// Performs user registration with role-based validation.
|
||||
/// For dealer/worker roles, requires additional verification documents.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [data]: Registration form data containing all required fields
|
||||
///
|
||||
/// Returns: Newly created User object on success
|
||||
///
|
||||
/// Throws: Exception on validation failure or registration error
|
||||
///
|
||||
/// Error messages (Vietnamese):
|
||||
/// - "Vui lòng điền đầy đủ thông tin bắt buộc"
|
||||
/// - "Số điện thoại không hợp lệ"
|
||||
/// - "Email không hợp lệ"
|
||||
/// - "Mật khẩu phải có ít nhất 6 ký tự"
|
||||
/// - "Vui lòng nhập số CCCD/CMND" (for dealer/worker)
|
||||
/// - "Vui lòng tải lên ảnh CCCD/CMND" (for dealer/worker)
|
||||
/// - "Vui lòng tải lên ảnh chứng chỉ hành nghề hoặc GPKD" (for dealer/worker)
|
||||
/// - "Số điện thoại đã được đăng ký"
|
||||
/// - "Email đã được đăng ký"
|
||||
Future<void> register(RegistrationData data) async {
|
||||
// Set loading state
|
||||
state = const AsyncValue.loading();
|
||||
|
||||
// Perform registration with error handling
|
||||
state = await AsyncValue.guard(() async {
|
||||
// Validate required fields
|
||||
if (data.fullName.isEmpty ||
|
||||
data.phoneNumber.isEmpty ||
|
||||
data.email.isEmpty ||
|
||||
data.password.isEmpty ||
|
||||
data.city == null ||
|
||||
data.city!.isEmpty) {
|
||||
throw Exception('Vui lòng điền đầy đủ thông tin bắt buộc');
|
||||
}
|
||||
|
||||
// Validate phone number (Vietnamese format: 10 digits starting with 0)
|
||||
final phoneRegex = RegExp(r'^0[0-9]{9}$');
|
||||
if (!phoneRegex.hasMatch(data.phoneNumber)) {
|
||||
throw Exception('Số điện thoại không hợp lệ');
|
||||
}
|
||||
|
||||
// Validate email format
|
||||
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
|
||||
if (!emailRegex.hasMatch(data.email)) {
|
||||
throw Exception('Email không hợp lệ');
|
||||
}
|
||||
|
||||
// Validate password length
|
||||
if (data.password.length < 6) {
|
||||
throw Exception('Mật khẩu phải có ít nhất 6 ký tự');
|
||||
}
|
||||
|
||||
// Role-based validation for dealer/worker (requires verification)
|
||||
if (data.role == UserRole.customer) {
|
||||
// For dealer/worker roles, CCCD and attachments are required
|
||||
if (data.cccd == null || data.cccd!.isEmpty) {
|
||||
throw Exception('Vui lòng nhập số CCCD/CMND');
|
||||
}
|
||||
|
||||
// Validate CCCD format (9 or 12 digits)
|
||||
final cccdRegex = RegExp(r'^[0-9]{9}$|^[0-9]{12}$');
|
||||
if (!cccdRegex.hasMatch(data.cccd!)) {
|
||||
throw Exception('Số CCCD/CMND không hợp lệ (phải có 9 hoặc 12 số)');
|
||||
}
|
||||
|
||||
// Validate attachments
|
||||
if (data.attachments == null || data.attachments!.isEmpty) {
|
||||
throw Exception('Vui lòng tải lên ảnh CCCD/CMND');
|
||||
}
|
||||
|
||||
if (data.attachments!.length < 2) {
|
||||
throw Exception('Vui lòng tải lên ảnh chứng chỉ hành nghề hoặc GPKD');
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate API call delay (2 seconds)
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
|
||||
// TODO: In production, call the registration API here
|
||||
// final response = await ref.read(authRepositoryProvider).register(data);
|
||||
|
||||
// Mock: Simulate registration success
|
||||
final now = DateTime.now();
|
||||
|
||||
// Determine initial status based on role
|
||||
// Dealer/Worker require admin approval (pending status)
|
||||
// Other roles are immediately active
|
||||
final initialStatus = data.role == UserRole.customer
|
||||
? UserStatus.pending
|
||||
: UserStatus.active;
|
||||
|
||||
// Create new user entity
|
||||
final newUser = User(
|
||||
userId: 'user_${DateTime.now().millisecondsSinceEpoch}',
|
||||
phoneNumber: data.phoneNumber,
|
||||
fullName: data.fullName,
|
||||
email: data.email,
|
||||
role: data.role,
|
||||
status: initialStatus,
|
||||
loyaltyTier: LoyaltyTier.gold, // Default tier for new users
|
||||
totalPoints: 0, // New users start with 0 points
|
||||
companyInfo: data.companyName != null || data.taxCode != null
|
||||
? CompanyInfo(
|
||||
name: data.companyName,
|
||||
taxId: data.taxCode,
|
||||
businessType: _getBusinessType(data.role),
|
||||
)
|
||||
: null,
|
||||
cccd: data.cccd,
|
||||
attachments: data.attachments ?? [],
|
||||
address: data.city,
|
||||
avatarUrl: null,
|
||||
referralCode: 'REF${data.phoneNumber.substring(0, 6)}',
|
||||
referredBy: null,
|
||||
erpnextCustomerId: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
lastLoginAt: null, // Not logged in yet
|
||||
);
|
||||
|
||||
return newUser;
|
||||
});
|
||||
}
|
||||
|
||||
/// Reset registration state
|
||||
///
|
||||
/// Clears the registration result. Useful when navigating away
|
||||
/// from success screen or starting a new registration.
|
||||
Future<void> reset() async {
|
||||
state = const AsyncValue.data(null);
|
||||
}
|
||||
|
||||
/// Get business type based on user role
|
||||
String _getBusinessType(UserRole role) {
|
||||
switch (role) {
|
||||
case UserRole.customer:
|
||||
return 'Đại lý/Thầu thợ/Kiến trúc sư';
|
||||
case UserRole.sales:
|
||||
return 'Nhân viên kinh doanh';
|
||||
case UserRole.admin:
|
||||
return 'Quản trị viên';
|
||||
case UserRole.accountant:
|
||||
return 'Kế toán';
|
||||
case UserRole.designer:
|
||||
return 'Thiết kế';
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if registration is in progress
|
||||
bool get isLoading => state.isLoading;
|
||||
|
||||
/// Get registration error if any
|
||||
Object? get error => state.error;
|
||||
|
||||
/// Get registered user if successful
|
||||
User? get registeredUser => state.value;
|
||||
|
||||
/// Check if registration was successful
|
||||
bool get isSuccess => state.hasValue && state.value != null;
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if registration is in progress
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isRegistering = ref.watch(isRegisteringProvider);
|
||||
/// if (isRegistering) {
|
||||
/// // Show loading indicator
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
bool isRegistering(Ref ref) {
|
||||
final registerState = ref.watch(registerProvider);
|
||||
return registerState.isLoading;
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if registration was successful
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final success = ref.watch(registrationSuccessProvider);
|
||||
/// if (success) {
|
||||
/// // Navigate to pending approval or OTP screen
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
bool registrationSuccess(Ref ref) {
|
||||
final registerState = ref.watch(registerProvider);
|
||||
return registerState.hasValue && registerState.value != null;
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'register_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Main provider for user registration state management.
|
||||
/// Handles registration process with role-based validation.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final registerState = ref.watch(registerProvider);
|
||||
/// registerState.when(
|
||||
/// data: (user) => SuccessScreen(user),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
@ProviderFor(Register)
|
||||
const registerProvider = RegisterProvider._();
|
||||
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Main provider for user registration state management.
|
||||
/// Handles registration process with role-based validation.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final registerState = ref.watch(registerProvider);
|
||||
/// registerState.when(
|
||||
/// data: (user) => SuccessScreen(user),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
final class RegisterProvider extends $AsyncNotifierProvider<Register, User?> {
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Main provider for user registration state management.
|
||||
/// Handles registration process with role-based validation.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final registerState = ref.watch(registerProvider);
|
||||
/// registerState.when(
|
||||
/// data: (user) => SuccessScreen(user),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
const RegisterProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'registerProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$registerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
Register create() => Register();
|
||||
}
|
||||
|
||||
String _$registerHash() => r'a073b5c5958b74c63a3cddfec7f6f018e14a5088';
|
||||
|
||||
/// Registration State Provider
|
||||
///
|
||||
/// Main provider for user registration state management.
|
||||
/// Handles registration process with role-based validation.
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// final registerState = ref.watch(registerProvider);
|
||||
/// registerState.when(
|
||||
/// data: (user) => SuccessScreen(user),
|
||||
/// loading: () => LoadingIndicator(),
|
||||
/// error: (error, stack) => ErrorWidget(error),
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
abstract class _$Register extends $AsyncNotifier<User?> {
|
||||
FutureOr<User?> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AsyncValue<User?>, User?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<User?>, User?>,
|
||||
AsyncValue<User?>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if registration is in progress
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isRegistering = ref.watch(isRegisteringProvider);
|
||||
/// if (isRegistering) {
|
||||
/// // Show loading indicator
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(isRegistering)
|
||||
const isRegisteringProvider = IsRegisteringProvider._();
|
||||
|
||||
/// Convenience provider for checking if registration is in progress
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isRegistering = ref.watch(isRegisteringProvider);
|
||||
/// if (isRegistering) {
|
||||
/// // Show loading indicator
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class IsRegisteringProvider extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
/// Convenience provider for checking if registration is in progress
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final isRegistering = ref.watch(isRegisteringProvider);
|
||||
/// if (isRegistering) {
|
||||
/// // Show loading indicator
|
||||
/// }
|
||||
/// ```
|
||||
const IsRegisteringProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'isRegisteringProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$isRegisteringHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<bool> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
bool create(Ref ref) {
|
||||
return isRegistering(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$isRegisteringHash() => r'2108b87b37451de9aaf799f9b8b380924bed2c87';
|
||||
|
||||
/// Convenience provider for checking if registration was successful
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final success = ref.watch(registrationSuccessProvider);
|
||||
/// if (success) {
|
||||
/// // Navigate to pending approval or OTP screen
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(registrationSuccess)
|
||||
const registrationSuccessProvider = RegistrationSuccessProvider._();
|
||||
|
||||
/// Convenience provider for checking if registration was successful
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final success = ref.watch(registrationSuccessProvider);
|
||||
/// if (success) {
|
||||
/// // Navigate to pending approval or OTP screen
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class RegistrationSuccessProvider
|
||||
extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
/// Convenience provider for checking if registration was successful
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final success = ref.watch(registrationSuccessProvider);
|
||||
/// if (success) {
|
||||
/// // Navigate to pending approval or OTP screen
|
||||
/// }
|
||||
/// ```
|
||||
const RegistrationSuccessProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'registrationSuccessProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$registrationSuccessHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<bool> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
bool create(Ref ref) {
|
||||
return registrationSuccess(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$registrationSuccessHash() =>
|
||||
r'6435b9ca4bf4c287497a39077a5d4558e0515ddc';
|
||||
@@ -0,0 +1,175 @@
|
||||
/// Selected Role State Provider
|
||||
///
|
||||
/// Manages the selected user role during registration.
|
||||
/// Simple state provider for role selection in the registration form.
|
||||
///
|
||||
/// Uses Riverpod 3.0 with code generation for type-safe state management.
|
||||
library;
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:worker/features/auth/domain/entities/user.dart';
|
||||
|
||||
part 'selected_role_provider.g.dart';
|
||||
|
||||
/// Selected Role Provider
|
||||
///
|
||||
/// Manages the currently selected user role in the registration form.
|
||||
/// Provides methods to select and clear role selection.
|
||||
///
|
||||
/// This provider is used to:
|
||||
/// - Track which role the user has selected
|
||||
/// - Conditionally show/hide verification fields based on role
|
||||
/// - Validate required documents for dealer/worker roles
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// // Watch the selected role
|
||||
/// final selectedRole = ref.watch(selectedRoleProvider);
|
||||
///
|
||||
/// // Select a role
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
///
|
||||
/// // Clear selection
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
///
|
||||
/// // Show verification section conditionally
|
||||
/// if (selectedRole == UserRole.customer) {
|
||||
/// VerificationSection(),
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
class SelectedRole extends _$SelectedRole {
|
||||
/// Initialize with no role selected
|
||||
@override
|
||||
UserRole? build() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Select a user role
|
||||
///
|
||||
/// Updates the state with the newly selected role.
|
||||
/// This triggers UI updates that depend on role selection.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [role]: The user role to select
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // User selects "Đại lý hệ thống" (dealer)
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
/// // This will show verification fields
|
||||
/// ```
|
||||
void selectRole(UserRole role) {
|
||||
state = role;
|
||||
}
|
||||
|
||||
/// Clear the role selection
|
||||
///
|
||||
/// Resets the state to null (no role selected).
|
||||
/// Useful when resetting the form or canceling registration.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // User clicks "Cancel" or goes back
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
/// // This will hide verification fields
|
||||
/// ```
|
||||
void clearRole() {
|
||||
state = null;
|
||||
}
|
||||
|
||||
/// Check if a role is currently selected
|
||||
///
|
||||
/// Returns true if any role has been selected, false otherwise.
|
||||
bool get hasSelection => state != null;
|
||||
|
||||
/// Check if verification is required for current role
|
||||
///
|
||||
/// Returns true if the selected role requires verification documents
|
||||
/// (CCCD, certificates, etc.). Currently only customer role requires this.
|
||||
///
|
||||
/// This is used to conditionally show the verification section:
|
||||
/// ```dart
|
||||
/// if (ref.read(selectedRoleProvider.notifier).requiresVerification) {
|
||||
/// // Show CCCD input, file uploads, etc.
|
||||
/// }
|
||||
/// ```
|
||||
bool get requiresVerification => state == UserRole.customer;
|
||||
|
||||
/// Get the display name for the current role (Vietnamese)
|
||||
///
|
||||
/// Returns a user-friendly Vietnamese name for the selected role,
|
||||
/// or null if no role is selected.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// final displayName = ref.read(selectedRoleProvider.notifier).displayName;
|
||||
/// // Returns: "Đại lý hệ thống" for customer role
|
||||
/// ```
|
||||
String? get displayName {
|
||||
if (state == null) return null;
|
||||
|
||||
switch (state!) {
|
||||
case UserRole.customer:
|
||||
return 'Đại lý/Thầu thợ/Kiến trúc sư';
|
||||
case UserRole.sales:
|
||||
return 'Nhân viên kinh doanh';
|
||||
case UserRole.admin:
|
||||
return 'Quản trị viên';
|
||||
case UserRole.accountant:
|
||||
return 'Kế toán';
|
||||
case UserRole.designer:
|
||||
return 'Thiết kế';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if verification is required
|
||||
///
|
||||
/// Returns true if the currently selected role requires verification
|
||||
/// documents (CCCD, certificates, etc.).
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final needsVerification = ref.watch(requiresVerificationProvider);
|
||||
/// if (needsVerification) {
|
||||
/// // Show verification section with file uploads
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
bool requiresVerification(Ref ref) {
|
||||
final selectedRole = ref.watch(selectedRoleProvider);
|
||||
return selectedRole == UserRole.customer;
|
||||
}
|
||||
|
||||
/// Convenience provider for getting role display name
|
||||
///
|
||||
/// Returns a user-friendly Vietnamese name for the selected role,
|
||||
/// or null if no role is selected.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final roleName = ref.watch(roleDisplayNameProvider);
|
||||
/// if (roleName != null) {
|
||||
/// Text('Bạn đang đăng ký với vai trò: $roleName');
|
||||
/// }
|
||||
/// ```
|
||||
@riverpod
|
||||
String? roleDisplayName(Ref ref) {
|
||||
final selectedRole = ref.watch(selectedRoleProvider);
|
||||
|
||||
if (selectedRole == null) return null;
|
||||
|
||||
switch (selectedRole) {
|
||||
case UserRole.customer:
|
||||
return 'Đại lý/Thầu thợ/Kiến trúc sư';
|
||||
case UserRole.sales:
|
||||
return 'Nhân viên kinh doanh';
|
||||
case UserRole.admin:
|
||||
return 'Quản trị viên';
|
||||
case UserRole.accountant:
|
||||
return 'Kế toán';
|
||||
case UserRole.designer:
|
||||
return 'Thiết kế';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'selected_role_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Selected Role Provider
|
||||
///
|
||||
/// Manages the currently selected user role in the registration form.
|
||||
/// Provides methods to select and clear role selection.
|
||||
///
|
||||
/// This provider is used to:
|
||||
/// - Track which role the user has selected
|
||||
/// - Conditionally show/hide verification fields based on role
|
||||
/// - Validate required documents for dealer/worker roles
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// // Watch the selected role
|
||||
/// final selectedRole = ref.watch(selectedRoleProvider);
|
||||
///
|
||||
/// // Select a role
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
///
|
||||
/// // Clear selection
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
///
|
||||
/// // Show verification section conditionally
|
||||
/// if (selectedRole == UserRole.customer) {
|
||||
/// VerificationSection(),
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(SelectedRole)
|
||||
const selectedRoleProvider = SelectedRoleProvider._();
|
||||
|
||||
/// Selected Role Provider
|
||||
///
|
||||
/// Manages the currently selected user role in the registration form.
|
||||
/// Provides methods to select and clear role selection.
|
||||
///
|
||||
/// This provider is used to:
|
||||
/// - Track which role the user has selected
|
||||
/// - Conditionally show/hide verification fields based on role
|
||||
/// - Validate required documents for dealer/worker roles
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// // Watch the selected role
|
||||
/// final selectedRole = ref.watch(selectedRoleProvider);
|
||||
///
|
||||
/// // Select a role
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
///
|
||||
/// // Clear selection
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
///
|
||||
/// // Show verification section conditionally
|
||||
/// if (selectedRole == UserRole.customer) {
|
||||
/// VerificationSection(),
|
||||
/// }
|
||||
/// ```
|
||||
final class SelectedRoleProvider
|
||||
extends $NotifierProvider<SelectedRole, UserRole?> {
|
||||
/// Selected Role Provider
|
||||
///
|
||||
/// Manages the currently selected user role in the registration form.
|
||||
/// Provides methods to select and clear role selection.
|
||||
///
|
||||
/// This provider is used to:
|
||||
/// - Track which role the user has selected
|
||||
/// - Conditionally show/hide verification fields based on role
|
||||
/// - Validate required documents for dealer/worker roles
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// // Watch the selected role
|
||||
/// final selectedRole = ref.watch(selectedRoleProvider);
|
||||
///
|
||||
/// // Select a role
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
///
|
||||
/// // Clear selection
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
///
|
||||
/// // Show verification section conditionally
|
||||
/// if (selectedRole == UserRole.customer) {
|
||||
/// VerificationSection(),
|
||||
/// }
|
||||
/// ```
|
||||
const SelectedRoleProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'selectedRoleProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$selectedRoleHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SelectedRole create() => SelectedRole();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(UserRole? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<UserRole?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$selectedRoleHash() => r'098c7fdaec4694d14a48c049556960eb6ed2dc06';
|
||||
|
||||
/// Selected Role Provider
|
||||
///
|
||||
/// Manages the currently selected user role in the registration form.
|
||||
/// Provides methods to select and clear role selection.
|
||||
///
|
||||
/// This provider is used to:
|
||||
/// - Track which role the user has selected
|
||||
/// - Conditionally show/hide verification fields based on role
|
||||
/// - Validate required documents for dealer/worker roles
|
||||
///
|
||||
/// Usage in widgets:
|
||||
/// ```dart
|
||||
/// // Watch the selected role
|
||||
/// final selectedRole = ref.watch(selectedRoleProvider);
|
||||
///
|
||||
/// // Select a role
|
||||
/// ref.read(selectedRoleProvider.notifier).selectRole(UserRole.customer);
|
||||
///
|
||||
/// // Clear selection
|
||||
/// ref.read(selectedRoleProvider.notifier).clearRole();
|
||||
///
|
||||
/// // Show verification section conditionally
|
||||
/// if (selectedRole == UserRole.customer) {
|
||||
/// VerificationSection(),
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
abstract class _$SelectedRole extends $Notifier<UserRole?> {
|
||||
UserRole? build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<UserRole?, UserRole?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<UserRole?, UserRole?>,
|
||||
UserRole?,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience provider for checking if verification is required
|
||||
///
|
||||
/// Returns true if the currently selected role requires verification
|
||||
/// documents (CCCD, certificates, etc.).
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final needsVerification = ref.watch(requiresVerificationProvider);
|
||||
/// if (needsVerification) {
|
||||
/// // Show verification section with file uploads
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(requiresVerification)
|
||||
const requiresVerificationProvider = RequiresVerificationProvider._();
|
||||
|
||||
/// Convenience provider for checking if verification is required
|
||||
///
|
||||
/// Returns true if the currently selected role requires verification
|
||||
/// documents (CCCD, certificates, etc.).
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final needsVerification = ref.watch(requiresVerificationProvider);
|
||||
/// if (needsVerification) {
|
||||
/// // Show verification section with file uploads
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class RequiresVerificationProvider
|
||||
extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
/// Convenience provider for checking if verification is required
|
||||
///
|
||||
/// Returns true if the currently selected role requires verification
|
||||
/// documents (CCCD, certificates, etc.).
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final needsVerification = ref.watch(requiresVerificationProvider);
|
||||
/// if (needsVerification) {
|
||||
/// // Show verification section with file uploads
|
||||
/// }
|
||||
/// ```
|
||||
const RequiresVerificationProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'requiresVerificationProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$requiresVerificationHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<bool> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
bool create(Ref ref) {
|
||||
return requiresVerification(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$requiresVerificationHash() =>
|
||||
r'400b4242bca2defd14e46361d2b77dd94a4e3e5e';
|
||||
|
||||
/// Convenience provider for getting role display name
|
||||
///
|
||||
/// Returns a user-friendly Vietnamese name for the selected role,
|
||||
/// or null if no role is selected.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final roleName = ref.watch(roleDisplayNameProvider);
|
||||
/// if (roleName != null) {
|
||||
/// Text('Bạn đang đăng ký với vai trò: $roleName');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@ProviderFor(roleDisplayName)
|
||||
const roleDisplayNameProvider = RoleDisplayNameProvider._();
|
||||
|
||||
/// Convenience provider for getting role display name
|
||||
///
|
||||
/// Returns a user-friendly Vietnamese name for the selected role,
|
||||
/// or null if no role is selected.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final roleName = ref.watch(roleDisplayNameProvider);
|
||||
/// if (roleName != null) {
|
||||
/// Text('Bạn đang đăng ký với vai trò: $roleName');
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
final class RoleDisplayNameProvider
|
||||
extends $FunctionalProvider<String?, String?, String?>
|
||||
with $Provider<String?> {
|
||||
/// Convenience provider for getting role display name
|
||||
///
|
||||
/// Returns a user-friendly Vietnamese name for the selected role,
|
||||
/// or null if no role is selected.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// final roleName = ref.watch(roleDisplayNameProvider);
|
||||
/// if (roleName != null) {
|
||||
/// Text('Bạn đang đăng ký với vai trò: $roleName');
|
||||
/// }
|
||||
/// ```
|
||||
const RoleDisplayNameProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'roleDisplayNameProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$roleDisplayNameHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<String?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
String? create(Ref ref) {
|
||||
return roleDisplayName(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(String? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<String?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$roleDisplayNameHash() => r'6cb4bfd9e76fb2f3ed52d4a249e5a2477bc6f39e';
|
||||
Reference in New Issue
Block a user