import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../models/group_model.dart'; import '../providers/group_provider.dart'; import '../theme/app_theme.dart'; import '../widgets/app_sidebar.dart'; import '../widgets/responsive_layout.dart'; class GroupsScreen extends StatefulWidget { const GroupsScreen({super.key}); @override State createState() => _GroupsScreenState(); } class _GroupsScreenState extends State { final _searchCtrl = TextEditingController(); String _search = ''; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadGroups(); }); } @override void dispose() { _searchCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return ResponsiveLayout( title: 'گروه‌ها', sidebar: const AppSidebar(), body: _GroupsBody( search: _search, searchCtrl: _searchCtrl, onSearch: (v) => setState(() => _search = v.toLowerCase()), ), ); } } class _GroupsBody extends StatelessWidget { final String search; final TextEditingController searchCtrl; final ValueChanged onSearch; const _GroupsBody({ required this.search, required this.searchCtrl, required this.onSearch, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── Header ─────────────────────────────────────────────── Row( children: [ const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'مدیریت گروه‌ها', style: TextStyle( fontSize: 24, fontWeight: FontWeight.w800, color: AppTheme.textPrimary, ), ), SizedBox(height: 4), Text( 'ایجاد و مدیریت گروه‌های ارتباطی', style: TextStyle( fontSize: 14, color: AppTheme.textSecondary), ), ], ), ), ElevatedButton.icon( onPressed: () => _showCreateDialog(context), icon: const Icon(Icons.group_add_rounded, size: 18), label: const Text('گروه جدید'), ), ], ), const SizedBox(height: 20), // ── Search ─────────────────────────────────────────────── TextField( controller: searchCtrl, onChanged: onSearch, decoration: const InputDecoration( hintText: 'جستجوی گروه...', prefixIcon: Icon(Icons.search_rounded), ), ), const SizedBox(height: 16), // ── Table ──────────────────────────────────────────────── Expanded( child: Consumer( builder: (_, provider, __) { if (provider.isLoading) { return const Center(child: CircularProgressIndicator()); } if (provider.status == LoadStatus.error) { return _ErrorView( message: provider.error ?? 'خطا', onRetry: () => provider.loadGroups(), ); } final filtered = provider.groups .where((g) => search.isEmpty || g.name.toLowerCase().contains(search)) .toList(); if (filtered.isEmpty) { return const _EmptyView( icon: Icons.groups_outlined, message: 'گروهی یافت نشد', ); } return _GroupsTable(groups: filtered); }, ), ), ], ), ); } void _showCreateDialog(BuildContext context) { showDialog( context: context, builder: (_) => const _CreateGroupDialog(), ); } } // ── Create Group Dialog ────────────────────────────────────────────────────── class _CreateGroupDialog extends StatefulWidget { const _CreateGroupDialog(); @override State<_CreateGroupDialog> createState() => _CreateGroupDialogState(); } class _CreateGroupDialogState extends State<_CreateGroupDialog> { final _formKey = GlobalKey(); final _nameCtrl = TextEditingController(); bool _loading = false; String? _error; @override void dispose() { _nameCtrl.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() { _loading = true; _error = null; }); final provider = context.read(); final group = await provider.createGroup( _nameCtrl.text.trim(), ); if (!mounted) return; setState(() => _loading = false); if (group != null) { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('گروه «${group.name}» با موفقیت ایجاد شد'), backgroundColor: AppTheme.success, ), ); } else { setState(() => _error = provider.error); } } @override Widget build(BuildContext context) { return AlertDialog( title: const Row( children: [ Icon(Icons.group_add_rounded, color: AppTheme.primary), SizedBox(width: 10), Text('ایجاد گروه جدید'), ], ), content: SizedBox( width: 400, child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: _nameCtrl, decoration: const InputDecoration( labelText: 'نام گروه', prefixIcon: Icon(Icons.groups_rounded), ), validator: (v) => (v == null || v.trim().isEmpty) ? 'نام گروه الزامی است' : null, ), if (_error != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppTheme.danger.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(8), border: Border.all( color: AppTheme.danger.withValues(alpha: 0.3)), ), child: Text( _error!, style: const TextStyle(color: AppTheme.danger, fontSize: 13), ), ), ], ], ), ), ), actions: [ TextButton( onPressed: _loading ? null : () => Navigator.of(context).pop(), child: const Text('انصراف'), ), ElevatedButton( onPressed: _loading ? null : _submit, child: _loading ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2)) : const Text('ایجاد'), ), ], ); } } // ── Groups Table ───────────────────────────────────────────────────────────── class _GroupsTable extends StatelessWidget { final List groups; const _GroupsTable({required this.groups}); @override Widget build(BuildContext context) { return Card( child: ClipRRect( borderRadius: BorderRadius.circular(12), child: SingleChildScrollView( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( columns: const [ DataColumn(label: Text('نام گروه')), DataColumn(label: Text('نوع')), DataColumn(label: Text('وضعیت')), DataColumn(label: Text('عملیات')), ], rows: groups.map((g) => _buildRow(context, g)).toList(), ), ), ), ), ); } DataRow _buildRow(BuildContext context, GroupModel group) { return DataRow( cells: [ DataCell( Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 34, height: 34, decoration: BoxDecoration( color: const Color(0xFF7C3AED).withValues(alpha: 0.12), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.groups_rounded, color: Color(0xFF7C3AED), size: 18, ), ), const SizedBox(width: 10), Text( group.name, style: const TextStyle(fontWeight: FontWeight.w600), ), ], ), ), DataCell( Text( group.type.label, style: const TextStyle(color: AppTheme.textSecondary), ), ), DataCell(_StatusBadge(isActive: group.isActive)), DataCell( TextButton.icon( onPressed: () => context.go('/groups/${group.id}'), icon: const Icon(Icons.arrow_forward_rounded, size: 16), label: const Text('جزئیات'), ), ), ], ); } } // ── Shared small widgets ───────────────────────────────────────────────────── class _StatusBadge extends StatelessWidget { final bool isActive; const _StatusBadge({required this.isActive}); @override Widget build(BuildContext context) { final color = isActive ? AppTheme.success : AppTheme.danger; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 6, height: 6, decoration: BoxDecoration(color: color, shape: BoxShape.circle), ), const SizedBox(width: 5), Text( isActive ? 'فعال' : 'غیرفعال', style: TextStyle( color: color, fontSize: 12, fontWeight: FontWeight.w600, ), ), ], ), ); } } class _EmptyView extends StatelessWidget { final IconData icon; final String message; const _EmptyView({required this.icon, required this.message}); @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, size: 64, color: AppTheme.border), const SizedBox(height: 16), Text( message, style: const TextStyle(color: AppTheme.textSecondary, fontSize: 16), ), ], ), ); } } class _ErrorView extends StatelessWidget { final String message; final VoidCallback onRetry; const _ErrorView({required this.message, required this.onRetry}); @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline_rounded, size: 64, color: AppTheme.danger), const SizedBox(height: 16), Text(message, style: const TextStyle(color: AppTheme.textSecondary)), const SizedBox(height: 16), ElevatedButton.icon( onPressed: onRetry, icon: const Icon(Icons.refresh_rounded), label: const Text('تلاش مجدد'), ), ], ), ); } }