Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/core/network/api_interceptors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class AuthInterceptor extends Interceptor {
}

Future<void> _endSession(HiveService hiveService) async {
await hiveService.authBox.clear();
await hiveService.clearUserData(keepPreferences: true);
_ref.read(authProvider.notifier).forceLogout();

try {
Expand Down
22 changes: 22 additions & 0 deletions lib/core/storage/hive_storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,28 @@ class HiveService {
Box get authBox => Hive.box(HiveBoxNames.authBox);
Box get cartBox => Hive.box(HiveBoxNames.cartBox);
Box get recentBox => Hive.box(HiveBoxNames.recentBox);

/// Xóa toàn bộ dữ liệu người dùng cục bộ khi đăng xuất (lịch sử tìm kiếm, sản phẩm vừa xem, giỏ hàng, token...).
/// Tùy chọn [keepPreferences] cho phép giữ lại cài đặt thiết bị như theme.
Future<void> clearUserData({bool keepPreferences = true}) async {
String? savedTheme;
if (keepPreferences && Hive.isBoxOpen(HiveBoxNames.authBox)) {
savedTheme = authBox.get('theme_mode') as String?;
}

if (Hive.isBoxOpen(HiveBoxNames.authBox)) {
await authBox.clear();
if (keepPreferences && savedTheme != null) {
await authBox.put('theme_mode', savedTheme);
}
}
if (Hive.isBoxOpen(HiveBoxNames.cartBox)) {
await cartBox.clear();
}
if (Hive.isBoxOpen(HiveBoxNames.recentBox)) {
await recentBox.clear();
}
}
}

/// Riverpod Provider cung cấp instance của HiveService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:shopnexus_flutter_app/features/account/data/models/order_view.da
import 'package:shopnexus_flutter_app/features/account/presentation/providers/buyer_orders_provider.dart';
import 'package:shopnexus_flutter_app/features/account/presentation/providers/orders_provider.dart';
import 'package:shopnexus_flutter_app/features/account/presentation/widgets/confirm_receipt_sheet.dart';
import 'package:shopnexus_flutter_app/shared/widgets/order_status_badge.dart';

class OrderDetailScreen extends ConsumerWidget {
final String orderId;
Expand Down Expand Up @@ -282,15 +283,7 @@ class OrderDetailScreen extends ConsumerWidget {
fontFamily: 'Inter',
),
),
Text(
view.statusLabel,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: theme.colorScheme.onSurface,
fontFamily: 'Inter',
),
),
OrderStatusBadge(view: view),
],
),
Divider(height: 24, color: dividerColor),
Expand Down
14 changes: 8 additions & 6 deletions lib/features/account/presentation/screens/profile_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,22 +268,24 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
v.order.completedAt != null ||
isDelivered;

final hasRefund =
v.order.declineReason != null ||
v.order.transport?.status == TransportStatus.returned ||
buyerRefundedOrderIds.contains(v.order.id);

switch (tabIndex) {
case 1: // Chờ xác nhận
return v.order.state == OrderState.awaitingConfirmation &&
!isCancelled;
case 2: // Đang xử lý
return v.order.state == OrderState.open &&
!isCompleted &&
v.order.transport?.status != TransportStatus.returned &&
!hasRefund &&
!isCancelled;
case 3: // Hoàn thành
return isCompleted && !isCancelled;
return isCompleted && !hasRefund && !isCancelled;
case 4: // Hoàn tiền
return (v.order.declineReason != null ||
v.order.transport?.status == TransportStatus.returned ||
buyerRefundedOrderIds.contains(v.order.id)) &&
!isCancelled;
return hasRefund && !isCancelled;
case 5: // Đã hủy
return isCancelled;
default:
Expand Down
26 changes: 18 additions & 8 deletions lib/features/account/presentation/widgets/orders_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,24 @@ class _OrdersListState extends ConsumerState<OrdersList> {
view.order.completedAt != null ||
isDelivered;

final hasRefund =
view.order.declineReason != null ||
view.order.transport?.status == TransportStatus.returned ||
refundedOrderIds.contains(view.order.id);

switch (selectedTab) {
case 1: // Chờ xác nhận
return view.order.state == OrderState.awaitingConfirmation &&
!isCancelled;
case 2: // Đang xử lý
return view.order.state == OrderState.open &&
!isCompleted &&
view.order.transport?.status != TransportStatus.returned &&
!hasRefund &&
!isCancelled;
case 3: // Hoàn thành
return isCompleted && !isCancelled;
return isCompleted && !hasRefund && !isCancelled;
case 4: // Hoàn tiền
return (view.order.declineReason != null ||
view.order.transport?.status == TransportStatus.returned ||
refundedOrderIds.contains(view.order.id)) &&
!isCancelled;
return hasRefund && !isCancelled;
case 5: // Đã hủy
return isCancelled;
case 0: // Tất cả
Expand Down Expand Up @@ -273,10 +275,18 @@ class _OrderRow extends ConsumerWidget {
fontFamily: 'Inter',
fontSize: 12,
height: 1.4,
fontWeight: view.isAwaitingConfirmation
fontWeight: (view.isAwaitingConfirmation ||
view.order.state == OrderState.cancelled ||
view.order.transport?.status == TransportStatus.failed)
? FontWeight.w600
: FontWeight.normal,
color: view.isAwaitingConfirmation
color: (view.order.state == OrderState.cancelled ||
view.order.transport?.status == TransportStatus.failed ||
view.order.transport?.status == TransportStatus.cancelled)
? (isDark
? const Color(0xFFF87171)
: const Color(0xFFDC2626))
: view.isAwaitingConfirmation
? theme.colorScheme.primary
: theme.colorScheme.onSurfaceVariant,
),
Expand Down
2 changes: 1 addition & 1 deletion lib/features/auth/data/repositories/auth_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AuthRepository {
} catch (_) {
// Offline or a server error; proceed with the local logout.
}
await _hiveService.authBox.clear();
await _hiveService.clearUserData(keepPreferences: true);
}

/// The tokens land in Hive here rather than in the notifier, because the
Expand Down
18 changes: 15 additions & 3 deletions lib/features/auth/presentation/providers/auth_provider.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shopnexus_flutter_app/features/account/presentation/providers/account_provider.dart';
import 'package:shopnexus_flutter_app/core/storage/hive_storage.dart';
import 'package:shopnexus_flutter_app/core/utils/error_handler.dart';
import 'package:shopnexus_flutter_app/features/account/presentation/providers/account_provider.dart';
import 'package:shopnexus_flutter_app/features/account/presentation/providers/wishlist_provider.dart';
import 'package:shopnexus_flutter_app/features/auth/data/models/auth_model.dart';
import 'package:shopnexus_flutter_app/features/auth/data/repositories/auth_repository.dart';
import 'package:shopnexus_flutter_app/features/cart/presentation/providers/cart_provider.dart';
import 'package:shopnexus_flutter_app/features/catalog/presentation/providers/catalog_provider.dart';

part 'auth_provider.freezed.dart';
part 'auth_provider.g.dart';
Expand Down Expand Up @@ -148,7 +151,7 @@ class AuthNotifier extends _$AuthNotifier {
try {
final repository = ref.read(authRepositoryProvider);
await repository.logout(deviceId: deviceId);
ref.invalidate(profileProvider);
_clearLocalSession();
state = const AuthState.unauthenticated();
} catch (e) {
state = AuthState.error(message: ErrorHandler.getErrorMessage(e));
Expand All @@ -157,10 +160,19 @@ class AuthNotifier extends _$AuthNotifier {

/// Buộc đăng xuất (khi refresh token thất bại hoặc hết hạn)
void forceLogout() {
ref.invalidate(profileProvider);
ref.read(hiveServiceProvider).clearUserData(keepPreferences: true);
_clearLocalSession();
state = const AuthState.unauthenticated();
}

void _clearLocalSession() {
ref.invalidate(profileProvider);
ref.invalidate(recentSearchesProvider);
ref.invalidate(recentlyViewedProductsProvider);
ref.invalidate(cartProvider);
ref.invalidate(wishlistProductsProvider);
}

/// Cập nhật lại token mới sau khi refresh thành công
void updateToken({
required String accessToken,
Expand Down
8 changes: 8 additions & 0 deletions lib/features/cart/data/repositories/cart_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ class CartRepository {
}
}

/// Xóa giỏ hàng cached trong Hive
Future<void> clearCachedCart() async {
try {
final box = _hiveService.cartBox;
await box.delete('cart_items');
} catch (_) {}
}

CartItem _row(CartItem? data) {
if (data == null) throw StateError('empty cart item');
return data;
Expand Down
Binary file modified lib/features/catalog/data/repositories/catalog_repository.dart
Binary file not shown.
Loading
Loading