This commit is contained in:
2025-10-28 23:46:07 +07:00
parent 73b77c27de
commit f32e1c16fb
10 changed files with 333 additions and 142 deletions

View File

@@ -50,15 +50,9 @@ class AuthRepositoryImpl implements AuthRepository {
@override
Future<Either<Failure, void>> logout() async {
try {
// Call remote data source to logout (optional - can fail silently)
try {
await remoteDataSource.logout();
} catch (e) {
// Ignore remote logout errors, still clear local data
}
// Clear all local authentication data
await secureStorage.clearAll();
// Just clear access token from secure storage
// No API call needed
await secureStorage.clearTokens();
return const Right(null);
} catch (e) {

View File

@@ -78,7 +78,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
// App title
Text(
'Warehouse Manager',
'Quản lý kho',
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onSurface,
@@ -90,7 +90,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
// Subtitle
Text(
'Login to continue',
'Đăng nhập để tiếp tục',
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),

View File

@@ -129,24 +129,11 @@ class AuthNotifier extends StateNotifier<AuthState> {
///
/// Clears authentication data and returns to initial state
Future<void> logout() async {
// Set loading state
state = state.copyWith(isLoading: true, error: null);
// Clear tokens from secure storage
await logoutUseCase();
// Call logout use case
final result = await logoutUseCase();
// Handle result
result.fold(
(failure) {
// Logout failed - but still reset to initial state
// (local data should be cleared even if API call fails)
state = const AuthState.initial();
},
(_) {
// Logout successful - reset to initial state
state = const AuthState.initial();
},
);
// Always reset to initial state (clear local data even if API call fails)
state = const AuthState.initial();
}
/// Check authentication status on app start

View File

@@ -56,8 +56,8 @@ class _LoginFormState extends State<LoginForm> {
controller: _usernameController,
enabled: !widget.isLoading,
decoration: InputDecoration(
labelText: 'Username',
hintText: 'Enter your username',
labelText: 'Tên đăng nhập',
hintText: 'Nhập tên đăng nhập',
prefixIcon: const Icon(Icons.person_outline),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
@@ -67,10 +67,10 @@ class _LoginFormState extends State<LoginForm> {
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Username is required';
return 'Vui lòng nhập tên đăng nhập';
}
if (value.trim().length < 3) {
return 'Username must be at least 3 characters';
return 'Tên đăng nhập phải có ít nhất 3 ký tự';
}
return null;
},
@@ -84,8 +84,8 @@ class _LoginFormState extends State<LoginForm> {
enabled: !widget.isLoading,
obscureText: _obscurePassword,
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
labelText: 'Mật khẩu',
hintText: 'Nhập mật khẩu',
prefixIcon: const Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
@@ -107,10 +107,10 @@ class _LoginFormState extends State<LoginForm> {
onFieldSubmitted: (_) => _handleSubmit(),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Password is required';
return 'Vui lòng nhập mật khẩu';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
return 'Mật khẩu phải có ít nhất 6 ký tự';
}
return null;
},
@@ -131,7 +131,7 @@ class _LoginFormState extends State<LoginForm> {
),
)
: const Icon(Icons.login),
label: Text(widget.isLoading ? 'Logging in...' : 'Login'),
label: Text(widget.isLoading ? 'Đang đăng nhập...' : 'Đăng nhập'),
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(