Fix anonymous account upgrade to preserve Firebase UID
This commit is contained in:
parent
81064da7f4
commit
0522e6cbbf
|
|
@ -131,6 +131,16 @@ class FirebaseAuthService implements AuthService {
|
|||
);
|
||||
}
|
||||
|
||||
bool get _hasAnonymousFirebaseUser =>
|
||||
_firebaseAuth?.currentUser?.isAnonymous == true;
|
||||
|
||||
void _updateAuthenticatedUser(fb.User user) {
|
||||
_updateState(AuthState.authenticated(
|
||||
_mapFirebaseUser(user),
|
||||
isFirebaseConfigured: true,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signInWithEmailAndPassword(String email, String password) async {
|
||||
final auth = _firebaseAuth;
|
||||
|
|
@ -149,13 +159,29 @@ class FirebaseAuthService implements AuthService {
|
|||
));
|
||||
|
||||
try {
|
||||
final normalizedEmail = email.trim();
|
||||
|
||||
// If the current Firebase identity is anonymous, upgrade that identity
|
||||
// instead of signing into a new Firebase UID. This preserves ownership
|
||||
// of any cloud data already associated with the guest account.
|
||||
if (_hasAnonymousFirebaseUser) {
|
||||
final credential = fb.EmailAuthProvider.credential(
|
||||
email: normalizedEmail,
|
||||
password: password,
|
||||
);
|
||||
final result = await auth.currentUser!.linkWithCredential(credential);
|
||||
if (result.user != null) {
|
||||
_updateAuthenticatedUser(result.user!);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final credential = await auth.signInWithEmailAndPassword(
|
||||
email: email.trim(),
|
||||
email: normalizedEmail,
|
||||
password: password,
|
||||
);
|
||||
if (credential.user != null) {
|
||||
final user = _mapFirebaseUser(credential.user!);
|
||||
_updateState(AuthState.authenticated(user, isFirebaseConfigured: true));
|
||||
_updateAuthenticatedUser(credential.user!);
|
||||
}
|
||||
} catch (e) {
|
||||
_updateState(AuthState.error(
|
||||
|
|
@ -188,16 +214,29 @@ class FirebaseAuthService implements AuthService {
|
|||
));
|
||||
|
||||
try {
|
||||
final credential = await auth.createUserWithEmailAndPassword(
|
||||
email: email.trim(),
|
||||
final normalizedEmail = email.trim();
|
||||
final emailCredential = fb.EmailAuthProvider.credential(
|
||||
email: normalizedEmail,
|
||||
password: password,
|
||||
);
|
||||
|
||||
fb.UserCredential credential;
|
||||
if (_hasAnonymousFirebaseUser) {
|
||||
// Upgrade the existing anonymous UID rather than creating a second
|
||||
// account. This keeps prior guest-owned cloud data attached to the user.
|
||||
credential = await auth.currentUser!.linkWithCredential(emailCredential);
|
||||
} else {
|
||||
credential = await auth.createUserWithEmailAndPassword(
|
||||
email: normalizedEmail,
|
||||
password: password,
|
||||
);
|
||||
}
|
||||
|
||||
if (credential.user != null) {
|
||||
if (displayName != null && displayName.trim().isNotEmpty) {
|
||||
await credential.user!.updateDisplayName(displayName.trim());
|
||||
}
|
||||
final user = _mapFirebaseUser(credential.user!);
|
||||
_updateState(AuthState.authenticated(user, isFirebaseConfigured: true));
|
||||
_updateAuthenticatedUser(credential.user!);
|
||||
}
|
||||
} catch (e) {
|
||||
_updateState(AuthState.error(
|
||||
|
|
@ -231,7 +270,14 @@ class FirebaseAuthService implements AuthService {
|
|||
|
||||
if (googleUser == null) {
|
||||
// User cancelled the sign-in modal/flow
|
||||
_updateState(_currentState.copyWith(status: _currentState.user != null ? AuthStatus.authenticated : AuthStatus.unauthenticated, clearError: true));
|
||||
_updateState(_currentState.copyWith(
|
||||
status: _currentState.user != null
|
||||
? (_currentState.user!.isAnonymous
|
||||
? AuthStatus.anonymous
|
||||
: AuthStatus.authenticated)
|
||||
: AuthStatus.unauthenticated,
|
||||
clearError: true,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -241,10 +287,17 @@ class FirebaseAuthService implements AuthService {
|
|||
idToken: googleAuth.idToken,
|
||||
);
|
||||
|
||||
final result = await auth.signInWithCredential(credential);
|
||||
fb.UserCredential result;
|
||||
if (_hasAnonymousFirebaseUser) {
|
||||
// Critical: link the Google provider to the existing anonymous user.
|
||||
// Do not call signInWithCredential here or the guest UID can be replaced.
|
||||
result = await auth.currentUser!.linkWithCredential(credential);
|
||||
} else {
|
||||
result = await auth.signInWithCredential(credential);
|
||||
}
|
||||
|
||||
if (result.user != null) {
|
||||
final user = _mapFirebaseUser(result.user!);
|
||||
_updateState(AuthState.authenticated(user, isFirebaseConfigured: true));
|
||||
_updateAuthenticatedUser(result.user!);
|
||||
}
|
||||
} catch (e) {
|
||||
_updateState(AuthState.error(
|
||||
|
|
@ -358,7 +411,11 @@ class FirebaseAuthService implements AuthService {
|
|||
case 'invalid-credential':
|
||||
return 'Invalid credentials. Please verify your email and password.';
|
||||
case 'email-already-in-use':
|
||||
return 'An account already exists with this email address.';
|
||||
return 'An account already exists with this email address. Sign in to that account instead.';
|
||||
case 'credential-already-in-use':
|
||||
return 'This Google account is already linked to another MotorSignal account. Sign in with that account instead of replacing the current guest account.';
|
||||
case 'provider-already-linked':
|
||||
return 'This sign-in provider is already linked to the current account.';
|
||||
case 'invalid-email':
|
||||
return 'The email address format is invalid.';
|
||||
case 'weak-password':
|
||||
|
|
|
|||
Loading…
Reference in New Issue