128 lines
3.6 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)),
);
/// ✅ ✅ ✅ SINGLE GLOBAL USER PROVIDER (ONLY ONE YOU SHOULD USE)
final userProvider =
StateNotifierProvider<UserNotifier, AsyncValue<User?>>((ref) {
final repo = ref.read(userRepositoryProvider);
return UserNotifier(ref, repo);
});
enum AuthAction { idle, login, signup }
class UserNotifier extends StateNotifier<AsyncValue<User?>> {
final Ref ref;
final UserRepositoryImpl repository;
final _storage = const FlutterSecureStorage();
static const _userKey = 'logged_in_user';
AuthAction lastAction = AuthAction.idle;
UserNotifier(this.ref, this.repository)
: super(const AsyncValue.data(null));
// ✅ ✅ AUTO LOGIN ON APP START
Future<void> loadUserFromStorage() async {
final jsonString = await _storage.read(key: _userKey);
if (jsonString == null) {
state = const AsyncValue.data(null);
return;
}
final jsonData = jsonDecode(jsonString);
final user = UserModel.fromJson(jsonData);
state = AsyncValue.data(user);
}
// ✅ ✅ LOGIN FLOW (FULLY SYNCHRONIZED)
Future<void> login(String email, String password) async {
lastAction = AuthAction.login;
try {
state = const AsyncValue.loading();
// 1⃣ Login API (partial user)
final partialUser = await repository.login(email, password);
// 2⃣ Fetch FULL user details
final fullUser = await repository.getUserDetails(partialUser.id);
// 3⃣ Store FULL user in secure storage ✅
await _storage.write(key: _userKey, value: fullUser.toRawJson());
// 4⃣ Update provider ONCE with FULL data ✅
state = AsyncValue.data(fullUser);
} catch (e, st) {
state = AsyncValue.error(e, st);
}
}
// ✅ ✅ SIGNUP
Future<void> signup(
String name,
String email,
String password,
String phone,
) async {
lastAction = AuthAction.signup;
try {
state = const AsyncValue.loading();
// ✅ 1⃣ Signup → returns USER ENTITY
final user = await repository.signup(name, email, password, phone);
// ✅ 2⃣ Convert User → UserModel for storage
final userModel = UserModel.fromEntity(user);
// ✅ 3⃣ Store safely
await _storage.write(
key: _userKey,
value: userModel.toRawJson(),
);
// ✅ 4⃣ Update provider state
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);
}
// ✅ ✅ PASSWORD RESET
Future<void> sendPasswordResetLink(String email) async {
try {
state = const AsyncValue.loading();
await repository.sendPasswordResetLink(email);
state = const AsyncValue.data(null);
} catch (e, st) {
state = AsyncValue.error(e, st);
}
}
}