This commit is contained in:
2026-05-26 12:28:12 +02:00
parent 2afe97c6db
commit 45455a16c4
12 changed files with 851 additions and 8 deletions

View File

@@ -0,0 +1,163 @@
import 'package:flux/features/tasks/models/task_status.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
// Sostituisci con i percorsi corretti di FLUX
import 'package:flux/features/tasks/models/task_model.dart';
class TaskRepository {
final SupabaseClient _supabase;
TaskRepository({SupabaseClient? supabase})
: _supabase = supabase ?? Supabase.instance.client;
// --- RECUPERO DEI TASK FILTRATI ---
Future<List<TaskModel>> getTasks({
required String companyId,
String? storeId,
String? staffId,
List<TaskStatus>? statuses,
int? limit,
}) async {
try {
// 1. FASE FILTRI (PostgrestFilterBuilder)
var filterBuilder = _supabase
.from('tasks')
.select('*, assigned_to_staff:staff_members!task_assignments(*)')
.eq('company_id', companyId);
if (storeId != null) {
filterBuilder = filterBuilder.or(
'store_id.eq.$storeId,store_id.is.null',
);
}
if (staffId != null) {
filterBuilder = filterBuilder.or(
'staff_id.eq.$staffId,staff_id.is.null',
);
}
if (statuses != null && statuses.isNotEmpty) {
final statusValues = statuses.map((s) => s.toValue).toList();
filterBuilder = filterBuilder.inFilter('status', statusValues);
}
// 2. FASE TRASFORMAZIONI (PostgrestTransformBuilder)
// L'ordinamento lo facciamo sempre, quindi partiamo da qui
var transformBuilder = filterBuilder
.order('due_date', ascending: true, nullsFirst: false)
.order('created_at', ascending: false, nullsFirst: false);
// Aggiungiamo il limite se richiesto
if (limit != null) {
transformBuilder = transformBuilder.limit(limit);
}
// 3. ESECUZIONE DELLA QUERY
final response = await transformBuilder;
return (response as List).map((json) => TaskModel.fromMap(json)).toList();
} catch (e) {
throw Exception('Errore nel recupero dei task: $e');
}
}
// --- 2. CREAZIONE DEL TASK ---
Future<TaskModel> createTask(TaskModel task) async {
try {
final taskData = task.toMap();
// Rimuoviamo l'array prima di inviare i dati alla tabella principale,
// la "Strada C" impone che la verità assoluta derivi dalla tabella di giunzione!
taskData.remove('assigned_to_ids');
// 1. Inseriamo il record base nella tabella tasks
final response = await _supabase
.from('tasks')
.insert(taskData)
.select()
.single();
final newTask = TaskModel.fromMap(response);
// 2. Se l'utente ha assegnato il task a qualcuno, popoliamo la giunzione
if (task.assignedToIds.isNotEmpty && newTask.id != null) {
await _syncAssignments(newTask.id!, task.assignedToIds);
// 3. Ricarichiamo il task appena creato per ottenere l'array e il JOIN aggiornati dal trigger!
return await getTaskById(newTask.id!);
}
return newTask;
} catch (e) {
throw Exception('Errore nella creazione del task: $e');
}
}
// --- 3. AGGIORNAMENTO DEL TASK ---
Future<TaskModel> updateTask(TaskModel task) async {
if (task.id == null)
throw Exception('ID Task mancante. Impossibile aggiornare.');
try {
final taskData = task.toMap();
taskData.remove(
'assigned_to_ids',
); // Sempre via l'array dal body principale
// 1. Aggiorniamo i dati base del task (titolo, stato, scadenza, ecc.)
await _supabase.from('tasks').update(taskData).eq('id', task.id!);
// 2. Sincronizziamo in modo distruttivo gli assegnatari nella tabella di giunzione
await _syncAssignments(task.id!, task.assignedToIds);
// 3. Ritorniamo il modello fresco di DB
return await getTaskById(task.id!);
} catch (e) {
throw Exception('Errore nell\'aggiornamento del task: $e');
}
}
// --- 4. ELIMINAZIONE DEL TASK ---
Future<void> deleteTask(String taskId) async {
try {
// Eliminando il task, se la Foreign Key su Supabase ha "ON DELETE CASCADE",
// le righe nella tabella di giunzione si distruggeranno da sole in automatico!
await _supabase.from('tasks').delete().eq('id', taskId);
} catch (e) {
throw Exception('Errore nell\'eliminazione del task: $e');
}
}
// --- HELPER: RECUPERO SINGOLO TASK ---
Future<TaskModel> getTaskById(String taskId) async {
try {
final response = await _supabase
.from('tasks')
.select('*, assigned_to_staff:staff!task_assignments(*)')
.eq('id', taskId)
.single();
return TaskModel.fromMap(response);
} catch (e) {
throw Exception('Errore nel recupero del singolo task: $e');
}
}
// --- HELPER: SINCRONIZZAZIONE DELLA TABELLA DI GIUNZIONE ---
Future<void> _syncAssignments(String taskId, List<String> staffIds) async {
// TECNICA "WIPE & REPLACE":
// Invece di capire chi è stato aggiunto e chi tolto, eliminiamo tutti i record
// di questo task e li reinseriamo. È fulmineo ed esclude a priori bug di disallineamento.
// 1. Facciamo piazza pulita
await _supabase.from('task_assignments').delete().eq('task_id', taskId);
// 2. Inseriamo le nuove assegnazioni (se ce ne sono)
if (staffIds.isNotEmpty) {
final List<Map<String, dynamic>> assignments = staffIds
.map((staffId) => {'task_id': taskId, 'staff_id': staffId})
.toList();
await _supabase.from('task_assignments').insert(assignments);
}
}
}