diff --git a/lib/core/constants/api_endpoints.dart b/lib/core/constants/api_endpoints.dart index d3e354b..f3a0ca2 100644 --- a/lib/core/constants/api_endpoints.dart +++ b/lib/core/constants/api_endpoints.dart @@ -41,6 +41,11 @@ class ApiEndpoints { /// Response: List of users static const String users = '/PortalUser/GetAllMemberUserShortInfo'; + /// Get current logged-in user + /// GET: /PortalUser/GetCurrentUser?getDep=false (requires auth token) + /// Response: Current user details + static const String getCurrentUser = '/PortalUser/GetCurrentUser?getDep=false'; + // ==================== Warehouse Endpoints ==================== /// Get all warehouses diff --git a/lib/core/storage/secure_storage.dart b/lib/core/storage/secure_storage.dart index c0b2542..1fe0453 100644 --- a/lib/core/storage/secure_storage.dart +++ b/lib/core/storage/secure_storage.dart @@ -55,6 +55,9 @@ class SecureStorage { /// Key for storing email static const String _emailKey = 'email'; + /// Key for storing current user ID + static const String _currentUserIdKey = 'current_user_id'; + // ==================== Token Management ==================== /// Save access token securely @@ -147,6 +150,25 @@ class SecureStorage { } } + /// Save current user ID + Future saveCurrentUserId(int userId) async { + try { + await _storage.write(key: _currentUserIdKey, value: userId.toString()); + } catch (e) { + throw Exception('Failed to save current user ID: $e'); + } + } + + /// Get current user ID + Future getCurrentUserId() async { + try { + final value = await _storage.read(key: _currentUserIdKey); + return value != null ? int.tryParse(value) : null; + } catch (e) { + throw Exception('Failed to read current user ID: $e'); + } + } + /// Check if user is authenticated (has valid access token) Future isAuthenticated() async { final token = await getAccessToken(); diff --git a/lib/docs/api.sh b/lib/docs/api.sh index 7c3799f..6253826 100644 --- a/lib/docs/api.sh +++ b/lib/docs/api.sh @@ -127,4 +127,25 @@ curl --request GET \ --header 'Sec-Fetch-Dest: empty' \ --header 'Sec-Fetch-Mode: cors' \ --header 'Sec-Fetch-Site: same-site' \ - --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0' \ No newline at end of file + --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0' + + + #Get current user + curl --request GET \ + --url 'https://dotnet.elidev.info:8157/ws/PortalUser/GetCurrentUser?getDep=false' \ + --compressed \ + --header 'Accept: application/json, text/plain, */*' \ + --header 'Accept-Encoding: gzip, deflate, br, zstd' \ + --header 'Accept-Language: en-US,en;q=0.5' \ + --header 'AccessToken: 1k5fXyQVXtGkfjwS4g2USldGyLSA7Zwa2jdj5tLe+3YfSDlk02aYgqsFh5xArkdL4N529x7IYJOGrLJJgLBPNVgD51zFfEYBzfJmMH2RUm7iegvDJaMCLISySw0zd6kcsqeJi7vtuybgY2NDPxDgiSOj4wX417PzB8AVg5bl1ZAAJ3LcVAqqtA1PDTU5ZU1QQYapNeBNxAHjnd2ojTZK1GJBIyY5Gd8P9gB880ppAKq8manNMZYsa4d8tkYf0SJUul2aqLIWJAwDGORpPmfjqkN4hMh85xAfPTZi6m4DdI0u2rHDMLaZ8eIsV16qA8wimSDnWi0VeG0SZ4ugbCdJAi3t1/uICTftiy06PJEkulBLV+h2xS/7SlmEY2xoN5ISi++3FNqsFPGa9QH6akGu2C7IXEUBCg3iGJx0uL+vULmVqk5OJIXdqiKVQ366hvhPlK2AM1zbh49x/ngibe08483WTL5uAY/fsKuBxQCpTc2368Gqhpd7QRtZFKpzikhyTWsR3nQIi6ExSstCeFbe8ehgo0PuTPZNHH5IHTc49snH6IZrSbR+F62Wu/D+4DlvMTK/ktG6LVQ3r3jSJC5MAQDV5Q9WK3RvsWMPvZrsaVW/Exz0GBgWP4W0adADg7MFSlnGDOJm6I4fCLHZIJCUww50L6iNmzvrdibrQT5jKACVgNquMZCfeZlf3m2BwUx9T6J45lAePpJ+QaMh+2voFqRiOLi98MLqOG6TW7z96sadzFVR9YU1xwM51jQDjnUlrXt0+msq29Jqt8LoCyQsG4r3RgS/tUJhximq11MDXsSXanpYM7jesjr8mAG4qjYN6z6c1Gl5N0dhcDF4HeEaIlNIgZ75FqtXZnLqvhHPyk6L2iR2ZT15nobZxLzOUad4a0OymUDUv7xuEBdEk5kmzZLDpbOxrKiyMpGSlbBhEoBMoA0u6ZKtBGQfCJ02s6Ri0WhLLM4XJCjGrpoEkTUuZ7YG39Zva19HGV0kkxeFYkG0lnZBO6jCggem5f+S2NQvXP/kUrWX1GeQFCq5PScvwJexLsbh0LKC2MGovkecoBKtNIK21V6ztvWL8lThJAl9' \ + --header 'AppID: Minhthu2016' \ + --header 'Connection: keep-alive' \ + --header 'Origin: https://dotnet.elidev.info:8158' \ + --header 'Priority: u=0' \ + --header 'Referer: https://dotnet.elidev.info:8158/' \ + --header 'Sec-Fetch-Dest: empty' \ + --header 'Sec-Fetch-Mode: cors' \ + --header 'Sec-Fetch-Site: same-site' \ + --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:144.0) Gecko/20100101 Firefox/144.0' \ + --header 'content-type: application/json' \ + --data '' \ No newline at end of file diff --git a/lib/features/products/presentation/pages/product_detail_page.dart b/lib/features/products/presentation/pages/product_detail_page.dart index 56c0bc7..a926f57 100644 --- a/lib/features/products/presentation/pages/product_detail_page.dart +++ b/lib/features/products/presentation/pages/product_detail_page.dart @@ -88,14 +88,14 @@ class _ProductDetailPageState extends ConsumerState { super.dispose(); } - /// Auto-select warehouse user based on stored email from login + /// Auto-select warehouse user based on stored user ID from login Future _autoSelectWarehouseUser() async { try { - // Get stored email from secure storage + // Get stored current user ID from secure storage final secureStorage = SecureStorage(); - final storedEmail = await secureStorage.getEmail(); - - if (storedEmail == null || storedEmail.isEmpty) { + final currentUserId = await secureStorage.getCurrentUserId(); + print('user $currentUserId'); + if (currentUserId == null) { return; } @@ -104,9 +104,9 @@ class _ProductDetailPageState extends ConsumerState { .where((user) => user.isWareHouseUser) .toList(); - // Find user with matching email + // Find user with matching ID final matchingUsers = warehouseUsers - .where((user) => user.email.toLowerCase() == storedEmail.toLowerCase()) + .where((user) => user.id == currentUserId) .toList(); final matchingUser = matchingUsers.isNotEmpty ? matchingUsers.first : null; @@ -656,7 +656,9 @@ class _ProductDetailPageState extends ConsumerState { _buildUserDropdown( label: 'Nhân viên *', value: _selectedEmployee, - users: ref.watch(usersListProvider), + users: ref.watch(usersListProvider) + .where((user) => user.roleId == 2) + .toList(), onChanged: (user) { setState(() { _selectedEmployee = user; diff --git a/lib/features/users/data/datasources/users_remote_datasource.dart b/lib/features/users/data/datasources/users_remote_datasource.dart index ea01cbf..128a357 100644 --- a/lib/features/users/data/datasources/users_remote_datasource.dart +++ b/lib/features/users/data/datasources/users_remote_datasource.dart @@ -8,6 +8,9 @@ import '../models/user_model.dart'; abstract class UsersRemoteDataSource { /// Fetch all users from the API Future> getUsers(); + + /// Get current logged-in user + Future getCurrentUser(); } /// Implementation of UsersRemoteDataSource using ApiClient @@ -54,4 +57,41 @@ class UsersRemoteDataSourceImpl implements UsersRemoteDataSource { throw ServerException('Failed to get users: ${e.toString()}'); } } + + @override + Future getCurrentUser() async { + try { + // Make API call to get current user + final response = await apiClient.get(ApiEndpoints.getCurrentUser); + + // Parse the API response using ApiResponse wrapper + final apiResponse = ApiResponse.fromJson( + response.data as Map, + (json) => UserModel.fromJson(json as Map), + ); + + // Check if the API call was successful + if (apiResponse.isSuccess && apiResponse.value != null) { + return apiResponse.value!; + } else { + // Throw exception with error message from API + throw ServerException( + apiResponse.errors.isNotEmpty + ? apiResponse.errors.first + : 'Failed to get current user', + ); + } + } catch (e) { + // Re-throw ServerException as-is + if (e is ServerException) { + rethrow; + } + // Re-throw NetworkException as-is + if (e is NetworkException) { + rethrow; + } + // Wrap other exceptions in ServerException + throw ServerException('Failed to get current user: ${e.toString()}'); + } + } } diff --git a/lib/features/warehouse/presentation/pages/warehouse_selection_page.dart b/lib/features/warehouse/presentation/pages/warehouse_selection_page.dart index 0d46123..c143d4f 100644 --- a/lib/features/warehouse/presentation/pages/warehouse_selection_page.dart +++ b/lib/features/warehouse/presentation/pages/warehouse_selection_page.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../core/di/providers.dart'; import '../../../../core/router/app_router.dart'; +import '../../../../core/storage/secure_storage.dart'; import '../widgets/warehouse_card.dart'; import '../widgets/warehouse_drawer.dart'; @@ -28,12 +29,34 @@ class _WarehouseSelectionPageState void initState() { super.initState(); // Load warehouses when page is first created - Future.microtask(() { + Future.microtask(() async { ref.read(warehouseProvider.notifier).loadWarehouses(); // Users are automatically loaded from local storage by UsersNotifier + + // Get current user and store user ID + await _getCurrentUserAndStoreId(); }); } + /// Get current user from API and store user ID in secure storage + Future _getCurrentUserAndStoreId() async { + try { + final secureStorage = SecureStorage(); + final usersDataSource = ref.read(usersRemoteDataSourceProvider); + + // Call API to get current user + final currentUser = await usersDataSource.getCurrentUser(); + + // Store the current user ID + await secureStorage.saveCurrentUserId(currentUser.id); + + debugPrint('Current user ID stored: ${currentUser.id}'); + } catch (e) { + // Silently fail - this is not critical + debugPrint('Error getting current user: $e'); + } + } + @override Widget build(BuildContext context) { // Watch warehouse state