coverage working

This commit is contained in:
José Salazar
2026-01-27 11:27:14 -05:00
parent 3dc2e90962
commit 0902c0ecf0
6 changed files with 19845 additions and 19282 deletions

View File

@@ -1,4 +1,5 @@
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'data/repositories_impl/coverage_repository_impl.dart';
import 'domain/repositories/coverage_repository.dart';
import 'domain/usecases/get_coverage_stats_usecase.dart';
@@ -11,7 +12,9 @@ class CoverageModule extends Module {
@override
void binds(Injector i) {
// Repositories
i.addSingleton<CoverageRepository>(CoverageRepositoryImpl.new);
i.addSingleton<CoverageRepository>(
() => CoverageRepositoryImpl(dataConnect: ExampleConnector.instance),
);
// Use Cases
i.addSingleton(GetShiftsForDateUseCase.new);

View File

@@ -1,3 +1,5 @@
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import '../../domain/repositories/coverage_repository.dart';
import '../../domain/ui_entities/coverage_entities.dart';
@@ -13,82 +15,43 @@ import '../../domain/ui_entities/coverage_entities.dart';
/// - Returns domain entities from `domain/ui_entities`.
class CoverageRepositoryImpl implements CoverageRepository {
/// Creates a [CoverageRepositoryImpl].
CoverageRepositoryImpl();
CoverageRepositoryImpl({required dc.ExampleConnector dataConnect})
: _dataConnect = dataConnect;
final dc.ExampleConnector _dataConnect;
/// Fetches shifts for a specific date.
@override
Future<List<CoverageShift>> getShiftsForDate({required DateTime date}) async {
// Simulate network delay
await Future<void>.delayed(const Duration(milliseconds: 500));
// Mock data - in production, this would come from data_connect
final DateTime today = DateTime.now();
final bool isToday = date.year == today.year &&
date.month == today.month &&
date.day == today.day;
if (!isToday) {
// Return empty list for non-today dates
final String? businessId =
dc.ClientSessionStore.instance.session?.business?.id;
print('Coverage: now=${DateTime.now().toIso8601String()}');
if (businessId == null || businessId.isEmpty) {
print('Coverage: missing businessId for date=${date.toIso8601String()}');
return <CoverageShift>[];
}
return <CoverageShift>[
CoverageShift(
id: '1',
title: 'Banquet Server',
location: 'Grand Ballroom',
startTime: '16:00',
workersNeeded: 10,
date: date,
workers: const <CoverageWorker>[
CoverageWorker(
name: 'Sarah Wilson',
status: 'confirmed',
checkInTime: '15:55',
),
CoverageWorker(
name: 'Mike Ross',
status: 'confirmed',
checkInTime: '16:00',
),
CoverageWorker(
name: 'Jane Doe',
status: 'confirmed',
checkInTime: null,
),
CoverageWorker(
name: 'John Smith',
status: 'late',
checkInTime: null,
),
],
),
CoverageShift(
id: '2',
title: 'Bartender',
location: 'Lobby Bar',
startTime: '17:00',
workersNeeded: 4,
date: date,
workers: const <CoverageWorker>[
CoverageWorker(
name: 'Emily Blunt',
status: 'confirmed',
checkInTime: '16:45',
),
CoverageWorker(
name: 'Chris Evans',
status: 'confirmed',
checkInTime: '16:50',
),
CoverageWorker(
name: 'Tom Holland',
status: 'confirmed',
checkInTime: null,
),
],
),
];
final DateTime start = DateTime(date.year, date.month, date.day);
final DateTime end =
DateTime(date.year, date.month, date.day, 23, 59, 59, 999);
print(
'Coverage: request businessId=$businessId dayStart=${start.toIso8601String()} dayEnd=${end.toIso8601String()}',
);
final fdc.QueryResult<
dc.ListStaffsApplicationsByBusinessForDayData,
dc.ListStaffsApplicationsByBusinessForDayVariables> result =
await _dataConnect
.listStaffsApplicationsByBusinessForDay(
businessId: businessId,
dayStart: _toTimestamp(start),
dayEnd: _toTimestamp(end),
)
.execute();
print(
'Coverage: ${date.toIso8601String()} staffsApplications=${result.data.applications.length}',
);
return _mapCoverageShifts(result.data.applications, date);
}
/// Fetches coverage statistics for a specific date.
@@ -120,4 +83,122 @@ class CoverageRepositoryImpl implements CoverageRepository {
late: late,
);
}
fdc.Timestamp _toTimestamp(DateTime dateTime) {
final int seconds = dateTime.millisecondsSinceEpoch ~/ 1000;
final int nanoseconds =
(dateTime.millisecondsSinceEpoch % 1000) * 1000000;
return fdc.Timestamp(nanoseconds, seconds);
}
Future<List<CoverageShift>> _mapCoverageShifts(
List<dc.ListStaffsApplicationsByBusinessForDayApplications> applications,
DateTime date,
) async {
if (applications.isEmpty) {
return <CoverageShift>[];
}
final Map<String, _CoverageGroup> groups =
<String, _CoverageGroup>{};
for (final dc.ListStaffsApplicationsByBusinessForDayApplications app
in applications) {
final String key = '${app.shiftId}:${app.roleId}';
final _CoverageGroup existing = groups[key] ??
_CoverageGroup(
shiftId: app.shiftId,
roleId: app.roleId,
roleName: app.shiftRole.role.name,
location: app.shiftRole.shift.location ?? '',
workers: <CoverageWorker>[],
);
existing.workers.add(
CoverageWorker(
name: app.staff.fullName,
status: _mapWorkerStatus(app.status),
checkInTime: _formatTime(app.checkInTime),
),
);
groups[key] = existing;
}
final List<_CoverageGroup> groupList = groups.values.toList();
final List<CoverageShift> shifts = <CoverageShift>[];
for (final _CoverageGroup group in groupList) {
final fdc.QueryResult<dc.GetShiftRoleByIdData,
dc.GetShiftRoleByIdVariables> shiftRoleResult =
await _dataConnect
.getShiftRoleById(
shiftId: group.shiftId,
roleId: group.roleId,
)
.execute();
final dc.GetShiftRoleByIdShiftRole? shiftRole =
shiftRoleResult.data.shiftRole;
if (shiftRole == null) {
continue;
}
final String startTime = _formatTime(shiftRole.startTime) ?? '00:00';
shifts.add(
CoverageShift(
id: shiftRole.id,
title: group.roleName,
location: group.location,
startTime: startTime,
workersNeeded: shiftRole.count,
date: date,
workers: group.workers,
),
);
}
return shifts;
}
String _mapWorkerStatus(
dc.EnumValue<dc.ApplicationStatus> status,
) {
if (status is dc.Known<dc.ApplicationStatus>) {
switch (status.value) {
case dc.ApplicationStatus.LATE:
return 'late';
case dc.ApplicationStatus.CHECKED_IN:
case dc.ApplicationStatus.CHECKED_OUT:
case dc.ApplicationStatus.ACCEPTED:
case dc.ApplicationStatus.CONFIRMED:
case dc.ApplicationStatus.PENDING:
case dc.ApplicationStatus.REJECTED:
case dc.ApplicationStatus.NO_SHOW:
return 'confirmed';
}
}
return 'confirmed';
}
String? _formatTime(fdc.Timestamp? timestamp) {
if (timestamp == null) {
return null;
}
final DateTime date = timestamp.toDateTime();
final String hour = date.hour.toString().padLeft(2, '0');
final String minute = date.minute.toString().padLeft(2, '0');
return '$hour:$minute';
}
}
class _CoverageGroup {
_CoverageGroup({
required this.shiftId,
required this.roleId,
required this.roleName,
required this.location,
required this.workers,
});
final String shiftId;
final String roleId;
final String roleName;
final String location;
final List<CoverageWorker> workers;
}