157 lines
5.1 KiB
Dart
157 lines
5.1 KiB
Dart
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),
|
|
),
|
|
);
|
|
}
|
|
}
|