import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../l10n/app_localizations.dart'; import '../l10n/app_localizations_helpers.dart'; import '../models/remote_command.dart'; import '../utils/navigation.dart'; import '../viewmodels/admin_pin_view_model.dart'; import '../viewmodels/remote_sync_view_model.dart'; import 'dialogs/new_tab_dialog.dart'; class AdminScreenView extends StatelessWidget { const AdminScreenView({super.key}); void _leave(BuildContext context) { final adminPinViewModel = context.read(); context.popOrGo('/bar'); adminPinViewModel.lock(); } Future _openNewTab(BuildContext context) async { final l10n = AppLocalizations.of(context); final name = await showNewTabDialog(context); if (name == null || !context.mounted) return; ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(l10n.tabOpened(name)))); } Future _confirmUnlink(BuildContext context) async { final l10n = AppLocalizations.of(context); final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(l10n.disconnectFromServer), content: Text(l10n.disconnectFromServerDescription), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: Text(l10n.cancel), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), style: FilledButton.styleFrom( backgroundColor: Theme.of(ctx).colorScheme.error, foregroundColor: Theme.of(ctx).colorScheme.onError, ), child: Text(l10n.disconnect), ), ], ), ); if (confirmed == true && context.mounted) { await context.read().unlink(); } } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final remoteSync = context.watch(); final scheme = Theme.of(context).colorScheme; final locale = Localizations.localeOf(context).toLanguageTag(); return PopScope( onPopInvokedWithResult: (didPop, result) { if (didPop) context.read().lock(); }, child: Scaffold( appBar: AppBar( leading: IconButton( onPressed: () => _leave(context), icon: const Icon(Icons.arrow_back), ), title: Text(l10n.admin), actions: [ IconButton( tooltip: l10n.logout, onPressed: () { final adminPinViewModel = context.read(); context.go('/bar'); adminPinViewModel.lock(); }, icon: const Icon(Icons.logout), ), ], ), body: ListView( padding: const EdgeInsets.symmetric(vertical: 12), children: [ _AdminSection( title: l10n.adminTools, children: [ _AdminTile( icon: Icons.person_add_alt_1_outlined, title: l10n.openNewTab, subtitle: l10n.openNewTabDescription, onTap: () => _openNewTab(context), ), _AdminTile( icon: Icons.inventory_2_outlined, title: l10n.products, subtitle: l10n.manageProducts, onTap: () => context.push('/products'), ), _AdminTile( icon: Icons.history_rounded, title: l10n.tabHistory, subtitle: l10n.closedTabs, onTap: () => context.push('/history'), ), ], ), const SizedBox(height: 8), _AdminSection( title: l10n.remoteServer, children: [ if (remoteSync.isConfigured) ...[ _AdminTile( icon: Icons.cloud_done_outlined, iconColor: scheme.primary, title: l10n.connected, subtitle: remoteSync.venueName != null ? l10n.deviceLinkedToVenue(remoteSync.venueName!) : l10n.deviceLinked, trailing: TextButton( onPressed: () => _confirmUnlink(context), style: TextButton.styleFrom( foregroundColor: scheme.error, ), child: Text(l10n.disconnect), ), onTap: null, ), ] else _AdminTile( icon: remoteSync.wasRevoked ? Icons.cloud_off_rounded : Icons.cloud_outlined, iconColor: remoteSync.wasRevoked ? scheme.error : null, title: l10n.notConnected, subtitle: remoteSync.wasRevoked ? l10n.deviceAccessRevoked : l10n.linkToDashboard, onTap: () => context.push('/register'), ), ], ), if (remoteSync.isConfigured) ...[ const SizedBox(height: 8), _AdminSection( title: l10n.remoteActivity, children: [ _AdminTile( icon: Icons.sync, title: l10n.syncNow, subtitle: remoteSync.isSyncing ? l10n.syncing : remoteSync.lastSyncAt != null ? l10n.lastSync( l10n.relativeTime(remoteSync.lastSyncAt!, locale), ) : l10n.notSyncedYet, trailing: remoteSync.isSyncing ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : null, onTap: () => remoteSync.syncNow(), ), ], ), if (remoteSync.activity.isNotEmpty) _AdminSection( title: l10n.remoteActivityHistory, children: [ for (final entry in remoteSync.activity) _AdminTile( icon: switch (entry.result) { CommandResult.completed => Icons.check_circle_outline, CommandResult.conflict => Icons.warning_amber_outlined, CommandResult.failed || CommandResult.expired => Icons.error_outline, }, iconColor: switch (entry.result) { CommandResult.completed => scheme.primary, CommandResult.conflict => scheme.tertiary, CommandResult.failed || CommandResult.expired => scheme.error, }, title: l10n.remoteCommandLabel(entry.commandType), subtitle: '${l10n.commandResultLabel(entry.result)} ยท ' '${l10n.relativeTime(entry.processedAt, locale)}', onTap: null, ), ], ), ], ], ), ), ); } } class _AdminSection extends StatelessWidget { final String title; final List children; const _AdminSection({required this.title, required this.children}); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title.toUpperCase(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, letterSpacing: 0.5, color: scheme.onSurface.withValues(alpha: 0.5), ), ), const SizedBox(height: 8), Container( decoration: BoxDecoration( color: scheme.onSurface.withValues(alpha: 0.04), borderRadius: BorderRadius.circular(14), border: Border.all( color: scheme.onSurface.withValues(alpha: 0.06), ), ), clipBehavior: Clip.antiAlias, child: Column(children: children), ), ], ), ); } } class _AdminTile extends StatelessWidget { final IconData icon; final Color? iconColor; final String title; final String? subtitle; final Widget? trailing; final VoidCallback? onTap; const _AdminTile({ required this.icon, this.iconColor, required this.title, this.subtitle, this.trailing, required this.onTap, }); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Material( color: Colors.transparent, child: InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ Icon( icon, size: 22, color: iconColor ?? scheme.onSurface.withValues(alpha: 0.7), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontWeight: FontWeight.w600, color: scheme.onSurface, ), ), if (subtitle != null) Text( subtitle!, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: scheme.onSurface.withValues(alpha: 0.5), ), ), ], ), ), if (trailing != null) ...[const SizedBox(width: 8), trailing!], if (onTap != null) Icon( Icons.chevron_right_rounded, color: scheme.onSurface.withValues(alpha: 0.3), ), ], ), ), ), ); } }