This commit is contained in:
2026-05-10 15:36:26 +02:00
parent 5c86483563
commit b91442872d
2 changed files with 163 additions and 1 deletions

View File

@@ -1,14 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/widgets/shared_forms/customer_section.dart';
import 'package:flux/core/widgets/shared_forms/model_section.dart';
import 'package:flux/core/widgets/shared_forms/shared_files_section.dart';
import 'package:flux/features/attachments/blocs/attachments_bloc.dart';
import 'package:flux/features/company/models/company_model.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/models/ticket_model.dart';
import 'package:flux/core/widgets/shared_forms/staff_section.dart';
import 'package:flux/features/tickets/models/ticket_status_extension.dart';
import 'package:flux/features/tickets/utils/ticket_pdf_service.dart';
import 'package:get_it/get_it.dart';
import 'package:printing/printing.dart';
class TicketFormScreen extends StatefulWidget {
final TicketModel? existingTicket;
@@ -121,6 +126,102 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
return newId;
}
void _showSuccessActions(
BuildContext context,
TicketModel ticket,
CompanyModel company,
) {
showModalBottomSheet(
context: context,
isDismissible: false, // Costringiamo l'operatore a una scelta conscia
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
builder: (context) => Container(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
),
const SizedBox(height: 24),
const Icon(Icons.check_circle, color: Colors.green, size: 64),
const SizedBox(height: 16),
Text(
"Ticket Salvato!",
style: Theme.of(
context,
).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
),
Text(
"Rif: ${ticket.referenceId}",
style: TextStyle(color: Colors.grey[600], fontSize: 18),
),
const SizedBox(height: 32),
// Griglia delle Azioni
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 1.5,
children: [
_ActionButton(
icon: Icons.print,
label: "Ricevuta A4",
onTap: () async {
final pdf = await TicketPdfService().generateTicketReceipt(
ticket,
company,
);
await Printing.layoutPdf(onLayout: (format) => pdf);
},
),
if (company.labelFormat != LabelFormat.none)
_ActionButton(
icon: Icons.label,
label: "Etichetta",
onTap: () async {
final pdf = await TicketPdfService().generateLabelPdf(
ticket,
company,
);
await Printing.layoutPdf(onLayout: (format) => pdf);
},
),
_ActionButton(
icon: Icons.email,
label: "Invia Email",
onTap: ticket.customerEmail != null
? () => _sendEmail(ticket)
: null,
),
_ActionButton(
icon: Icons.close,
label: "Chiudi",
color: Colors.blue[900],
textColor: Colors.white,
onTap: () => Navigator.of(context).pop(), // Torna alla lista
),
],
),
],
),
),
);
}
Future<void> _sendEmail(TicketModel ticket) async {
//TODO send ticket receipt via email
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@@ -133,7 +234,11 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
}
if (state.status == TicketFormStatus.success) {
Navigator.of(context).pop();
_showSuccessActions(
context,
state.ticket,
GetIt.I.get<SessionCubit>().state.company!,
);
} else if (state.status == TicketFormStatus.successAndAddAnother) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
@@ -597,3 +702,55 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
);
}
}
// Widget helper per i bottoni dell'Action Hub
class _ActionButton extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback? onTap;
final Color? color;
final Color? textColor;
const _ActionButton({
required this.icon,
required this.label,
this.onTap,
this.color,
this.textColor,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
child: Container(
decoration: BoxDecoration(
color: onTap == null ? Colors.grey[100] : (color ?? Colors.grey[200]),
borderRadius: BorderRadius.circular(16),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
color: onTap == null
? Colors.grey
: (textColor ?? Colors.blue[900]),
),
const SizedBox(height: 8),
Text(
label,
style: TextStyle(
fontWeight: FontWeight.bold,
color: onTap == null
? Colors.grey
: (textColor ?? Colors.blue[900]),
),
),
],
),
),
);
}
}