feat: implement SMS OTP auth and fix access_token key

- verifyPhoneNumber / verifyPhoneNumberForLink: call POST /auth/send-otp
- signInWithOTP: pass code to POST /auth/phone, use access_token key
- linkPhoneWithOTP: pass code to POST /auth/verify-phone
- login / register: fix token key data['token'] → data['access_token']

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-25 15:26:47 -05:00
co-authored by Claude Sonnet 4.6
parent a4a6099722
commit f941270bd9
+19 -9
View File
@@ -24,7 +24,7 @@ class AuthProvider extends ChangeNotifier {
Future<void> login(String email, String password) async {
try {
final data = await _api.post('/auth/login', {'email': email, 'password': password});
await _api.saveToken(data['token'] as String);
await _api.saveToken(data['access_token'] as String);
user = Usuario.fromDocument(data['user'] as Map<String, dynamic>);
userAverageScore = await _loadAverageScore(user!.id);
authStatus = AuthStatus.authenticated;
@@ -44,7 +44,7 @@ class AuthProvider extends ChangeNotifier {
'password': password,
'name': name.trim(),
});
await _api.saveToken(data['token'] as String);
await _api.saveToken(data['access_token'] as String);
user = Usuario.fromDocument(data['user'] as Map<String, dynamic>);
authStatus = AuthStatus.authenticated;
notifyListeners();
@@ -57,13 +57,18 @@ class AuthProvider extends ChangeNotifier {
}
Future<void> verifyPhoneNumber(String phoneNumber) async {
// ponytail: backend does direct login by phone, no OTP step
try {
await _api.post('/auth/send-otp', {'phone': phoneNumber});
} catch (e) {
NotificationsService.showSnackBarError('Error al enviar código SMS');
rethrow;
}
}
Future<void> signInWithOTP(String phoneNumber, String smsCode) async {
try {
final data = await _api.post('/auth/phone', {'phone': phoneNumber});
await _api.saveToken(data['token'] as String);
final data = await _api.post('/auth/phone', {'phone': phoneNumber, 'code': smsCode});
await _api.saveToken(data['access_token'] as String);
user = Usuario.fromDocument(data['user'] as Map<String, dynamic>);
authStatus = AuthStatus.authenticated;
notifyListeners();
@@ -71,24 +76,29 @@ class AuthProvider extends ChangeNotifier {
} catch (e) {
authStatus = AuthStatus.notAuthenticated;
notifyListeners();
NotificationsService.showSnackBarError('Error al iniciar sesión con teléfono');
NotificationsService.showSnackBarError('Código incorrecto o expirado');
}
}
Future<void> verifyPhoneNumberForLink(String phoneNumber) async {
// ponytail: no OTP step, linkPhoneWithOTP does the actual call
try {
await _api.post('/auth/send-otp', {'phone': phoneNumber});
} catch (e) {
NotificationsService.showSnackBarError('Error al enviar código SMS');
rethrow;
}
}
Future<void> linkPhoneWithOTP(String phoneNumber, String smsCode) async {
try {
await _api.post('/auth/verify-phone', {'phone': phoneNumber});
await _api.post('/auth/verify-phone', {'phone': phoneNumber, 'code': smsCode});
user = await _fetchMe();
NotificationsService.showSnackbar('Número vinculado exitosamente');
authStatus = AuthStatus.authenticated;
notifyListeners();
NavigationService.replaceTo(Flurorouter.profileRoute);
} catch (e) {
NotificationsService.showSnackBarError('Error al vincular teléfono');
NotificationsService.showSnackBarError('Código incorrecto o expirado');
}
}