lavorazione dei ticket
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flux/features/tickets/models/ticket_model.dart';
|
||||
|
||||
Future<({TicketResult result, double finalPrice})?> showCompletionTicketDialog(
|
||||
BuildContext context, {
|
||||
required double calculatedTotal,
|
||||
}) async {
|
||||
return showDialog<({TicketResult result, double finalPrice})>(
|
||||
context: context,
|
||||
barrierDismissible: false, // Obbliga l'utente a premere un bottone
|
||||
builder: (context) => CompletionTicketDialog(initialTotal: calculatedTotal),
|
||||
);
|
||||
}
|
||||
|
||||
class CompletionTicketDialog extends StatefulWidget {
|
||||
final double initialTotal;
|
||||
|
||||
const CompletionTicketDialog({super.key, required this.initialTotal});
|
||||
|
||||
@override
|
||||
State<CompletionTicketDialog> createState() => _CompletionTicketDialogState();
|
||||
}
|
||||
|
||||
class _CompletionTicketDialogState extends State<CompletionTicketDialog> {
|
||||
late final TextEditingController _priceCtrl;
|
||||
TicketResult _selectedResult = TicketResult.success; // Default: Riparato!
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Inizializziamo il campo testuale con il totale calcolato
|
||||
_priceCtrl = TextEditingController(
|
||||
text: widget.initialTotal.toStringAsFixed(2),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_priceCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return AlertDialog(
|
||||
title: const Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle_outline, color: Colors.green),
|
||||
SizedBox(width: 8),
|
||||
Text('Completa Lavorazione'),
|
||||
],
|
||||
),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite, // Per allargare bene la modale
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Specifica l\'esito della lavorazione e il totale da incassare.',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// --- ESITO LAVORAZIONE (Choice Chips) ---
|
||||
const Text('Esito:', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ChoiceChip(
|
||||
label: const Center(child: Text('Riparato')),
|
||||
selectedColor: Colors.green.withValues(alpha: 0.2),
|
||||
selected: _selectedResult == TicketResult.success,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
setState(() => _selectedResult = TicketResult.success);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: ChoiceChip(
|
||||
label: const Center(child: Text('Non Riparato')),
|
||||
selectedColor: Colors.red.withValues(alpha: 0.2),
|
||||
selected: _selectedResult == TicketResult.failure,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
setState(() => _selectedResult = TicketResult.failure);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// --- PREZZO FINALE ---
|
||||
const Text(
|
||||
'Totale da pagare al ritiro:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _priceCtrl,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp(r'[0-9.,]'),
|
||||
), // Solo numeri, punti e virgole
|
||||
],
|
||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.euro),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: theme.colorScheme.surfaceContainerHighest.withValues(
|
||||
alpha: 0.3,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Annulla'),
|
||||
),
|
||||
FilledButton.icon(
|
||||
style: FilledButton.styleFrom(backgroundColor: Colors.green.shade600),
|
||||
onPressed: () {
|
||||
// Conversione sicura: cambiamo un'eventuale virgola italiana in punto
|
||||
final safePriceText = _priceCtrl.text.replaceAll(',', '.');
|
||||
final finalPrice = double.tryParse(safePriceText) ?? 0.0;
|
||||
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop((result: _selectedResult, finalPrice: finalPrice));
|
||||
},
|
||||
icon: const Icon(Icons.save),
|
||||
label: const Text('Conferma Completamento'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flux/core/routes/routes.dart';
|
||||
import 'package:flux/features/tickets/blocs/ticket_form_cubit.dart';
|
||||
import 'package:flux/features/tickets/blocs/ticket_form_state.dart';
|
||||
import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart';
|
||||
import 'package:flux/features/tickets/models/ticket_model.dart';
|
||||
import 'package:flux/features/tickets/ui/ticket_workspace/completion_ticket_dialog.dart';
|
||||
import 'package:flux/features/tickets/ui/ticket_workspace/pause_ticket_dialog.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class TicketWorkspaceScreen extends StatelessWidget {
|
||||
const TicketWorkspaceScreen({super.key});
|
||||
@@ -285,8 +289,30 @@ class TicketWorkspaceScreen extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
backgroundColor: Colors.green.shade600,
|
||||
),
|
||||
onPressed: () {
|
||||
// TODO: Logica Completa Riparazione
|
||||
onPressed: () async {
|
||||
// 1. Apriamo la nuova modale avanzata e aspettiamo il Record.
|
||||
// (Per ora passiamo 0.0, poi lo sostituiremo con la somma dei costi)
|
||||
final completionData = await showCompletionTicketDialog(
|
||||
context,
|
||||
calculatedTotal: 0.0,
|
||||
);
|
||||
|
||||
// 2. Se l'utente ha premuto "Conferma" e non "Annulla"...
|
||||
if (completionData != null && context.mounted) {
|
||||
// 3. Lanciamo l'azione nel Cubit
|
||||
await context.read<TicketFormCubit>().completeTicket(
|
||||
result: completionData.result,
|
||||
finalPrice: completionData.finalPrice,
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
// 4. Avvisiamo il "Vigile Urbano" di ricaricare la lista
|
||||
context.read<TicketListCubit>().fetchTickets(reset: true);
|
||||
|
||||
// 5. Teletrasporto alla Base
|
||||
context.goNamed(Routes.home);
|
||||
}
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.check_circle_outline),
|
||||
label: const Text(
|
||||
|
||||
Reference in New Issue
Block a user