@ -1,3 +1,4 @@
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:http/http.dart ' as http ;
import ' dart:convert ' ;
@ -9,14 +10,16 @@ import '../layouts/main_layout.dart';
class CartPage extends StatefulWidget {
final int tableId ;
final int personne ;
final String ? tablename ;
final List < dynamic > cartItems ;
const CartPage ( {
Key ? key ,
super . key ,
required this . tableId ,
required this . personne ,
required this . cartItems ,
} ) : super ( key: key ) ;
this . tablename ,
} ) ;
@ override
State < CartPage > createState ( ) = > _CartPageState ( ) ;
@ -47,7 +50,7 @@ class _CartPageState extends State<CartPage> {
nom: item [ ' nom ' ] ? ? ' Article ' ,
prix: _parsePrice ( item [ ' prix ' ] ) ,
quantity: 1 ,
notes : item [ ' notes ' ] ? ? ' ' ,
commentaire : item [ ' commentaire ' ] ? ? ' ' ,
) ;
}
}
@ -97,7 +100,7 @@ class _CartPageState extends State<CartPage> {
barrierDismissible: false ,
builder: ( BuildContext context ) {
return AlertDialog (
title: Text (
title: const Text (
' Confirmer la commande ' ,
style: TextStyle ( fontWeight: FontWeight . bold ) ,
) ,
@ -105,9 +108,9 @@ class _CartPageState extends State<CartPage> {
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text ( ' Êtes-vous sûr de vouloir valider cette commande ? ' ) ,
SizedBox ( height: 16 ) ,
Text (
const Text ( ' Êtes-vous sûr de vouloir valider cette commande ? ' ) ,
const SizedBox ( height: 16 ) ,
const Text (
' Récapitulatif: ' ,
style: TextStyle ( fontWeight: FontWeight . bold ) ,
) ,
@ -123,7 +126,8 @@ class _CartPageState extends State<CartPage> {
child: Text ( ' Annuler ' , style: TextStyle ( color: Colors . grey [ 600 ] ) ) ,
) ,
ElevatedButton (
onPressed: _isValidating
onPressed:
_isValidating
? null
: ( ) {
Navigator . of ( context ) . pop ( ) ;
@ -133,8 +137,9 @@ class _CartPageState extends State<CartPage> {
backgroundColor: Colors . green [ 700 ] ,
foregroundColor: Colors . white ,
) ,
child: _isValidating
? SizedBox (
child:
_isValidating
? const SizedBox (
width: 16 ,
height: 16 ,
child: CircularProgressIndicator (
@ -144,7 +149,7 @@ class _CartPageState extends State<CartPage> {
) ,
) ,
)
: Text ( ' Valider ' ) ,
: const Text ( ' Valider ' ) ,
) ,
] ,
) ;
@ -165,12 +170,14 @@ class _CartPageState extends State<CartPage> {
" reservation_id " : 1 , / / Peut ê tre null si pas de réservation
" serveur " : " Serveur par défaut " , / / Valeur par défaut comme demandé
" commentaires " : _getOrderComments ( ) ,
" items " : _cartItems
" items " :
_cartItems
. map (
( item ) = > {
" menu_id " : item . id ,
" quantite " : item . quantity ,
" commentaires " : item . notes . isNotEmpty ? item . notes : null ,
" commentaires " :
item . commentaire . isNotEmpty ? item . commentaire : null ,
} ,
)
. toList ( ) ,
@ -207,9 +214,10 @@ class _CartPageState extends State<CartPage> {
String _getOrderComments ( ) {
/ / Concaténer toutes les notes des articles pour les commentaires généraux
List < String > allNotes = _cartItems
. where ( ( item ) = > item . notes . isNotEmpty )
. map ( ( item ) = > ' ${ item . nom } : ${ item . notes } ' )
List < String > allNotes =
_cartItems
. where ( ( item ) = > item . commentaire . isNotEmpty )
. map ( ( item ) = > ' ${ item . nom } : ${ item . commentaire } ' )
. toList ( ) ;
return allNotes . join ( ' ; ' ) ;
@ -225,11 +233,11 @@ class _CartPageState extends State<CartPage> {
title: Row (
children: [
Icon ( Icons . check_circle , color: Colors . green [ 700 ] ) ,
SizedBox ( width: 8 ) ,
Text ( ' Commande validée ' ) ,
const SizedBox ( width: 8 ) ,
const Text ( ' Commande validée ' ) ,
] ,
) ,
content: Text (
content: const Text (
' Votre commande a été envoyée en cuisine avec succès ! ' ,
) ,
actions: [
@ -237,12 +245,13 @@ class _CartPageState extends State<CartPage> {
onPressed: ( ) {
Navigator . of ( context ) . pushAndRemoveUntil (
MaterialPageRoute (
builder: ( context ) = > MainLayout ( child: TablesScreen ( ) ) ,
builder:
( context ) = > const MainLayout ( child: TablesScreen ( ) ) ,
) ,
( route ) = > false ,
) ;
} ,
child: Text ( ' OK ' ) ,
child: const Text ( ' OK ' ) ,
) ,
] ,
) ;
@ -252,23 +261,26 @@ class _CartPageState extends State<CartPage> {
Future < void > _updateTableStatus ( ) async {
try {
final updateResponse = await http . put (
final _ = await http . put (
Uri . parse (
' https://restaurant.careeracademy.mg/api/tables/ ${ widget . tableId } ' ) ,
' https://restaurant.careeracademy.mg/api/tables/ ${ widget . tableId } ' ,
) ,
headers: { ' Content-Type ' : ' application/json ' } ,
body: json . encode ( { " status " : " occupied " } ) ,
) ;
} catch ( e ) {
if ( kDebugMode ) {
print ( " Erreur lors de la mise à jour du statut de la table: $ e " ) ;
}
}
}
void _showErrorDialog ( String message ) {
showDialog (
context: context ,
builder: ( BuildContext context ) {
return AlertDialog (
title: Row (
title: const Row (
children: [
Icon ( Icons . error , color: Colors . red ) ,
SizedBox ( width: 8 ) ,
@ -279,13 +291,232 @@ class _CartPageState extends State<CartPage> {
actions: [
TextButton (
onPressed: ( ) = > Navigator . of ( context ) . pop ( ) ,
child: Text ( ' OK ' ) ,
child: const Text ( ' OK ' ) ,
) ,
] ,
) ;
} ,
) ;
}
Future < void > _payerDirectement ( ) async {
if ( _cartItems . isEmpty ) {
ScaffoldMessenger . of ( context ) . showSnackBar (
const SnackBar (
content: Text ( ' Aucun article dans le panier ' ) ,
backgroundColor: Colors . red ,
) ,
) ;
return ;
}
/ / Calculer le total
double total = _cartItems . fold ( 0.0 , ( sum , item ) {
return sum + ( item . prix * item . quantity ) ;
} ) ;
/ / Confirmer le paiement
final bool ? confirm = await showDialog < bool > (
context: context ,
builder:
( context ) = > AlertDialog (
title: const Text ( ' Confirmer le paiement ' ) ,
content: Column (
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text ( ' ${ widget . tablename } ' ) ,
const SizedBox ( height: 8 ) ,
Text ( ' Articles: ${ _cartItems . length } ' ) ,
const SizedBox ( height: 8 ) ,
Text (
' Total: ${ total . toStringAsFixed ( 0 ) } MGA ' ,
style: const TextStyle (
fontSize: 18 ,
fontWeight: FontWeight . bold ,
) ,
) ,
const SizedBox ( height: 16 ) ,
const Text ( ' Valider et payer cette commande ? ' ) ,
] ,
) ,
actions: [
TextButton (
onPressed: ( ) = > Navigator . of ( context ) . pop ( false ) ,
child: const Text ( ' Annuler ' ) ,
) ,
ElevatedButton (
onPressed: ( ) = > Navigator . of ( context ) . pop ( true ) ,
style: ElevatedButton . styleFrom (
backgroundColor: Colors . orange [ 600 ] ,
) ,
child: const Text ( ' Confirmer le paiement ' ) ,
) ,
] ,
) ,
) ;
if ( confirm ! = true ) return ;
setState ( ( ) {
_isValidating = true ;
} ) ;
try {
/ / 1. Créer la commande avec les items du panier
final response = await http . post (
Uri . parse ( ' https://restaurant.careeracademy.mg/api/commandes ' ) ,
headers: { ' Content-Type ' : ' application/json ' } ,
body: jsonEncode ( {
' table_id ' : widget . tableId ,
' statut ' : ' payee ' , / / Directement payée
' items ' :
_cartItems
. map (
( item ) = > {
' menu_id ' : item . id ,
' quantite ' : item . quantity ,
' prix_unitaire ' : item . prix ,
' commentaire ' : item . commentaire ,
/ / Pas de réservation
} ,
)
. toList ( ) ,
' methode_paiement ' : ' especes ' ,
' montant_paye ' : total ,
' date_paiement ' : DateTime . now ( ) . toIso8601String ( ) ,
' client_id ' : 1 , / / Valeur par défaut
' reservation_id ' : 1 ,
' serveur ' : ' Serveur par défaut ' , / / Valeur par défaut
} ) ,
) ;
if ( response . statusCode = = 201 ) {
final commandeData = jsonDecode ( response . body ) ;
/ / 2. Libérer la table
await http . patch (
Uri . parse (
' https://restaurant.careeracademy.mg/api/tables/ ${ widget . tableId } ' ,
) ,
headers: { ' Content-Type ' : ' application/json ' } ,
body: jsonEncode ( { ' statut ' : ' libre ' } ) ,
) ;
/ / 3. Succès
Navigator . of ( context ) . pushAndRemoveUntil (
MaterialPageRoute (
builder: ( context ) = > const MainLayout ( child: TablesScreen ( ) ) ,
) ,
( route ) = > false ,
) ;
} else {
throw Exception ( ' Erreur lors du paiement ' ) ;
}
} catch ( e ) {
ScaffoldMessenger . of ( context ) . showSnackBar (
SnackBar (
content: Text ( ' Erreur: ${ e . toString ( ) } ' ) ,
backgroundColor: Colors . red ,
) ,
) ;
} finally {
setState ( ( ) {
_isValidating = false ;
} ) ;
}
}
void _showPaymentSuccessDialog (
Map < String , dynamic > commandeData ,
double total ,
) {
showDialog (
context: context ,
barrierDismissible: false ,
builder:
( context ) = > AlertDialog (
title: const Row (
children: [
Icon ( Icons . check_circle , color: Colors . green , size: 28 ) ,
SizedBox ( width: 8 ) ,
Text ( ' Paiement confirmé ' ) ,
] ,
) ,
content: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Text ( ' Commande # ${ commandeData [ ' numeroCommande ' ] } ' ) ,
const SizedBox ( height: 8 ) ,
Text ( ' ${ widget . tablename } libérée ' ) ,
const SizedBox ( height: 8 ) ,
Text (
' Montant: ${ total . toStringAsFixed ( 2 ) } € ' ,
style: const TextStyle ( fontWeight: FontWeight . bold ) ,
) ,
const SizedBox ( height: 16 ) ,
const Text ( ' Voulez-vous imprimer un reçu ? ' ) ,
] ,
) ,
actions: [
TextButton (
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
Navigator . of ( context ) . pop ( ) ; / / Retour au menu principal
} ,
child: const Text ( ' Non merci ' ) ,
) ,
ElevatedButton (
onPressed: ( ) async {
Navigator . of ( context ) . pop ( ) ;
await _imprimerTicketPaiement ( commandeData , total ) ;
Navigator . of ( context ) . pop ( ) ; / / Retour au menu principal
} ,
child: const Text ( ' Imprimer ' ) ,
) ,
] ,
) ,
) ;
}
Future < void > _imprimerTicketPaiement (
Map < String , dynamic > commandeData ,
double total ,
) async {
try {
/ / Préparer les données pour l ' impression
_cartItems
. map (
( item ) = > {
' nom ' : item . nom ,
' quantite ' : item . quantity ,
' prix_unitaire ' : item . prix ,
' sous_total ' : item . prix * item . quantity ,
} ,
)
. toList ( ) ;
/ / Appeler le service d ' impression
/ / await PlatformPrintService . printFacture (
/ / commande: widget . commande ,
/ / paymentMethod: widget . paymentMethod ,
/ / ) ;
ScaffoldMessenger . of ( context ) . showSnackBar (
const SnackBar (
content: Text ( ' Ticket imprimé avec succès ' ) ,
backgroundColor: Colors . green ,
) ,
) ;
} catch ( e ) {
ScaffoldMessenger . of ( context ) . showSnackBar (
SnackBar (
content: Text ( ' Erreur d \' impression: ${ e . toString ( ) } ' ) ,
backgroundColor: Colors . orange ,
) ,
) ;
}
}
@ override
Widget build ( BuildContext context ) {
@ -296,9 +527,9 @@ class _CartPageState extends State<CartPage> {
elevation: 0 ,
leading: IconButton (
onPressed: ( ) = > Navigator . pop ( context ) ,
icon: Icon ( Icons . arrow_back , color: Colors . black ) ,
icon: const Icon ( Icons . arrow_back , color: Colors . black ) ,
) ,
title: Text (
title: const Text (
' Panier ' ,
style: TextStyle (
color: Colors . black ,
@ -309,15 +540,16 @@ class _CartPageState extends State<CartPage> {
actions: [
TextButton (
onPressed: ( ) = > Navigator . pop ( context ) ,
child: Text (
child: const Text (
' Retour au menu ' ,
style: TextStyle ( color: Colors . black , fontSize: 16 ) ,
) ,
) ,
SizedBox ( width: 16 ) ,
const SizedBox ( width: 16 ) ,
] ,
) ,
body: _cartItems . isEmpty
body:
_cartItems . isEmpty
? Center (
child: Column (
mainAxisAlignment: MainAxisAlignment . center ,
@ -327,7 +559,7 @@ class _CartPageState extends State<CartPage> {
size: 80 ,
color: Colors . grey [ 400 ] ,
) ,
SizedBox ( height: 16 ) ,
const SizedBox ( height: 16 ) ,
Text (
' Votre panier est vide ' ,
style: TextStyle ( fontSize: 18 , color: Colors . grey [ 600 ] ) ,
@ -340,10 +572,10 @@ class _CartPageState extends State<CartPage> {
/ / Header avec infos table
Container (
width: double . infinity ,
padding: EdgeInsets . all ( 20 ) ,
padding: const EdgeInsets . all ( 20 ) ,
color: Colors . white ,
child: Text (
' Table ${ widget . tableId } • ${ widget . personne } personne ${ widget . personne > 1 ? ' s ' : ' ' } ' ,
' ${ widget . tablename } • ${ widget . personne } personne ${ widget . personne > 1 ? ' s ' : ' ' } ' ,
style: TextStyle ( fontSize: 16 , color: Colors . grey [ 600 ] ) ,
) ,
) ,
@ -351,13 +583,14 @@ class _CartPageState extends State<CartPage> {
/ / Liste des articles
Expanded (
child: ListView . separated (
padding: EdgeInsets . all ( 16 ) ,
padding: const EdgeInsets . all ( 16 ) ,
itemCount: _cartItems . length ,
separatorBuilder: ( context , index ) = > SizedBox ( height: 12 ) ,
separatorBuilder:
( context , index ) = > const SizedBox ( height: 12 ) ,
itemBuilder: ( context , index ) {
final item = _cartItems [ index ] ;
return Container (
padding: EdgeInsets . all ( 16 ) ,
padding: const EdgeInsets . all ( 16 ) ,
decoration: BoxDecoration (
color: Colors . white ,
borderRadius: BorderRadius . circular ( 12 ) ,
@ -365,7 +598,7 @@ class _CartPageState extends State<CartPage> {
BoxShadow (
color: Colors . black . withOpacity ( 0.05 ) ,
blurRadius: 5 ,
offset: Offset ( 0 , 2 ) ,
offset: const Offset ( 0 , 2 ) ,
) ,
] ,
) ,
@ -373,12 +606,13 @@ class _CartPageState extends State<CartPage> {
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
mainAxisAlignment:
MainAxisAlignment . spaceBetween ,
children: [
Expanded (
child: Text (
item . nom ,
style: TextStyle (
style: const TextStyle (
fontSize: 18 ,
fontWeight: FontWeight . bold ,
) ,
@ -386,11 +620,11 @@ class _CartPageState extends State<CartPage> {
) ,
IconButton (
onPressed: ( ) = > _removeItem ( index ) ,
icon: Icon (
icon: const Icon (
Icons . delete_outline ,
color: Colors . red ,
) ,
constraints: BoxConstraints ( ) ,
constraints: const BoxConstraints ( ) ,
padding: EdgeInsets . zero ,
) ,
] ,
@ -402,10 +636,10 @@ class _CartPageState extends State<CartPage> {
color: Colors . grey [ 600 ] ,
) ,
) ,
if ( item . notes . isNotEmpty ) . . . [
SizedBox ( height: 8 ) ,
if ( item . commentaire . isNotEmpty ) . . . [
const SizedBox ( height: 8 ) ,
Text (
' Notes: ${ item . notes } ' ,
' Notes: ${ item . commentaire } ' ,
style: TextStyle (
fontSize: 14 ,
color: Colors . grey [ 600 ] ,
@ -413,42 +647,45 @@ class _CartPageState extends State<CartPage> {
) ,
) ,
] ,
SizedBox ( height: 16 ) ,
const SizedBox ( height: 16 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
mainAxisAlignment:
MainAxisAlignment . spaceBetween ,
children: [
/ / Contrôles de quantité
Row (
children: [
IconButton (
onPressed: ( ) = > _updateQuantity (
onPressed:
( ) = > _updateQuantity (
index ,
item . quantity - 1 ,
) ,
icon: Icon ( Icons . remove ) ,
icon: const Icon ( Icons . remove ) ,
style: IconButton . styleFrom (
backgroundColor: Colors . grey [ 200 ] ,
minimumSize: Size ( 40 , 40 ) ,
minimumSize: const Size ( 40 , 40 ) ,
) ,
) ,
SizedBox ( width: 16 ) ,
const SizedBox ( width: 16 ) ,
Text (
item . quantity . toString ( ) ,
style: TextStyle (
style: const TextStyle (
fontSize: 18 ,
fontWeight: FontWeight . bold ,
) ,
) ,
SizedBox ( width: 16 ) ,
const SizedBox ( width: 16 ) ,
IconButton (
onPressed: ( ) = > _updateQuantity (
onPressed:
( ) = > _updateQuantity (
index ,
item . quantity + 1 ,
) ,
icon: Icon ( Icons . add ) ,
icon: const Icon ( Icons . add ) ,
style: IconButton . styleFrom (
backgroundColor: Colors . grey [ 200 ] ,
minimumSize: Size ( 40 , 40 ) ,
minimumSize: const Size ( 40 , 40 ) ,
) ,
) ,
] ,
@ -473,7 +710,7 @@ class _CartPageState extends State<CartPage> {
/ / Récapitulatif
Container (
padding: EdgeInsets . all ( 20 ) ,
padding: const EdgeInsets . all ( 20 ) ,
decoration: BoxDecoration (
color: Colors . white ,
border: Border ( top: BorderSide ( color: Colors . grey [ 200 ] ! ) ) ,
@ -481,53 +718,62 @@ class _CartPageState extends State<CartPage> {
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text (
const Text (
' Récapitulatif ' ,
style: TextStyle (
fontSize: 20 ,
fontWeight: FontWeight . bold ,
) ,
) ,
SizedBox ( height: 16 ) ,
const SizedBox ( height: 16 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
children: [
Text ( ' Articles: ' , style: TextStyle ( fontSize: 16 ) ) ,
const Text (
' Articles: ' ,
style: TextStyle ( fontSize: 16 ) ,
) ,
Text (
_getTotalArticles ( ) . toString ( ) ,
style: TextStyle ( fontSize: 16 ) ,
style: const TextStyle ( fontSize: 16 ) ,
) ,
] ,
) ,
SizedBox ( height: 8 ) ,
const SizedBox ( height: 8 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
children: [
Text ( ' Table: ' , style: TextStyle ( fontSize: 16 ) ) ,
const Text (
' Table: ' ,
style: TextStyle ( fontSize: 16 ) ,
) ,
Text (
widget . tableId . toString ( ) ,
style: TextStyle ( fontSize: 16 ) ,
style: const TextStyle ( fontSize: 16 ) ,
) ,
] ,
) ,
SizedBox ( height: 8 ) ,
const SizedBox ( height: 8 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
children: [
Text ( ' Personnes: ' , style: TextStyle ( fontSize: 16 ) ) ,
const Text (
' Personnes: ' ,
style: TextStyle ( fontSize: 16 ) ,
) ,
Text (
widget . personne . toString ( ) ,
style: TextStyle ( fontSize: 16 ) ,
style: const TextStyle ( fontSize: 16 ) ,
) ,
] ,
) ,
SizedBox ( height: 16 ) ,
Divider ( ) ,
SizedBox ( height: 8 ) ,
const SizedBox ( height: 16 ) ,
const Divider ( ) ,
const SizedBox ( height: 8 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
children: [
Text (
const Text (
' Total: ' ,
style: TextStyle (
fontSize: 18 ,
@ -536,24 +782,25 @@ class _CartPageState extends State<CartPage> {
) ,
Text (
' ${ _calculateTotal ( ) . toStringAsFixed ( 2 ) } MGA ' ,
style: TextStyle (
style: const TextStyle (
fontSize: 18 ,
fontWeight: FontWeight . bold ,
) ,
) ,
] ,
) ,
SizedBox ( height: 20 ) ,
const SizedBox ( height: 20 ) ,
SizedBox (
width: double . infinity ,
child: ElevatedButton (
onPressed: _cartItems . isNotEmpty & & ! _isValidating
onPressed:
_cartItems . isNotEmpty & & ! _isValidating
? _showConfirmationDialog
: null ,
style: ElevatedButton . styleFrom (
backgroundColor: Colors . green [ 700 ] ,
foregroundColor: Colors . white ,
padding: EdgeInsets . symmetric ( vertical: 16 ) ,
padding: const EdgeInsets . symmetric ( vertical: 16 ) ,
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 12 ) ,
) ,
@ -563,7 +810,7 @@ class _CartPageState extends State<CartPage> {
mainAxisAlignment: MainAxisAlignment . center ,
children: [
if ( _isValidating ) . . . [
SizedBox (
const SizedBox (
width: 20 ,
height: 20 ,
child: CircularProgressIndicator (
@ -573,8 +820,8 @@ class _CartPageState extends State<CartPage> {
) ,
) ,
) ,
SizedBox ( width: 8 ) ,
Text (
const SizedBox ( width: 8 ) ,
const Text (
' Validation en cours... ' ,
style: TextStyle (
fontSize: 16 ,
@ -582,9 +829,9 @@ class _CartPageState extends State<CartPage> {
) ,
) ,
] else . . . [
Icon ( Icons . check , size: 20 ) ,
SizedBox ( width: 8 ) ,
Text (
const Icon ( Icons . check , size: 20 ) ,
const SizedBox ( width: 8 ) ,
const Text (
' Valider la commande ' ,
style: TextStyle (
fontSize: 16 ,
@ -596,6 +843,63 @@ class _CartPageState extends State<CartPage> {
) ,
) ,
) ,
const SizedBox ( height: 12 ) ,
/ / Bouton Payer directement
SizedBox (
width: double . infinity ,
child: ElevatedButton (
onPressed:
_cartItems . isNotEmpty & & ! _isValidating
? _payerDirectement
: null ,
style: ElevatedButton . styleFrom (
backgroundColor: Colors . orange [ 600 ] ,
foregroundColor: Colors . white ,
padding: const EdgeInsets . symmetric ( vertical: 16 ) ,
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 12 ) ,
) ,
disabledBackgroundColor: Colors . grey [ 300 ] ,
) ,
child: Row (
mainAxisAlignment: MainAxisAlignment . center ,
children: [
if ( _isValidating ) . . . [
const SizedBox (
width: 20 ,
height: 20 ,
child: CircularProgressIndicator (
strokeWidth: 2 ,
valueColor: AlwaysStoppedAnimation < Color > (
Colors . white ,
) ,
) ,
) ,
const SizedBox ( width: 8 ) ,
const Text (
' Traitement... ' ,
style: TextStyle (
fontSize: 16 ,
fontWeight: FontWeight . bold ,
) ,
) ,
] else . . . [
const Icon ( Icons . payment , size: 20 ) ,
const SizedBox ( width: 8 ) ,
const Text (
' Payer directement ' ,
style: TextStyle (
fontSize: 16 ,
fontWeight: FontWeight . bold ,
) ,
) ,
] ,
] ,
) ,
) ,
) ,
] ,
) ,
) ,
@ -610,13 +914,13 @@ class CartItemModel {
final String nom ;
final double prix ;
int quantity ;
final String notes ;
final String commentaire ;
CartItemModel ( {
required this . id ,
required this . nom ,
required this . prix ,
required this . quantity ,
required this . notes ,
required this . commentaire ,
} ) ;
}