Initial Commit: Duty Schedule and Attendance Logbook
This commit is contained in:
@@ -81,3 +81,22 @@ class AppSetting {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RamadanConfig {
|
||||
RamadanConfig({required this.enabled, required this.autoDetect});
|
||||
|
||||
final bool enabled;
|
||||
final bool autoDetect;
|
||||
|
||||
factory RamadanConfig.fromJson(Map<String, dynamic> json) {
|
||||
return RamadanConfig(
|
||||
enabled: json['enabled'] as bool? ?? false,
|
||||
autoDetect: json['auto_detect'] as bool? ?? true,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'enabled': enabled,
|
||||
'auto_detect': autoDetect,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import '../utils/app_time.dart';
|
||||
|
||||
class AttendanceLog {
|
||||
AttendanceLog({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.dutyScheduleId,
|
||||
required this.checkInAt,
|
||||
required this.checkInLat,
|
||||
required this.checkInLng,
|
||||
this.checkOutAt,
|
||||
this.checkOutLat,
|
||||
this.checkOutLng,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String userId;
|
||||
final String dutyScheduleId;
|
||||
final DateTime checkInAt;
|
||||
final double checkInLat;
|
||||
final double checkInLng;
|
||||
final DateTime? checkOutAt;
|
||||
final double? checkOutLat;
|
||||
final double? checkOutLng;
|
||||
|
||||
bool get isCheckedOut => checkOutAt != null;
|
||||
|
||||
factory AttendanceLog.fromMap(Map<String, dynamic> map) {
|
||||
return AttendanceLog(
|
||||
id: map['id'] as String,
|
||||
userId: map['user_id'] as String,
|
||||
dutyScheduleId: map['duty_schedule_id'] as String,
|
||||
checkInAt: AppTime.parse(map['check_in_at'] as String),
|
||||
checkInLat: (map['check_in_lat'] as num).toDouble(),
|
||||
checkInLng: (map['check_in_lng'] as num).toDouble(),
|
||||
checkOutAt: map['check_out_at'] == null
|
||||
? null
|
||||
: AppTime.parse(map['check_out_at'] as String),
|
||||
checkOutLat: (map['check_out_lat'] as num?)?.toDouble(),
|
||||
checkOutLng: (map['check_out_lng'] as num?)?.toDouble(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import '../utils/app_time.dart';
|
||||
|
||||
class ChatMessage {
|
||||
ChatMessage({
|
||||
required this.id,
|
||||
required this.threadId,
|
||||
required this.senderId,
|
||||
required this.body,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String threadId;
|
||||
final String senderId;
|
||||
final String body;
|
||||
final DateTime createdAt;
|
||||
|
||||
factory ChatMessage.fromMap(Map<String, dynamic> map) {
|
||||
return ChatMessage(
|
||||
id: map['id'] as String,
|
||||
threadId: map['thread_id'] as String,
|
||||
senderId: map['sender_id'] as String,
|
||||
body: map['body'] as String,
|
||||
createdAt: AppTime.parse(map['created_at'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'thread_id': threadId,
|
||||
'sender_id': senderId,
|
||||
'body': body,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import '../utils/app_time.dart';
|
||||
|
||||
class LivePosition {
|
||||
LivePosition({
|
||||
required this.userId,
|
||||
required this.lat,
|
||||
required this.lng,
|
||||
required this.updatedAt,
|
||||
required this.inPremise,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
final double lat;
|
||||
final double lng;
|
||||
final DateTime updatedAt;
|
||||
final bool inPremise;
|
||||
|
||||
factory LivePosition.fromMap(Map<String, dynamic> map) {
|
||||
return LivePosition(
|
||||
userId: map['user_id'] as String,
|
||||
lat: (map['lat'] as num).toDouble(),
|
||||
lng: (map['lng'] as num).toDouble(),
|
||||
updatedAt: AppTime.parse(map['updated_at'] as String),
|
||||
inPremise: map['in_premise'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import '../utils/app_time.dart';
|
||||
|
||||
class PassSlip {
|
||||
PassSlip({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.dutyScheduleId,
|
||||
required this.reason,
|
||||
required this.status,
|
||||
required this.requestedAt,
|
||||
this.approvedBy,
|
||||
this.approvedAt,
|
||||
this.slipStart,
|
||||
this.slipEnd,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String userId;
|
||||
final String dutyScheduleId;
|
||||
final String reason;
|
||||
final String status; // 'pending', 'approved', 'rejected', 'completed'
|
||||
final DateTime requestedAt;
|
||||
final String? approvedBy;
|
||||
final DateTime? approvedAt;
|
||||
final DateTime? slipStart;
|
||||
final DateTime? slipEnd;
|
||||
|
||||
/// Whether the slip is active (approved but not yet completed).
|
||||
bool get isActive => status == 'approved' && slipEnd == null;
|
||||
|
||||
/// Whether the active slip has exceeded 1 hour.
|
||||
bool get isExceeded =>
|
||||
isActive &&
|
||||
slipStart != null &&
|
||||
AppTime.now().difference(slipStart!) > const Duration(hours: 1);
|
||||
|
||||
factory PassSlip.fromMap(Map<String, dynamic> map) {
|
||||
return PassSlip(
|
||||
id: map['id'] as String,
|
||||
userId: map['user_id'] as String,
|
||||
dutyScheduleId: map['duty_schedule_id'] as String,
|
||||
reason: map['reason'] as String,
|
||||
status: map['status'] as String? ?? 'pending',
|
||||
requestedAt: AppTime.parse(map['requested_at'] as String),
|
||||
approvedBy: map['approved_by'] as String?,
|
||||
approvedAt: map['approved_at'] == null
|
||||
? null
|
||||
: AppTime.parse(map['approved_at'] as String),
|
||||
slipStart: map['slip_start'] == null
|
||||
? null
|
||||
: AppTime.parse(map['slip_start'] as String),
|
||||
slipEnd: map['slip_end'] == null
|
||||
? null
|
||||
: AppTime.parse(map['slip_end'] as String),
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -1,15 +1,25 @@
|
||||
class Profile {
|
||||
Profile({required this.id, required this.role, required this.fullName});
|
||||
Profile({
|
||||
required this.id,
|
||||
required this.role,
|
||||
required this.fullName,
|
||||
this.religion = 'catholic',
|
||||
this.allowTracking = false,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String role;
|
||||
final String fullName;
|
||||
final String religion;
|
||||
final bool allowTracking;
|
||||
|
||||
factory Profile.fromMap(Map<String, dynamic> map) {
|
||||
return Profile(
|
||||
id: map['id'] as String,
|
||||
role: map['role'] as String? ?? 'standard',
|
||||
fullName: map['full_name'] as String? ?? '',
|
||||
religion: map['religion'] as String? ?? 'catholic',
|
||||
allowTracking: map['allow_tracking'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user