feat: Implement session management with SessionListener and integrate krow_data_connect
This commit is contained in:
@@ -1,56 +1,16 @@
|
||||
import 'dart:async';
|
||||
import 'package:client_authentication/src/domain/repositories/auth_repository_interface.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
class ClientIntroPage extends StatefulWidget {
|
||||
class ClientIntroPage extends StatelessWidget {
|
||||
const ClientIntroPage({super.key});
|
||||
|
||||
@override
|
||||
State<ClientIntroPage> createState() => _ClientIntroPageState();
|
||||
}
|
||||
|
||||
class _ClientIntroPageState extends State<ClientIntroPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_checkSession();
|
||||
}
|
||||
|
||||
Future<void> _checkSession() async {
|
||||
// Check session immediately without artificial delay
|
||||
if (!mounted) return;
|
||||
|
||||
try {
|
||||
final AuthRepositoryInterface authRepo =
|
||||
Modular.get<AuthRepositoryInterface>();
|
||||
// Add a timeout to prevent infinite loading
|
||||
final user = true;
|
||||
|
||||
if (mounted) {
|
||||
if (user != null) {
|
||||
Modular.to.navigate(ClientPaths.home);
|
||||
} else {
|
||||
Modular.to.navigate(ClientPaths.getStarted);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('ClientIntroPage: Session check error: $e');
|
||||
if (mounted) {
|
||||
Modular.to.navigate(ClientPaths.getStarted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
body: Center(
|
||||
child: Image.asset(
|
||||
'assets/logo-blue.png',
|
||||
package: 'design_system',
|
||||
UiImageAssets.logoBlue,
|
||||
width: 120,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -17,9 +17,8 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
Completer<String?>? _pendingVerification;
|
||||
|
||||
@override
|
||||
Stream<domain.User?> get currentUser => _service.auth
|
||||
.authStateChanges()
|
||||
.map((User? firebaseUser) {
|
||||
Stream<domain.User?> get currentUser =>
|
||||
_service.auth.authStateChanges().map((User? firebaseUser) {
|
||||
if (firebaseUser == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -49,20 +48,24 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
// For real numbers, we can support auto-verification if desired.
|
||||
// But since this method returns a verificationId for manual OTP entry,
|
||||
// we might not handle direct sign-in here unless the architecture changes.
|
||||
// Currently, we just ignore it for the completer flow,
|
||||
// Currently, we just ignore it for the completer flow,
|
||||
// or we could sign in directly if the credential is provided.
|
||||
},
|
||||
verificationFailed: (FirebaseAuthException e) {
|
||||
if (!completer.isCompleted) {
|
||||
// Map Firebase network errors to NetworkException
|
||||
if (e.code == 'network-request-failed' ||
|
||||
if (e.code == 'network-request-failed' ||
|
||||
e.message?.contains('Unable to resolve host') == true) {
|
||||
completer.completeError(
|
||||
const domain.NetworkException(technicalMessage: 'Auth network failure'),
|
||||
const domain.NetworkException(
|
||||
technicalMessage: 'Auth network failure',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
completer.completeError(
|
||||
domain.SignInFailedException(technicalMessage: 'Firebase ${e.code}: ${e.message}'),
|
||||
domain.SignInFailedException(
|
||||
technicalMessage: 'Firebase ${e.code}: ${e.message}',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -110,21 +113,18 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
verificationId: verificationId,
|
||||
smsCode: smsCode,
|
||||
);
|
||||
final UserCredential userCredential = await _service.run(
|
||||
() async {
|
||||
try {
|
||||
return await _service.auth.signInWithCredential(credential);
|
||||
} on FirebaseAuthException catch (e) {
|
||||
if (e.code == 'invalid-verification-code') {
|
||||
throw const domain.InvalidCredentialsException(
|
||||
technicalMessage: 'Invalid OTP code entered.',
|
||||
);
|
||||
}
|
||||
rethrow;
|
||||
final UserCredential userCredential = await _service.run(() async {
|
||||
try {
|
||||
return await _service.auth.signInWithCredential(credential);
|
||||
} on FirebaseAuthException catch (e) {
|
||||
if (e.code == 'invalid-verification-code') {
|
||||
throw const domain.InvalidCredentialsException(
|
||||
technicalMessage: 'Invalid OTP code entered.',
|
||||
);
|
||||
}
|
||||
},
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}, requiresAuthentication: false);
|
||||
final User? firebaseUser = userCredential.user;
|
||||
if (firebaseUser == null) {
|
||||
throw const domain.SignInFailedException(
|
||||
@@ -135,13 +135,9 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
|
||||
final QueryResult<GetUserByIdData, GetUserByIdVariables> response =
|
||||
await _service.run(
|
||||
() => _service.connector
|
||||
.getUserById(
|
||||
id: firebaseUser.uid,
|
||||
)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
() => _service.connector.getUserById(id: firebaseUser.uid).execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
final GetUserByIdUser? user = response.data.user;
|
||||
|
||||
GetStaffByUserIdStaffs? staffRecord;
|
||||
@@ -150,10 +146,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
if (user == null) {
|
||||
await _service.run(
|
||||
() => _service.connector
|
||||
.createUser(
|
||||
id: firebaseUser.uid,
|
||||
role: UserBaseRole.USER,
|
||||
)
|
||||
.createUser(id: firebaseUser.uid, role: UserBaseRole.USER)
|
||||
.userRole('STAFF')
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
@@ -161,11 +154,9 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
} else {
|
||||
// User exists in PostgreSQL. Check if they have a STAFF profile.
|
||||
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
|
||||
staffResponse = await _service.run(
|
||||
staffResponse = await _service.run(
|
||||
() => _service.connector
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.getStaffByUserId(userId: firebaseUser.uid)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
@@ -208,11 +199,9 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
}
|
||||
|
||||
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
|
||||
staffResponse = await _service.run(
|
||||
staffResponse = await _service.run(
|
||||
() => _service.connector
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.getStaffByUserId(userId: firebaseUser.uid)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user