Files
lab-app/lib/core/providers/auth_provider.dart
T
2026-06-10 23:22:15 +03:00

196 lines
5.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/widgets.dart' show Locale;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pocketbase/pocketbase.dart';
import '../auth/auth_repository.dart';
import '../services/notification_service.dart';
import '../../models/tenant.dart';
import '../../models/user_profile.dart';
import 'locale_provider.dart';
class AuthState {
const AuthState({
this.profile,
this.activeTenant,
this.memberships = const [],
this.isLoading = true,
this.error,
});
final UserProfile? profile;
final TenantMembership? activeTenant;
final List<TenantMembership> memberships;
final bool isLoading;
final String? error;
bool get isAuthenticated => profile != null;
AuthState copyWith({
UserProfile? profile,
TenantMembership? activeTenant,
List<TenantMembership>? memberships,
bool? isLoading,
String? error,
bool clearError = false,
}) =>
AuthState(
profile: profile ?? this.profile,
activeTenant: activeTenant ?? this.activeTenant,
memberships: memberships ?? this.memberships,
isLoading: isLoading ?? this.isLoading,
error: clearError ? null : (error ?? this.error),
);
}
class AuthNotifier extends StateNotifier<AuthState> {
AuthNotifier({this.onLocaleLoaded}) : super(const AuthState()) {
_init();
}
final void Function(String languageCode)? onLocaleLoaded;
final _repo = AuthRepository.instance;
Future<void> _init() async {
final loggedIn = await _repo.isLoggedIn();
if (!loggedIn) {
state = const AuthState(isLoading: false);
return;
}
try {
final result = await _repo.refreshSession();
state = AuthState(
profile: result.user,
memberships: result.tenants,
activeTenant:
result.tenants.isEmpty ? null : result.tenants.first,
isLoading: false,
);
final isLab = result.tenants.isNotEmpty && result.tenants.first.tenant.isLab;
NotificationService.loginUser(result.user.id, isLab: isLab);
_applyLocale(result.user.preferredLanguage);
} catch (_) {
state = const AuthState(isLoading: false);
}
}
void _applyLocale(String? code) {
if (code != null && code.isNotEmpty) {
onLocaleLoaded?.call(code);
}
}
Future<void> signIn(String email, String password) async {
state = state.copyWith(isLoading: true, clearError: true);
try {
final result = await _repo.login(email, password);
state = AuthState(
profile: result.user,
memberships: result.tenants,
activeTenant:
result.tenants.isEmpty ? null : result.tenants.first,
isLoading: false,
);
final isLab = result.tenants.isNotEmpty && result.tenants.first.tenant.isLab;
NotificationService.loginUser(result.user.id, isLab: isLab);
_applyLocale(result.user.preferredLanguage);
} catch (e) {
state = state.copyWith(isLoading: false, error: _parseError(e));
}
}
Future<void> register({
required String email,
required String password,
String? firstName,
String? lastName,
}) async {
state = state.copyWith(isLoading: true, clearError: true);
try {
final result = await _repo.register(
email: email,
password: password,
firstName: firstName,
lastName: lastName,
);
state = AuthState(
profile: result.user,
memberships: result.tenants,
activeTenant:
result.tenants.isEmpty ? null : result.tenants.first,
isLoading: false,
);
} catch (e) {
state = state.copyWith(isLoading: false, error: _parseError(e));
rethrow;
}
}
Future<void> signOut() async {
await _repo.logout();
await NotificationService.logoutUser();
state = const AuthState(isLoading: false);
}
void setActiveTenant(TenantMembership membership) {
state = state.copyWith(activeTenant: membership);
}
Future<void> refresh() async {
try {
final result = await _repo.refreshSession();
final currentId = state.activeTenant?.tenant.id;
final newActive = currentId != null
? result.tenants.firstWhere(
(m) => m.tenant.id == currentId,
orElse: () => result.tenants.isNotEmpty
? result.tenants.first
: state.activeTenant!,
)
: (result.tenants.isNotEmpty ? result.tenants.first : null);
state = state.copyWith(
profile: result.user,
memberships: result.tenants,
activeTenant: newActive,
);
} catch (_) {}
}
Future<void> updateLanguage(String languageCode) async {
final userId = state.profile?.id;
if (userId == null) return;
await _repo.updateUserLanguage(userId, languageCode);
}
Future<void> updateTenantInfo({
required String tenantId,
required String companyName,
String? defaultCurrency,
}) async {
await _repo.updateTenant(
tenantId,
companyName: companyName,
defaultCurrency: defaultCurrency,
);
await refresh();
}
String _parseError(Object e) {
if (e is ClientException) {
final code = e.statusCode;
if (code == 400 || code == 401 || code == 403) {
return 'E-posta veya şifre hatalı.';
}
final msg = e.response['message'] as String? ?? '';
if (msg.isNotEmpty) return msg;
}
return 'Bağlantı hatası. Lütfen tekrar deneyin.';
}
}
final authProvider =
StateNotifierProvider<AuthNotifier, AuthState>((ref) {
return AuthNotifier(
onLocaleLoaded: (code) =>
ref.read(localeProvider.notifier).setLocale(Locale(code)),
);
});