import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import '../models/pass_slip.dart'; import 'profile_provider.dart'; import 'supabase_provider.dart'; import 'stream_recovery.dart'; import 'realtime_controller.dart'; /// All visible pass slips (own for staff, all for admin/dispatcher). final passSlipsProvider = StreamProvider>((ref) { final client = ref.watch(supabaseClientProvider); final profileAsync = ref.watch(currentProfileProvider); final profile = profileAsync.valueOrNull; if (profile == null) return Stream.value(const []); final isAdmin = profile.role == 'admin' || profile.role == 'dispatcher'; final wrapper = StreamRecoveryWrapper( stream: isAdmin ? client .from('pass_slips') .stream(primaryKey: ['id']) .order('requested_at', ascending: false) : client .from('pass_slips') .stream(primaryKey: ['id']) .eq('user_id', profile.id) .order('requested_at', ascending: false), onPollData: () async { final query = client.from('pass_slips').select(); final data = isAdmin ? await query.order('requested_at', ascending: false) : await query .eq('user_id', profile.id) .order('requested_at', ascending: false); return data.map(PassSlip.fromMap).toList(); }, fromMap: PassSlip.fromMap, channelName: 'pass_slips', onStatusChanged: ref.read(realtimeControllerProvider).handleChannelStatus, ); ref.onDispose(wrapper.dispose); return wrapper.stream.map((result) => result.data); }); /// Currently active pass slip for the logged-in user (approved, not completed). final activePassSlipProvider = Provider((ref) { final slips = ref.watch(passSlipsProvider).valueOrNull ?? []; final userId = ref.watch(currentUserIdProvider); if (userId == null) return null; try { return slips.firstWhere((s) => s.userId == userId && s.isActive); } catch (_) { return null; } }); /// Active pass slips for all users (for dashboard IT Staff Pulse). final activePassSlipsProvider = Provider>((ref) { final slips = ref.watch(passSlipsProvider).valueOrNull ?? []; return slips.where((s) => s.isActive).toList(); }); final passSlipControllerProvider = Provider((ref) { final client = ref.watch(supabaseClientProvider); return PassSlipController(client); }); class PassSlipController { PassSlipController(this._client); final SupabaseClient _client; Future requestSlip({ required String dutyScheduleId, required String reason, }) async { final userId = _client.auth.currentUser?.id; if (userId == null) throw Exception('Not authenticated'); await _client.from('pass_slips').insert({ 'user_id': userId, 'duty_schedule_id': dutyScheduleId, 'reason': reason, }); } Future approveSlip(String slipId) async { final userId = _client.auth.currentUser?.id; if (userId == null) throw Exception('Not authenticated'); await _client .from('pass_slips') .update({ 'status': 'approved', 'approved_by': userId, 'approved_at': DateTime.now().toUtc().toIso8601String(), 'slip_start': DateTime.now().toUtc().toIso8601String(), }) .eq('id', slipId); } Future rejectSlip(String slipId) async { await _client .from('pass_slips') .update({ 'status': 'rejected', 'approved_by': _client.auth.currentUser?.id, 'approved_at': DateTime.now().toUtc().toIso8601String(), }) .eq('id', slipId); } Future completeSlip(String slipId) async { await _client .from('pass_slips') .update({ 'status': 'completed', 'slip_end': DateTime.now().toUtc().toIso8601String(), }) .eq('id', slipId); } }