Initial commit: Eventify frontend
This commit is contained in:
141
lib/features/auth/services/auth_service.dart
Normal file
141
lib/features/auth/services/auth_service.dart
Normal file
@@ -0,0 +1,141 @@
|
||||
// lib/features/auth/services/auth_service.dart
|
||||
import 'package:flutter/foundation.dart' show kDebugMode, debugPrint;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../core/api/api_client.dart';
|
||||
import '../../../core/api/api_endpoints.dart';
|
||||
import '../../../core/storage/token_storage.dart';
|
||||
import '../models/user_model.dart';
|
||||
|
||||
class AuthService {
|
||||
final ApiClient _api = ApiClient();
|
||||
|
||||
/// LOGIN → returns UserModel
|
||||
Future<UserModel> login(String username, String password) async {
|
||||
try {
|
||||
final res = await _api.post(
|
||||
ApiEndpoints.login,
|
||||
body: {
|
||||
"username": username,
|
||||
"password": password,
|
||||
},
|
||||
requiresAuth: false,
|
||||
);
|
||||
|
||||
final token = res['token'];
|
||||
if (token == null) {
|
||||
throw Exception('Token missing from response');
|
||||
}
|
||||
|
||||
final serverUsername = (res['username'] is String && (res['username'] as String).isNotEmpty) ? res['username'] as String : null;
|
||||
final serverEmail = (res['email'] is String && (res['email'] as String).isNotEmpty) ? res['email'] as String : null;
|
||||
// savedEmail is the canonical identifier for this account
|
||||
final savedEmail = serverEmail ?? username;
|
||||
// candidate display name (server username or email fallback)
|
||||
final displayCandidate = serverUsername ?? savedEmail;
|
||||
|
||||
// save token (TokenStorage stays responsible for token)
|
||||
await TokenStorage.saveToken(token.toString(), savedEmail);
|
||||
|
||||
// persist per-account fields in SharedPreferences
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
// mark current logged-in account
|
||||
await prefs.setString('current_email', savedEmail);
|
||||
// always keep a canonical 'email' pointing to current user's email for old callers
|
||||
await prefs.setString('email', savedEmail);
|
||||
// save per-account display name (do not overwrite an explicit per-account display name if already set)
|
||||
final perKey = 'display_name_$savedEmail';
|
||||
final existingPer = prefs.getString(perKey);
|
||||
if (existingPer == null || existingPer.trim().isEmpty) {
|
||||
await prefs.setString(perKey, displayCandidate);
|
||||
}
|
||||
// save server-provided email (if any) separately too
|
||||
if (serverEmail != null) await prefs.setString('server_email', serverEmail);
|
||||
|
||||
// Save phone if provided (optional)
|
||||
if (res['phone_number'] != null) await prefs.setString('phone_number', res['phone_number'].toString());
|
||||
|
||||
return UserModel.fromJson(res);
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('AuthService.login error: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// REGISTER → returns UserModel
|
||||
Future<UserModel> register({
|
||||
required String email,
|
||||
required String phoneNumber,
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
final res = await _api.post(
|
||||
ApiEndpoints.register,
|
||||
body: {
|
||||
"email": email,
|
||||
"phone_number": phoneNumber,
|
||||
"password": password,
|
||||
},
|
||||
requiresAuth: false,
|
||||
);
|
||||
|
||||
final token = res['token'];
|
||||
if (token == null) {
|
||||
throw Exception('Token missing from response');
|
||||
}
|
||||
|
||||
final serverUsername = (res['username'] is String && (res['username'] as String).isNotEmpty) ? res['username'] as String : null;
|
||||
final serverEmail = (res['email'] is String && (res['email'] as String).isNotEmpty) ? res['email'] as String : null;
|
||||
final savedEmail = serverEmail ?? email;
|
||||
final savedUsername = serverUsername ?? savedEmail;
|
||||
final savedRole = (res['role'] ?? 'user').toString();
|
||||
final savedPhone = (res['phone_number'] ?? phoneNumber)?.toString();
|
||||
|
||||
// Save token + canonical user id for token storage
|
||||
await TokenStorage.saveToken(token.toString(), savedEmail);
|
||||
|
||||
// Persist per-account keys
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('current_email', savedEmail);
|
||||
await prefs.setString('email', savedEmail);
|
||||
|
||||
// Set display_name_<email> if not present yet
|
||||
final perKey = 'display_name_$savedEmail';
|
||||
final existing = prefs.getString(perKey);
|
||||
if (existing == null || existing.trim().isEmpty) {
|
||||
await prefs.setString(perKey, savedUsername);
|
||||
}
|
||||
|
||||
// Optionally save phone/email in prefs
|
||||
await prefs.setString('server_email', savedEmail);
|
||||
if (savedPhone != null) await prefs.setString('phone_number', savedPhone);
|
||||
|
||||
// Return a simple UserModel (defensive)
|
||||
return UserModel(
|
||||
username: savedUsername,
|
||||
email: savedEmail,
|
||||
role: savedRole,
|
||||
token: token.toString(),
|
||||
phoneNumber: savedPhone,
|
||||
);
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('AuthService.register error: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Logout – clear auth token and current_email (keep per-account display_name entries so they persist)
|
||||
Future<void> logout() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
// clear token storage (should delete token + auth headers)
|
||||
await TokenStorage.clear();
|
||||
// remove current_email marker so no previous account remains current
|
||||
await prefs.remove('current_email');
|
||||
// Also remove canonical 'email' pointing to current user
|
||||
await prefs.remove('email');
|
||||
// Do not delete display_name_<email> entries — they are per-account and should remain on device.
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('AuthService.logout warning: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user