a
This commit is contained in:
@@ -107,6 +107,7 @@ class TicketModel extends Equatable {
|
||||
final TicketResult? ticketResult;
|
||||
final String? resolutionNotes;
|
||||
final String? customerName;
|
||||
final String? customerEmail;
|
||||
final String? targetModelName;
|
||||
final String? sourceModelName;
|
||||
final String? createdById;
|
||||
@@ -142,6 +143,7 @@ class TicketModel extends Equatable {
|
||||
this.ticketResult,
|
||||
this.resolutionNotes,
|
||||
this.customerName,
|
||||
this.customerEmail,
|
||||
this.targetModelName,
|
||||
this.sourceModelName,
|
||||
this.createdById,
|
||||
@@ -192,6 +194,7 @@ class TicketModel extends Equatable {
|
||||
TicketResult? ticketResult,
|
||||
String? resolutionNotes,
|
||||
String? customerName,
|
||||
String? customerEmail,
|
||||
String? targetModelName,
|
||||
String? sourceModelName,
|
||||
String? createdById,
|
||||
@@ -228,6 +231,7 @@ class TicketModel extends Equatable {
|
||||
ticketResult: ticketResult ?? this.ticketResult,
|
||||
resolutionNotes: resolutionNotes ?? this.resolutionNotes,
|
||||
customerName: customerName ?? this.customerName,
|
||||
customerEmail: customerEmail ?? this.customerEmail,
|
||||
targetModelName: targetModelName ?? this.targetModelName,
|
||||
sourceModelName: sourceModelName ?? this.sourceModelName,
|
||||
createdById: createdById ?? this.createdById,
|
||||
@@ -276,6 +280,7 @@ class TicketModel extends Equatable {
|
||||
ticketResult: TicketResult.fromString(map['ticket_result'] as String?),
|
||||
resolutionNotes: map['resolution_notes'] as String?,
|
||||
customerName: (map['customer']?['name'] as String?).myFormat(),
|
||||
customerEmail: (map['customer']?['email'] as String?).myFormat(),
|
||||
targetModelName: (map['target_model']?['name_with_brand'] as String?)
|
||||
?.myFormat(),
|
||||
sourceModelName: (map['source_model']?['name_with_brand'] as String?)
|
||||
|
||||
@@ -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]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user