4 changed files with 856 additions and 0 deletions
@ -0,0 +1,802 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:http/http.dart' as http; |
|||
import 'dart:convert'; |
|||
|
|||
class OrderHistoryPage extends StatefulWidget { |
|||
@override |
|||
_OrderHistoryPageState createState() => _OrderHistoryPageState(); |
|||
} |
|||
|
|||
class _OrderHistoryPageState extends State<OrderHistoryPage> |
|||
with TickerProviderStateMixin { |
|||
late AnimationController _animationController; |
|||
List<AnimationController> _cardAnimationControllers = []; |
|||
List<CommandeData> commandes = []; |
|||
bool isLoading = true; |
|||
String? error; |
|||
|
|||
// Informations de pagination |
|||
int currentPage = 1; |
|||
int totalPages = 1; |
|||
int totalItems = 0; |
|||
int itemsPerPage = 10; |
|||
|
|||
final String baseUrl = 'https://restaurant.careeracademy.mg'; // Remplacez par votre URL |
|||
final Map<String, String> _headers = { |
|||
'Content-Type': 'application/json', |
|||
'Accept': 'application/json', |
|||
}; |
|||
|
|||
@override |
|||
void initState() { |
|||
super.initState(); |
|||
_animationController = AnimationController( |
|||
duration: Duration(milliseconds: 1000), |
|||
vsync: this, |
|||
); |
|||
|
|||
_loadCommandes(); |
|||
} |
|||
|
|||
Future<void> _loadCommandes() async { |
|||
try { |
|||
setState(() { |
|||
isLoading = true; |
|||
error = null; |
|||
}); |
|||
|
|||
final response = await http.get( |
|||
Uri.parse('$baseUrl/api/commandes?statut=payee'), |
|||
headers: _headers, |
|||
); |
|||
|
|||
final dynamic responseBody = json.decode(response.body); |
|||
print('Réponse getCommandes: ${responseBody}'); |
|||
|
|||
if (response.statusCode == 200) { |
|||
// Adapter la structure de réponse {data: [...], pagination: {...}} |
|||
final Map<String, dynamic> responseData = json.decode(response.body); |
|||
final List<dynamic> data = responseData['data'] ?? []; |
|||
final Map<String, dynamic> pagination = responseData['pagination'] ?? {}; |
|||
|
|||
setState(() { |
|||
commandes = data.map((json) => CommandeData.fromJson(json)).toList(); |
|||
|
|||
// Mettre à jour les informations de pagination |
|||
currentPage = pagination['currentPage'] ?? 1; |
|||
totalPages = pagination['totalPages'] ?? 1; |
|||
totalItems = pagination['totalItems'] ?? 0; |
|||
itemsPerPage = pagination['itemsPerPage'] ?? 10; |
|||
|
|||
isLoading = false; |
|||
}); |
|||
|
|||
_initializeAnimations(); |
|||
_startAnimations(); |
|||
} else { |
|||
setState(() { |
|||
error = 'Erreur lors du chargement des commandes'; |
|||
isLoading = false; |
|||
}); |
|||
} |
|||
} catch (e) { |
|||
setState(() { |
|||
error = 'Erreur de connexion: $e'; |
|||
isLoading = false; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
void _initializeAnimations() { |
|||
_cardAnimationControllers = List.generate( |
|||
commandes.length, |
|||
(index) => AnimationController( |
|||
duration: Duration(milliseconds: 600), |
|||
vsync: this, |
|||
), |
|||
); |
|||
} |
|||
|
|||
void _startAnimations() async { |
|||
_animationController.forward(); |
|||
|
|||
for (int i = 0; i < _cardAnimationControllers.length; i++) { |
|||
await Future.delayed(Duration(milliseconds: 150)); |
|||
if (mounted) { |
|||
_cardAnimationControllers[i].forward(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@override |
|||
void dispose() { |
|||
_animationController.dispose(); |
|||
for (var controller in _cardAnimationControllers) { |
|||
controller.dispose(); |
|||
} |
|||
super.dispose(); |
|||
} |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Scaffold( |
|||
backgroundColor: Colors.white, |
|||
appBar: AppBar( |
|||
title: Text('Historique des commandes'), |
|||
backgroundColor: Colors.white, |
|||
foregroundColor: Colors.black, |
|||
elevation: 0, |
|||
), |
|||
body: RefreshIndicator( |
|||
onRefresh: _loadCommandes, |
|||
child: Column( |
|||
children: [ |
|||
_buildHeader(), |
|||
Expanded( |
|||
child: _buildContent(), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
Widget _buildHeader() { |
|||
return AnimatedBuilder( |
|||
animation: _animationController, |
|||
builder: (context, child) { |
|||
return Transform.translate( |
|||
offset: Offset(0, -50 * (1 - _animationController.value)), |
|||
child: Opacity( |
|||
opacity: _animationController.value, |
|||
child: Container( |
|||
width: double.infinity, |
|||
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 5), |
|||
padding: EdgeInsets.all(10), |
|||
decoration: BoxDecoration( |
|||
color: Colors.white, |
|||
borderRadius: BorderRadius.circular(12), |
|||
boxShadow: [ |
|||
BoxShadow( |
|||
color: Colors.grey.withOpacity(0.08), |
|||
blurRadius: 6, |
|||
offset: Offset(0, 2), |
|||
), |
|||
], |
|||
), |
|||
child: Column( |
|||
children: [ |
|||
Text( |
|||
'Historique des commandes payées', |
|||
style: TextStyle( |
|||
fontSize: 18, |
|||
fontWeight: FontWeight.bold, |
|||
color: Color(0xFF2c3e50), |
|||
), |
|||
textAlign: TextAlign.center, |
|||
), |
|||
SizedBox(height: 2), |
|||
Text( |
|||
'Consultez toutes les commandes qui ont été payées', |
|||
style: TextStyle( |
|||
fontSize: 12, |
|||
color: Colors.grey.shade600, |
|||
), |
|||
textAlign: TextAlign.center, |
|||
), |
|||
if (totalItems > 0) |
|||
Padding( |
|||
padding: EdgeInsets.only(top: 4), |
|||
child: Text( |
|||
'$totalItems commande${totalItems > 1 ? 's' : ''} • Page $currentPage/$totalPages', |
|||
style: TextStyle( |
|||
fontSize: 10, |
|||
color: Colors.grey.shade500, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
textAlign: TextAlign.center, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
Widget _buildContent() { |
|||
if (isLoading) { |
|||
return Center( |
|||
child: CircularProgressIndicator(), |
|||
); |
|||
} |
|||
|
|||
if (error != null) { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
Icon(Icons.error_outline, size: 64, color: Colors.grey), |
|||
SizedBox(height: 16), |
|||
Text(error!, style: TextStyle(color: Colors.grey)), |
|||
SizedBox(height: 16), |
|||
ElevatedButton( |
|||
onPressed: _loadCommandes, |
|||
child: Text('Réessayer'), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
if (commandes.isEmpty) { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
Icon(Icons.payment, size: 64, color: Colors.grey), |
|||
SizedBox(height: 16), |
|||
Text( |
|||
'Aucune commande payée', |
|||
style: TextStyle(color: Colors.grey, fontSize: 16), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
return ListView.builder( |
|||
padding: EdgeInsets.symmetric(horizontal: 20), |
|||
itemCount: commandes.length, |
|||
itemBuilder: (context, index) { |
|||
return _buildOrderCard(commandes[index], index); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
Widget _buildOrderCard(CommandeData commande, int index) { |
|||
if (index >= _cardAnimationControllers.length) { |
|||
return SizedBox.shrink(); |
|||
} |
|||
|
|||
return AnimatedBuilder( |
|||
animation: _cardAnimationControllers[index], |
|||
builder: (context, child) { |
|||
return Transform.translate( |
|||
offset: Offset(0, 50 * (1 - _cardAnimationControllers[index].value)), |
|||
child: Opacity( |
|||
opacity: _cardAnimationControllers[index].value, |
|||
child: Container( |
|||
margin: EdgeInsets.only(bottom: 12), |
|||
child: Material( |
|||
elevation: 8, |
|||
borderRadius: BorderRadius.circular(15), |
|||
child: InkWell( |
|||
borderRadius: BorderRadius.circular(15), |
|||
onTap: () { |
|||
// Action au tap |
|||
}, |
|||
child: Container( |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(15), |
|||
color: Colors.white, |
|||
border: Border( |
|||
left: BorderSide( |
|||
color: Color(0xFF4CAF50), |
|||
width: 3, |
|||
), |
|||
), |
|||
), |
|||
child: Column( |
|||
children: [ |
|||
_buildOrderHeader(commande), |
|||
_buildOrderItems(commande), |
|||
_buildOrderFooter(commande), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
), |
|||
), |
|||
), |
|||
); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
Widget _buildOrderHeader(CommandeData commande) { |
|||
return Container( |
|||
padding: EdgeInsets.all(12), |
|||
decoration: BoxDecoration( |
|||
border: Border( |
|||
bottom: BorderSide( |
|||
color: Colors.grey.shade200, |
|||
width: 1, |
|||
), |
|||
), |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Container( |
|||
width: 35, |
|||
height: 35, |
|||
decoration: BoxDecoration( |
|||
gradient: LinearGradient( |
|||
colors: [Color(0xFF667eea), Color(0xFF764ba2)], |
|||
), |
|||
borderRadius: BorderRadius.circular(8), |
|||
), |
|||
child: Center( |
|||
child: Text( |
|||
commande.getTableShortName(), |
|||
style: TextStyle( |
|||
color: Colors.white, |
|||
fontWeight: FontWeight.bold, |
|||
fontSize: 10, |
|||
), |
|||
), |
|||
), |
|||
), |
|||
SizedBox(width: 8), |
|||
Expanded( |
|||
child: Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
Text( |
|||
commande.tablename, |
|||
style: TextStyle( |
|||
fontSize: 14, |
|||
fontWeight: FontWeight.w600, |
|||
color: Color(0xFF2c3e50), |
|||
), |
|||
), |
|||
SizedBox(height: 2), |
|||
Text( |
|||
commande.numeroCommande, |
|||
style: TextStyle( |
|||
fontSize: 10, |
|||
color: Colors.grey, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
SizedBox(height: 2), |
|||
Row( |
|||
children: [ |
|||
Icon(Icons.calendar_today, size: 12, color: Colors.grey), |
|||
SizedBox(width: 3), |
|||
Text( |
|||
_formatDateTime(commande.dateCommande), |
|||
style: TextStyle(color: Colors.grey, fontSize: 10), |
|||
), |
|||
SizedBox(width: 8), |
|||
Icon(Icons.person, size: 12, color: Colors.grey), |
|||
SizedBox(width: 3), |
|||
Text( |
|||
commande.serveur, |
|||
style: TextStyle(color: Colors.grey, fontSize: 10), |
|||
), |
|||
], |
|||
), |
|||
], |
|||
), |
|||
), |
|||
Container( |
|||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), |
|||
decoration: BoxDecoration( |
|||
gradient: LinearGradient( |
|||
colors: [Color(0xFF4CAF50), Color(0xFF45a049)], |
|||
), |
|||
borderRadius: BorderRadius.circular(10), |
|||
), |
|||
child: Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
Icon( |
|||
Icons.check_circle, |
|||
color: Colors.white, |
|||
size: 10, |
|||
), |
|||
SizedBox(width: 3), |
|||
Text( |
|||
'PAYÉE', |
|||
style: TextStyle( |
|||
color: Colors.white, |
|||
fontWeight: FontWeight.w600, |
|||
fontSize: 8, |
|||
letterSpacing: 0.3, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
Widget _buildOrderItems(CommandeData commande) { |
|||
return Container( |
|||
padding: EdgeInsets.all(10), |
|||
child: Column( |
|||
children: commande.items.map((item) => _buildOrderItem(item)).toList(), |
|||
), |
|||
); |
|||
} |
|||
|
|||
Widget _buildOrderItem(CommandeItem item) { |
|||
return Container( |
|||
padding: EdgeInsets.symmetric(vertical: 6), |
|||
decoration: BoxDecoration( |
|||
border: Border( |
|||
bottom: BorderSide( |
|||
color: Colors.grey.shade100, |
|||
width: 1, |
|||
), |
|||
), |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Container( |
|||
width: 32, |
|||
height: 32, |
|||
decoration: BoxDecoration( |
|||
gradient: LinearGradient( |
|||
colors: [Color(0xFFffeaa7), Color(0xFFfdcb6e)], |
|||
), |
|||
borderRadius: BorderRadius.circular(8), |
|||
), |
|||
child: Center( |
|||
child: Text( |
|||
_getMenuIcon(item.menuNom), |
|||
style: TextStyle(fontSize: 14), |
|||
), |
|||
), |
|||
), |
|||
SizedBox(width: 8), |
|||
Expanded( |
|||
child: Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
Text( |
|||
item.menuNom, |
|||
style: TextStyle( |
|||
fontSize: 12, |
|||
fontWeight: FontWeight.w600, |
|||
color: Color(0xFF2c3e50), |
|||
), |
|||
), |
|||
if (item.commentaires != null && item.commentaires!.isNotEmpty) |
|||
Text( |
|||
item.commentaires!, |
|||
style: TextStyle( |
|||
fontSize: 9, |
|||
color: Colors.grey.shade600, |
|||
fontStyle: FontStyle.italic, |
|||
), |
|||
), |
|||
Text( |
|||
'${item.quantite}x × ${_formatPrice(item.prixUnitaire)}', |
|||
style: TextStyle( |
|||
fontSize: 10, |
|||
color: Colors.grey, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
Text( |
|||
_formatPrice(item.totalItem), |
|||
style: TextStyle( |
|||
fontSize: 13, |
|||
fontWeight: FontWeight.bold, |
|||
color: Color(0xFF4CAF50), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
Widget _buildOrderFooter(CommandeData commande) { |
|||
return Container( |
|||
padding: EdgeInsets.all(10), |
|||
decoration: BoxDecoration( |
|||
color: Colors.grey.shade50, |
|||
borderRadius: BorderRadius.only( |
|||
bottomLeft: Radius.circular(15), |
|||
bottomRight: Radius.circular(15), |
|||
), |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Row( |
|||
children: [ |
|||
Container( |
|||
width: 28, |
|||
height: 28, |
|||
decoration: BoxDecoration( |
|||
gradient: LinearGradient( |
|||
colors: [Color(0xFF4CAF50), Color(0xFF45a049)], |
|||
), |
|||
borderRadius: BorderRadius.circular(6), |
|||
), |
|||
child: Center( |
|||
child: Icon( |
|||
_getPaymentIcon(commande.modePaiement), |
|||
color: Colors.white, |
|||
size: 14, |
|||
), |
|||
), |
|||
), |
|||
SizedBox(width: 6), |
|||
Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
Text( |
|||
_getPaymentMethodText(commande.modePaiement), |
|||
style: TextStyle( |
|||
fontSize: 10, |
|||
color: Colors.grey.shade600, |
|||
), |
|||
), |
|||
if (commande.totalTva > 0) |
|||
Text( |
|||
'TVA: ${_formatPrice(commande.totalTva)}', |
|||
style: TextStyle( |
|||
fontSize: 9, |
|||
color: Colors.grey.shade500, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
], |
|||
), |
|||
Container( |
|||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), |
|||
decoration: BoxDecoration( |
|||
color: Color(0xFF4CAF50).withOpacity(0.1), |
|||
borderRadius: BorderRadius.circular(15), |
|||
), |
|||
child: Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
Icon( |
|||
Icons.attach_money, |
|||
color: Color(0xFF4CAF50), |
|||
size: 14, |
|||
), |
|||
Text( |
|||
_formatPrice(commande.totalTtc), |
|||
style: TextStyle( |
|||
fontSize: 14, |
|||
fontWeight: FontWeight.bold, |
|||
color: Color(0xFF4CAF50), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
String _formatDateTime(DateTime dateTime) { |
|||
return '${dateTime.day.toString().padLeft(2, '0')}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.year} à ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}'; |
|||
} |
|||
|
|||
String _formatPrice(double priceInCents) { |
|||
// Les prix sont déjà en centimes dans votre API (ex: 20000.00 = 200.00 €) |
|||
return '${(priceInCents / 100).toStringAsFixed(2)} Ar'; |
|||
} |
|||
|
|||
String _getMenuIcon(String menuNom) { |
|||
String lowerName = menuNom.toLowerCase(); |
|||
if (lowerName.contains('pizza')) return '🍕'; |
|||
if (lowerName.contains('steak') || lowerName.contains('steack')) return '🥩'; |
|||
if (lowerName.contains('frite')) return '🍟'; |
|||
if (lowerName.contains('salade')) return '🥗'; |
|||
if (lowerName.contains('soupe')) return '🍲'; |
|||
if (lowerName.contains('burger')) return '🍔'; |
|||
if (lowerName.contains('poisson')) return '🐟'; |
|||
if (lowerName.contains('poulet')) return '🍗'; |
|||
if (lowerName.contains('pâtes') || lowerName.contains('pasta')) return '🍝'; |
|||
if (lowerName.contains('dessert') || lowerName.contains('gâteau')) return '🍰'; |
|||
if (lowerName.contains('boisson')) return '🥤'; |
|||
return '🍽️'; |
|||
} |
|||
|
|||
IconData _getPaymentIcon(String? method) { |
|||
if (method == null) return Icons.help_outline; |
|||
switch (method.toLowerCase()) { |
|||
case 'especes': |
|||
case 'cash': |
|||
return Icons.money; |
|||
case 'carte': |
|||
case 'card': |
|||
return Icons.credit_card; |
|||
case 'mobile': |
|||
case 'paypal': |
|||
return Icons.smartphone; |
|||
default: |
|||
return Icons.payment; |
|||
} |
|||
} |
|||
|
|||
String _getPaymentMethodText(String? method) { |
|||
if (method == null) return 'Non défini'; |
|||
switch (method.toLowerCase()) { |
|||
case 'especes': |
|||
case 'cash': |
|||
return 'Espèces'; |
|||
case 'carte': |
|||
case 'card': |
|||
return 'Carte'; |
|||
case 'mobile': |
|||
case 'paypal': |
|||
return 'Mobile'; |
|||
default: |
|||
return method; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Modèles de données adaptés à votre API |
|||
class CommandeData { |
|||
final int id; |
|||
final int clientId; |
|||
final int tableId; |
|||
final int reservationId; |
|||
final String numeroCommande; |
|||
final String statut; |
|||
final double totalHt; |
|||
final double totalTva; |
|||
final double totalTtc; |
|||
final String? modePaiement; |
|||
final String? commentaires; |
|||
final String serveur; |
|||
final DateTime dateCommande; |
|||
final DateTime? dateService; |
|||
final DateTime createdAt; |
|||
final DateTime updatedAt; |
|||
final List<CommandeItem> items; |
|||
final String tablename; |
|||
|
|||
CommandeData({ |
|||
required this.id, |
|||
required this.clientId, |
|||
required this.tableId, |
|||
required this.reservationId, |
|||
required this.numeroCommande, |
|||
required this.statut, |
|||
required this.totalHt, |
|||
required this.totalTva, |
|||
required this.totalTtc, |
|||
this.modePaiement, |
|||
this.commentaires, |
|||
required this.serveur, |
|||
required this.dateCommande, |
|||
this.dateService, |
|||
required this.createdAt, |
|||
required this.updatedAt, |
|||
required this.items, |
|||
required this.tablename, |
|||
}); |
|||
|
|||
factory CommandeData.fromJson(Map<String, dynamic> json) { |
|||
return CommandeData( |
|||
id: json['id'], |
|||
clientId: json['client_id'], |
|||
tableId: json['table_id'], |
|||
reservationId: json['reservation_id'], |
|||
numeroCommande: json['numero_commande'], |
|||
statut: json['statut'], |
|||
totalHt: (json['total_ht'] ?? 0).toDouble(), |
|||
totalTva: (json['total_tva'] ?? 0).toDouble(), |
|||
totalTtc: (json['total_ttc'] ?? 0).toDouble(), |
|||
modePaiement: json['mode_paiement'], |
|||
commentaires: json['commentaires'], |
|||
serveur: json['serveur'], |
|||
dateCommande: DateTime.parse(json['date_commande']), |
|||
dateService: json['date_service'] != null |
|||
? DateTime.parse(json['date_service']) |
|||
: null, |
|||
createdAt: DateTime.parse(json['created_at']), |
|||
updatedAt: DateTime.parse(json['updated_at']), |
|||
items: (json['items'] as List) |
|||
.map((item) => CommandeItem.fromJson(item)) |
|||
.toList(), |
|||
tablename: json['tablename'] ?? 'Table inconnue', |
|||
); |
|||
} |
|||
|
|||
String getTableShortName() { |
|||
if (tablename.toLowerCase().contains('caisse')) return 'C'; |
|||
if (tablename.toLowerCase().contains('terrasse')) return 'T'; |
|||
|
|||
// Extraire le numéro de la table |
|||
RegExp regExp = RegExp(r'\d+'); |
|||
Match? match = regExp.firstMatch(tablename); |
|||
if (match != null) { |
|||
return 'T${match.group(0)}'; |
|||
} |
|||
|
|||
return tablename.substring(0, 1).toUpperCase(); |
|||
} |
|||
} |
|||
|
|||
class CommandeItem { |
|||
final int id; |
|||
final int commandeId; |
|||
final int menuId; |
|||
final int quantite; |
|||
final double prixUnitaire; |
|||
final double totalItem; |
|||
final String? commentaires; |
|||
final String statut; |
|||
final DateTime createdAt; |
|||
final DateTime updatedAt; |
|||
final String menuNom; |
|||
final String menuDescription; |
|||
final double menuPrixActuel; |
|||
final String tablename; |
|||
|
|||
CommandeItem({ |
|||
required this.id, |
|||
required this.commandeId, |
|||
required this.menuId, |
|||
required this.quantite, |
|||
required this.prixUnitaire, |
|||
required this.totalItem, |
|||
this.commentaires, |
|||
required this.statut, |
|||
required this.createdAt, |
|||
required this.updatedAt, |
|||
required this.menuNom, |
|||
required this.menuDescription, |
|||
required this.menuPrixActuel, |
|||
required this.tablename, |
|||
}); |
|||
|
|||
factory CommandeItem.fromJson(Map<String, dynamic> json) { |
|||
return CommandeItem( |
|||
id: json['id'], |
|||
commandeId: json['commande_id'], |
|||
menuId: json['menu_id'], |
|||
quantite: json['quantite'], |
|||
prixUnitaire: (json['prix_unitaire'] ?? 0).toDouble(), |
|||
totalItem: (json['total_item'] ?? 0).toDouble(), |
|||
commentaires: json['commentaires'], |
|||
statut: json['statut'], |
|||
createdAt: DateTime.parse(json['created_at']), |
|||
updatedAt: DateTime.parse(json['updated_at']), |
|||
menuNom: json['menu_nom'], |
|||
menuDescription: json['menu_description'], |
|||
menuPrixActuel: (json['menu_prix_actuel'] ?? 0).toDouble(), |
|||
tablename: json['tablename'] ?? '', |
|||
); |
|||
} |
|||
} |
|||
|
|||
// Usage dans votre app principale |
|||
class MyApp extends StatelessWidget { |
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return MaterialApp( |
|||
title: 'Historique des Commandes', |
|||
theme: ThemeData( |
|||
primarySwatch: Colors.blue, |
|||
visualDensity: VisualDensity.adaptivePlatformDensity, |
|||
), |
|||
home: OrderHistoryPage(), |
|||
debugShowCheckedModeBanner: false, |
|||
); |
|||
} |
|||
} |
|||
|
|||
void main() { |
|||
runApp(MyApp()); |
|||
} |
|||
Loading…
Reference in new issue