Attendance validation involving Location Detection + Facial Recoginition with Liveness Detection
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import '../models/leave_of_absence.dart';
|
||||
import 'profile_provider.dart';
|
||||
import 'supabase_provider.dart';
|
||||
import 'stream_recovery.dart';
|
||||
import 'realtime_controller.dart';
|
||||
|
||||
/// All visible leaves (own for standard, all for admin/dispatcher/it_staff).
|
||||
final leavesProvider = StreamProvider<List<LeaveOfAbsence>>((ref) {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
final profileAsync = ref.watch(currentProfileProvider);
|
||||
final profile = profileAsync.valueOrNull;
|
||||
if (profile == null) return Stream.value(const <LeaveOfAbsence>[]);
|
||||
|
||||
final hasFullAccess =
|
||||
profile.role == 'admin' ||
|
||||
profile.role == 'dispatcher' ||
|
||||
profile.role == 'it_staff';
|
||||
|
||||
final wrapper = StreamRecoveryWrapper<LeaveOfAbsence>(
|
||||
stream: hasFullAccess
|
||||
? client
|
||||
.from('leave_of_absence')
|
||||
.stream(primaryKey: ['id'])
|
||||
.order('start_time', ascending: false)
|
||||
: client
|
||||
.from('leave_of_absence')
|
||||
.stream(primaryKey: ['id'])
|
||||
.eq('user_id', profile.id)
|
||||
.order('start_time', ascending: false),
|
||||
onPollData: () async {
|
||||
final query = client.from('leave_of_absence').select();
|
||||
final data = hasFullAccess
|
||||
? await query.order('start_time', ascending: false)
|
||||
: await query
|
||||
.eq('user_id', profile.id)
|
||||
.order('start_time', ascending: false);
|
||||
return data.map(LeaveOfAbsence.fromMap).toList();
|
||||
},
|
||||
fromMap: LeaveOfAbsence.fromMap,
|
||||
channelName: 'leave_of_absence',
|
||||
onStatusChanged: ref.read(realtimeControllerProvider).handleChannelStatus,
|
||||
);
|
||||
|
||||
ref.onDispose(wrapper.dispose);
|
||||
return wrapper.stream.map((result) => result.data);
|
||||
});
|
||||
|
||||
final leaveControllerProvider = Provider<LeaveController>((ref) {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
return LeaveController(client);
|
||||
});
|
||||
|
||||
class LeaveController {
|
||||
LeaveController(this._client);
|
||||
|
||||
final SupabaseClient _client;
|
||||
|
||||
/// File a leave of absence for the current user.
|
||||
/// Caller controls auto-approval based on role policy.
|
||||
Future<void> fileLeave({
|
||||
required String leaveType,
|
||||
required String justification,
|
||||
required DateTime startTime,
|
||||
required DateTime endTime,
|
||||
required bool autoApprove,
|
||||
}) async {
|
||||
final uid = _client.auth.currentUser!.id;
|
||||
await _client.from('leave_of_absence').insert({
|
||||
'user_id': uid,
|
||||
'leave_type': leaveType,
|
||||
'justification': justification,
|
||||
'start_time': startTime.toIso8601String(),
|
||||
'end_time': endTime.toIso8601String(),
|
||||
'status': autoApprove ? 'approved' : 'pending',
|
||||
'filed_by': uid,
|
||||
});
|
||||
}
|
||||
|
||||
/// Approve a leave request.
|
||||
Future<void> approveLeave(String leaveId) async {
|
||||
await _client
|
||||
.from('leave_of_absence')
|
||||
.update({'status': 'approved'})
|
||||
.eq('id', leaveId);
|
||||
}
|
||||
|
||||
/// Reject a leave request.
|
||||
Future<void> rejectLeave(String leaveId) async {
|
||||
await _client
|
||||
.from('leave_of_absence')
|
||||
.update({'status': 'rejected'})
|
||||
.eq('id', leaveId);
|
||||
}
|
||||
|
||||
/// Cancel an approved leave.
|
||||
Future<void> cancelLeave(String leaveId) async {
|
||||
await _client
|
||||
.from('leave_of_absence')
|
||||
.update({'status': 'cancelled'})
|
||||
.eq('id', leaveId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user