Files
flux/lib/features/tasks/blocs/task_form_cubit.dart
mark-cachy 5ce0110197
Some checks failed
Build and Release FLUX (Multi-Platform) / build-windows (push) Successful in 6m20s
Build and Release FLUX (Multi-Platform) / build-android (push) Failing after 11m52s
Build and Release FLUX (Multi-Platform) / build-web (push) Successful in 1m0s
fix operations e tasks
2026-06-04 13:42:29 +02:00

307 lines
9.7 KiB
Dart

import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/master_data/staff/data/staff_repository.dart';
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
import 'package:flux/features/settings/data/settings_repository.dart';
import 'package:flux/features/tasks/data/task_repository.dart';
import 'package:flux/features/tasks/models/task_model.dart';
import 'package:flux/features/tasks/models/task_reminder_config.dart';
import 'package:flux/features/tasks/models/task_status.dart';
import 'package:get_it/get_it.dart';
part 'task_form_state.dart';
class TaskFormCubit extends Cubit<TaskFormState> {
final TasksRepository _repository = GetIt.I.get<TasksRepository>();
final SettingsRepository _settingsRepository = GetIt.I
.get<SettingsRepository>();
final _staffRepository = GetIt.I.get<StaffRepository>();
final SessionCubit _sessionCubit = GetIt.I.get<SessionCubit>();
final List<StaffMemberModel>? _preloadedStaff;
TaskFormCubit({
String? initialTaskId, // <-- RIPRISTINATO PER DEEP LINK
TaskModel? existingTask,
List<StaffMemberModel>? allStaff,
}) : _preloadedStaff = allStaff,
super(const TaskFormState()) {
// Avviamo l'inizializzazione centralizzata (gestisce sia mem, sia deep link, sia nuovo)
initForm(initialTaskId: initialTaskId, existingTask: existingTask);
}
String get _companyId => _sessionCubit.state.company!.id!;
StaffMemberModel get _currentUser => _sessionCubit.state.currentStaffMember!;
String? get _currentStoreId => _sessionCubit.state.currentStore?.id;
// --- ARMED INITIALIZATION (Nuovo, Esistente o Deep Link) ---
Future<void> initForm({
String? initialTaskId,
TaskModel? existingTask,
}) async {
emit(state.copyWith(status: TaskFormStatus.loading));
try {
TaskModel? task = existingTask;
// 1. Se arriviamo da Deep Link col solo ID, lo scarichiamo dal DB
if (initialTaskId != null && task == null) {
task = await _repository.fetchTaskById(initialTaskId);
}
if (task != null) {
// CASO: TASK ESISTENTE (Modifica o Deep Link pronto)
emit(
state.copyWith(
id: task.id,
title: task.title,
description: task.description,
dueDate: task.dueDate,
isGlobal: task.isGlobal, // Sfrutta il tuo getter storeId == null
selectedStaffIds: task.assignedToIds,
taskStatus: task.status,
),
);
await _loadExistingTaskReminders(task.id!);
} else {
// CASO: NUOVO TASK
await _initializeNewTaskReminders();
}
// 2. Carichiamo e raggruppiamo il personale (Global o Store)
await _loadAndGroupStaff();
// Mandiamo lo status a 'initial' così il FormScreen sincronizza i controller di testo!
emit(state.copyWith(status: TaskFormStatus.initial));
} catch (e) {
emit(
state.copyWith(
status: TaskFormStatus.failure,
errorMessage: e.toString(),
),
);
}
}
// --- LOGICA GESTIONE STAFF (GLOBAL STAFF / STORE STAFF) ---
Future<void> _loadAndGroupStaff() async {
final List<StaffMemberModel> staffList;
// SE C'È LO STAFF PASCIUTO DALL'APP USA QUELLO, ALTRIMENTI CHIAMA IL REPO
if (_preloadedStaff != null && _preloadedStaff.isNotEmpty) {
staffList = _preloadedStaff;
} else {
staffList = await _staffRepository.getStaffMembers(_companyId);
}
final Map<String, List<StaffMemberModel>> grouped = {};
for (var staff in staffList) {
if (!state.isGlobal) {
final belongsToCurrentStore = staff.assignedStores.any(
(store) => store.id == _currentStoreId,
);
if (!belongsToCurrentStore) continue;
}
if (staff.assignedStores.isEmpty) {
grouped.putIfAbsent('Direzione / Senza Sede', () => []).add(staff);
} else {
for (var store in staff.assignedStores) {
if (!state.isGlobal && store.id != _currentStoreId) continue;
final storeName = store.name;
grouped.putIfAbsent(storeName, () => []).add(staff);
}
}
}
emit(state.copyWith(groupedAvailableStaff: grouped));
}
// Se l'utente switcha su "Globale Aziendale", ricarichiamo lo staff di conseguenza
void toggleGlobalScope(bool g) async {
emit(state.copyWith(isGlobal: g, status: TaskFormStatus.loading));
await _loadAndGroupStaff();
emit(
state.copyWith(status: TaskFormStatus.initial),
); // Ri-notifichiamo la UI
}
// --- INIT REMINDER ---
Future<void> _initializeNewTaskReminders() async {
try {
final defaults = await _settingsRepository.getMyReminderDefaults(
companyId: _companyId,
staffId: _currentUser.id!,
);
final initialReminders = defaults
.map(
(d) => TaskReminderConfig(
minutesBefore: d.minutesBefore,
channel: d.channel,
),
)
.toList();
emit(state.copyWith(reminders: initialReminders));
} catch (e) {
emit(
state.copyWith(
reminders: const [
TaskReminderConfig(minutesBefore: 15, channel: 'push'),
],
),
);
}
}
Future<void> _loadExistingTaskReminders(String taskId) async {
try {
final existingConfigs = await _repository.fetchPersonalReminders(
taskId: taskId,
staffId: _currentUser.id!,
);
emit(state.copyWith(reminders: existingConfigs));
} catch (e) {
debugPrint('Errore caricamento reminder: $e');
}
}
// --- AGGIORNAMENTO CAMPI ---
void updateTitle(String t) => emit(state.copyWith(title: t));
void updateDescription(String d) => emit(state.copyWith(description: d));
void updateDueDate(DateTime? d) => emit(state.copyWith(dueDate: d));
void toggleStaffSelection(String staffId) {
final updated = List<String>.from(state.selectedStaffIds);
updated.contains(staffId) ? updated.remove(staffId) : updated.add(staffId);
emit(state.copyWith(selectedStaffIds: updated));
}
void toggleStoreSelection(String storeName, bool selectAll) {
final updated = List<String>.from(state.selectedStaffIds);
final storeStaff = state.groupedAvailableStaff[storeName] ?? [];
for (var staff in storeStaff) {
if (staff.id == null) continue;
if (selectAll) {
if (!updated.contains(staff.id)) updated.add(staff.id!);
} else {
updated.remove(staff.id);
}
}
emit(state.copyWith(selectedStaffIds: updated));
}
// --- AZIONI REMINDER ---
void addReminderRule(int minutesBefore, String channel) {
final updated = List<TaskReminderConfig>.from(state.reminders);
final newConfig = TaskReminderConfig(
minutesBefore: minutesBefore,
channel: channel,
);
if (!updated.contains(newConfig)) {
updated.add(newConfig);
updated.sort((a, b) => a.minutesBefore.compareTo(b.minutesBefore));
emit(state.copyWith(reminders: updated));
}
}
void removeReminderRule(int index) {
final updated = List<TaskReminderConfig>.from(state.reminders)
..removeAt(index);
emit(state.copyWith(reminders: updated));
}
// --- SALVATAGGIO ---
Future<void> saveTask() async {
if (!state.isFormValid) return;
emit(state.copyWith(status: TaskFormStatus.submitting));
final taskToSave = TaskModel(
id: state.id,
companyId: _companyId,
createdBy: _currentUser,
title: state.title.trim(),
description: state.description.trim(),
dueDate: state.dueDate,
storeId: state.isGlobal
? null
: _currentStoreId, // Gestione nativa basata sulla tua logica
assignedToIds: state.selectedStaffIds,
);
try {
if (state.id == null) {
await _repository.createTask(
task: taskToSave,
assignedStaffIds: state.selectedStaffIds,
currentUserId: _currentUser.id!,
currentUserCustomReminders: state.reminders,
);
} else {
await _repository.updateTask(
task: taskToSave,
assignedStaffIds: state.selectedStaffIds,
currentUserId: _currentUser.id!,
currentUserCustomReminders: state.reminders,
);
}
emit(state.copyWith(status: TaskFormStatus.success));
} catch (e) {
emit(
state.copyWith(
status: TaskFormStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> deleteTask() async {
if (state.id == null) return;
emit(state.copyWith(status: TaskFormStatus.submitting));
try {
await _repository.deleteTask(state.id!);
emit(state.copyWith(status: TaskFormStatus.success));
} catch (e) {
emit(
state.copyWith(
status: TaskFormStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> updateTaskLocalStatus(TaskStatus newStatus) async {
emit(state.copyWith(taskStatus: newStatus));
}
Future<void> updateTaskStatus(TaskStatus newStatus) async {
try {
// Chiamiamo il repo passando il task aggiornato
await _repository.updateTaskStatus(
taskId: state.id!,
newStatus: newStatus,
updatedById: _currentUser.id!,
);
if (!isClosed) {
// Se l'update va a buon fine, aggiorniamo lo stato locale del cubit
emit(
state.copyWith(status: TaskFormStatus.success, taskStatus: newStatus),
);
}
} catch (e) {
if (!isClosed) {
emit(
state.copyWith(
status: TaskFormStatus.failure,
errorMessage: e.toString(),
),
);
}
}
}
}