mmmh
All checks were successful
Build and Release FLUX (Multi-Platform) / build-android (push) Successful in 2m11s
Build and Release FLUX (Multi-Platform) / build-web (push) Successful in 1m1s
Build and Release FLUX (Multi-Platform) / build-windows (push) Successful in 8m5s

This commit is contained in:
2026-06-04 12:34:38 +02:00
parent 01515910b6
commit 4efc3ce182
14 changed files with 517 additions and 426 deletions

View File

@@ -21,7 +21,7 @@ class TasksRepository {
}) async {
try {
final response = await _supabase
.from('task_reminders')
.from(Tables.taskReminders)
.select()
.eq('task_id', taskId)
.eq('staff_id', staffId)
@@ -53,13 +53,17 @@ class TasksRepository {
int? limit,
}) async {
try {
// 1. FASE FILTRI: Usa il join esplicito stile "Notes"
// 1. FASE FILTRI: Disambiguazione completa su Tasks e Assignments
var filterBuilder = _supabase
.from(Tables.tasks)
.select('''
*,
creator:${Tables.staffMembers}!created_by_id(*),
updater:${Tables.staffMembers}!updated_by_id(*),
task_assignments:${Tables.taskAssignments} (
${Tables.staffMembers} (*)
*,
assignee:${Tables.staffMembers}!staff_id(*),
assigner:${Tables.staffMembers}!assigned_by_id(*)
)
''')
.eq('company_id', companyId);
@@ -71,7 +75,6 @@ class TasksRepository {
}
if (staffId != null) {
// Grazie al trigger, hai l'array pronto per il filtro senza impazzire!
filterBuilder = filterBuilder.contains('assigned_to_ids', [staffId]);
}
@@ -105,8 +108,12 @@ class TasksRepository {
.from(Tables.tasks)
.select('''
*,
creator:${Tables.staffMembers}!created_by_id(*),
updater:${Tables.staffMembers}!updated_by_id(*),
task_assignments:${Tables.taskAssignments} (
${Tables.staffMembers} (*)
*,
assignee:${Tables.staffMembers}!staff_id(*),
assigner:${Tables.staffMembers}!assigned_by_id(*)
)
''')
.eq('id', taskId)
@@ -122,14 +129,11 @@ class TasksRepository {
// =========================================================================
// REALTIME STREAM (La sentinella per la bacheca)
// =========================================================================
Stream<List<TaskModel>> watchCompanyTasks(String companyId) {
Stream<List<Map<String, dynamic>>> watchCompanyTasks(String companyId) {
return _supabase
.from('tasks')
.stream(primaryKey: ['id'])
.eq('company_id', companyId)
.map((listOfMaps) {
return listOfMaps.map((map) => TaskModel.fromMap(map)).toList();
});
.eq('company_id', companyId);
}
// =========================================================================
@@ -160,6 +164,7 @@ class TasksRepository {
'task_id': taskId,
'staff_id': staffId,
'company_id': task.companyId,
'assigned_by_id': currentUserId,
},
)
.toList();
@@ -276,7 +281,7 @@ class TasksRepository {
// 1. Aggiornamento dati Task Base
await _supabase
.from('tasks')
.from(Tables.tasks)
.update({
'title': task.title,
'description': task.description,
@@ -286,15 +291,51 @@ class TasksRepository {
})
.eq('id', taskId);
// 2. Aggiornamento Assegnazioni: eliminiamo le vecchie, inseriamo le nuove
await _supabase.from('task_assignments').delete().eq('task_id', taskId);
if (assignedStaffIds.isNotEmpty) {
final assignmentsToInsert = assignedStaffIds
// 🥷 2. GESTIONE CHIRURGICA DELLE ASSEGNAZIONI (Addio spam!)
// A) Recuperiamo chi è GIÀ assegnato a questo task
final existingAssignmentsResponse = await _supabase
.from('task_assignments')
.select('staff_id')
.eq('task_id', taskId);
final List<String> existingStaffIds =
(existingAssignmentsResponse as List)
.map((row) => row['staff_id'] as String)
.toList();
// B) Calcoliamo i Delta con i Set di Dart (Pura magia matematica)
final newStaffIdsSet = assignedStaffIds.toSet();
final existingStaffIdsSet = existingStaffIds.toSet();
// Quelli da inserire (presenti nei nuovi, ma non nei vecchi)
final toInsertIds = newStaffIdsSet
.difference(existingStaffIdsSet)
.toList();
// Quelli da eliminare (presenti nei vecchi, ma non nei nuovi)
final toDeleteIds = existingStaffIdsSet
.difference(newStaffIdsSet)
.toList();
// C) Eseguiamo solo lo stretto necessario
if (toDeleteIds.isNotEmpty) {
await _supabase
.from('task_assignments')
.delete()
.eq('task_id', taskId)
.inFilter('staff_id', toDeleteIds);
}
if (toInsertIds.isNotEmpty) {
final assignmentsToInsert = toInsertIds
.map(
(staffId) => {
'task_id': taskId,
'staff_id': staffId,
'company_id': task.companyId,
'assigned_by_id':
currentUserId, // Il nostro salvavita anti-fantasma
},
)
.toList();
@@ -352,6 +393,35 @@ class TasksRepository {
}
}
Future<void> updateTaskStatus({
required String taskId,
required TaskStatus newStatus,
required String? updatedById,
}) async {
try {
await _supabase
.from(Tables.tasks)
.update({
'status': newStatus.toValue,
'updated_by_id': updatedById,
'updated_at': DateTime.now().toIso8601String(),
})
.eq('id', taskId);
} catch (e) {
throw Exception(
'Errore durante l\'aggiornamento dello stato del task: $e',
);
}
}
Future<void> deleteTask(String taskId) async {
try {
await _supabase.from(Tables.tasks).delete().eq('id', taskId);
} catch (e) {
throw Exception('Errore durante la cancellazione del task: $e');
}
}
// --- HELPER PRIVATO PER LA MAPPA DEL REMINDER ---
Map<String, dynamic> _buildReminderRow(
TaskModel task,