refactor(session): migrate V2 session listener initialization to improve dependency injection and role handling
This commit is contained in:
@@ -30,16 +30,6 @@ void main() async {
|
||||
logStateChanges: false, // Set to true for verbose debugging
|
||||
);
|
||||
|
||||
// Initialize V2 session listener for Firebase Auth state changes.
|
||||
// Role validation calls GET /auth/session via the V2 API.
|
||||
V2SessionService.instance.initializeAuthListener(
|
||||
allowedRoles: <String>[
|
||||
'CLIENT',
|
||||
'BUSINESS',
|
||||
'BOTH',
|
||||
], // Only allow users with CLIENT, BUSINESS, or BOTH roles
|
||||
);
|
||||
|
||||
runApp(
|
||||
ModularApp(
|
||||
module: AppModule(),
|
||||
|
||||
@@ -27,11 +27,20 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_setupSessionListener();
|
||||
_initializeSession();
|
||||
}
|
||||
|
||||
void _setupSessionListener() {
|
||||
_sessionSubscription = V2SessionService.instance.onSessionStateChanged
|
||||
void _initializeSession() {
|
||||
// Resolve V2SessionService via DI — this triggers CoreModule's lazy
|
||||
// singleton, which wires setApiService(). Must happen before
|
||||
// initializeAuthListener so the session endpoint is reachable.
|
||||
final V2SessionService sessionService = Modular.get<V2SessionService>();
|
||||
|
||||
sessionService.initializeAuthListener(
|
||||
allowedRoles: const <String>['CLIENT', 'BUSINESS', 'BOTH'],
|
||||
);
|
||||
|
||||
_sessionSubscription = sessionService.onSessionStateChanged
|
||||
.listen((SessionState state) {
|
||||
_handleSessionChange(state);
|
||||
});
|
||||
|
||||
@@ -28,15 +28,6 @@ void main() async {
|
||||
logStateChanges: false, // Set to true for verbose debugging
|
||||
);
|
||||
|
||||
// Initialize V2 session listener for Firebase Auth state changes.
|
||||
// Role validation calls GET /auth/session via the V2 API.
|
||||
V2SessionService.instance.initializeAuthListener(
|
||||
allowedRoles: <String>[
|
||||
'STAFF',
|
||||
'BOTH',
|
||||
], // Only allow users with STAFF or BOTH roles
|
||||
);
|
||||
|
||||
runApp(
|
||||
ModularApp(
|
||||
module: AppModule(),
|
||||
|
||||
@@ -27,11 +27,20 @@ class _SessionListenerState extends State<SessionListener> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_setupSessionListener();
|
||||
_initializeSession();
|
||||
}
|
||||
|
||||
void _setupSessionListener() {
|
||||
_sessionSubscription = V2SessionService.instance.onSessionStateChanged
|
||||
void _initializeSession() {
|
||||
// Resolve V2SessionService via DI — this triggers CoreModule's lazy
|
||||
// singleton, which wires setApiService(). Must happen before
|
||||
// initializeAuthListener so the session endpoint is reachable.
|
||||
final V2SessionService sessionService = Modular.get<V2SessionService>();
|
||||
|
||||
sessionService.initializeAuthListener(
|
||||
allowedRoles: const <String>['STAFF', 'BOTH'],
|
||||
);
|
||||
|
||||
_sessionSubscription = sessionService.onSessionStateChanged
|
||||
.listen((SessionState state) {
|
||||
_handleSessionChange(state);
|
||||
});
|
||||
|
||||
@@ -18,9 +18,8 @@ class CoreModule extends Module {
|
||||
// 2. Register the base API service
|
||||
i.addLazySingleton<BaseApiService>(() => ApiService(i.get<Dio>()));
|
||||
|
||||
// 2b. Wire the V2 session service with the API service.
|
||||
// This uses a post-registration callback so the singleton gets
|
||||
// its dependency as soon as the injector resolves BaseApiService.
|
||||
// 2b. Register V2SessionService — wires the singleton with ApiService.
|
||||
// Resolved eagerly by SessionListener.initState() after Modular is ready.
|
||||
i.addLazySingleton<V2SessionService>(() {
|
||||
final V2SessionService service = V2SessionService.instance;
|
||||
service.setApiService(i.get<BaseApiService>());
|
||||
|
||||
@@ -42,23 +42,10 @@ class V2SessionService with SessionHandlerMixin {
|
||||
@override
|
||||
Future<String?> fetchUserRole(String userId) async {
|
||||
try {
|
||||
// Wait for ApiService to be injected (happens after CoreModule.exportedBinds).
|
||||
// On cold start, initializeAuthListener fires before DI is ready.
|
||||
if (_apiService == null) {
|
||||
debugPrint(
|
||||
'[V2SessionService] ApiService not yet injected; '
|
||||
'waiting for DI initialization...',
|
||||
);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 200));
|
||||
if (_apiService != null) break;
|
||||
}
|
||||
}
|
||||
|
||||
final BaseApiService? api = _apiService;
|
||||
if (api == null) {
|
||||
debugPrint(
|
||||
'[V2SessionService] ApiService still null after waiting 2 s; '
|
||||
'[V2SessionService] ApiService not injected; '
|
||||
'cannot fetch user role.',
|
||||
);
|
||||
return null;
|
||||
@@ -74,8 +61,16 @@ class V2SessionService with SessionHandlerMixin {
|
||||
// Per V2 auth doc, GET /auth/session is used for app startup hydration.
|
||||
_hydrateSessionStores(data);
|
||||
|
||||
final String? role = data['role'] as String?;
|
||||
return role;
|
||||
// Derive role from the presence of staff/business context.
|
||||
// The session endpoint returns { user, tenant, business, vendor, staff }
|
||||
// — there is no explicit "role" field.
|
||||
final bool hasStaff = data['staff'] is Map<String, dynamic>;
|
||||
final bool hasBusiness = data['business'] is Map<String, dynamic>;
|
||||
|
||||
if (hasStaff && hasBusiness) return 'BOTH';
|
||||
if (hasStaff) return 'STAFF';
|
||||
if (hasBusiness) return 'BUSINESS';
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user