import 'package:flutter/material.dart'; import '../../theme/app_theme.dart'; import '../services/market_history_admin_api.dart'; enum AdminGateStatus { loading, authorized, forbidden, unauthorized, error } /// Probes admin API access before showing [child]. /// /// Calls `GET /v1/admin/market-history/sync-runs?limit=1`. /// Returns 403 → not authorized UI; 200 → [child]. class AdminGate extends StatefulWidget { const AdminGate({ super.key, required this.child, this.api, }); final Widget child; final MarketHistoryAdminApi? api; @override State createState() => _AdminGateState(); } class _AdminGateState extends State { AdminGateStatus _status = AdminGateStatus.loading; String? _errorMessage; @override void initState() { super.initState(); _probe(); } Future _probe() async { final MarketHistoryAdminApi api = widget.api ?? MarketHistoryAdminApi(); try { await api.fetchSyncRuns(limit: 1); if (!mounted) { return; } setState(() => _status = AdminGateStatus.authorized); } on MarketHistoryAdminApiException catch (e) { if (!mounted) { return; } setState(() { _errorMessage = e.message; _status = switch (e.statusCode) { 401 => AdminGateStatus.unauthorized, 403 => AdminGateStatus.forbidden, _ => AdminGateStatus.error, }; }); } catch (e) { if (!mounted) { return; } setState(() { _status = AdminGateStatus.error; _errorMessage = e.toString(); }); } } @override Widget build(BuildContext context) { return switch (_status) { AdminGateStatus.loading => const Scaffold( key: Key('admin-gate-loading'), body: Center( child: CircularProgressIndicator(color: AppColors.accent), ), ), AdminGateStatus.authorized => widget.child, AdminGateStatus.forbidden => _messageScaffold( key: const Key('admin-gate-forbidden'), title: 'Not authorized', message: 'Your account does not have admin access.', icon: Icons.lock_outline, ), AdminGateStatus.unauthorized => _messageScaffold( key: const Key('admin-gate-unauthorized'), title: 'Sign in required', message: 'Sign in again to access the admin portal.', icon: Icons.login, ), AdminGateStatus.error => _messageScaffold( key: const Key('admin-gate-error'), title: 'Admin check failed', message: _errorMessage ?? 'Unknown error', icon: Icons.error_outline, showRetry: true, ), }; } Widget _messageScaffold({ required Key key, required String title, required String message, required IconData icon, bool showRetry = false, }) { return Scaffold( key: key, appBar: AppBar(title: const Text('Admin portal')), body: Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 40, color: AppColors.textSecondary), const SizedBox(height: 12), Text( title, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( message, style: const TextStyle(color: AppColors.textSecondary), textAlign: TextAlign.center, ), if (showRetry) ...[ const SizedBox(height: 16), FilledButton( onPressed: () { setState(() => _status = AdminGateStatus.loading); _probe(); }, child: const Text('Retry'), ), ], ], ), ), ), ); } }