diff --git a/lib/layouts/main_layout.dart b/lib/layouts/main_layout.dart new file mode 100644 index 0000000..6a8df76 --- /dev/null +++ b/lib/layouts/main_layout.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; +import '../widgets/bottom_navigation.dart'; + +class MainLayout extends StatefulWidget { + final Widget child; + final int currentIndex; + + const MainLayout({super.key, required this.child, this.currentIndex = 0}); + + @override + // ignore: library_private_types_in_public_api + _MainLayoutState createState() => _MainLayoutState(); +} + +class _MainLayoutState extends State { + int _selectedIndex = 0; + + @override + void initState() { + super.initState(); + _selectedIndex = widget.currentIndex; + } + + @override + Widget build(BuildContext context) { + final isDesktop = MediaQuery.of(context).size.width >= 768; + + return Scaffold( + backgroundColor: Colors.grey.shade50, + body: Row( + children: [ + // Desktop Sidebar + if (isDesktop) _buildDesktopSidebar(), + + // Main Content + Expanded( + child: Column( + children: [ + // Page Content + Expanded(child: widget.child), + + // Bottom Navigation + AppBottomNavigation( + selectedIndex: _selectedIndex, + onItemTapped: _onItemTapped, + isDesktop: isDesktop, + ), + ], + ), + ), + ], + ), + ); + } + + void _onItemTapped(int index) { + setState(() { + _selectedIndex = index; + }); + + // Global navigation logic + switch (index) { + case 0: + Navigator.pushReplacementNamed(context, '/tables'); + break; + case 1: + Navigator.pushReplacementNamed(context, '/commandes'); + break; + case 2: + Navigator.pushReplacementNamed(context, '/categories'); + break; + case 3: + Navigator.pushReplacementNamed(context, '/menus'); + break; + } + } + + Widget _buildDesktopSidebar() { + return Container( + width: 250, + color: Colors.white, + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(20), + child: const Text( + 'Restaurant App', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ), + Expanded( + child: ListView( + children: [ + _buildSidebarItem( + icon: Icons.table_restaurant, + title: 'Tables', + route: '/tables', + index: 0, + ), + _buildSidebarItem( + icon: Icons.receipt_long_outlined, + title: 'Commandes', + route: '/commandes', + index: 1, + ), + _buildSidebarItem( + icon: Icons.category_outlined, + title: 'Catégories', + route: '/categories', + index: 2, + ), + _buildSidebarItem( + icon: Icons.restaurant_menu, + title: 'Menus', + route: '/menus', + index: 3, + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildSidebarItem({ + required IconData icon, + required String title, + required String route, + required int index, + }) { + final isSelected = _selectedIndex == index; + + return ListTile( + leading: Icon( + icon, + color: isSelected ? Colors.green.shade700 : Colors.grey.shade600, + ), + title: Text( + title, + style: TextStyle( + color: isSelected ? Colors.green.shade700 : Colors.grey.shade700, + fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, + ), + ), + selected: isSelected, + selectedTileColor: Colors.green.shade50, + onTap: () { + setState(() { + _selectedIndex = index; + }); + Navigator.pushReplacementNamed(context, route); + }, + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index a347b78..507e235 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,37 @@ import 'package:flutter/material.dart'; -import '/pages/tables.dart'; // Assure-toi que ce fichier existe dans ton projet +import 'layouts/main_layout.dart'; +import 'pages/tables.dart'; +// import 'pages/commandes_screen.dart'; +// import 'pages/categories_screen.dart'; +// import 'pages/menus_screen.dart'; void main() { - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatelessWidget { + const MyApp({super.key}); + @override Widget build(BuildContext context) { return MaterialApp( - title: 'Sélection de Table', - debugShowCheckedModeBanner: false, + title: 'Restaurant App', theme: ThemeData( - primarySwatch: Colors.deepOrange, + primarySwatch: Colors.green, visualDensity: VisualDensity.adaptivePlatformDensity, ), - home: TablesScreen(), + initialRoute: '/tables', + routes: { + '/tables': + (context) => + const MainLayout(currentIndex: 0, child: TablesScreen()), + // '/commandes': + // (context) => MainLayout(currentIndex: 1, child: CommandesScreen()), + // '/categories': + // (context) => MainLayout(currentIndex: 2, child: CategoriesScreen()), + // '/menus': + // (context) => MainLayout(currentIndex: 3, child: MenusScreen()), + }, ); } } diff --git a/lib/pages/categories_screen.dart b/lib/pages/categories_screen.dart new file mode 100644 index 0000000..613744d --- /dev/null +++ b/lib/pages/categories_screen.dart @@ -0,0 +1 @@ +// TODO Implement this library. diff --git a/lib/pages/commandes_screen.dart b/lib/pages/commandes_screen.dart new file mode 100644 index 0000000..613744d --- /dev/null +++ b/lib/pages/commandes_screen.dart @@ -0,0 +1 @@ +// TODO Implement this library. diff --git a/lib/pages/menus_screen.dart b/lib/pages/menus_screen.dart new file mode 100644 index 0000000..613744d --- /dev/null +++ b/lib/pages/menus_screen.dart @@ -0,0 +1 @@ +// TODO Implement this library. diff --git a/lib/pages/tables.dart b/lib/pages/tables.dart index 3af4768..5ba0bdb 100644 --- a/lib/pages/tables.dart +++ b/lib/pages/tables.dart @@ -1,8 +1,7 @@ -import 'dart:convert'; -import 'dart:io' show Platform; -import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; +import 'dart:convert'; import 'menu.dart'; // Assure-toi que ce fichier contient la page MenuPage @@ -31,8 +30,10 @@ class TableData { class TablesScreen extends StatefulWidget { const TablesScreen({super.key}); + @override - State createState() => _TablesScreenState(); + // ignore: library_private_types_in_public_api + _TablesScreenState createState() => _TablesScreenState(); } class _TablesScreenState extends State { @@ -58,11 +59,139 @@ class _TablesScreenState extends State { }); } else { setState(() => isLoading = false); - print('Erreur API: ${response.statusCode}'); + if (kDebugMode) { + print('Erreur API: ${response.statusCode}'); + } } } catch (e) { setState(() => isLoading = false); - print('Erreur réseau: $e'); + if (kDebugMode) { + print('Erreur: $e'); + } + } + } + + Future _addTable() async { + // Add table logic + final result = await showDialog>( + context: context, + builder: (context) => const _AddEditTableDialog(), + ); + + if (result != null) { + // Call API to add table + _callAddTableAPI(result); + } + } + + Future _callAddTableAPI(Map tableData) async { + try { + final url = Uri.parse("https://restaurant.careeracademy.mg/api/tables"); + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(tableData), + ); + + if (response.statusCode == 201) { + fetchTables(); // Refresh the list + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Table ajoutée avec succès')), + ); + } + } catch (e) { + ScaffoldMessenger.of( + // ignore: use_build_context_synchronously + context, + ).showSnackBar(SnackBar(content: Text('Erreur: $e'))); + } + } + + Future _editTable(TableData table) async { + final result = await showDialog>( + context: context, + builder: (context) => _AddEditTableDialog(table: table), + ); + + if (result != null) { + _callEditTableAPI(table.id, result); + } + } + + Future _callEditTableAPI(int id, Map tableData) async { + try { + final url = Uri.parse( + "https://restaurant.careeracademy.mg/api/tables/$id", + ); + final response = await http.put( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(tableData), + ); + + if (response.statusCode == 200) { + fetchTables(); + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Table modifiée avec succès')), + ); + } + } catch (e) { + ScaffoldMessenger.of( + // ignore: use_build_context_synchronously + context, + ).showSnackBar(SnackBar(content: Text('Erreur: $e'))); + } + } + + Future _deleteTable(int id) async { + final confirm = await showDialog( + context: context, + builder: + (context) => AlertDialog( + title: const Text('Confirmer la suppression'), + content: const Text( + 'Êtes-vous sûr de vouloir supprimer cette table?', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Annuler'), + ), + ElevatedButton( + onPressed: () => Navigator.pop(context, true), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + child: const Text('Supprimer'), + ), + ], + ), + ); + + if (confirm == true) { + _callDeleteTableAPI(id); + } + } + + Future _callDeleteTableAPI(int id) async { + try { + final url = Uri.parse( + "https://restaurant.careeracademy.mg/api/tables/$id", + ); + final response = await http.delete(url); + + if (response.statusCode == 200) { + fetchTables(); + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Table supprimée avec succès')), + ); + } + } catch (e) { + ScaffoldMessenger.of( + // ignore: use_build_context_synchronously + context, + ).showSnackBar(SnackBar(content: Text('Erreur: $e'))); } } @@ -71,7 +200,7 @@ class _TablesScreenState extends State { case 'available': return Colors.green; case 'occupied': - return Colors.red; + return Colors.orange; case 'reserved': return Colors.orange; default: @@ -92,143 +221,449 @@ class _TablesScreenState extends State { } } - bool isDesktop() { - if (kIsWeb) return true; - try { - return Platform.isWindows || Platform.isMacOS || Platform.isLinux; - } catch (_) { - return false; - } + bool isTableSelectable(String status) { + return status == 'available'; } @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; - final crossAxisCount = screenWidth > 1200 ? 4 : screenWidth > 800 ? 3 : 2; - - return Scaffold( - appBar: AppBar( - title: const Text('Sélectionner une table'), - actions: isDesktop() - ? [ - IconButton( - icon: const Icon(Icons.refresh), - onPressed: () { - setState(() => isLoading = true); - fetchTables(); - }, + final isDesktop = screenWidth >= 768; + + int crossAxisCount = 2; + if (screenWidth > 1200) { + crossAxisCount = 4; + } else if (screenWidth > 800) { + crossAxisCount = 3; + } + + if (isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + return Column( + children: [ + // Header + Container( + color: Colors.white, + padding: const EdgeInsets.all(20), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 30), + const Text( + 'Sélectionner une table', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 8), + Text( + 'Choisissez une table pour commencer une nouvelle commande', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + ], ), - ] - : null, - ), - body: isLoading - ? const Center(child: CircularProgressIndicator()) - : Padding( - padding: const EdgeInsets.all(12.0), - child: GridView.builder( - itemCount: tables.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - childAspectRatio: 2.3, + ), + // Add button (desktop only) + if (isDesktop) + ElevatedButton.icon( + onPressed: _addTable, + icon: const Icon(Icons.add, size: 20), + label: const Text('Ajouter'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green.shade700, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + ), ), - itemBuilder: (context, index) { - final table = tables[index]; - final isAvailable = table.status == 'available'; + ], + ), + ), - return Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(14), + // Content - Reduced height + Expanded( + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + children: [ + // Tables Grid - Reduced flex + Expanded( + flex: isDesktop ? 2 : 4, // Reduced from 3/4 to 2/4 + child: GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + childAspectRatio: isDesktop ? 1.1 : 0.85, // Adjusted ), - child: Padding( - padding: const EdgeInsets.all(10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - table.nom, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: getStatusColor(table.status), - borderRadius: BorderRadius.circular(50), - ), - child: Text( - getStatusLabel(table.status), - style: const TextStyle( - color: Colors.white, - fontSize: 10, + itemCount: tables.length, + itemBuilder: (context, index) { + final table = tables[index]; + final isSelectable = isTableSelectable(table.status); + + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + boxShadow: [ + BoxShadow( + // ignore: deprecated_member_use + color: Colors.black.withOpacity(0.05), + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + child: Stack( + children: [ + // Desktop CRUD menu + if (isDesktop) + Positioned( + top: 8, + right: 8, + child: PopupMenuButton( + icon: Icon( + Icons.more_vert, + size: 16, + color: Colors.grey.shade600, ), - ), - ), - ], - ), - const Spacer(), - Row( - children: [ - const Icon(Icons.people_outline, - size: 14, color: Colors.grey), - const SizedBox(width: 4), - Text( - '${table.capacity} personnes', - style: const TextStyle( - fontSize: 11.5, - color: Colors.grey, - ), - ), - ], - ), - const SizedBox(height: 8), - SizedBox( - width: double.infinity, - height: 30, - child: ElevatedButton( - onPressed: isAvailable - ? () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => MenuPage( - tableId: table.id, - personne: table.capacity, + onSelected: (value) { + switch (value) { + case 'edit': + _editTable(table); + break; + case 'delete': + _deleteTable(table.id); + break; + } + }, + itemBuilder: + (context) => [ + const PopupMenuItem( + value: 'edit', + child: Row( + children: [ + Icon(Icons.edit, size: 16), + SizedBox(width: 8), + Text('Modifier'), + ], ), ), - ); - } - : null, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.deepOrange, - padding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), + const PopupMenuItem( + value: 'delete', + child: Row( + children: [ + Icon( + Icons.delete, + size: 16, + color: Colors.red, + ), + SizedBox(width: 8), + Text( + 'Supprimer', + style: TextStyle( + color: Colors.red, + ), + ), + ], + ), + ), + ], ), ), - child: const Text( - "Réserver", - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), + + // Table content + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + table.nom, + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: Colors.black87, + ), + ), + const Spacer(), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: getStatusColor(table.status), + borderRadius: BorderRadius.circular( + 12, + ), + ), + child: Text( + getStatusLabel(table.status), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Icon( + Icons.people_outline, + size: 16, + color: Colors.grey.shade600, + ), + const SizedBox(width: 6), + Text( + 'Capacité: ${table.capacity} personnes', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + const Spacer(), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: + isSelectable + ? () { + // Handle table selection + ScaffoldMessenger.of( + context, + ).showSnackBar( + SnackBar( + content: Text( + 'Table ${table.nom} sélectionnée', + ), + ), + ); + } + : null, + style: ElevatedButton.styleFrom( + backgroundColor: + isSelectable + ? Colors.green.shade700 + : Colors.grey.shade300, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + vertical: 8, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 8, + ), + ), + ), + child: Text( + isSelectable + ? 'Sélectionner' + : 'Indisponible', + style: const TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + ), + ], ), ), - ), - ], - ), - ), - ); - }, + ], + ), + ); + }, + ), + ), + + // Legend - Compact + Container( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildLegendItem('Disponible', Colors.green), + const SizedBox(width: 20), + _buildLegendItem('Occupée', Colors.orange), + const SizedBox(width: 20), + _buildLegendItem('Réservée', Colors.orange), + ], + ), + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildLegendItem(String label, Color color) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 12, + height: 12, + decoration: BoxDecoration(color: color, shape: BoxShape.circle), + ), + const SizedBox(width: 6), + Text( + label, + style: TextStyle(fontSize: 13, color: Colors.grey.shade700), + ), + ], + ); + } +} + +// Add/Edit Table Dialog +class _AddEditTableDialog extends StatefulWidget { + final TableData? table; + + const _AddEditTableDialog({this.table}); + + @override + _AddEditTableDialogState createState() => _AddEditTableDialogState(); +} + +class _AddEditTableDialogState extends State<_AddEditTableDialog> { + final _formKey = GlobalKey(); + late TextEditingController _nomController; + late TextEditingController _capacityController; + String _selectedStatus = 'available'; + + final List> _statusOptions = [ + {'value': 'available', 'label': 'Disponible'}, + {'value': 'occupied', 'label': 'Occupée'}, + {'value': 'reserved', 'label': 'Réservée'}, + ]; + + @override + void initState() { + super.initState(); + _nomController = TextEditingController(text: widget.table?.nom ?? ''); + _capacityController = TextEditingController( + text: widget.table?.capacity.toString() ?? '', + ); + _selectedStatus = widget.table?.status ?? 'available'; + } + + @override + void dispose() { + _nomController.dispose(); + _capacityController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final isEditing = widget.table != null; + + return AlertDialog( + title: Text(isEditing ? 'Modifier la table' : 'Ajouter une table'), + content: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + controller: _nomController, + decoration: const InputDecoration( + labelText: 'Nom de la table', + border: OutlineInputBorder(), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Veuillez entrer un nom'; + } + return null; + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _capacityController, + decoration: const InputDecoration( + labelText: 'Capacité', + border: OutlineInputBorder(), ), + keyboardType: TextInputType.number, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Veuillez entrer la capacité'; + } + if (int.tryParse(value) == null) { + return 'Veuillez entrer un nombre valide'; + } + return null; + }, ), + const SizedBox(height: 16), + DropdownButtonFormField( + value: _selectedStatus, + decoration: const InputDecoration( + labelText: 'Statut', + border: OutlineInputBorder(), + ), + items: + _statusOptions.map((option) { + return DropdownMenuItem( + value: option['value'], + child: Text(option['label']!), + ); + }).toList(), + onChanged: (value) { + setState(() { + _selectedStatus = value!; + }); + }, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Annuler'), + ), + ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + final result = { + 'nom': _nomController.text, + 'capacity': int.parse(_capacityController.text), + 'status': _selectedStatus, + }; + Navigator.pop(context, result); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green.shade700, + ), + child: Text(isEditing ? 'Modifier' : 'Ajouter'), + ), + ], ); } } diff --git a/lib/widgets/bottom_navigation.dart b/lib/widgets/bottom_navigation.dart new file mode 100644 index 0000000..d2b9dc3 --- /dev/null +++ b/lib/widgets/bottom_navigation.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; + +class AppBottomNavigation extends StatelessWidget { + final int selectedIndex; + final Function(int) onItemTapped; + final bool isDesktop; + + const AppBottomNavigation({ + super.key, + required this.selectedIndex, + required this.onItemTapped, + this.isDesktop = false, + }); + + @override + Widget build(BuildContext context) { + if (isDesktop) return const SizedBox.shrink(); + + return Container( + color: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + child: Row( + children: [ + // Tables Tab + GestureDetector( + onTap: () => onItemTapped(0), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: + selectedIndex == 0 + ? Colors.green.shade700 + : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.table_restaurant, + color: + selectedIndex == 0 + ? Colors.white + : Colors.grey.shade600, + size: 16, + ), + const SizedBox(width: 6), + Text( + 'Tables', + style: TextStyle( + color: + selectedIndex == 0 + ? Colors.white + : Colors.grey.shade600, + fontWeight: + selectedIndex == 0 + ? FontWeight.w500 + : FontWeight.normal, + ), + ), + ], + ), + ), + ), + + const SizedBox(width: 20), + + // Commandes Tab + GestureDetector( + onTap: () => onItemTapped(1), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: + selectedIndex == 1 + ? Colors.green.shade700 + : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.receipt_long_outlined, + color: + selectedIndex == 1 + ? Colors.white + : Colors.grey.shade600, + size: 16, + ), + const SizedBox(width: 6), + Text( + 'Commandes', + style: TextStyle( + color: + selectedIndex == 1 + ? Colors.white + : Colors.grey.shade600, + fontWeight: + selectedIndex == 1 + ? FontWeight.w500 + : FontWeight.normal, + ), + ), + ], + ), + ), + ), + + const Spacer(), + + // User Profile Section + _buildUserProfile(), + ], + ), + ); + } + + Widget _buildUserProfile() { + return Row( + children: [ + Icon(Icons.person_outline, color: Colors.grey.shade600, size: 16), + const SizedBox(width: 6), + Text('Chef Pierre', style: TextStyle(color: Colors.grey.shade600)), + const SizedBox(width: 8), + Icon(Icons.expand_more, color: Colors.grey.shade600, size: 16), + ], + ); + } +} diff --git a/lib/widgets/mobile_bottom_navigation.dart b/lib/widgets/mobile_bottom_navigation.dart new file mode 100644 index 0000000..9ddb11f --- /dev/null +++ b/lib/widgets/mobile_bottom_navigation.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +class MobileBottomNavigation extends StatelessWidget { + final int selectedIndex; + final Function(int) onItemTapped; + + const MobileBottomNavigation({ + super.key, + required this.selectedIndex, + required this.onItemTapped, + }); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildBottomNavItem( + icon: Icons.table_restaurant, + label: 'Tables', + index: 0, + ), + _buildBottomNavItem( + icon: Icons.receipt_long_outlined, + label: 'Commandes', + index: 1, + ), + ], + ), + ); + } + + Widget _buildBottomNavItem({ + required IconData icon, + required String label, + required int index, + }) { + final isSelected = selectedIndex == index; + + return GestureDetector( + onTap: () => onItemTapped(index), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + color: isSelected ? Colors.green.shade700 : Colors.grey.shade600, + size: 24, + ), + const SizedBox(height: 4), + Text( + label, + style: TextStyle( + color: isSelected ? Colors.green.shade700 : Colors.grey.shade600, + fontSize: 12, + fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, + ), + ), + ], + ), + ); + } +}