forked from eatvio/eatvio_app
feat(session): centralize session teardown and refresh
Add SessionLifecycleService to reset user-scoped cubits, analytics, socket id and account-scoped preferences on logout, 401 or account deletion. Run the same refresh after every successful auth path, including registration v1/v2, and ignore 401 responses from stale tokens so an old request cannot terminate the new user's session. Refs: #1113
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/session/session_lifecycle_service.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
@@ -17,12 +19,14 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
final SettingsRepository settingsRepository;
|
||||
final ConsultantRepository consultantRepository;
|
||||
final ConsultationsRepository consultationsRepository;
|
||||
final SessionLifecycleService sessionLifecycleService;
|
||||
|
||||
SettingsCubit({
|
||||
required this.profileRepository,
|
||||
required this.settingsRepository,
|
||||
required this.profileRepository,
|
||||
required this.settingsRepository,
|
||||
required this.consultantRepository,
|
||||
required this.consultationsRepository,
|
||||
required this.sessionLifecycleService,
|
||||
}) : super(const SettingsState.loading());
|
||||
|
||||
Future<void> init() async {
|
||||
@@ -30,10 +34,12 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
late final ConsultationRequestModel? consultantInfo;
|
||||
late final bool hasActiveConsultation;
|
||||
late final OAuthAccountsDataModel? oauthAccounts;
|
||||
|
||||
|
||||
try {
|
||||
if (profile.phoneConfirmationState.contains('confirmed')) {
|
||||
consultantInfo = await consultantRepository.getMyRequestStatus(profile.slug);
|
||||
consultantInfo = await consultantRepository.getMyRequestStatus(
|
||||
profile.slug,
|
||||
);
|
||||
} else {
|
||||
consultantInfo = null;
|
||||
}
|
||||
@@ -41,14 +47,14 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
await reportFrom(e, st, this);
|
||||
consultantInfo = null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
hasActiveConsultation = await _checkActiveConsultation();
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
hasActiveConsultation = false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
final oauthResponse = await settingsRepository.getOAuthAccounts();
|
||||
oauthAccounts = oauthResponse.data;
|
||||
@@ -56,7 +62,7 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
await reportFrom(e, st, this);
|
||||
oauthAccounts = null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
emit(
|
||||
SettingsState.loaded(
|
||||
@@ -74,9 +80,13 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateProfileDetails({required ProfileDetailsModel profileDetailsModel}) async {
|
||||
Future<void> updateProfileDetails({
|
||||
required ProfileDetailsModel profileDetailsModel,
|
||||
}) async {
|
||||
try {
|
||||
await settingsRepository.updateProfileDetails(profileDetailsModel: profileDetailsModel);
|
||||
await settingsRepository.updateProfileDetails(
|
||||
profileDetailsModel: profileDetailsModel,
|
||||
);
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
} finally {
|
||||
@@ -84,9 +94,13 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateProfileSettings({required ProfileSettingsModel profileSettingsModel}) async {
|
||||
Future<void> updateProfileSettings({
|
||||
required ProfileSettingsModel profileSettingsModel,
|
||||
}) async {
|
||||
try {
|
||||
await settingsRepository.updateProfileSettings(profileSettingsModel: profileSettingsModel);
|
||||
await settingsRepository.updateProfileSettings(
|
||||
profileSettingsModel: profileSettingsModel,
|
||||
);
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
} finally {
|
||||
@@ -97,9 +111,15 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
Future<bool> deleteAccount() async {
|
||||
try {
|
||||
await profileRepository.deleteAccount();
|
||||
await sessionLifecycleService.endSession(
|
||||
reason: SessionEndReason.accountDeleted,
|
||||
);
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
if (e is DioException && e.response?.statusCode == 401) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -135,11 +155,14 @@ class SettingsCubit extends Cubit<SettingsState> {
|
||||
|
||||
Future<bool> _checkActiveConsultation() async {
|
||||
try {
|
||||
final userPurchases = await consultationsRepository.getUserPurchases(null, null);
|
||||
final userPurchases = await consultationsRepository.getUserPurchases(
|
||||
null,
|
||||
null,
|
||||
);
|
||||
final activeStates = ChosenPlanStateEnum.getActiveStates();
|
||||
|
||||
return userPurchases.any((purchase) =>
|
||||
activeStates.contains(purchase.chosenPlanState)
|
||||
|
||||
return userPurchases.any(
|
||||
(purchase) => activeStates.contains(purchase.chosenPlanState),
|
||||
);
|
||||
} catch (e, st) {
|
||||
await reportFrom(e, st, this);
|
||||
|
||||
@@ -698,7 +698,6 @@ class _DeleteAccountBottomSheet extends State<DeleteAccountBottomSheet> {
|
||||
onPressed: () async {
|
||||
final result = await widget.cubit.deleteAccount();
|
||||
if (result == true) {
|
||||
AppRouter.navigatorKey.currentContext?.go('/auth-screen');
|
||||
return;
|
||||
}
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
|
||||
Reference in New Issue
Block a user