import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/endpoints/admin_invites.dart'; import '../api/endpoints/admin_quarantine.dart'; import '../api/endpoints/admin_requests.dart'; import '../api/endpoints/admin_users.dart'; import '../library/library_providers.dart' show dioProvider; import '../models/admin_request.dart'; import '../models/admin_user.dart'; final adminRequestsApiProvider = FutureProvider((ref) async { return AdminRequestsApi(await ref.watch(dioProvider.future)); }); final adminQuarantineApiProvider = FutureProvider((ref) async { return AdminQuarantineApi(await ref.watch(dioProvider.future)); }); final adminUsersApiProvider = FutureProvider((ref) async { return AdminUsersApi(await ref.watch(dioProvider.future)); }); final adminInvitesApiProvider = FutureProvider((ref) async { return AdminInvitesApi(await ref.watch(dioProvider.future)); }); class AdminCounts { const AdminCounts({ required this.requests, required this.quarantine, required this.users, }); final int requests; final int quarantine; final int users; } /// Fans out to the three list endpoints in parallel and rolls them up /// into `{requests, quarantine, users}` for the landing screen badges. final adminCountsProvider = FutureProvider((ref) async { final requestsApi = await ref.watch(adminRequestsApiProvider.future); final quarantineApi = await ref.watch(adminQuarantineApiProvider.future); final usersApi = await ref.watch(adminUsersApiProvider.future); final results = await Future.wait([ requestsApi.list(), quarantineApi.list(), usersApi.list(), ]); return AdminCounts( requests: (results[0] as List).length, quarantine: (results[1] as List).length, users: (results[2] as List).length, ); }); class AdminRequestsController extends AsyncNotifier> { @override Future> build() async { final api = await ref.watch(adminRequestsApiProvider.future); return api.list(); } Future approve(String id) async { await _decide(id, (api) => api.approve(id)); } Future reject(String id) async { await _decide(id, (api) => api.reject(id)); } Future _decide( String id, Future Function(AdminRequestsApi api) action, ) async { final api = await ref.read(adminRequestsApiProvider.future); final current = state.value ?? const []; state = AsyncData(current.where((r) => r.id != id).toList()); try { await action(api); // Refresh landing badge. ref.invalidate(adminCountsProvider); } catch (e, st) { state = AsyncData(current); Error.throwWithStackTrace(e, st); } } } final adminRequestsProvider = AsyncNotifierProvider>( AdminRequestsController.new); /// Read side defined here so the Requests screen can join requester /// UUID → username for display. Mutation methods (setAdmin, /// setAutoApprove, resetPassword, delete) are appended in Slice 3 /// alongside the Users screen. class AdminUsersController extends AsyncNotifier> { @override Future> build() async { final api = await ref.watch(adminUsersApiProvider.future); return api.list(); } } final adminUsersProvider = AsyncNotifierProvider>( AdminUsersController.new);