mah....volare
This commit is contained in:
@@ -217,8 +217,6 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
String? reference,
|
||||
String? note,
|
||||
String? type,
|
||||
String? providerId,
|
||||
String? providerDisplayName,
|
||||
String? subType,
|
||||
String? description,
|
||||
DateTime? expirationDate,
|
||||
@@ -248,10 +246,6 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
final updated = current.copyWith(
|
||||
reference: reference ?? current.reference,
|
||||
note: note ?? current.note,
|
||||
providerId: clearProvider ? null : (providerId ?? current.providerId),
|
||||
providerDisplayName: clearProvider
|
||||
? null
|
||||
: (providerDisplayName ?? current.providerDisplayName),
|
||||
quantity: newQuantity ?? current.quantity,
|
||||
type: clearType ? null : (type ?? current.type),
|
||||
description: clearDescription
|
||||
@@ -274,6 +268,18 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
emit(state.copyWith(operation: updated));
|
||||
}
|
||||
|
||||
void updateProvider(ProviderModel? newProvider) {
|
||||
final current = state.operation;
|
||||
|
||||
final updatedOperation = current.copyWith(
|
||||
// Se newProvider è null, passiamo una funzione che ritorna null per sbiancare i campi!
|
||||
providerId: () => newProvider?.id,
|
||||
provider: () => newProvider,
|
||||
);
|
||||
|
||||
emit(state.copyWith(operation: updatedOperation));
|
||||
}
|
||||
|
||||
void updateCustomer(CustomerModel customer) {
|
||||
final bool isBusiness = customer.isBusiness;
|
||||
final updatedOperation = state.operation.copyWith(
|
||||
@@ -293,13 +299,8 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
}) {
|
||||
// 1. Aggiorniamo il tipo nel modello in canna
|
||||
// (Presumo tu abbia un metodo copyWith o simile)
|
||||
final updatedOp = state.operation.copyWith(type: newType, subType: '');
|
||||
|
||||
// 2. Prepariamoci ad auto-selezionare il provider
|
||||
String? newProviderId = updatedOp.providerId;
|
||||
String? newProviderName = updatedOp.providerDisplayName;
|
||||
|
||||
// 3. LA LOGICA DI DEFAULT
|
||||
// 2. LA LOGICA DI DEFAULT
|
||||
if (defaultProviderId != null) {
|
||||
// Troviamo il provider di default nella lista
|
||||
final defaultProvider = allProviders
|
||||
@@ -309,25 +310,13 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
if (defaultProvider != null) {
|
||||
// Usiamo l'extension appena creata!
|
||||
if (defaultProvider.supportsOperation(newType)) {
|
||||
newProviderId = defaultProvider.id;
|
||||
newProviderName = defaultProvider.name;
|
||||
updateProvider(defaultProvider);
|
||||
} else {
|
||||
// Se cambi tipo (es. da Mobile a Luce) e il default non lo supporta, sbianchiamo
|
||||
newProviderId = null;
|
||||
newProviderName = null;
|
||||
updateProvider(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emettiamo il nuovo stato
|
||||
emit(
|
||||
state.copyWith(
|
||||
operation: updatedOp.copyWith(
|
||||
providerId: newProviderId,
|
||||
providerDisplayName: newProviderName,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setTypeWithSmartDefaults({
|
||||
@@ -338,7 +327,7 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
final currentOp = state.operation;
|
||||
|
||||
// -----------------------------------------
|
||||
// 1. SMART DATES: Calcolo Scadenze Default
|
||||
// 1. SMART DATES: Calcolo Scadenze Default (Invariato)
|
||||
// -----------------------------------------
|
||||
DateTime? defaultDate;
|
||||
final now = DateTime.now();
|
||||
@@ -354,28 +343,19 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// 2. SMART PROVIDER: Filtro e Auto-Selezione
|
||||
// 2. SMART PROVIDER: Filtro e Auto-Selezione ad Oggetti
|
||||
// -----------------------------------------
|
||||
String? newProviderId = currentOp.providerId;
|
||||
String? newProviderName = currentOp.providerDisplayName;
|
||||
// Pescatore direttamente l'oggetto dal modello corrente
|
||||
ProviderModel? targetProvider = currentOp.provider;
|
||||
|
||||
// A) Il provider attuale è ancora compatibile col nuovo tipo scelto?
|
||||
if (newProviderId != null && newProviderId.isNotEmpty) {
|
||||
final currentProvider = allProviders
|
||||
.where((p) => p.id == newProviderId)
|
||||
.firstOrNull;
|
||||
|
||||
if (currentProvider == null ||
|
||||
!currentProvider.supportsOperation(newType)) {
|
||||
// Non è più compatibile (es. da TIM fisso passo a Energy). Lo sbianchiamo!
|
||||
newProviderId = null;
|
||||
newProviderName = null;
|
||||
}
|
||||
if (targetProvider != null && !targetProvider.supportsOperation(newType)) {
|
||||
// Non è più compatibile (es. da TIM fisso passo a Energy). Lo sbianchiamo!
|
||||
targetProvider = null;
|
||||
}
|
||||
|
||||
// B) Se non c'è un provider selezionato, proviamo ad auto-inserire quello di default del negozio
|
||||
if ((newProviderId == null || newProviderId.isEmpty) &&
|
||||
defaultProviderId != null) {
|
||||
if (targetProvider == null && defaultProviderId != null) {
|
||||
final defaultProvider = allProviders
|
||||
.where((p) => p.id == defaultProviderId)
|
||||
.firstOrNull;
|
||||
@@ -383,8 +363,7 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
// Controlliamo che il default del negozio supporti questa specifica operazione
|
||||
if (defaultProvider != null &&
|
||||
defaultProvider.supportsOperation(newType)) {
|
||||
newProviderId = defaultProvider.id;
|
||||
newProviderName = defaultProvider.name;
|
||||
targetProvider = defaultProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,13 +374,16 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
state.copyWith(
|
||||
operation: currentOp.copyWith(
|
||||
type: newType,
|
||||
subType:
|
||||
'', // Resettiamo il sottotipo per evitare incongruenze (es. passo da Luce a DAZN)
|
||||
subType: '', // Resettiamo il sottotipo per evitare incongruenze
|
||||
expirationDate:
|
||||
defaultDate, // Impostiamo la scadenza di default se calcolata
|
||||
providerId: newProviderId,
|
||||
providerDisplayName: newProviderName,
|
||||
// 🥷 APPLICHIAMO IL TRUCCO NINJA DELLE FUNZIONI
|
||||
// Se targetProvider è null, le funzioni ritorneranno null sbiancando il DB!
|
||||
providerId: () => targetProvider?.id,
|
||||
provider: () => targetProvider,
|
||||
|
||||
// Nota: Per azzerare davvero questi due, ricordati in futuro di applicare
|
||||
// il trucco delle funzioni anche a modelId e modelDisplayName nel modello!
|
||||
modelId: null,
|
||||
modelDisplayName: null,
|
||||
),
|
||||
|
||||
@@ -12,72 +12,103 @@ class OperationListCubit extends Cubit<OperationListState> {
|
||||
final OperationsRepository _repository = GetIt.I<OperationsRepository>();
|
||||
final SessionCubit _sessionCubit = GetIt.I<SessionCubit>();
|
||||
|
||||
OperationListCubit() : super(const OperationListState()) {
|
||||
loadOperations(refresh: true);
|
||||
}
|
||||
OperationListCubit() : super(const OperationListState());
|
||||
|
||||
Future<void> loadOperations({bool refresh = false}) async {
|
||||
// 🥷 MOTORE 1: DESKTOP (Sostituisce la lista)
|
||||
Future<void> loadSpecificPageDesktop(int page) async {
|
||||
if (state.status == OperationListStatus.loading) return;
|
||||
if (!refresh && state.hasReachedMax) return;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OperationListStatus.loading,
|
||||
errorMessage: null,
|
||||
operations: refresh ? [] : state.operations,
|
||||
hasReachedMax: refresh ? false : state.hasReachedMax,
|
||||
),
|
||||
);
|
||||
emit(state.copyWith(status: OperationListStatus.loading));
|
||||
|
||||
try {
|
||||
final currentOffset = refresh ? 0 : state.operations.length;
|
||||
final companyId = _sessionCubit.state.company?.id;
|
||||
|
||||
if (companyId == null) {
|
||||
throw Exception("Company ID non trovato nella sessione");
|
||||
}
|
||||
|
||||
final newOperations = await _repository.fetchOperations(
|
||||
companyId: companyId,
|
||||
offset: currentOffset,
|
||||
limit: 50,
|
||||
searchTerm: state.query,
|
||||
dateRange: state.dateRange,
|
||||
final paginatedData = await _repository.fetchPaginatedOperations(
|
||||
companyId: companyId!,
|
||||
page: page,
|
||||
itemsPerPage: state.itemsPerPage,
|
||||
);
|
||||
|
||||
final bool reachedMax = newOperations.length < 50;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OperationListStatus.success,
|
||||
operations: refresh
|
||||
? newOperations
|
||||
: [...state.operations, ...newOperations],
|
||||
hasReachedMax: reachedMax,
|
||||
operations: paginatedData.operations, // 🎯 SOSTITUISCE I DATI
|
||||
totalItems: paginatedData.totalCount,
|
||||
currentPage: page,
|
||||
hasReachedMax: paginatedData.operations.length < state.itemsPerPage,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OperationListStatus.failure,
|
||||
errorMessage: "Errore nel caricamento operazioni: $e",
|
||||
errorMessage: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void updateFilters({String? query, DateTimeRange? range}) {
|
||||
// 🥷 MOTORE 2: MOBILE (Accoda alla lista)
|
||||
Future<void> loadNextPageMobile({bool refresh = false}) async {
|
||||
if (state.status == OperationListStatus.loading) return;
|
||||
if (state.hasReachedMax && !refresh) return;
|
||||
|
||||
// Se stiamo pullando verso il basso (refresh), ripartiamo da pagina 1
|
||||
final targetPage = refresh ? 1 : state.currentPage + 1;
|
||||
|
||||
// Mostriamo il loading solo se è un refresh totale, altrimenti manteniamo lo stato success
|
||||
// per non far sparire la UI mentre carica in fondo
|
||||
if (refresh) emit(state.copyWith(status: OperationListStatus.loading));
|
||||
|
||||
try {
|
||||
final companyId = _sessionCubit.state.company?.id;
|
||||
final paginatedData = await _repository.fetchPaginatedOperations(
|
||||
companyId: companyId!,
|
||||
page: targetPage,
|
||||
itemsPerPage: state.itemsPerPage,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OperationListStatus.success,
|
||||
// 🎯 ACCODA I DATI SE NON È REFRESH, ALTRIMENTI SOSTITUISCE
|
||||
operations:
|
||||
refresh ? paginatedData.operations : List.of(state.operations)
|
||||
..addAll(paginatedData.operations),
|
||||
totalItems: paginatedData.totalCount,
|
||||
currentPage: targetPage,
|
||||
hasReachedMax: paginatedData.operations.length < state.itemsPerPage,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OperationListStatus.failure,
|
||||
errorMessage: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void updateFilters({String? text, DateTimeRange? range}) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
query: query ?? state.query,
|
||||
dateRange: range ?? state.dateRange,
|
||||
// 🥷 FORZIAMO IL TIPO: Diciamo a Dart che il risultato del ternario è proprio una funzione
|
||||
searchTerm: text != null ? () => text : null,
|
||||
dateRange: range != null ? () => range : null,
|
||||
|
||||
currentPage: 1, // Reset obbligatorio alla prima pagina
|
||||
hasReachedMax: false,
|
||||
),
|
||||
);
|
||||
loadOperations(refresh: true);
|
||||
|
||||
// Ricarichiamo la pagina 1 con i nuovi filtri applicati
|
||||
loadSpecificPageDesktop(1);
|
||||
}
|
||||
|
||||
void clearFilters() {
|
||||
emit(const OperationListState()); // Resetta tutto allo stato iniziale
|
||||
loadOperations(refresh: true);
|
||||
// Invece di un const vuoto che potrebbe bruciarti l'impostazione itemsPerPage,
|
||||
// creiamo uno stato pulito ma manteniamo la preferenza di paginazione.
|
||||
emit(OperationListState(itemsPerPage: state.itemsPerPage));
|
||||
|
||||
loadSpecificPageDesktop(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,35 +5,57 @@ enum OperationListStatus { initial, loading, success, failure }
|
||||
class OperationListState extends Equatable {
|
||||
final OperationListStatus status;
|
||||
final List<OperationModel> operations;
|
||||
final bool hasReachedMax;
|
||||
final String? errorMessage;
|
||||
final String query;
|
||||
|
||||
// Paginazione Ibrida
|
||||
final int currentPage;
|
||||
final int itemsPerPage;
|
||||
final int totalItems;
|
||||
final bool hasReachedMax;
|
||||
|
||||
// 🥷 I FILTRI MANCANTI (Riparati!)
|
||||
final String? searchTerm;
|
||||
final DateTimeRange? dateRange;
|
||||
|
||||
const OperationListState({
|
||||
this.status = OperationListStatus.initial,
|
||||
this.operations = const [],
|
||||
this.hasReachedMax = false,
|
||||
this.errorMessage,
|
||||
this.query = '',
|
||||
this.currentPage = 1,
|
||||
this.itemsPerPage = 25,
|
||||
this.totalItems = 0,
|
||||
this.hasReachedMax = false,
|
||||
this.searchTerm,
|
||||
this.dateRange,
|
||||
});
|
||||
|
||||
int get totalPages => (totalItems / itemsPerPage).ceil();
|
||||
|
||||
// 🥷 COPYWITH AVANZATO: Gestisce lo sbiancamento dei filtri alla perfezione
|
||||
OperationListState copyWith({
|
||||
OperationListStatus? status,
|
||||
List<OperationModel>? operations,
|
||||
bool? hasReachedMax,
|
||||
String? errorMessage,
|
||||
String? query,
|
||||
DateTimeRange? dateRange,
|
||||
int? currentPage,
|
||||
int? itemsPerPage,
|
||||
int? totalItems,
|
||||
bool? hasReachedMax,
|
||||
String? Function()? searchTerm, // Callback per gestire il null esplicito
|
||||
DateTimeRange? Function()?
|
||||
dateRange, // Callback per gestire il null esplicito
|
||||
}) {
|
||||
return OperationListState(
|
||||
status: status ?? this.status,
|
||||
operations: operations ?? this.operations,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
currentPage: currentPage ?? this.currentPage,
|
||||
itemsPerPage: itemsPerPage ?? this.itemsPerPage,
|
||||
totalItems: totalItems ?? this.totalItems,
|
||||
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
|
||||
errorMessage: errorMessage,
|
||||
query: query ?? this.query,
|
||||
dateRange: dateRange ?? this.dateRange,
|
||||
|
||||
// Se passi la funzione la eseguiamo, altrimenti teniamo il valore corrente
|
||||
searchTerm: searchTerm != null ? searchTerm() : this.searchTerm,
|
||||
dateRange: dateRange != null ? dateRange() : this.dateRange,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,9 +63,12 @@ class OperationListState extends Equatable {
|
||||
List<Object?> get props => [
|
||||
status,
|
||||
operations,
|
||||
hasReachedMax,
|
||||
errorMessage,
|
||||
query,
|
||||
currentPage,
|
||||
itemsPerPage,
|
||||
totalItems,
|
||||
hasReachedMax,
|
||||
searchTerm,
|
||||
dateRange,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user