152 lines
4.2 KiB
Dart
152 lines
4.2 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:autos/data/models/user_model.dart';
|
|
import 'package:autos/data/repositories/user_repository_impl.dart';
|
|
import 'package:autos/data/sources/remote/api_service.dart';
|
|
import 'package:autos/domain/entities/user.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_riverpod/legacy.dart';
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
|
|
// Provide a single ApiService instance across the app
|
|
final apiServiceProvider = Provider<ApiService>((ref) => ApiService());
|
|
|
|
// Provide repository that depends on ApiService
|
|
final userRepositoryProvider = Provider<UserRepositoryImpl>(
|
|
(ref) => UserRepositoryImpl(ref.read(apiServiceProvider)),
|
|
);
|
|
|
|
// Manage user state
|
|
final loginProvider = StateNotifierProvider<UserNotifier, AsyncValue<User?>>((
|
|
ref,
|
|
) {
|
|
final repo = ref.read(userRepositoryProvider);
|
|
return UserNotifier(repo);
|
|
});
|
|
|
|
final signupProvider = StateNotifierProvider<UserNotifier, AsyncValue<User?>>((
|
|
ref,
|
|
) {
|
|
final repo = ref.read(userRepositoryProvider);
|
|
return UserNotifier(repo);
|
|
});
|
|
|
|
final userProvider = StateNotifierProvider<UserNotifier, AsyncValue<User?>>((
|
|
ref,
|
|
) {
|
|
final repo = ref.read(userRepositoryProvider);
|
|
return UserNotifier(repo);
|
|
});
|
|
|
|
final userDetailsProvider = FutureProvider<UserModel?>((ref) async {
|
|
final userAsync = ref.watch(userProvider);
|
|
|
|
// Waiting for login provider to finish
|
|
if (userAsync.isLoading) return null;
|
|
|
|
final user = userAsync.value;
|
|
if (user == null) return null;
|
|
|
|
// Fetch Full Details
|
|
final repo = ref.read(userRepositoryProvider);
|
|
return await repo.getUserDetails(user.id);
|
|
});
|
|
|
|
enum AuthAction { idle, login, signup }
|
|
|
|
class UserNotifier extends StateNotifier<AsyncValue<User?>> {
|
|
final UserRepositoryImpl repository;
|
|
final _storage = const FlutterSecureStorage();
|
|
static const _userKey = 'logged_in_user';
|
|
AuthAction lastAction = AuthAction.idle;
|
|
|
|
UserNotifier(this.repository) : super(const AsyncValue.data(null));
|
|
|
|
///Load saved user from storage (auto-login)
|
|
Future<void> loadUserFromStorage() async {
|
|
final jsonString = await _storage.read(key: _userKey);
|
|
if (jsonString != null) {
|
|
debugPrint("RESULT: $jsonString");
|
|
final jsonData = jsonDecode(jsonString);
|
|
final user = UserModel.fromJson(jsonData);
|
|
await Future.microtask(() {});
|
|
state = AsyncValue.data(user);
|
|
}
|
|
}
|
|
|
|
///Login
|
|
Future<void> login(String email, String password) async {
|
|
lastAction = AuthAction.login;
|
|
state = const AsyncValue.loading();
|
|
try {
|
|
final user = await repository.login(email, password);
|
|
// ✅ Save user to secure storage
|
|
if (user is UserModel) {
|
|
await _storage.write(key: _userKey, value: user.toRawJson());
|
|
}
|
|
state = AsyncValue.data(user);
|
|
} catch (e, st) {
|
|
state = AsyncValue.error(e, st);
|
|
}
|
|
}
|
|
|
|
/// Logout
|
|
Future<void> logout() async {
|
|
await _storage.delete(key: _userKey);
|
|
state = const AsyncValue.data(null);
|
|
}
|
|
|
|
///Sign up
|
|
Future<void> signup(
|
|
String name,
|
|
String email,
|
|
String password,
|
|
String phone,
|
|
) async {
|
|
lastAction = AuthAction.signup;
|
|
state = const AsyncValue.loading();
|
|
try {
|
|
final user = await repository.signup(name, email, password, phone);
|
|
state = AsyncValue.data(user);
|
|
} catch (e, st) {
|
|
state = AsyncValue.error(e, st);
|
|
}
|
|
}
|
|
|
|
///Reset password
|
|
Future<void> sendPasswordResetLink(String email) async {
|
|
state = const AsyncValue.loading();
|
|
try {
|
|
await repository.sendPasswordResetLink(email);
|
|
state = const AsyncValue.data(null);
|
|
} catch (e, st) {
|
|
state = AsyncValue.error(e, st);
|
|
}
|
|
}
|
|
|
|
/// Fetch user details from backend
|
|
Future<void> getUserDetails(String userId) async {
|
|
state = const AsyncValue.loading();
|
|
|
|
try {
|
|
final user = await repository.getUserDetails(userId);
|
|
|
|
// Save full details separately
|
|
await saveUserDetails(user);
|
|
|
|
state = AsyncValue.data(user);
|
|
} catch (e, st) {
|
|
state = AsyncValue.error(e, st);
|
|
}
|
|
}
|
|
|
|
/// Save full user details separately
|
|
Future<void> saveUserDetails(UserModel user) async {
|
|
await _storage.write(
|
|
key: 'logged_in_user_details',
|
|
value: user.toRawJson(),
|
|
);
|
|
}
|
|
}
|