This commit is contained in:
2026-05-29 12:26:41 +02:00
parent 6211cc6729
commit 5ad3e12b1f
18 changed files with 1303 additions and 372 deletions

View File

@@ -1,49 +1,50 @@
import 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.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_status.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
part 'dashboard_task_list_state.dart';
class DashboardTaskListCubit extends Cubit<DashboardTaskListState> {
final TaskRepository _repository = GetIt.I.get<TaskRepository>();
final SupabaseClient _supabase = GetIt.I.get<SupabaseClient>();
RealtimeChannel? _taskChannel;
final String staffId;
final String companyId;
StreamSubscription<void>? _taskSubscription;
DashboardTaskListCubit() : super(DashboardTaskListState());
void startListening({required String staffId}) async {
emit(state.copyWith(status: DashboardTaskListStatus.loading));
await _loadTasks(staffId: staffId);
_taskChannel?.unsubscribe();
_taskChannel = _supabase
.channel('public:tasks_staff_$staffId')
.onPostgresChanges(
event: PostgresChangeEvent.all,
schema: 'public',
table: 'tasks',
filter: PostgresChangeFilter(
type: PostgresChangeFilterType.eq,
column: 'staff_id',
value: staffId,
),
callback: (payload) {
_loadTasks(staffId: staffId);
},
);
_taskChannel?.subscribe();
DashboardTaskListCubit({required this.staffId, required this.companyId})
: super(const DashboardTaskListState()) {
_initRealtime();
}
Future<void> _loadTasks({required String staffId}) async {
void _initRealtime() {
emit(state.copyWith(status: DashboardTaskListStatus.loading));
// Primo caricamento
_loadTasksSilently();
// Inizio ascolto campanello
_taskSubscription = _repository.watchCompanyTasks(companyId).listen((_) {
// Quando il campanello suona (qualcosa è cambiato a DB), ricarichiamo!
_loadTasksSilently();
});
}
Future<void> loadTasks() async {
emit(state.copyWith(status: DashboardTaskListStatus.loading));
await _loadTasksSilently();
}
Future<void> _loadTasksSilently() async {
try {
final tasks = await _repository.getTasks(
companyId: GetIt.I.get<SessionCubit>().state.company!.id!,
companyId: companyId,
staffId: staffId,
statuses: [TaskStatus.open, TaskStatus.inProgress],
limit: 10,
);
emit(
@@ -65,7 +66,8 @@ class DashboardTaskListCubit extends Cubit<DashboardTaskListState> {
@override
Future<void> close() {
_taskChannel?.unsubscribe();
// Stacchiamo l'abbonamento. Il controller.onCancel nel Repo farà il resto!
_taskSubscription?.cancel();
return super.close();
}
}

View File

@@ -4,6 +4,7 @@ import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/routes/routes.dart';
import 'package:flux/core/theme/theme.dart';
import 'package:flux/features/home/dashboard_task_list/blocs/dashboard_task_list_cubit.dart';
import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart';
import 'package:flux/features/tasks/models/task_status.dart';
@@ -14,11 +15,12 @@ class DashboardTasksCard extends StatelessWidget {
Widget build(BuildContext context) {
// Recuperiamo lo staff (o l'utente) loggato
// Adatta il getter in base a come è strutturato il tuo SessionState
final currentStaffId = context
.read<SessionCubit>()
final currentStaffId = GetIt.I
.get<SessionCubit>()
.state
.currentStaffMember
?.id;
final companyId = GetIt.I.get<SessionCubit>().state.company!.id!;
if (currentStaffId == null) {
return const SizedBox.shrink(); // Sicurezza se lo stato non è pronto
@@ -26,7 +28,7 @@ class DashboardTasksCard extends StatelessWidget {
return BlocProvider(
create: (context) =>
DashboardTaskListCubit()..startListening(staffId: currentStaffId),
DashboardTaskListCubit(staffId: currentStaffId, companyId: companyId),
child: const _DashboardTasksCardContent(),
);
}