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:
steinhelge
2025-11-24 20:52:27 +01:00
commit c829f78984
148 changed files with 8462 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
import 'package:cloud_firestore/cloud_firestore.dart';
enum DeviationType {
dailyMax,
weeklyMax,
dailyRest,
weeklyRest,
averageExceeded,
nightWork,
}
enum DeviationSeverity {
warning,
violation,
}
class DeviationMetadata {
final double actualValue;
final double limitValue;
final String? period;
DeviationMetadata({
required this.actualValue,
required this.limitValue,
this.period,
});
factory DeviationMetadata.fromMap(Map<String, dynamic> map) {
return DeviationMetadata(
actualValue: (map['actualValue'] ?? 0).toDouble(),
limitValue: (map['limitValue'] ?? 0).toDouble(),
period: map['period'],
);
}
Map<String, dynamic> toMap() {
return {
'actualValue': actualValue,
'limitValue': limitValue,
'period': period,
};
}
}
class Deviation {
final String id;
final String userId;
final String organizationId;
final String timeRegistrationId;
final DeviationType type;
final DeviationSeverity severity;
final String description;
final DateTime detectedAt;
final DateTime? acknowledgedAt;
final String? acknowledgedBy;
final DeviationMetadata metadata;
Deviation({
required this.id,
required this.userId,
required this.organizationId,
required this.timeRegistrationId,
required this.type,
required this.severity,
required this.description,
required this.detectedAt,
this.acknowledgedAt,
this.acknowledgedBy,
required this.metadata,
});
factory Deviation.fromFirestore(DocumentSnapshot doc) {
final data = doc.data() as Map<String, dynamic>;
return Deviation(
id: doc.id,
userId: data['userId'] ?? '',
organizationId: data['organizationId'] ?? '',
timeRegistrationId: data['timeRegistrationId'] ?? '',
type: _parseType(data['type']),
severity: _parseSeverity(data['severity']),
description: data['description'] ?? '',
detectedAt: (data['detectedAt'] as Timestamp).toDate(),
acknowledgedAt: data['acknowledgedAt'] != null
? (data['acknowledgedAt'] as Timestamp).toDate()
: null,
acknowledgedBy: data['acknowledgedBy'],
metadata: DeviationMetadata.fromMap(data['metadata'] ?? {}),
);
}
Map<String, dynamic> toFirestore() {
return {
'userId': userId,
'organizationId': organizationId,
'timeRegistrationId': timeRegistrationId,
'type': type.name,
'severity': severity.name,
'description': description,
'detectedAt': Timestamp.fromDate(detectedAt),
'acknowledgedAt':
acknowledgedAt != null ? Timestamp.fromDate(acknowledgedAt!) : null,
'acknowledgedBy': acknowledgedBy,
'metadata': metadata.toMap(),
};
}
static DeviationType _parseType(String? typeString) {
switch (typeString) {
case 'dailyMax':
return DeviationType.dailyMax;
case 'weeklyMax':
return DeviationType.weeklyMax;
case 'dailyRest':
return DeviationType.dailyRest;
case 'weeklyRest':
return DeviationType.weeklyRest;
case 'averageExceeded':
return DeviationType.averageExceeded;
case 'nightWork':
return DeviationType.nightWork;
default:
return DeviationType.dailyMax;
}
}
static DeviationSeverity _parseSeverity(String? severityString) {
switch (severityString) {
case 'violation':
return DeviationSeverity.violation;
default:
return DeviationSeverity.warning;
}
}
String get typeDisplayName {
switch (type) {
case DeviationType.dailyMax:
return 'Maks daglig arbeidstid';
case DeviationType.weeklyMax:
return 'Maks ukentlig arbeidstid';
case DeviationType.dailyRest:
return 'Daglig hviletid';
case DeviationType.weeklyRest:
return 'Ukentlig hviletid';
case DeviationType.averageExceeded:
return 'Gjennomsnittsberegning overskredet';
case DeviationType.nightWork:
return 'Nattarbeid';
}
}
bool get isAcknowledged => acknowledgedAt != null;
Deviation copyWith({
String? userId,
String? organizationId,
String? timeRegistrationId,
DeviationType? type,
DeviationSeverity? severity,
String? description,
DateTime? detectedAt,
DateTime? acknowledgedAt,
String? acknowledgedBy,
DeviationMetadata? metadata,
}) {
return Deviation(
id: id,
userId: userId ?? this.userId,
organizationId: organizationId ?? this.organizationId,
timeRegistrationId: timeRegistrationId ?? this.timeRegistrationId,
type: type ?? this.type,
severity: severity ?? this.severity,
description: description ?? this.description,
detectedAt: detectedAt ?? this.detectedAt,
acknowledgedAt: acknowledgedAt ?? this.acknowledgedAt,
acknowledgedBy: acknowledgedBy ?? this.acknowledgedBy,
metadata: metadata ?? this.metadata,
);
}
}