fix operations e tasks
This commit is contained in:
@@ -273,7 +273,6 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
|
||||
final updatedOperation = current.copyWith(
|
||||
// Se newProvider è null, passiamo una funzione che ritorna null per sbiancare i campi!
|
||||
providerId: () => newProvider?.id,
|
||||
provider: () => newProvider,
|
||||
);
|
||||
|
||||
@@ -379,7 +378,6 @@ class OperationFormCubit extends Cubit<OperationFormState> {
|
||||
defaultDate, // Impostiamo la scadenza di default se calcolata
|
||||
// 🥷 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
|
||||
|
||||
@@ -59,7 +59,7 @@ class OperationsRepository {
|
||||
*,
|
||||
${Tables.customers}(*),
|
||||
${Tables.stores}(name),
|
||||
${Tables.providers}(name, color_hex),
|
||||
${Tables.providers}(*),
|
||||
${Tables.models}(name_with_brand),
|
||||
${Tables.staffMembers}(name),
|
||||
${Tables.attachments}(*)
|
||||
|
||||
@@ -30,7 +30,6 @@ class OperationModel extends Equatable {
|
||||
final DateTime? createdAt;
|
||||
final String type;
|
||||
final String? subType;
|
||||
final String? providerId;
|
||||
final String? modelId;
|
||||
final String? modelDisplayName;
|
||||
final String? description;
|
||||
@@ -60,7 +59,6 @@ class OperationModel extends Equatable {
|
||||
this.createdAt,
|
||||
this.type = '',
|
||||
this.subType,
|
||||
this.providerId,
|
||||
this.modelId,
|
||||
this.modelDisplayName,
|
||||
this.description,
|
||||
@@ -90,7 +88,6 @@ class OperationModel extends Equatable {
|
||||
String? type,
|
||||
String? subType,
|
||||
// 🥷 TRUCCO APPLICATO ANCHE QUI:
|
||||
String? Function()? providerId,
|
||||
ProviderModel? Function()? provider,
|
||||
String? modelId,
|
||||
String? modelDisplayName,
|
||||
@@ -118,7 +115,6 @@ class OperationModel extends Equatable {
|
||||
type: type ?? this.type,
|
||||
subType: subType ?? this.subType,
|
||||
// Se la funzione è passata, la eseguiamo (anche se ritorna null), altrimenti teniamo il vecchio
|
||||
providerId: providerId != null ? providerId() : this.providerId,
|
||||
provider: provider != null ? provider() : this.provider,
|
||||
|
||||
modelId: modelId ?? this.modelId,
|
||||
@@ -149,7 +145,6 @@ class OperationModel extends Equatable {
|
||||
createdAt,
|
||||
type,
|
||||
subType,
|
||||
providerId,
|
||||
provider,
|
||||
modelId,
|
||||
modelDisplayName,
|
||||
@@ -187,8 +182,6 @@ class OperationModel extends Equatable {
|
||||
subType: map['sub_type'] as String?,
|
||||
|
||||
// I campi relazionali nullabili restano rigorosamente null!
|
||||
providerId: map['provider_id'] as String?,
|
||||
// MAGIA ANTI-CRASH: Usiamo ?['chiave'] per non far esplodere i join vuoti
|
||||
provider: (map[Tables.providers] != null)
|
||||
? ProviderModel.fromMap(map[Tables.providers] as Map<String, dynamic>)
|
||||
: null,
|
||||
@@ -243,7 +236,7 @@ class OperationModel extends Equatable {
|
||||
if (id != null) 'id': id,
|
||||
'type': type,
|
||||
'sub_type': subType,
|
||||
'provider_id': providerId,
|
||||
'provider_id': provider?.id,
|
||||
'model_id': modelId,
|
||||
'description': description,
|
||||
if (expirationDate != null)
|
||||
|
||||
@@ -571,7 +571,7 @@ class _RichOperationCard extends StatelessWidget {
|
||||
),
|
||||
|
||||
// Tag Gestore (Agganciato dinamicamente al displayColor generato dall'esadecimale del DB!)
|
||||
if (operation.providerId != null)
|
||||
if (operation.provider != null)
|
||||
_MiniChip(
|
||||
label: operation.provider?.name ?? 'Gestore',
|
||||
color:
|
||||
|
||||
@@ -138,13 +138,13 @@ class OperationDetailsSection extends StatelessWidget {
|
||||
: 'Nessun gestore selezionato',
|
||||
style: TextStyle(
|
||||
color:
|
||||
(currentOp?.providerId == null ||
|
||||
currentOp!.providerId!.isEmpty)
|
||||
(currentOp?.provider == null ||
|
||||
currentOp!.provider!.name.isEmpty)
|
||||
? Colors.grey
|
||||
: null,
|
||||
fontWeight:
|
||||
(currentOp?.providerId == null ||
|
||||
currentOp!.providerId!.isEmpty)
|
||||
(currentOp?.provider == null ||
|
||||
currentOp!.provider!.name.isEmpty)
|
||||
? FontWeight.normal
|
||||
: FontWeight.bold,
|
||||
),
|
||||
|
||||
@@ -58,6 +58,7 @@ class TaskFormCubit extends Cubit<TaskFormState> {
|
||||
dueDate: task.dueDate,
|
||||
isGlobal: task.isGlobal, // Sfrutta il tuo getter storeId == null
|
||||
selectedStaffIds: task.assignedToIds,
|
||||
taskStatus: task.status,
|
||||
),
|
||||
);
|
||||
await _loadExistingTaskReminders(task.id!);
|
||||
@@ -272,6 +273,10 @@ class TaskFormCubit extends Cubit<TaskFormState> {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flux/core/utils/extensions.dart';
|
||||
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
|
||||
import 'package:flux/features/tasks/models/task_status.dart';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
enum TaskStatus { open, inProgress, completed }
|
||||
|
||||
extension TaskStatusExtension on TaskStatus {
|
||||
String get name {
|
||||
String get displayName {
|
||||
switch (this) {
|
||||
case TaskStatus.open:
|
||||
return 'Da Iniziare';
|
||||
|
||||
@@ -124,6 +124,30 @@ class _TaskFormScreenState extends State<TaskFormScreen> {
|
||||
appBar: AppBar(
|
||||
title: Text(isEditing ? 'Modifica Task' : 'Nuovo Task'),
|
||||
actions: [
|
||||
// 🥷 1. BOTTONE COMPLETAMENTO RAPIDO (Solo se in edit e non già completato)
|
||||
if (isEditing && state.taskStatus != TaskStatus.completed)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
context.read<TaskFormCubit>().updateTaskStatus(
|
||||
TaskStatus.completed,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.check_circle_outline),
|
||||
label: const Text('Completa'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green.shade600,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 🥷 2. LOADER O BOTTONE SALVA
|
||||
if (state.status == TaskFormStatus.submitting)
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
@@ -134,13 +158,18 @@ class _TaskFormScreenState extends State<TaskFormScreen> {
|
||||
),
|
||||
)
|
||||
else
|
||||
TextButton.icon(
|
||||
onPressed: state.isFormValid ? () => cubit.saveTask() : null,
|
||||
icon: const Icon(Icons.save),
|
||||
label: const Text('Salva'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.orange,
|
||||
disabledForegroundColor: Colors.grey,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: TextButton.icon(
|
||||
onPressed: state.isFormValid
|
||||
? () => cubit.saveTask()
|
||||
: null,
|
||||
icon: const Icon(Icons.save),
|
||||
label: const Text('Salva'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.orange,
|
||||
disabledForegroundColor: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -183,43 +212,6 @@ class _TaskFormScreenState extends State<TaskFormScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (state.id != null &&
|
||||
state.taskStatus != TaskStatus.completed)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 24.0),
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
// Chiama direttamente l'update immediato nel DB!
|
||||
context
|
||||
.read<TaskFormCubit>()
|
||||
.updateTaskStatus(TaskStatus.completed);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.check_circle_outline,
|
||||
size: 28,
|
||||
),
|
||||
label: const Text(
|
||||
'Segna come Completato',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green.shade600,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(height: 30),
|
||||
_buildFormFields(context, state, cubit),
|
||||
const SizedBox(height: 30),
|
||||
ElevatedButton.icon(
|
||||
@@ -302,6 +294,45 @@ class _TaskFormScreenState extends State<TaskFormScreen> {
|
||||
),
|
||||
onChanged: cubit.updateDescription,
|
||||
),
|
||||
if (state.id != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
DropdownButtonFormField<TaskStatus>(
|
||||
// Leggiamo lo stato attuale dal Cubit (o usiamo un default per i nuovi task)
|
||||
initialValue: state.taskStatus,
|
||||
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Stato Attuale',
|
||||
prefixIcon: const Icon(Icons.flag_outlined),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
|
||||
// Mappiamo tutti i valori dell'enum in elementi della tendina
|
||||
items: TaskStatus.values.map((TaskStatus status) {
|
||||
return DropdownMenuItem<TaskStatus>(
|
||||
value: status,
|
||||
child: Text(
|
||||
status
|
||||
.displayName, // Usa la property displayName del tuo enum!
|
||||
style: TextStyle(
|
||||
fontWeight: status == state.taskStatus
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
onChanged: (TaskStatus? newStatus) {
|
||||
if (newStatus != null && newStatus != state.taskStatus) {
|
||||
context.read<TaskFormCubit>().updateTaskStatus(newStatus);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// --- SCADENZA ---
|
||||
|
||||
Reference in New Issue
Block a user