Some checks failed
Deploy to Cloudflare Pages / build-and-deploy (push) Has been cancelled
Reviewed-on: #14 Co-authored-by: mark-cachy <marco@catelli.it> Co-committed-by: mark-cachy <marco@catelli.it>
218 lines
7.1 KiB
Dart
218 lines
7.1 KiB
Dart
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()),
|
|
);
|
|
|
|
/// 1. INIZIALIZZAZIONE (Se stiamo modificando un ticket esistente)
|
|
Future<void> initForm({String? id, TicketModel? existingTicket}) async {
|
|
if (existingTicket != null) {
|
|
// SCENARIO 1 (App Native / Navigazione interna Web):
|
|
// Abbiamo l'oggetto intero passato via 'extra'. Lo mostriamo all'istante!
|
|
emit(
|
|
state.copyWith(ticket: existingTicket, status: TicketFormStatus.ready),
|
|
);
|
|
} else if (id != null) {
|
|
// SCENARIO 2 (Web Refresh o Link condiviso):
|
|
// L'utente ha premuto F5 su /tickets/form/123. L'extra è andato perso, ma abbiamo l'ID!
|
|
emit(
|
|
state.copyWith(status: TicketFormStatus.loading),
|
|
); // Mostriamo uno spinner
|
|
try {
|
|
final fetchedTicket = await _repository.getTicketById(
|
|
id,
|
|
); // Lo scarichiamo!
|
|
emit(
|
|
state.copyWith(ticket: fetchedTicket, status: TicketFormStatus.ready),
|
|
);
|
|
} catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketFormStatus.failure,
|
|
errorMessage: 'Ticket non trovato',
|
|
),
|
|
);
|
|
}
|
|
} else {
|
|
// SCENARIO 3 (Nuovo Ticket):
|
|
// È 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().copyWith(
|
|
companyId: companyId,
|
|
storeId: currentStore?.id,
|
|
createdById: currentUser?.id,
|
|
createdByName: currentUser?.name,
|
|
// Impostiamo lo stato iniziale
|
|
ticketStatus: 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(
|
|
createdById: staffId,
|
|
createdByName: 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,
|
|
ticketStatus: status ?? state.ticket.ticketStatus,
|
|
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,
|
|
ticketStatus: 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(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 5.1 SALVATAGGIO SILENZIOSO (Per generare il QR Code al volo)
|
|
Future<String?> saveTicketDraft() async {
|
|
// Non mettiamo lo stato 'saving' per non far sfarfallare tutta la UI,
|
|
// usiamo un caricamento invisibile.
|
|
try {
|
|
final ticketToSave = state.ticket;
|
|
|
|
if (ticketToSave.customerId == null || ticketToSave.customerId!.isEmpty) {
|
|
throw Exception("Seleziona un cliente prima di poter usare il QR.");
|
|
}
|
|
|
|
final savedTicket = await _repository.saveTicket(ticketToSave);
|
|
|
|
// Aggiorniamo silenziosamente lo stato con il ticket che ora ha un ID!
|
|
emit(state.copyWith(ticket: savedTicket, status: TicketFormStatus.ready));
|
|
|
|
return savedTicket.id;
|
|
} catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
status: TicketFormStatus.failure,
|
|
errorMessage: e.toString(),
|
|
),
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
}
|