234 lines
8.4 KiB
Dart
234 lines
8.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:em2rp/models/depot_model.dart';
|
|
import 'package:em2rp/services/travel_service.dart';
|
|
import 'package:em2rp/utils/colors.dart';
|
|
import 'package:em2rp/views/widgets/inputs/address_autocomplete_field.dart';
|
|
|
|
class DepotManagement extends StatefulWidget {
|
|
const DepotManagement({super.key});
|
|
|
|
@override
|
|
State<DepotManagement> createState() => _DepotManagementState();
|
|
}
|
|
|
|
class _DepotManagementState extends State<DepotManagement> {
|
|
final _service = TravelService();
|
|
bool _isLoading = false;
|
|
|
|
void _showDepotDialog({DepotModel? depot}) {
|
|
final nameCtrl = TextEditingController(text: depot?.name ?? '');
|
|
final addressCtrl = TextEditingController(text: depot?.address ?? '');
|
|
final formKey = GlobalKey<FormState>();
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
title: Text(depot == null ? 'Ajouter un dépôt' : 'Modifier le dépôt'),
|
|
content: SizedBox(
|
|
width: 420,
|
|
child: Form(
|
|
key: formKey,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextFormField(
|
|
controller: nameCtrl,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Nom du dépôt *',
|
|
border: OutlineInputBorder(),
|
|
prefixIcon: Icon(Icons.warehouse_outlined),
|
|
hintText: 'ex: Dépôt principal',
|
|
),
|
|
validator: (v) =>
|
|
v == null || v.trim().isEmpty ? 'Requis' : null,
|
|
),
|
|
const SizedBox(height: 16),
|
|
AddressAutocompleteField(
|
|
controller: addressCtrl,
|
|
label: 'Adresse du dépôt *',
|
|
validator: (v) =>
|
|
v == null || v.trim().isEmpty ? 'Requis' : null,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: const Text('Annuler'),
|
|
),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.rouge,
|
|
foregroundColor: Colors.white,
|
|
),
|
|
onPressed: () async {
|
|
if (!formKey.currentState!.validate()) return;
|
|
Navigator.pop(ctx);
|
|
setState(() => _isLoading = true);
|
|
try {
|
|
if (depot == null) {
|
|
await _service.addDepot(DepotModel(
|
|
id: '',
|
|
name: nameCtrl.text.trim(),
|
|
address: addressCtrl.text.trim(),
|
|
));
|
|
} else {
|
|
await _service.updateDepot(depot.copyWith(
|
|
name: nameCtrl.text.trim(),
|
|
address: addressCtrl.text.trim(),
|
|
));
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text('Erreur: $e'), backgroundColor: Colors.red),
|
|
);
|
|
}
|
|
} finally {
|
|
if (mounted) setState(() => _isLoading = false);
|
|
}
|
|
},
|
|
child: Text(depot == null ? 'Ajouter' : 'Enregistrer'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _delete(DepotModel depot) async {
|
|
final confirm = await showDialog<bool>(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
title: const Text('Supprimer le dépôt'),
|
|
content: Text('Supprimer "${depot.name}" ?'),
|
|
actions: [
|
|
TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('Annuler')),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.red,
|
|
foregroundColor: Colors.white,
|
|
),
|
|
onPressed: () => Navigator.pop(ctx, true),
|
|
child: const Text('Supprimer'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
if (confirm == true) {
|
|
setState(() => _isLoading = true);
|
|
try {
|
|
await _service.deleteDepot(depot.id);
|
|
} finally {
|
|
if (mounted) setState(() => _isLoading = false);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(Icons.warehouse_outlined, color: AppColors.rouge, size: 28),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
'Dépôts',
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.headlineSmall
|
|
?.copyWith(fontWeight: FontWeight.bold),
|
|
),
|
|
const Spacer(),
|
|
ElevatedButton.icon(
|
|
icon: const Icon(Icons.add),
|
|
label: const Text('Ajouter un dépôt'),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.rouge,
|
|
foregroundColor: Colors.white,
|
|
),
|
|
onPressed: () => _showDepotDialog(),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'Définissez les adresses de départ pour le calcul des frais de déplacement.',
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]),
|
|
),
|
|
const SizedBox(height: 24),
|
|
if (_isLoading) const Center(child: CircularProgressIndicator()),
|
|
Expanded(
|
|
child: StreamBuilder<List<DepotModel>>(
|
|
stream: _service.watchDepots(),
|
|
builder: (context, snap) {
|
|
if (snap.connectionState == ConnectionState.waiting) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
final depots = snap.data ?? [];
|
|
if (depots.isEmpty) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(Icons.warehouse_outlined,
|
|
size: 64, color: Colors.grey[300]),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
'Aucun dépôt configuré',
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.titleMedium
|
|
?.copyWith(color: Colors.grey[500]),
|
|
),
|
|
const SizedBox(height: 8),
|
|
const Text('Ajoutez un dépôt pour commencer.'),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
return ListView.separated(
|
|
itemCount: depots.length,
|
|
separatorBuilder: (_, __) => const Divider(height: 1),
|
|
itemBuilder: (context, i) {
|
|
final d = depots[i];
|
|
return ListTile(
|
|
leading: CircleAvatar(
|
|
backgroundColor: AppColors.rouge.withValues(alpha: 0.1),
|
|
child: Icon(Icons.warehouse_outlined, color: AppColors.rouge),
|
|
),
|
|
title: Text(d.name,
|
|
style: const TextStyle(fontWeight: FontWeight.w600)),
|
|
subtitle: Text(d.address),
|
|
trailing: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
icon: const Icon(Icons.edit_outlined),
|
|
tooltip: 'Modifier',
|
|
onPressed: () => _showDepotDialog(depot: d),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.delete_outline, color: Colors.red),
|
|
tooltip: 'Supprimer',
|
|
onPressed: () => _delete(d),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|