Added My Schedule tab in attendance screen
Allow 1 Day, Whole Week and Date Range swapping
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
@@ -53,6 +55,20 @@ final dutySchedulesProvider = StreamProvider<List<DutySchedule>>((ref) {
|
||||
);
|
||||
|
||||
ref.onDispose(wrapper.dispose);
|
||||
|
||||
// Immediate poll so any changes that happened while this provider was
|
||||
// not alive (e.g. a swap was accepted on another device) are reflected
|
||||
// right away — before the 3-second periodic timer fires.
|
||||
wrapper.pollNow();
|
||||
|
||||
// Periodic safety-net: keep polling every 3 s so that ownership changes
|
||||
// (swap accepted → user_id updated on duty_schedules) are always picked
|
||||
// up even if Supabase Realtime misses the event.
|
||||
final dutyRefreshTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
||||
wrapper.pollNow();
|
||||
});
|
||||
ref.onDispose(dutyRefreshTimer.cancel);
|
||||
|
||||
return wrapper.stream.map((result) => result.data);
|
||||
});
|
||||
|
||||
@@ -127,6 +143,7 @@ final swapRequestsProvider = StreamProvider<List<SwapRequest>>((ref) {
|
||||
final data = await client
|
||||
.from('swap_requests')
|
||||
.select()
|
||||
.inFilter('status', ['pending', 'admin_review'])
|
||||
.order('created_at', ascending: false);
|
||||
return data.map(SwapRequest.fromMap).toList();
|
||||
},
|
||||
@@ -136,13 +153,28 @@ final swapRequestsProvider = StreamProvider<List<SwapRequest>>((ref) {
|
||||
);
|
||||
|
||||
ref.onDispose(wrapper.dispose);
|
||||
|
||||
// Immediate poll: fetch fresh data right away so any status changes that
|
||||
// happened while this provider was not alive are reflected instantly,
|
||||
// before the 3-second periodic timer fires for the first time.
|
||||
wrapper.pollNow();
|
||||
|
||||
// Periodic safety-net: keep polling every 3 s to catch any status changes
|
||||
// that Supabase Realtime may have missed (e.g. when the swap_requests table
|
||||
// is not yet in the supabase_realtime publication).
|
||||
final refreshTimer = Timer.periodic(const Duration(seconds: 3), (_) {
|
||||
wrapper.pollNow();
|
||||
});
|
||||
ref.onDispose(refreshTimer.cancel);
|
||||
|
||||
return wrapper.stream.map((result) {
|
||||
// only return requests that are still actionable; once a swap has been
|
||||
// accepted or rejected we no longer need to bubble it up to the UI for
|
||||
// either party. admins still see "admin_review" rows so they can act on
|
||||
// escalated cases.
|
||||
return result.data.where((row) {
|
||||
if (!(row.requesterId == profileId || row.recipientId == profileId)) {
|
||||
// admins see all swaps; standard users only see swaps they're in
|
||||
if (!isAdmin && !(row.requesterId == profileId || row.recipientId == profileId)) {
|
||||
return false;
|
||||
}
|
||||
// only keep pending and admin_review statuses
|
||||
@@ -151,6 +183,20 @@ final swapRequestsProvider = StreamProvider<List<SwapRequest>>((ref) {
|
||||
});
|
||||
});
|
||||
|
||||
/// IDs of swap requests that were acted on locally (accepted, rejected, etc.).
|
||||
/// Kept as a global provider so the set survives tab switches — widget state
|
||||
/// is disposed when the user navigates away from My Schedule.
|
||||
final locallyRemovedSwapIdsProvider = StateProvider<Set<String>>((ref) => {});
|
||||
|
||||
/// IDs of duty_schedules owned by the current user that were created by an accepted swap.
|
||||
final swappedScheduleIdsProvider = Provider<Set<String>>((ref) {
|
||||
final schedules = ref.watch(dutySchedulesProvider).valueOrNull ?? [];
|
||||
return {
|
||||
for (final s in schedules)
|
||||
if (s.swapRequestId != null) s.id,
|
||||
};
|
||||
});
|
||||
|
||||
final workforceControllerProvider = Provider<WorkforceController>((ref) {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
return WorkforceController(client);
|
||||
|
||||
Reference in New Issue
Block a user