feat-add-files-from-qr (#8)

Reviewed-on: http://catelliub.zapto.org:3000/brontomark/flux/pulls/8
Co-authored-by: Mark M2 Macbook <marco@catelli.it>
Co-committed-by: Mark M2 Macbook <marco@catelli.it>
This commit is contained in:
2026-04-26 10:15:34 +02:00
committed by brontomark
parent 90bd5ecacf
commit 1c2bcf9df7
46 changed files with 2376 additions and 327 deletions

View File

@@ -1,5 +1,7 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/utils/functions.dart';
import 'package:flux/core/utils/string_extensions.dart';
import 'package:flux/features/customers/models/customer_file_model.dart';
import 'package:get_it/get_it.dart';
@@ -76,6 +78,19 @@ class CustomerRepository {
}
}
/// Ascolta in tempo reale i file caricati per un cliente
Stream<List<CustomerFileModel>> getCustomerFilesStream(String customerId) {
return _supabase
.from('customer_file')
.stream(primaryKey: ['id'])
.eq('customer_id', customerId)
.order('created_at', ascending: false)
.map(
(listOfMaps) =>
listOfMaps.map((map) => CustomerFileModel.fromMap(map)).toList(),
);
}
/// Recupera i file di un cliente specifico
Future<List<CustomerFileModel>> getCustomerFiles(String customerId) async {
try {
@@ -92,11 +107,6 @@ class CustomerRepository {
}
}
/// Salva il riferimento del file nel DB
Future<void> saveCustomerFile(CustomerFileModel file) async {
await _supabase.from('customer_file').insert(file.toMap());
}
/// Carica un file e salva il riferimento nel database
Future<CustomerFileModel> uploadAndRegisterFile({
required String customerId,
@@ -113,7 +123,7 @@ class CustomerRepository {
customerId: customerId,
name: cleanFileName.fileNameWithoutExtension(),
extension: cleanFileName.fileExtension(),
url: storagePath,
storagePath: storagePath,
fileSize: fileSize,
);
final String mimeType = fileToSave.extension.toLowerCase() == 'pdf'
@@ -160,10 +170,31 @@ class CustomerRepository {
.eq('id', id);
}
/// Elimina un file dallo storage
Future<void> deleteDocument(String fullPath) async {
// Il path dovrebbe essere ricavato dall'URL
final path = fullPath.split('documents/').last;
await _supabase.storage.from('documents').remove([path]);
Future<void> deleteDocuments(List<CustomerFileModel> files) async {
if (files.isEmpty) return;
// 1. Prepariamo le liste di ID e di Percorsi
final List<String> idsToDelete = files.map((f) => f.id!).toList();
final List<String> storagePaths = files.map((f) => f.storagePath).toList();
try {
// 2. Cancellazione MASSIVA dal DB (una sola chiamata invece di un ciclo!)
// .in_ dice: "cancella tutti i record il cui ID è contenuto in questa lista"
await _supabase
.from('customer_file')
.delete()
.inFilter('id', idsToDelete);
// 3. Cancellazione MASSIVA dallo Storage
await _supabase.storage.from('documents').remove(storagePaths);
debugPrint("Eliminati con successo ${files.length} file.");
} on PostgrestException catch (e) {
debugPrint("Errore DB: ${e.message}");
throw 'Errore database: ${e.message}';
} catch (e) {
debugPrint("Errore generico: $e");
throw 'Errore durante l\'eliminazione dei file: $e';
}
}
}