This commit is contained in:
2026-10-01 16:03:32 +05:30
commit 3db47c4648
102 changed files with 5067 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../labels.dart';
import '../services/auth_controller.dart';
import 'add_dealer_screen.dart';
import 'admin_screen.dart';
import 'events_screen.dart';
import 'login_requests_screen.dart';
import 'service_points_screen.dart';
import 'stock_screen.dart';
class HomeShell extends StatefulWidget {
const HomeShell({super.key});
@override
State<HomeShell> createState() => _HomeShellState();
}
class _HomeShellState extends State<HomeShell> {
int _index = 0;
int _pendingLogins = 0;
int _stockVersion = 0;
Timer? _pendingTimer;
@override
void initState() {
super.initState();
_refreshPending();
_pendingTimer = Timer.periodic(const Duration(seconds: 8), (_) => _refreshPending());
}
@override
void dispose() {
_pendingTimer?.cancel();
super.dispose();
}
Future<void> _refreshPending() async {
final role = context.read<AuthController>().user?.role;
if (role != 'superAdmin' && role != 'salesRep') return;
try {
final requests = await context.read<AuthController>().api.loginRequests();
if (!mounted) return;
setState(() => _pendingLogins = requests.length);
} catch (_) {}
}
Future<void> _logout() async {
final auth = context.read<AuthController>();
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Log out'),
content: Text('Remove the saved login for ${auth.user?.name ?? 'this account'}?'),
actions: [
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')),
FilledButton(onPressed: () => Navigator.pop(context, true), child: const Text('Log out')),
],
),
);
if (confirmed == true && mounted) {
await context.read<AuthController>().logout();
}
}
@override
Widget build(BuildContext context) {
final auth = context.watch<AuthController>();
final role = auth.user?.role ?? 'dealer';
final pages = <Widget>[
StockScreen(key: ValueKey(_stockVersion)),
const EventsScreen(),
const ServicePointsScreen(),
if (role == 'superAdmin') const AdminScreen(),
];
final destinations = <NavigationDestination>[
const NavigationDestination(icon: Icon(Icons.inventory_2_outlined), label: 'Stock'),
const NavigationDestination(icon: Icon(Icons.event_note_outlined), label: 'Plans'),
const NavigationDestination(icon: Icon(Icons.handyman_outlined), label: 'Service'),
if (role == 'superAdmin')
const NavigationDestination(icon: Icon(Icons.admin_panel_settings_outlined), label: 'Admin'),
];
final safeIndex = _index.clamp(0, pages.length - 1);
final titles = ['Stock', 'Plans', 'Service', 'Admin'];
return Scaffold(
appBar: AppBar(
title: Text(titles[safeIndex]),
actions: [
if (role == 'superAdmin' || role == 'salesRep')
IconButton(
tooltip: 'Login requests',
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const LoginRequestsScreen()),
);
_refreshPending();
},
icon: Badge(
isLabelVisible: _pendingLogins > 0,
label: Text('$_pendingLogins'),
child: const Icon(Icons.how_to_reg_outlined),
),
),
if (role == 'salesRep')
IconButton(
tooltip: 'Add dealer',
onPressed: () async {
final created = await Navigator.of(context).push<bool>(
MaterialPageRoute(builder: (_) => const AddDealerScreen()),
);
if (created != true || !context.mounted) return;
try {
await context.read<AuthController>().refreshProfile();
} catch (_) {}
if (context.mounted) setState(() => _stockVersion++);
},
icon: const Icon(Icons.add_business_outlined),
),
IconButton(
tooltip: 'Account',
onPressed: _logout,
icon: const Icon(Icons.logout),
),
],
),
body: Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 960),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
child: Text(
'${auth.user?.name ?? ''} · ${roleLabel(role)}',
style: Theme.of(context).textTheme.labelLarge,
),
),
Expanded(child: pages[safeIndex]),
],
),
),
),
bottomNavigationBar: NavigationBar(
selectedIndex: safeIndex,
destinations: destinations,
onDestinationSelected: (index) => setState(() => _index = index),
),
);
}
}