resolve
This commit is contained in:
commit
d9998e1a79
@ -37,7 +37,7 @@ class CommandeDetail {
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.items,
|
||||
this.tablename,
|
||||
required this.tablename,
|
||||
});
|
||||
|
||||
factory CommandeDetail.fromJson(Map<String, dynamic> json) {
|
||||
@ -56,6 +56,7 @@ class CommandeDetail {
|
||||
totalTtc: double.tryParse(data['total_ttc']?.toString() ?? '0') ?? 0.0,
|
||||
modePaiement: data['mode_paiement'],
|
||||
commentaires: data['commentaires'],
|
||||
tablename: json['tablename'] ?? 'Inconnue',
|
||||
serveur: data['serveur'] ?? 'Serveur par défaut',
|
||||
dateCommande:
|
||||
data['date_commande'] != null
|
||||
@ -78,7 +79,6 @@ class CommandeDetail {
|
||||
?.map((item) => CommandeItem.fromJson(item))
|
||||
.toList() ??
|
||||
[],
|
||||
tablename: data['tablename'] ?? 'Table inconnue',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@ class TableOrder {
|
||||
final double? total; // Optionnel pour les commandes en cours
|
||||
final bool isEncashed;
|
||||
final String? time; // Heure de la commande si applicable
|
||||
final String? date; // Date de la commande si applicable
|
||||
final DateTime? date; // Date de la commande si applicable
|
||||
final String? tablename; // Date de la commande si applicable
|
||||
// final int? persons; // Nombre de personnes si applicable
|
||||
|
||||
TableOrder({
|
||||
@ -25,31 +26,34 @@ class TableOrder {
|
||||
this.isEncashed = false,
|
||||
this.time,
|
||||
this.date,
|
||||
this.tablename,
|
||||
// this.persons,
|
||||
});
|
||||
factory TableOrder.fromJson(Map<String, dynamic> json) {
|
||||
return TableOrder(
|
||||
id: json['id'] ?? 0,
|
||||
nom: json['nom'] ?? '',
|
||||
capacity: json['capacity'] ?? 1,
|
||||
status: json['statut'] ?? 'available',
|
||||
location: json['location'] ?? '',
|
||||
tablename: json['tablename'] ?? '',
|
||||
createdAt: json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: DateTime.now(),
|
||||
updatedAt: json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: DateTime.now(),
|
||||
total: json['total_ht'] != null
|
||||
? double.tryParse(json['total_ht'].toString())
|
||||
: null,
|
||||
isEncashed: json['is_encashed'] ?? false,
|
||||
time: json['time'],
|
||||
date: json['date_commande'] != null
|
||||
? DateTime.parse(json['date_commande']) // tu avais mis updated_at ici par erreur
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
factory TableOrder.fromJson(Map<String, dynamic> json) {
|
||||
return TableOrder(
|
||||
id: json['id'] ?? 0,
|
||||
nom: json['nom'] ?? '',
|
||||
capacity: json['capacity'] ?? 1,
|
||||
status: json['status'] ?? 'available',
|
||||
location: json['location'] ?? '',
|
||||
createdAt:
|
||||
json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: DateTime.now(),
|
||||
updatedAt:
|
||||
json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: DateTime.now(),
|
||||
total: json['total'] != null ? (json['total'] as num).toDouble() : null,
|
||||
isEncashed: json['is_encashed'] ?? false,
|
||||
time: json['time'],
|
||||
date: json['date'],
|
||||
// persons: json['persons'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
@ -58,6 +62,7 @@ class TableOrder {
|
||||
'capacity': capacity,
|
||||
'status': status,
|
||||
'location': location,
|
||||
'tablename': tablename,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
if (total != null) 'total': total,
|
||||
@ -122,7 +127,7 @@ class TableOrder {
|
||||
double? total,
|
||||
bool? isEncashed,
|
||||
String? time,
|
||||
String? date,
|
||||
DateTime? date,
|
||||
int? persons,
|
||||
}) {
|
||||
return TableOrder(
|
||||
@ -153,6 +158,10 @@ class TableOrder {
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
|
||||
get items => null;
|
||||
|
||||
where(bool Function(dynamic commande) param0) {}
|
||||
}
|
||||
|
||||
// Énumération pour les statuts (optionnel, pour plus de type safety)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import './tables.dart';
|
||||
import '../layouts/main_layout.dart';
|
||||
|
||||
@ -54,6 +55,15 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Méthode pour gérer la touche Entrée
|
||||
void _handleKeyPress(KeyEvent event) {
|
||||
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
if (!_isLoading) {
|
||||
_login();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _login() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
@ -99,279 +109,295 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5), // Light gray background
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Container(
|
||||
width: 400,
|
||||
padding: const EdgeInsets.all(40.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Logo personnalisé
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
child: Image.asset(
|
||||
'assets/logo_transparent.png',
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
// Fallback en cas d'erreur de chargement
|
||||
return Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.green,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.restaurant_menu,
|
||||
color: Colors.white,
|
||||
size: 32,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Title
|
||||
const Text(
|
||||
'Restaurant App',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Subtitle
|
||||
const Text(
|
||||
'Connectez-vous pour accéder au système de commandes',
|
||||
style: TextStyle(color: Colors.grey, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Error message
|
||||
if (_errorMessage != null)
|
||||
return KeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKeyEvent: _handleKeyPress,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5), // Light gray background
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Container(
|
||||
width: 400,
|
||||
padding: const EdgeInsets.all(40.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Logo personnalisé
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red.shade50,
|
||||
border: Border.all(color: Colors.red.shade200),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
style: TextStyle(
|
||||
color: Colors.red.shade600,
|
||||
fontSize: 14,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
width: 80,
|
||||
height: 80,
|
||||
child: Image.asset(
|
||||
'assets/logo_transparent.png',
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
// Fallback en cas d'erreur de chargement
|
||||
return Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.green,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.restaurant_menu,
|
||||
color: Colors.white,
|
||||
size: 32,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Email label
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Email',
|
||||
// Title
|
||||
const Text(
|
||||
'Restaurant App',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Email field
|
||||
TextFormField(
|
||||
controller: emailController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(
|
||||
Icons.email_outlined,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
hintText: 'serveur@restaurant.com',
|
||||
hintStyle: const TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: const BorderSide(color: Colors.green),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
// Subtitle
|
||||
const Text(
|
||||
'Connectez-vous pour accéder au système de commandes',
|
||||
style: TextStyle(color: Colors.grey, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Veuillez entrer votre email';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Password label
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Mot de passe',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Password field
|
||||
TextFormField(
|
||||
controller: passwordController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(
|
||||
Icons.lock_outline,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
hintText: '••••••••',
|
||||
hintStyle: const TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: const BorderSide(color: Colors.green),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
),
|
||||
obscureText: true,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Veuillez entrer votre mot de passe';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Login button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isLoading ? null : _login,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
// Error message
|
||||
if (_errorMessage != null)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red.shade50,
|
||||
border: Border.all(color: Colors.red.shade200),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child:
|
||||
_isLoading
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
: const Text(
|
||||
'Se connecter',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Demo accounts section
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Comptes de démonstration :',
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
style: TextStyle(
|
||||
color: Colors.red.shade600,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.grey,
|
||||
height: 1.4,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Serveur : ',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'serveur@restaurant.com / serveur123\n',
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Admin : ',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'admin@restaurant.com / admin123',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Email label
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Email',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Email field
|
||||
TextFormField(
|
||||
controller: emailController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(
|
||||
Icons.email_outlined,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
hintText: 'serveur@restaurant.com',
|
||||
hintStyle: const TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: const BorderSide(color: Colors.green),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Veuillez entrer votre email';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Password label
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Mot de passe',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black87,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Password field
|
||||
TextFormField(
|
||||
controller: passwordController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(
|
||||
Icons.lock_outline,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
hintText: '••••••••',
|
||||
hintStyle: const TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
borderSide: const BorderSide(color: Colors.green),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 16,
|
||||
),
|
||||
),
|
||||
obscureText: true,
|
||||
textInputAction: TextInputAction.done,
|
||||
onFieldSubmitted: (_) => _login(), // Validation quand on appuie sur Entrée
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Veuillez entrer votre mot de passe';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Login button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isLoading ? null : _login,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child:
|
||||
_isLoading
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
: const Text(
|
||||
'Se connecter',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Demo accounts section
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Comptes de démonstration :',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.grey,
|
||||
height: 1.4,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Serveur : ',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'serveur@restaurant.com / serveur123\n',
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Admin : ',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'admin@restaurant.com / admin123',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Astuce : Appuyez sur Entrée pour vous connecter',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -432,4 +458,4 @@ class HomeScreen extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,10 @@ class RestaurantApiService {
|
||||
static Future<List<TableOrder>> getCommandes() async {
|
||||
try {
|
||||
final response = await http
|
||||
.get(Uri.parse('$baseUrl/api/commandes'), headers: _headers)
|
||||
.get(
|
||||
Uri.parse('$baseUrl/api/commandes?statut=servie'),
|
||||
headers: _headers,
|
||||
)
|
||||
.timeout(
|
||||
const Duration(seconds: 30),
|
||||
onTimeout: () => throw TimeoutException('Délai d\'attente dépassé'),
|
||||
@ -171,6 +174,7 @@ class RestaurantApiService {
|
||||
totalTtc: 14.00,
|
||||
modePaiement: null,
|
||||
commentaires: null,
|
||||
tablename: 'a',
|
||||
serveur: "Serveur par défaut",
|
||||
dateCommande: DateTime.parse("2025-08-02T15:03:44.000Z"),
|
||||
dateService: null,
|
||||
@ -234,7 +238,6 @@ class RestaurantApiService {
|
||||
updatedAt: DateTime.now(),
|
||||
total: 27.00,
|
||||
time: '00:02',
|
||||
date: '02/08/2025',
|
||||
),
|
||||
// Ajoutez d'autres tables de test...
|
||||
];
|
||||
|
||||
@ -12,8 +12,13 @@ class CommandeCard extends StatelessWidget {
|
||||
required this.onAllerCaisse,
|
||||
});
|
||||
|
||||
String _formatTime(DateTime dateTime) {
|
||||
return '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')} ${dateTime.day.toString().padLeft(2, '0')}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.year}';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
@ -38,7 +43,7 @@ class CommandeCard extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Table ${commande.tableNumber}',
|
||||
' ${commande.tablename}',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -57,7 +62,7 @@ class CommandeCard extends StatelessWidget {
|
||||
Icon(Icons.check_circle, color: Colors.white, size: 16),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
'À encaisser',
|
||||
'Près à encaisser',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
@ -78,7 +83,8 @@ class CommandeCard extends StatelessWidget {
|
||||
Icon(Icons.access_time, size: 16, color: Colors.grey[600]),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'${commande.time} • ${commande.date} ',
|
||||
// Fixed: Pass DateTime directly, not as string
|
||||
commande.date != null ? _formatTime(commande.date!) : 'Date non disponible',
|
||||
style: TextStyle(color: Colors.grey[600], fontSize: 14),
|
||||
),
|
||||
],
|
||||
@ -99,7 +105,7 @@ class CommandeCard extends StatelessWidget {
|
||||
style: TextStyle(color: Colors.grey[600], fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
'${commande.total?.toStringAsFixed(2)} MGA',
|
||||
'${commande.total?.toStringAsFixed(2) ?? '0.00'} MGA',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -129,4 +135,4 @@ class CommandeCard extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
# Project-level configuration.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(itrimobe LANGUAGES CXX)
|
||||
project(commande LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "itrimobe")
|
||||
set(BINARY_NAME "commande")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
|
||||
@ -90,12 +90,12 @@ BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "com.example" "\0"
|
||||
VALUE "FileDescription", "itrimobe" "\0"
|
||||
VALUE "FileDescription", "commande" "\0"
|
||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||
VALUE "InternalName", "itrimobe" "\0"
|
||||
VALUE "InternalName", "commande" "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0"
|
||||
VALUE "OriginalFilename", "itrimobe.exe" "\0"
|
||||
VALUE "ProductName", "itrimobe" "\0"
|
||||
VALUE "OriginalFilename", "commande.exe" "\0"
|
||||
VALUE "ProductName", "commande" "\0"
|
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||
END
|
||||
END
|
||||
|
||||
@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.Create(L"itrimobe", origin, size)) {
|
||||
if (!window.Create(L"commande", origin, size)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
window.SetQuitOnClose(true);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 33 KiB |
Loading…
Reference in New Issue
Block a user