refactot ticket model + cubit

This commit is contained in:
2026-05-06 12:20:26 +02:00
parent 1e9e6947b3
commit bdde092976
3 changed files with 236 additions and 14 deletions

View File

@@ -0,0 +1,169 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/customers/models/customer_model.dart';
import 'package:flux/features/tickets/models/ticket_model.dart';
import 'package:flux/features/tickets/data/ticket_repository.dart';
import 'package:get_it/get_it.dart';
import 'ticket_form_state.dart';
class TicketFormCubit extends Cubit<TicketFormState> {
final TicketRepository _repository = GetIt.I.get<TicketRepository>();
final SessionCubit _sessionCubit = GetIt.I.get<SessionCubit>();
TicketFormCubit()
: super(
// Inizializziamo con un ticket vuoto di default
TicketFormState(
ticket: TicketModel.empty(
companyId: GetIt.I.get<SessionCubit>().state.company!.id!,
),
),
);
/// 1. INIZIALIZZAZIONE (Se stiamo modificando un ticket esistente)
void initForm(TicketModel? existingTicket) {
if (existingTicket != null) {
emit(
state.copyWith(ticket: existingTicket, status: TicketFormStatus.ready),
);
} else {
// È un nuovo ticket! Inseriamo i default base (Azienda, Negozio, Creatore)
final currentUser = _sessionCubit.state.currentStaffMember;
final currentStore = _sessionCubit.state.currentStore;
final companyId = _sessionCubit.state.company?.id ?? '';
final newTicket =
TicketModel.empty(
companyId: _sessionCubit.state.company!.id!,
).copyWith(
companyId: companyId,
storeId: currentStore?.id,
staffId: currentUser?.id,
createdById: currentUser?.name,
// Impostiamo lo stato iniziale
status: TicketStatus.open,
ticketType: TicketType.repair, // Default
);
emit(state.copyWith(ticket: newTicket, status: TicketFormStatus.ready));
}
}
/// 2. AGGIORNAMENTO CLIENTE (Usato dal nostro SharedCustomerSection!)
void updateCustomer(CustomerModel customer) {
emit(
state.copyWith(
ticket: state.ticket.copyWith(
customerId: customer.id,
customerName: customer.name,
alternativePhoneNumber: customer.phoneNumber, // Comodo come fallback!
),
),
);
}
/// 3. AGGIORNAMENTO MODELLO (Usato dal nostro SharedModelSection!)
void updateModel({required String modelId, required String modelName}) {
emit(
state.copyWith(
ticket: state.ticket.copyWith(
targetModelId: modelId,
targetModelName: modelName,
),
),
);
}
void updateCreator({required String staffId, required String staffName}) {
emit(
state.copyWith(
ticket: state.ticket.copyWith(staffId: staffId, createdById: staffName),
),
);
}
/// 4. AGGIORNAMENTO GENERICO DEI CAMPI
void updateFields({
TicketType? ticketType,
TicketStatus? status,
String? request,
String? targetSn,
String? alternativePhoneNumber,
bool? hasCourtesyDevice,
String? includedAccessories,
String? publicNotes,
String? internalNotes,
double? customerPrice,
double? internalCost,
String? assignedToId,
String? assignedToName,
}) {
emit(
state.copyWith(
ticket: state.ticket.copyWith(
ticketType: ticketType ?? state.ticket.ticketType,
status: status ?? state.ticket.status,
request: request ?? state.ticket.request,
targetSn: targetSn ?? state.ticket.targetSn,
alternativePhoneNumber:
alternativePhoneNumber ?? state.ticket.alternativePhoneNumber,
hasCourtesyDevice:
hasCourtesyDevice ?? state.ticket.hasCourtesyDevice,
includedAccessories:
includedAccessories ?? state.ticket.includedAccessories,
publicNotes: publicNotes ?? state.ticket.publicNotes,
internalNotes: internalNotes ?? state.ticket.internalNotes,
customerPrice: customerPrice ?? state.ticket.customerPrice,
internalCost: internalCost ?? state.ticket.internalCost,
assignedToId: assignedToId ?? state.ticket.assignedToId,
assignedToName: assignedToName ?? state.ticket.assignedToName,
),
),
);
}
/// 5. SALVATAGGIO
Future<void> saveTicket({required bool keepAdding}) async {
emit(state.copyWith(status: TicketFormStatus.saving));
try {
final ticketToSave = state.ticket;
// Validazione base
if (ticketToSave.customerId == null || ticketToSave.customerId!.isEmpty) {
throw Exception("Seleziona un cliente prima di salvare.");
}
final savedTicket = await _repository.saveTicket(ticketToSave);
if (keepAdding) {
emit(
state.copyWith(
status: TicketFormStatus.successAndAddAnother,
// Svuotiamo il form per il prossimo, mantenendo Store e Creatore ATTUALI
ticket: TicketModel.empty().copyWith(
companyId: savedTicket.companyId,
storeId: savedTicket.storeId,
createdById: ticketToSave
.createdById, // Manteniamo quello selezionato nella tendina!
createdByName: ticketToSave.createdByName,
status: TicketStatus.open,
ticketType: TicketType.repair,
),
),
);
} else {
emit(
state.copyWith(status: TicketFormStatus.success, ticket: savedTicket),
);
}
} catch (e) {
emit(
state.copyWith(
status: TicketFormStatus.failure,
errorMessage: e.toString(),
),
);
}
}
}

View File

@@ -0,0 +1,40 @@
import 'package:equatable/equatable.dart';
import 'package:flux/features/tickets/models/ticket_model.dart';
// Adatta gli import al tuo progetto!
enum TicketFormStatus {
initial,
ready,
loading,
saving,
success,
successAndAddAnother,
failure,
}
class TicketFormState extends Equatable {
final TicketModel ticket;
final TicketFormStatus status;
final String? errorMessage;
const TicketFormState({
required this.ticket,
this.status = TicketFormStatus.initial,
this.errorMessage,
});
@override
List<Object?> get props => [ticket, status, errorMessage];
TicketFormState copyWith({
TicketModel? ticket,
TicketFormStatus? status,
String? errorMessage,
}) {
return TicketFormState(
ticket: ticket ?? this.ticket,
status: status ?? this.status,
errorMessage: errorMessage,
);
}
}

View File

@@ -96,7 +96,6 @@ class TicketModel extends Equatable {
final DateTime? closedAt;
final DateTime? returnedAt;
final String request;
final String? staffId;
final WarrantyType? warrantyType;
final String? publicNotes;
final String? internalNotes;
@@ -112,7 +111,10 @@ class TicketModel extends Equatable {
final String? customerName;
final String? targetModelName;
final String? sourceModelName;
final String? staffName;
final String? createdById;
final String? createdByName;
final String? assignedToId;
final String? assignedToName;
final String? includedAccessories;
const TicketModel({
@@ -130,7 +132,6 @@ class TicketModel extends Equatable {
this.closedAt,
this.returnedAt,
this.request = '',
this.staffId,
this.warrantyType,
this.publicNotes,
this.internalNotes,
@@ -146,14 +147,17 @@ class TicketModel extends Equatable {
this.customerName,
this.targetModelName,
this.sourceModelName,
this.staffName,
this.createdById,
this.createdByName,
this.assignedToId,
this.assignedToName,
this.includedAccessories,
});
/// Factory per creare un ticket vuoto (utile per i form di creazione)
factory TicketModel.empty({required String companyId, String? storeId}) {
factory TicketModel.empty({String? companyId, String? storeId}) {
return TicketModel(
companyId: companyId,
companyId: companyId ?? '',
storeId: storeId,
ticketType: TicketType.repair, // Valore di default
status: TicketStatus.open,
@@ -195,7 +199,10 @@ class TicketModel extends Equatable {
String? customerName,
String? targetModelName,
String? sourceModelName,
String? staffName,
String? createdById,
String? createdByName,
String? assignedToId,
String? assignedToName,
String? includedAccessories,
}) {
return TicketModel(
@@ -213,7 +220,6 @@ class TicketModel extends Equatable {
closedAt: closedAt ?? this.closedAt,
returnedAt: returnedAt ?? this.returnedAt,
request: request ?? this.request,
staffId: staffId ?? this.staffId,
warrantyType: warrantyType ?? this.warrantyType,
publicNotes: publicNotes ?? this.publicNotes,
internalNotes: internalNotes ?? this.internalNotes,
@@ -230,7 +236,10 @@ class TicketModel extends Equatable {
customerName: customerName ?? this.customerName,
targetModelName: targetModelName ?? this.targetModelName,
sourceModelName: sourceModelName ?? this.sourceModelName,
staffName: staffName ?? this.staffName,
createdById: createdById ?? this.createdById,
createdByName: createdByName ?? this.createdByName,
assignedToId: assignedToId ?? this.assignedToId,
assignedToName: assignedToName ?? this.assignedToName,
includedAccessories: includedAccessories ?? this.includedAccessories,
);
}
@@ -259,7 +268,6 @@ class TicketModel extends Equatable {
? DateTime.parse(map['returned_at']).toLocal()
: null,
request: map['request'] as String? ?? '',
staffId: map['staff_id'] as String?,
warrantyType: WarrantyType.fromString(map['warranty_type'] as String?),
publicNotes: map['public_notes'] as String?,
internalNotes: map['internal_notes'] as String?,
@@ -279,7 +287,10 @@ class TicketModel extends Equatable {
?.myFormat(),
sourceModelName: (map['source_model']?['name_with_brand'] as String?)
?.myFormat(),
staffName: (map['staff']?['name'] as String?).myFormat(),
createdById: map['staff_id'] as String?,
createdByName: (map['staff']?['name'] as String?).myFormat(),
assignedToId: map['assigned_to_id'] as String?,
assignedToName: (map['assigned_to']?['name'] as String?).myFormat(),
includedAccessories: map['included_accessories'] as String?,
);
}
@@ -301,7 +312,7 @@ class TicketModel extends Equatable {
if (returnedAt != null)
'returned_at': returnedAt!.toUtc().toIso8601String(),
'request': request,
'staff_id': staffId,
'created_by_id': createdById,
'warranty_type': warrantyType,
'public_notes': publicNotes,
'internal_notes': internalNotes,
@@ -334,7 +345,6 @@ class TicketModel extends Equatable {
closedAt,
returnedAt,
request,
staffId,
warrantyType,
publicNotes,
internalNotes,
@@ -351,6 +361,9 @@ class TicketModel extends Equatable {
customerName,
targetModelName,
sourceModelName,
staffName,
createdById,
createdByName,
assignedToId,
assignedToName,
];
}