Initial commit: DLS - Dental Lab System
- Flutter + PocketBase dental lab management system - Clinic & lab dashboards, job tracking, patient management - Product catalog, finance tracking, multi-language support - AI assistant integration, realtime notifications - Windows installer (Inno Setup) included - Developed by kovakyazilim.com
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
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)),
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user