import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../providers/dashboard_providers.dart'; import '../../../widgets/error_view.dart'; import '../../../core/providers/auth_provider.dart'; class TeamScreen extends ConsumerWidget { const TeamScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final async = ref.watch(teamProvider); final myRole = ref.watch(authProvider).employee?.role ?? ''; final isOwner = myRole == 'OWNER'; return Scaffold( appBar: AppBar(title: const Text('Team')), floatingActionButton: isOwner ? FloatingActionButton.extended( onPressed: () async { final invited = await showModalBottomSheet( context: context, isScrollControlled: true, useSafeArea: true, builder: (_) => const _InviteSheet(), ); if (invited == true) ref.invalidate(teamProvider); }, icon: const Icon(Icons.person_add_outlined), label: const Text('Invite'), ) : null, body: async.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => ErrorView( message: 'Failed to load team', onRetry: () => ref.invalidate(teamProvider), ), data: (members) { if (members.isEmpty) { return const Center( child: Text('No team members', style: TextStyle(color: Color(0xFF9CA3AF))), ); } return RefreshIndicator( onRefresh: () async => ref.invalidate(teamProvider), child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), itemCount: members.length, separatorBuilder: (_, _) => const SizedBox(height: 8), itemBuilder: (_, i) => _MemberCard( member: members[i], isOwner: isOwner, onDeactivate: () async { await ref .read(teamServiceProvider) .deactivateMember(members[i].id); ref.invalidate(teamProvider); }, onReactivate: () async { await ref .read(teamServiceProvider) .reactivateMember(members[i].id); ref.invalidate(teamProvider); }, onRoleChange: (role) async { await ref .read(teamServiceProvider) .updateRole(members[i].id, role); ref.invalidate(teamProvider); }, ), ), ); }, ), ); } } class _MemberCard extends StatelessWidget { final dynamic member; final bool isOwner; final VoidCallback onDeactivate; final VoidCallback onReactivate; final ValueChanged onRoleChange; const _MemberCard({ required this.member, required this.isOwner, required this.onDeactivate, required this.onReactivate, required this.onRoleChange, }); @override Widget build(BuildContext context) { final isActive = member.isActive as bool; final role = member.role as String; return Card( child: Padding( padding: const EdgeInsets.all(14), child: Row( children: [ CircleAvatar( backgroundColor: isActive ? const Color(0xFFE1EFFE) : const Color(0xFFF3F4F6), radius: 22, child: Text( (member.firstName as String) .substring(0, 1) .toUpperCase(), style: TextStyle( color: isActive ? const Color(0xFF1A56DB) : const Color(0xFF9CA3AF), fontWeight: FontWeight.bold, ), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( member.fullName as String, style: TextStyle( fontWeight: FontWeight.w600, color: isActive ? null : const Color(0xFF9CA3AF), ), ), const SizedBox(width: 8), _RoleBadge(role: role), ], ), Text( member.email as String, style: const TextStyle( fontSize: 12, color: Color(0xFF6B7280)), ), if (!isActive) const Text( 'Inactive', style: TextStyle( fontSize: 11, color: Color(0xFF9CA3AF)), ), ], ), ), if (isOwner && role != 'OWNER') PopupMenuButton( onSelected: (v) { if (v == 'deactivate') onDeactivate(); if (v == 'reactivate') onReactivate(); if (v == 'MANAGER' || v == 'AGENT') onRoleChange(v); }, itemBuilder: (_) => [ if (role != 'MANAGER') const PopupMenuItem( value: 'MANAGER', child: Text('Make Manager')), if (role != 'AGENT') const PopupMenuItem( value: 'AGENT', child: Text('Make Agent')), const PopupMenuDivider(), if (isActive) const PopupMenuItem( value: 'deactivate', child: Text('Deactivate', style: TextStyle(color: Color(0xFFE02424))), ) else const PopupMenuItem( value: 'reactivate', child: Text('Reactivate', style: TextStyle(color: Color(0xFF0E9F6E))), ), ], ), ], ), ), ); } } class _RoleBadge extends StatelessWidget { final String role; const _RoleBadge({required this.role}); @override Widget build(BuildContext context) { final colors = { 'OWNER': (const Color(0xFFFFF3CD), const Color(0xFF92400E)), 'MANAGER': (const Color(0xFFE1EFFE), const Color(0xFF1E40AF)), 'AGENT': (const Color(0xFFF3F4F6), const Color(0xFF374151)), }; final (bg, fg) = colors[role] ?? (const Color(0xFFF3F4F6), const Color(0xFF374151)); return Container( padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2), decoration: BoxDecoration(color: bg, borderRadius: BorderRadius.circular(4)), child: Text(role, style: TextStyle( fontSize: 10, color: fg, fontWeight: FontWeight.w600)), ); } } class _InviteSheet extends ConsumerStatefulWidget { const _InviteSheet(); @override ConsumerState<_InviteSheet> createState() => _InviteSheetState(); } class _InviteSheetState extends ConsumerState<_InviteSheet> { final _formKey = GlobalKey(); bool _loading = false; final _firstName = TextEditingController(); final _lastName = TextEditingController(); final _email = TextEditingController(); String _role = 'AGENT'; @override void dispose() { for (final c in [_firstName, _lastName, _email]) { c.dispose(); } super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() => _loading = true); try { await ref.read(teamServiceProvider).inviteMember({ 'firstName': _firstName.text.trim(), 'lastName': _lastName.text.trim(), 'email': _email.text.trim(), 'role': _role, }); if (mounted) Navigator.of(context).pop(true); } catch (e) { if (mounted) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text('Error: $e'))); } } finally { if (mounted) setState(() => _loading = false); } } @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), child: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Text('Invite Team Member', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const Spacer(), if (_loading) const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2)) else TextButton( onPressed: _submit, child: const Text('Invite')), ], ), const SizedBox(height: 16), TextFormField( controller: _firstName, decoration: const InputDecoration(labelText: 'First Name'), validator: (v) => v == null || v.isEmpty ? 'Required' : null, ), const SizedBox(height: 12), TextFormField( controller: _lastName, decoration: const InputDecoration(labelText: 'Last Name'), validator: (v) => v == null || v.isEmpty ? 'Required' : null, ), const SizedBox(height: 12), TextFormField( controller: _email, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(labelText: 'Email'), validator: (v) => v == null || v.isEmpty ? 'Required' : null, ), const SizedBox(height: 12), InputDecorator( decoration: const InputDecoration(labelText: 'Role'), child: DropdownButton( value: _role, isExpanded: true, underline: const SizedBox(), items: const [ DropdownMenuItem(value: 'MANAGER', child: Text('Manager')), DropdownMenuItem(value: 'AGENT', child: Text('Agent')), ], onChanged: (v) => setState(() => _role = v!), ), ), const SizedBox(height: 20), ElevatedButton( onPressed: _loading ? null : _submit, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(48)), child: const Text('Send Invitation'), ), ], ), ), ), ); } }