feat: Update session navigation and enhance error handling in data services
This commit is contained in:
@@ -52,7 +52,7 @@ class _SessionListenerState extends State<SessionListener> {
|
|||||||
// Only show dialog if user was previously authenticated (session expired)
|
// Only show dialog if user was previously authenticated (session expired)
|
||||||
if (_isInitialState) {
|
if (_isInitialState) {
|
||||||
_isInitialState = false;
|
_isInitialState = false;
|
||||||
Modular.to.toGetStartedPage();
|
Modular.to.toClientGetStartedPage();
|
||||||
} else if (!_sessionExpiredDialogShown) {
|
} else if (!_sessionExpiredDialogShown) {
|
||||||
_sessionExpiredDialogShown = true;
|
_sessionExpiredDialogShown = true;
|
||||||
_showSessionExpiredDialog();
|
_showSessionExpiredDialog();
|
||||||
@@ -77,7 +77,7 @@ class _SessionListenerState extends State<SessionListener> {
|
|||||||
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
||||||
} else {
|
} else {
|
||||||
_isInitialState = false;
|
_isInitialState = false;
|
||||||
Modular.to.toInitialPage();
|
Modular.to.toClientGetStartedPage();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ class _SessionListenerState extends State<SessionListener> {
|
|||||||
DataConnectService.instance.handleSignOut();
|
DataConnectService.instance.handleSignOut();
|
||||||
|
|
||||||
// Navigate to authentication
|
// Navigate to authentication
|
||||||
Modular.to.toInitialPage();
|
Modular.to.toClientGetStartedPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class _SessionListenerState extends State<SessionListener> {
|
|||||||
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
_showSessionErrorDialog(state.errorMessage ?? 'Session error occurred');
|
||||||
} else {
|
} else {
|
||||||
_isInitialState = false;
|
_isInitialState = false;
|
||||||
Modular.to.toInitialPage();
|
Modular.to.toGetStartedPage();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ class _SessionListenerState extends State<SessionListener> {
|
|||||||
DataConnectService.instance.handleSignOut();
|
DataConnectService.instance.handleSignOut();
|
||||||
|
|
||||||
// Navigate to authentication
|
// Navigate to authentication
|
||||||
Modular.to.toInitialPage();
|
Modular.to.toGetStartedPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class DataConnectService with DataErrorHandler, SessionHandlerMixin {
|
|||||||
// 2. Check Cache
|
// 2. Check Cache
|
||||||
if (_cachedBusinessId != null) return _cachedBusinessId!;
|
if (_cachedBusinessId != null) return _cachedBusinessId!;
|
||||||
|
|
||||||
// 3. Check Auth Status
|
// 3. Fetch from Data Connect using Firebase UID
|
||||||
final firebase_auth.User? user = _auth.currentUser;
|
final firebase_auth.User? user = _auth.currentUser;
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw const NotAuthenticatedException(
|
throw const NotAuthenticatedException(
|
||||||
@@ -91,8 +91,24 @@ class DataConnectService with DataErrorHandler, SessionHandlerMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Fallback (should ideally not happen if DB is seeded and session is initialized)
|
try {
|
||||||
// Ideally we'd have a getBusinessByUserId query here.
|
final fdc.QueryResult<
|
||||||
|
dc.GetBusinessesByUserIdData,
|
||||||
|
dc.GetBusinessesByUserIdVariables
|
||||||
|
>
|
||||||
|
response = await executeProtected(
|
||||||
|
() => connector.getBusinessesByUserId(userId: user.uid).execute(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.data.businesses.isNotEmpty) {
|
||||||
|
_cachedBusinessId = response.data.businesses.first.id;
|
||||||
|
return _cachedBusinessId!;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to fetch business ID from Data Connect: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Fallback (should ideally not happen if DB is seeded)
|
||||||
return user.uid;
|
return user.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,12 @@ mixin DataErrorHandler {
|
|||||||
try {
|
try {
|
||||||
return await action().timeout(timeout);
|
return await action().timeout(timeout);
|
||||||
} on TimeoutException {
|
} on TimeoutException {
|
||||||
|
debugPrint(
|
||||||
|
'DataErrorHandler: Request timed out after ${timeout.inSeconds}s',
|
||||||
|
);
|
||||||
throw ServiceUnavailableException(
|
throw ServiceUnavailableException(
|
||||||
technicalMessage: 'Request timed out after ${timeout.inSeconds}s');
|
technicalMessage: 'Request timed out after ${timeout.inSeconds}s',
|
||||||
|
);
|
||||||
} on SocketException catch (e) {
|
} on SocketException catch (e) {
|
||||||
throw NetworkException(technicalMessage: 'SocketException: ${e.message}');
|
throw NetworkException(technicalMessage: 'SocketException: ${e.message}');
|
||||||
} on FirebaseException catch (e) {
|
} on FirebaseException catch (e) {
|
||||||
@@ -32,16 +36,26 @@ mixin DataErrorHandler {
|
|||||||
msg.contains('offline') ||
|
msg.contains('offline') ||
|
||||||
msg.contains('network') ||
|
msg.contains('network') ||
|
||||||
msg.contains('connection failed')) {
|
msg.contains('connection failed')) {
|
||||||
|
debugPrint(
|
||||||
|
'DataErrorHandler: Firebase network error: ${e.code} - ${e.message}',
|
||||||
|
);
|
||||||
throw NetworkException(
|
throw NetworkException(
|
||||||
technicalMessage: 'Firebase ${e.code}: ${e.message}');
|
technicalMessage: 'Firebase ${e.code}: ${e.message}',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (code == 'deadline-exceeded') {
|
if (code == 'deadline-exceeded') {
|
||||||
|
debugPrint(
|
||||||
|
'DataErrorHandler: Firebase timeout error: ${e.code} - ${e.message}',
|
||||||
|
);
|
||||||
throw ServiceUnavailableException(
|
throw ServiceUnavailableException(
|
||||||
technicalMessage: 'Firebase ${e.code}: ${e.message}');
|
technicalMessage: 'Firebase ${e.code}: ${e.message}',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
debugPrint('DataErrorHandler: Firebase error: ${e.code} - ${e.message}');
|
||||||
// Fallback for other Firebase errors
|
// Fallback for other Firebase errors
|
||||||
throw ServerException(
|
throw ServerException(
|
||||||
technicalMessage: 'Firebase ${e.code}: ${e.message}');
|
technicalMessage: 'Firebase ${e.code}: ${e.message}',
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
final String errorStr = e.toString().toLowerCase();
|
final String errorStr = e.toString().toLowerCase();
|
||||||
if (errorStr.contains('socketexception') ||
|
if (errorStr.contains('socketexception') ||
|
||||||
@@ -56,15 +70,16 @@ mixin DataErrorHandler {
|
|||||||
errorStr.contains('grpc error') ||
|
errorStr.contains('grpc error') ||
|
||||||
errorStr.contains('terminated') ||
|
errorStr.contains('terminated') ||
|
||||||
errorStr.contains('connectexception')) {
|
errorStr.contains('connectexception')) {
|
||||||
|
debugPrint('DataErrorHandler: Network-related error: $e');
|
||||||
throw NetworkException(technicalMessage: e.toString());
|
throw NetworkException(technicalMessage: e.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's already an AppException, rethrow it
|
// If it's already an AppException, rethrow it
|
||||||
if (e is AppException) rethrow;
|
if (e is AppException) rethrow;
|
||||||
|
|
||||||
// Debugging: Log unexpected errors
|
// Debugging: Log unexpected errors
|
||||||
debugPrint('DataErrorHandler: Unhandled exception caught: $e');
|
debugPrint('DataErrorHandler: Unhandled exception caught: $e');
|
||||||
|
|
||||||
throw UnknownException(technicalMessage: e.toString());
|
throw UnknownException(technicalMessage: e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||||
|
|
||||||
class StaffSession {
|
class StaffSession {
|
||||||
|
const StaffSession({required this.user, this.staff, this.ownerId});
|
||||||
|
|
||||||
final domain.User user;
|
final domain.User user;
|
||||||
final domain.Staff? staff;
|
final domain.Staff? staff;
|
||||||
final String? ownerId;
|
final String? ownerId;
|
||||||
|
|
||||||
const StaffSession({
|
|
||||||
required this.user,
|
|
||||||
this.staff,
|
|
||||||
this.ownerId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StaffSessionStore {
|
class StaffSessionStore {
|
||||||
|
StaffSessionStore._();
|
||||||
StaffSession? _session;
|
StaffSession? _session;
|
||||||
|
|
||||||
StaffSession? get session => _session;
|
StaffSession? get session => _session;
|
||||||
@@ -26,6 +23,4 @@ class StaffSessionStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final StaffSessionStore instance = StaffSessionStore._();
|
static final StaffSessionStore instance = StaffSessionStore._();
|
||||||
|
|
||||||
StaffSessionStore._();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user