Initial commit: TimeReg Flutter app med Firebase backend
- Opprettet Flutter-prosjekt med alle nødvendige avhengigheter - Implementert datamodeller (User, TimeRegistration, TariffProfile, Deviation, AuditLog) - Implementert tjenester (AuthService, TimeService) - Implementert Riverpod providers for state management - Opprettet autentiseringsskjermer (login, signup, reset password) - Opprettet hjemmeskjerm med timer-funksjonalitet - Opprettet placeholder-skjermer for historikk, rapporter og profil - Lagt til norsk dokumentasjon i README
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import '../models/user_model.dart';
|
||||
|
||||
class AuthService {
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
|
||||
// Hent nåværende bruker
|
||||
User? get currentUser => _auth.currentUser;
|
||||
|
||||
// Stream av autentiseringstilstand
|
||||
Stream<User?> get authStateChanges => _auth.authStateChanges();
|
||||
|
||||
// Registrer ny bruker med e-post og passord
|
||||
Future<UserCredential> signUpWithEmail({
|
||||
required String email,
|
||||
required String password,
|
||||
required String displayName,
|
||||
required String organizationId,
|
||||
String? departmentId,
|
||||
}) async {
|
||||
try {
|
||||
// Opprett bruker i Firebase Auth
|
||||
final userCredential = await _auth.createUserWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
// Oppdater displayName
|
||||
await userCredential.user?.updateDisplayName(displayName);
|
||||
|
||||
// Opprett brukerdata i Firestore
|
||||
await _createUserDocument(
|
||||
uid: userCredential.user!.uid,
|
||||
email: email,
|
||||
displayName: displayName,
|
||||
organizationId: organizationId,
|
||||
departmentId: departmentId,
|
||||
);
|
||||
|
||||
return userCredential;
|
||||
} on FirebaseAuthException catch (e) {
|
||||
throw _handleAuthException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Logg inn med e-post og passord
|
||||
Future<UserCredential> signInWithEmail({
|
||||
required String email,
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
return await _auth.signInWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
} on FirebaseAuthException catch (e) {
|
||||
throw _handleAuthException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Tilbakestill passord
|
||||
Future<void> resetPassword(String email) async {
|
||||
try {
|
||||
await _auth.sendPasswordResetEmail(email: email);
|
||||
} on FirebaseAuthException catch (e) {
|
||||
throw _handleAuthException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Logg ut
|
||||
Future<void> signOut() async {
|
||||
await _auth.signOut();
|
||||
}
|
||||
|
||||
// Hent brukerdata fra Firestore
|
||||
Future<UserModel?> getUserData(String uid) async {
|
||||
try {
|
||||
final doc = await _firestore.collection('users').doc(uid).get();
|
||||
if (doc.exists) {
|
||||
return UserModel.fromFirestore(doc);
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
throw Exception('Kunne ikke hente brukerdata: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Stream av brukerdata
|
||||
Stream<UserModel?> userDataStream(String uid) {
|
||||
return _firestore
|
||||
.collection('users')
|
||||
.doc(uid)
|
||||
.snapshots()
|
||||
.map((doc) => doc.exists ? UserModel.fromFirestore(doc) : null);
|
||||
}
|
||||
|
||||
// Opprett brukerdokument i Firestore
|
||||
Future<void> _createUserDocument({
|
||||
required String uid,
|
||||
required String email,
|
||||
required String displayName,
|
||||
required String organizationId,
|
||||
String? departmentId,
|
||||
}) async {
|
||||
// Hent standard tariffprofil for organisasjonen
|
||||
final defaultProfile = await _getDefaultTariffProfile(organizationId);
|
||||
|
||||
final userData = UserModel(
|
||||
uid: uid,
|
||||
email: email,
|
||||
displayName: displayName,
|
||||
role: UserRole.employee,
|
||||
tariffProfileId: defaultProfile,
|
||||
organizationId: organizationId,
|
||||
departmentId: departmentId,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
preferences: UserPreferences(),
|
||||
);
|
||||
|
||||
await _firestore.collection('users').doc(uid).set(userData.toFirestore());
|
||||
}
|
||||
|
||||
// Hent standard tariffprofil for organisasjon
|
||||
Future<String> _getDefaultTariffProfile(String organizationId) async {
|
||||
final query = await _firestore
|
||||
.collection('tariff_profiles')
|
||||
.where('organizationId', isEqualTo: organizationId)
|
||||
.where('isDefault', isEqualTo: true)
|
||||
.limit(1)
|
||||
.get();
|
||||
|
||||
if (query.docs.isNotEmpty) {
|
||||
return query.docs.first.id;
|
||||
}
|
||||
|
||||
// Hvis ingen standard profil finnes, returner en placeholder
|
||||
return 'default_aml';
|
||||
}
|
||||
|
||||
// Håndter Firebase Auth exceptions
|
||||
String _handleAuthException(FirebaseAuthException e) {
|
||||
switch (e.code) {
|
||||
case 'weak-password':
|
||||
return 'Passordet er for svakt';
|
||||
case 'email-already-in-use':
|
||||
return 'E-postadressen er allerede i bruk';
|
||||
case 'invalid-email':
|
||||
return 'Ugyldig e-postadresse';
|
||||
case 'user-not-found':
|
||||
return 'Ingen bruker funnet med denne e-postadressen';
|
||||
case 'wrong-password':
|
||||
return 'Feil passord';
|
||||
case 'user-disabled':
|
||||
return 'Denne brukerkontoen er deaktivert';
|
||||
case 'too-many-requests':
|
||||
return 'For mange forsøk. Prøv igjen senere';
|
||||
case 'operation-not-allowed':
|
||||
return 'Denne operasjonen er ikke tillatt';
|
||||
default:
|
||||
return 'En feil oppstod: ${e.message}';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user