a
This commit is contained in:
@@ -107,6 +107,7 @@ class TicketModel extends Equatable {
|
|||||||
final TicketResult? ticketResult;
|
final TicketResult? ticketResult;
|
||||||
final String? resolutionNotes;
|
final String? resolutionNotes;
|
||||||
final String? customerName;
|
final String? customerName;
|
||||||
|
final String? customerEmail;
|
||||||
final String? targetModelName;
|
final String? targetModelName;
|
||||||
final String? sourceModelName;
|
final String? sourceModelName;
|
||||||
final String? createdById;
|
final String? createdById;
|
||||||
@@ -142,6 +143,7 @@ class TicketModel extends Equatable {
|
|||||||
this.ticketResult,
|
this.ticketResult,
|
||||||
this.resolutionNotes,
|
this.resolutionNotes,
|
||||||
this.customerName,
|
this.customerName,
|
||||||
|
this.customerEmail,
|
||||||
this.targetModelName,
|
this.targetModelName,
|
||||||
this.sourceModelName,
|
this.sourceModelName,
|
||||||
this.createdById,
|
this.createdById,
|
||||||
@@ -192,6 +194,7 @@ class TicketModel extends Equatable {
|
|||||||
TicketResult? ticketResult,
|
TicketResult? ticketResult,
|
||||||
String? resolutionNotes,
|
String? resolutionNotes,
|
||||||
String? customerName,
|
String? customerName,
|
||||||
|
String? customerEmail,
|
||||||
String? targetModelName,
|
String? targetModelName,
|
||||||
String? sourceModelName,
|
String? sourceModelName,
|
||||||
String? createdById,
|
String? createdById,
|
||||||
@@ -228,6 +231,7 @@ class TicketModel extends Equatable {
|
|||||||
ticketResult: ticketResult ?? this.ticketResult,
|
ticketResult: ticketResult ?? this.ticketResult,
|
||||||
resolutionNotes: resolutionNotes ?? this.resolutionNotes,
|
resolutionNotes: resolutionNotes ?? this.resolutionNotes,
|
||||||
customerName: customerName ?? this.customerName,
|
customerName: customerName ?? this.customerName,
|
||||||
|
customerEmail: customerEmail ?? this.customerEmail,
|
||||||
targetModelName: targetModelName ?? this.targetModelName,
|
targetModelName: targetModelName ?? this.targetModelName,
|
||||||
sourceModelName: sourceModelName ?? this.sourceModelName,
|
sourceModelName: sourceModelName ?? this.sourceModelName,
|
||||||
createdById: createdById ?? this.createdById,
|
createdById: createdById ?? this.createdById,
|
||||||
@@ -276,6 +280,7 @@ class TicketModel extends Equatable {
|
|||||||
ticketResult: TicketResult.fromString(map['ticket_result'] as String?),
|
ticketResult: TicketResult.fromString(map['ticket_result'] as String?),
|
||||||
resolutionNotes: map['resolution_notes'] as String?,
|
resolutionNotes: map['resolution_notes'] as String?,
|
||||||
customerName: (map['customer']?['name'] as String?).myFormat(),
|
customerName: (map['customer']?['name'] as String?).myFormat(),
|
||||||
|
customerEmail: (map['customer']?['email'] as String?).myFormat(),
|
||||||
targetModelName: (map['target_model']?['name_with_brand'] as String?)
|
targetModelName: (map['target_model']?['name_with_brand'] as String?)
|
||||||
?.myFormat(),
|
?.myFormat(),
|
||||||
sourceModelName: (map['source_model']?['name_with_brand'] as String?)
|
sourceModelName: (map['source_model']?['name_with_brand'] as String?)
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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/customer_section.dart';
|
||||||
import 'package:flux/core/widgets/shared_forms/model_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/core/widgets/shared_forms/shared_files_section.dart';
|
||||||
import 'package:flux/features/attachments/blocs/attachments_bloc.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_cubit.dart';
|
||||||
import 'package:flux/features/tickets/blocs/ticket_form_state.dart';
|
import 'package:flux/features/tickets/blocs/ticket_form_state.dart';
|
||||||
import 'package:flux/features/tickets/models/ticket_model.dart';
|
import 'package:flux/features/tickets/models/ticket_model.dart';
|
||||||
import 'package:flux/core/widgets/shared_forms/staff_section.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/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 {
|
class TicketFormScreen extends StatefulWidget {
|
||||||
final TicketModel? existingTicket;
|
final TicketModel? existingTicket;
|
||||||
@@ -121,6 +126,102 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
|||||||
return newId;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
@@ -133,7 +234,11 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.status == TicketFormStatus.success) {
|
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) {
|
} else if (state.status == TicketFormStatus.successAndAddAnother) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
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