import 'dart:async'; import 'package:flutter/material.dart'; import 'models/client.dart'; import 'models/activity.dart'; import 'models/app_stats.dart'; import 'screens/dashboard_screen.dart'; import 'screens/clients_screen.dart'; import 'screens/survey_screen.dart'; import 'screens/surveys_list_screen.dart'; import 'screens/pricing_screen.dart'; import 'services/crm_api_service.dart'; import 'services/auth_service.dart'; class AppShell extends StatefulWidget { final AuthUser currentUser; final VoidCallback onLogout; const AppShell({ super.key, required this.currentUser, required this.onLogout, }); @override State createState() => _AppShellState(); } class _AppShellState extends State { int _currentIndex = 0; bool _backendReady = false; List _clients = []; List _activities = []; List _surveys = []; List _pricing = []; AppStats _stats = const AppStats( totalClients: 0, avgVolume: 0, revenueOpportunity: 0, todayEntries: 0, pendingFollowups: 0, ); final _api = CrmApiService(); Timer? _pollingTimer; @override void initState() { super.initState(); _api.setToken(widget.currentUser.token); _loadFromBackend(); _startPolling(); } void _startPolling() { _pollingTimer = Timer.periodic(const Duration(seconds: 10), (_) { _loadFromBackend(silent: true); }); } @override void dispose() { _pollingTimer?.cancel(); super.dispose(); } Future _loadFromBackend({bool silent = false}) async { try { final results = await Future.wait([ _api.loadClients(), _api.fetchSurveys(), _api.fetchPricing(), ]); final clients = results[0] as List; final surveys = results[1]; final pricing = results[2]; if (!mounted) return; setState(() { _clients = clients; _surveys = surveys; _pricing = pricing; _stats = _computeStats(clients); _backendReady = true; }); } catch (_) { if (mounted && !silent) setState(() => _backendReady = false); } } AppStats _computeStats(List clients) { if (clients.isEmpty) { return const AppStats( totalClients: 0, avgVolume: 0, revenueOpportunity: 0, todayEntries: 0, pendingFollowups: 0, ); } final totalVolume = clients.fold(0.0, (acc, c) => acc + c.parcelVolume); final avg = (totalVolume / clients.length).round(); return AppStats( totalClients: clients.length, avgVolume: avg, revenueOpportunity: double.parse((totalVolume * 0.01).toStringAsFixed(2)), todayEntries: 0, pendingFollowups: clients.where((c) => c.dataConsent == DataConsent.basicOnly).length, ); } void _handleAddClient(Client incoming) async { final newClient = incoming.copyWith( recordedByName: widget.currentUser.name, recordedByEmail: widget.currentUser.email, recordedByRole: widget.currentUser.role, ); // Optimistic UI update with a temp ID setState(() { _clients = [newClient, ..._clients]; _activities = [ Activity( id: 'act_${DateTime.now().millisecondsSinceEpoch}', clientName: newClient.name, action: 'Survey submitted just now', icon: ActivityIcon.shipping, status: ActivityStatus.newStatus, ), ..._activities, ]; _stats = _computeStats(_clients); }); // Persist to backend and swap temp ID with server-assigned ID final saved = await _api.createClient(newClient); if (saved != null && mounted) { setState(() { _clients = _clients .map((c) => c.id == newClient.id ? saved : c) .toList(); }); } } void _handleUpdateNotes(String clientId, String newNotes) async { setState(() { _clients = _clients.map((c) { if (c.id == clientId) { return c.copyWith(notes: newNotes, lastUpdated: 'Updated just now'); } return c; }).toList(); final updated = _clients.firstWhere((c) => c.id == clientId); _activities = [ Activity( id: 'act_${DateTime.now().millisecondsSinceEpoch}', clientName: updated.name, action: 'Profile updated by Rep', icon: ActivityIcon.edit, ), ..._activities, ]; }); final updated = _clients.firstWhere((c) => c.id == clientId); await _api.updateClient(updated); } void _handleCompleteClientProfile( String clientId, double parcelVolume, int activeContracts, String provider, String notes, ) async { String efficiency = 'High Efficiency'; if (provider == 'Blue Dart Express') efficiency = 'Premium Service'; if (provider == 'Gati-KWE') efficiency = 'Cost Leader'; if (provider == 'Delhivery') efficiency = 'Local Last Mile'; setState(() { _clients = _clients.map((c) { if (c.id != clientId) return c; return c.copyWith( parcelVolume: parcelVolume, activeContracts: activeContracts, provider: provider, efficiency: efficiency, notes: notes, dataConsent: DataConsent.full, lastUpdated: 'Just now', surveySubmitted: true, recordedByName: widget.currentUser.name, recordedByEmail: widget.currentUser.email, recordedByRole: widget.currentUser.role, ); }).toList(); _stats = _computeStats(_clients); }); final updated = _clients.firstWhere((c) => c.id == clientId); await _api.updateClient(updated); } void _navigateTo(int index) { if (index == 4) { Navigator.push(context, MaterialPageRoute( builder: (ctx) => Scaffold( appBar: AppBar( backgroundColor: Colors.white, elevation: 0, iconTheme: const IconThemeData(color: Colors.black87), title: const Text('Add Client', style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold)), ), body: SurveyScreen( clients: _clients, onAddClient: _handleAddClient, onNavigate: (i) { Navigator.pop(ctx); _navigateTo(i); }, backendReady: _backendReady, isActive: true, ), ), )); return; } setState(() => _currentIndex = index); } @override Widget build(BuildContext context) { final screens = [ DashboardScreen( stats: _stats, activities: _activities, clients: _clients, surveys: _surveys, pricing: _pricing, onNavigate: _navigateTo, onDataChanged: _loadFromBackend, backendReady: _backendReady, onLogout: widget.onLogout, isActive: _currentIndex == 0, ), ClientsScreen( clients: _clients, onUpdateClientNotes: _handleUpdateNotes, onCompleteClientProfile: _handleCompleteClientProfile, onNavigate: _navigateTo, backendReady: _backendReady, isActive: _currentIndex == 1, ), SurveysListScreen( surveys: _surveys, onDataChanged: _loadFromBackend, isActive: _currentIndex == 2, ), PricingScreen( pricing: _pricing, backendReady: _backendReady, onDataChanged: _loadFromBackend, isActive: _currentIndex == 3, ), ]; return Scaffold( body: SafeArea( child: IndexedStack( index: _currentIndex, children: screens, ), ), bottomNavigationBar: NavigationBar( selectedIndex: _currentIndex, onDestinationSelected: _navigateTo, height: 68, destinations: const [ NavigationDestination(icon: Icon(Icons.dashboard_outlined), selectedIcon: Icon(Icons.dashboard), label: 'Home'), NavigationDestination(icon: Icon(Icons.people_outline), selectedIcon: Icon(Icons.people), label: 'Clients'), NavigationDestination(icon: Icon(Icons.storefront_outlined), selectedIcon: Icon(Icons.storefront), label: 'Surveys'), NavigationDestination(icon: Icon(Icons.local_shipping_outlined), selectedIcon: Icon(Icons.local_shipping), label: 'Pricing'), ], ), ); } }