refactor: centralize data connect error handling and resolve build issues across applications

This commit addresses several critical issues across the mobile monorepo:

1. Centralized Error Handling: Integrated DataErrorHandler mixin into all repository implementations, ensuring consistent mapping of Data Connect exceptions to domain AppExceptions.
2. Build Stabilization: Fixed numerous type mismatches, parameter signature errors in widgets (e.g., google_places_flutter itemBuilder), and naming conflicts (StaffSession, FirebaseAuth).
3. Code Quality: Applied 'dart fix' across all modified packages and manually cleared debug print statements and UI clutter.
4. Mono-repo alignment: Standardized Data Connect usage and aliasing ('dc.') for better maintainability.

Signed-off-by: Suriya <suriya@tenext.in>
This commit is contained in:
2026-02-06 13:28:57 +05:30
parent e0636e46a3
commit 5e7bf0d5c0
150 changed files with 1506 additions and 2547 deletions

View File

@@ -1,15 +1,16 @@
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_data_connect/src/session/staff_session_store.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:intl/intl.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:krow_core/core.dart';
import '../../domain/repositories/shifts_repository_interface.dart';
class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
class ShiftsRepositoryImpl
with dc.DataErrorHandler
implements ShiftsRepositoryInterface {
final dc.ExampleConnector _dataConnect;
final FirebaseAuth _auth = FirebaseAuth.instance;
final firebase_auth.FirebaseAuth _auth = firebase_auth.FirebaseAuth.instance;
ShiftsRepositoryImpl() : _dataConnect = dc.ExampleConnector.instance;
@@ -22,7 +23,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
Future<String> _getStaffId() async {
// 1. Check Session Store
final StaffSession? session = StaffSessionStore.instance.session;
final dc.StaffSession? session = dc.StaffSessionStore.instance.session;
if (session?.staff?.id != null) {
return session!.staff!.id;
}
@@ -31,15 +32,15 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
if (_cachedStaffId != null) return _cachedStaffId!;
// 3. Fetch from Data Connect using Firebase UID
final user = _auth.currentUser;
final firebase_auth.User? user = _auth.currentUser;
if (user == null) {
throw Exception('User is not authenticated');
}
try {
final response = await _dataConnect
final fdc.QueryResult<dc.GetStaffByUserIdData, dc.GetStaffByUserIdVariables> response = await executeProtected(() => _dataConnect
.getStaffByUserId(userId: user.uid)
.execute();
.execute());
if (response.data.staffs.isNotEmpty) {
_cachedStaffId = response.data.staffs.first.id;
return _cachedStaffId!;
@@ -52,10 +53,10 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
return user.uid;
}
DateTime? _toDateTime(dynamic t, {String? debugKey}) {
DateTime? _toDateTime(dynamic t) {
if (t == null) return null;
DateTime? dt;
if (t is Timestamp) {
if (t is fdc.Timestamp) {
dt = t.toDateTime();
} else if (t is String) {
dt = DateTime.tryParse(t);
@@ -73,11 +74,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
if (dt != null) {
final local = DateTimeUtils.toDeviceTime(dt);
if (debugKey != null && debugKey.isNotEmpty) {
print(
'ShiftDate convert: key=$debugKey raw=$t parsed=${dt.toIso8601String()} local=${local.toIso8601String()}',
);
}
return local;
}
return null;
@@ -103,135 +100,125 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
@override
Future<List<Shift>> getHistoryShifts() async {
try {
final staffId = await _getStaffId();
final response = await _dataConnect
.listCompletedApplicationsByStaffId(staffId: staffId)
.execute();
final List<Shift> shifts = [];
final staffId = await _getStaffId();
final fdc.QueryResult<dc.ListCompletedApplicationsByStaffIdData, dc.ListCompletedApplicationsByStaffIdVariables> response = await executeProtected(() => _dataConnect
.listCompletedApplicationsByStaffId(staffId: staffId)
.execute());
final List<Shift> shifts = [];
for (final app in response.data.applications) {
_shiftToAppIdMap[app.shift.id] = app.id;
_appToRoleIdMap[app.id] = app.shiftRole.id;
for (final app in response.data.applications) {
_shiftToAppIdMap[app.shift.id] = app.id;
_appToRoleIdMap[app.id] = app.shiftRole.id;
final String roleName = app.shiftRole.role.name;
final String orderName =
(app.shift.order.eventName ?? '').trim().isNotEmpty
? app.shift.order.eventName!
: app.shift.order.business.businessName;
final String title = '$roleName - $orderName';
final DateTime? shiftDate = _toDateTime(app.shift.date);
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
final DateTime? createdDt = _toDateTime(app.createdAt);
final String roleName = app.shiftRole.role.name;
final String orderName =
(app.shift.order.eventName ?? '').trim().isNotEmpty
? app.shift.order.eventName!
: app.shift.order.business.businessName;
final String title = '$roleName - $orderName';
final DateTime? shiftDate = _toDateTime(app.shift.date);
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
final DateTime? createdDt = _toDateTime(app.createdAt);
shifts.add(
Shift(
id: app.shift.id,
roleId: app.shiftRole.roleId,
title: title,
clientName: app.shift.order.business.businessName,
logoUrl: app.shift.order.business.companyLogoUrl,
hourlyRate: app.shiftRole.role.costPerHour,
location: app.shift.location ?? '',
locationAddress: app.shift.order.teamHub.hubName,
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: _mapStatus(dc.ApplicationStatus.CHECKED_OUT),
description: app.shift.description,
durationDays: app.shift.durationDays,
requiredSlots: app.shiftRole.count,
filledSlots: app.shiftRole.assigned ?? 0,
hasApplied: true,
),
);
}
return shifts;
} catch (e) {
return <Shift>[];
shifts.add(
Shift(
id: app.shift.id,
roleId: app.shiftRole.roleId,
title: title,
clientName: app.shift.order.business.businessName,
logoUrl: app.shift.order.business.companyLogoUrl,
hourlyRate: app.shiftRole.role.costPerHour,
location: app.shift.location ?? '',
locationAddress: app.shift.order.teamHub.hubName,
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: _mapStatus(dc.ApplicationStatus.CHECKED_OUT),
description: app.shift.description,
durationDays: app.shift.durationDays,
requiredSlots: app.shiftRole.count,
filledSlots: app.shiftRole.assigned ?? 0,
hasApplied: true,
),
);
}
return shifts;
}
Future<List<Shift>> _fetchApplications({
DateTime? start,
DateTime? end,
}) async {
try {
final staffId = await _getStaffId();
var query = _dataConnect.getApplicationsByStaffId(staffId: staffId);
if (start != null && end != null) {
query = query
.dayStart(_toTimestamp(start))
.dayEnd(_toTimestamp(end));
}
final response = await query.execute();
final apps = response.data.applications;
final List<Shift> shifts = [];
for (final app in apps) {
_shiftToAppIdMap[app.shift.id] = app.id;
_appToRoleIdMap[app.id] = app.shiftRole.id;
final String roleName = app.shiftRole.role.name;
final String orderName =
(app.shift.order.eventName ?? '').trim().isNotEmpty
? app.shift.order.eventName!
: app.shift.order.business.businessName;
final String title = '$roleName - $orderName';
final DateTime? shiftDate = _toDateTime(app.shift.date);
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
final DateTime? createdDt = _toDateTime(app.createdAt);
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
final bool hasCheckIn = app.checkInTime != null;
final bool hasCheckOut = app.checkOutTime != null;
dc.ApplicationStatus? appStatus;
if (app.status is dc.Known<dc.ApplicationStatus>) {
appStatus = (app.status as dc.Known<dc.ApplicationStatus>).value;
}
final String mappedStatus = hasCheckOut
? 'completed'
: hasCheckIn
? 'checked_in'
: _mapStatus(appStatus ?? dc.ApplicationStatus.ACCEPTED);
shifts.add(
Shift(
id: app.shift.id,
roleId: app.shiftRole.roleId,
title: title,
clientName: app.shift.order.business.businessName,
logoUrl: app.shift.order.business.companyLogoUrl,
hourlyRate: app.shiftRole.role.costPerHour,
location: app.shift.location ?? '',
locationAddress: app.shift.order.teamHub.hubName,
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: mappedStatus,
description: app.shift.description,
durationDays: app.shift.durationDays,
requiredSlots: app.shiftRole.count,
filledSlots: app.shiftRole.assigned ?? 0,
hasApplied: true,
),
);
}
return shifts;
} catch (e) {
return <Shift>[];
final staffId = await _getStaffId();
var query = _dataConnect.getApplicationsByStaffId(staffId: staffId);
if (start != null && end != null) {
query = query.dayStart(_toTimestamp(start)).dayEnd(_toTimestamp(end));
}
final fdc.QueryResult<dc.GetApplicationsByStaffIdData, dc.GetApplicationsByStaffIdVariables> response = await executeProtected(() => query.execute());
final apps = response.data.applications;
final List<Shift> shifts = [];
for (final app in apps) {
_shiftToAppIdMap[app.shift.id] = app.id;
_appToRoleIdMap[app.id] = app.shiftRole.id;
final String roleName = app.shiftRole.role.name;
final String orderName =
(app.shift.order.eventName ?? '').trim().isNotEmpty
? app.shift.order.eventName!
: app.shift.order.business.businessName;
final String title = '$roleName - $orderName';
final DateTime? shiftDate = _toDateTime(app.shift.date);
final DateTime? startDt = _toDateTime(app.shiftRole.startTime);
final DateTime? endDt = _toDateTime(app.shiftRole.endTime);
final DateTime? createdDt = _toDateTime(app.createdAt);
// Override status to reflect the application state (e.g., CHECKED_OUT, ACCEPTED)
final bool hasCheckIn = app.checkInTime != null;
final bool hasCheckOut = app.checkOutTime != null;
dc.ApplicationStatus? appStatus;
if (app.status is dc.Known<dc.ApplicationStatus>) {
appStatus = (app.status as dc.Known<dc.ApplicationStatus>).value;
}
final String mappedStatus = hasCheckOut
? 'completed'
: hasCheckIn
? 'checked_in'
: _mapStatus(appStatus ?? dc.ApplicationStatus.ACCEPTED);
shifts.add(
Shift(
id: app.shift.id,
roleId: app.shiftRole.roleId,
title: title,
clientName: app.shift.order.business.businessName,
logoUrl: app.shift.order.business.companyLogoUrl,
hourlyRate: app.shiftRole.role.costPerHour,
location: app.shift.location ?? '',
locationAddress: app.shift.order.teamHub.hubName,
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: mappedStatus,
description: app.shift.description,
durationDays: app.shift.durationDays,
requiredSlots: app.shiftRole.count,
filledSlots: app.shiftRole.assigned ?? 0,
hasApplied: true,
),
);
}
return shifts;
}
Timestamp _toTimestamp(DateTime dateTime) {
fdc.Timestamp _toTimestamp(DateTime dateTime) {
final DateTime utc = dateTime.toUtc();
final int seconds = utc.millisecondsSinceEpoch ~/ 1000;
final int nanoseconds = (utc.microsecondsSinceEpoch % 1000000) * 1000;
return Timestamp(nanoseconds, seconds);
return fdc.Timestamp(nanoseconds, seconds);
}
String _mapStatus(dc.ApplicationStatus status) {
@@ -252,74 +239,60 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
@override
Future<List<Shift>> getAvailableShifts(String query, String type) async {
try {
final String? vendorId = dc.StaffSessionStore.instance.session?.ownerId;
if (vendorId == null || vendorId.isEmpty) {
return <Shift>[];
}
final result = await _dataConnect
.listShiftRolesByVendorId(vendorId: vendorId)
.execute();
final allShiftRoles = result.data.shiftRoles;
final List<Shift> mappedShifts = [];
for (final sr in allShiftRoles) {
print(
'FindShifts raw: shiftId=${sr.shiftId} roleId=${sr.roleId} '
'start=${sr.startTime?.toJson()} end=${sr.endTime?.toJson()} '
'shiftDate=${sr.shift.date?.toJson()}',
);
final DateTime? shiftDate = _toDateTime(sr.shift.date);
final startDt = _toDateTime(sr.startTime);
final endDt = _toDateTime(sr.endTime);
final createdDt = _toDateTime(sr.createdAt);
print(
'FindShifts mapped: shiftId=${sr.shiftId} '
'origStart=${sr.startTime?.toJson()} '
'origEnd=${sr.endTime?.toJson()} '
'mappedStart=${startDt != null ? DateFormat('HH:mm').format(startDt) : ''} '
'mappedEnd=${endDt != null ? DateFormat('HH:mm').format(endDt) : ''}',
);
mappedShifts.add(
Shift(
id: sr.shiftId,
roleId: sr.roleId,
title: sr.role.name,
clientName: sr.shift.order.business.businessName,
logoUrl: null,
hourlyRate: sr.role.costPerHour,
location: sr.shift.location ?? '',
locationAddress: sr.shift.locationAddress ?? '',
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null
? DateFormat('HH:mm').format(startDt)
: '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: sr.shift.status?.stringValue.toLowerCase() ?? 'open',
description: sr.shift.description,
durationDays: sr.shift.durationDays,
requiredSlots: sr.count,
filledSlots: sr.assigned ?? 0,
),
);
}
if (query.isNotEmpty) {
return mappedShifts
.where(
(s) =>
s.title.toLowerCase().contains(query.toLowerCase()) ||
s.clientName.toLowerCase().contains(query.toLowerCase()),
)
.toList();
}
return mappedShifts;
} catch (e) {
final String? vendorId = dc.StaffSessionStore.instance.session?.ownerId;
if (vendorId == null || vendorId.isEmpty) {
return <Shift>[];
}
final fdc.QueryResult<dc.ListShiftRolesByVendorIdData, dc.ListShiftRolesByVendorIdVariables> result = await executeProtected(() => _dataConnect
.listShiftRolesByVendorId(vendorId: vendorId)
.execute());
final allShiftRoles = result.data.shiftRoles;
final List<Shift> mappedShifts = [];
for (final sr in allShiftRoles) {
final DateTime? shiftDate = _toDateTime(sr.shift.date);
final startDt = _toDateTime(sr.startTime);
final endDt = _toDateTime(sr.endTime);
final createdDt = _toDateTime(sr.createdAt);
mappedShifts.add(
Shift(
id: sr.shiftId,
roleId: sr.roleId,
title: sr.role.name,
clientName: sr.shift.order.business.businessName,
logoUrl: null,
hourlyRate: sr.role.costPerHour,
location: sr.shift.location ?? '',
locationAddress: sr.shift.locationAddress ?? '',
date: shiftDate?.toIso8601String() ?? '',
startTime: startDt != null
? DateFormat('HH:mm').format(startDt)
: '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: sr.shift.status?.stringValue.toLowerCase() ?? 'open',
description: sr.shift.description,
durationDays: sr.shift.durationDays,
requiredSlots: sr.count,
filledSlots: sr.assigned ?? 0,
),
);
}
if (query.isNotEmpty) {
return mappedShifts
.where(
(s) =>
s.title.toLowerCase().contains(query.toLowerCase()) ||
s.clientName.toLowerCase().contains(query.toLowerCase()),
)
.toList();
}
return mappedShifts;
}
@override
@@ -328,108 +301,101 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
}
Future<Shift?> _getShiftDetails(String shiftId, {String? roleId}) async {
try {
if (roleId != null && roleId.isNotEmpty) {
final roleResult = await _dataConnect
.getShiftRoleById(shiftId: shiftId, roleId: roleId)
.execute();
final sr = roleResult.data.shiftRole;
if (sr == null) return null;
if (roleId != null && roleId.isNotEmpty) {
final roleResult = await executeProtected(() => _dataConnect
.getShiftRoleById(shiftId: shiftId, roleId: roleId)
.execute());
final sr = roleResult.data.shiftRole;
if (sr == null) return null;
final DateTime? startDt = _toDateTime(sr.startTime);
final DateTime? endDt = _toDateTime(sr.endTime);
final DateTime? createdDt = _toDateTime(sr.createdAt);
final DateTime? startDt = _toDateTime(sr.startTime);
final DateTime? endDt = _toDateTime(sr.endTime);
final DateTime? createdDt = _toDateTime(sr.createdAt);
final String? staffId = await _getStaffId();
bool hasApplied = false;
String status = 'open';
if (staffId != null) {
final apps = await _dataConnect
.getApplicationsByStaffId(staffId: staffId)
.execute();
final app = apps.data.applications
.where(
(a) => a.shiftId == shiftId && a.shiftRole.roleId == roleId,
)
.firstOrNull;
if (app != null) {
hasApplied = true;
if (app.status is dc.Known<dc.ApplicationStatus>) {
final dc.ApplicationStatus s =
(app.status as dc.Known<dc.ApplicationStatus>).value;
status = _mapStatus(s);
}
}
final String staffId = await _getStaffId();
bool hasApplied = false;
String status = 'open';
final apps = await executeProtected(() =>
_dataConnect.getApplicationsByStaffId(staffId: staffId).execute());
final app = apps.data.applications
.where(
(a) => a.shiftId == shiftId && a.shiftRole.roleId == roleId,
)
.firstOrNull;
if (app != null) {
hasApplied = true;
if (app.status is dc.Known<dc.ApplicationStatus>) {
final dc.ApplicationStatus s =
(app.status as dc.Known<dc.ApplicationStatus>).value;
status = _mapStatus(s);
}
return Shift(
id: sr.shiftId,
roleId: sr.roleId,
title: sr.shift.order.business.businessName,
clientName: sr.shift.order.business.businessName,
logoUrl: sr.shift.order.business.companyLogoUrl,
hourlyRate: sr.role.costPerHour,
location: sr.shift.location ?? sr.shift.order.teamHub.hubName,
locationAddress: sr.shift.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: status,
description: sr.shift.description,
durationDays: null,
requiredSlots: sr.count,
filledSlots: sr.assigned ?? 0,
hasApplied: hasApplied,
totalValue: sr.totalValue,
);
}
final result = await _dataConnect.getShiftById(id: shiftId).execute();
final s = result.data.shift;
if (s == null) return null;
int? required;
int? filled;
try {
final rolesRes = await _dataConnect
.listShiftRolesByShiftId(shiftId: shiftId)
.execute();
if (rolesRes.data.shiftRoles.isNotEmpty) {
required = 0;
filled = 0;
for (var r in rolesRes.data.shiftRoles) {
required = (required ?? 0) + r.count;
filled = (filled ?? 0) + (r.assigned ?? 0);
}
}
} catch (_) {}
final startDt = _toDateTime(s.startTime);
final endDt = _toDateTime(s.endTime);
final createdDt = _toDateTime(s.createdAt);
return Shift(
id: s.id,
title: s.title,
clientName: s.order.business.businessName,
logoUrl: null,
hourlyRate: s.cost ?? 0.0,
location: s.location ?? '',
locationAddress: s.locationAddress ?? '',
id: sr.shiftId,
roleId: sr.roleId,
title: sr.shift.order.business.businessName,
clientName: sr.shift.order.business.businessName,
logoUrl: sr.shift.order.business.companyLogoUrl,
hourlyRate: sr.role.costPerHour,
location: sr.shift.location ?? sr.shift.order.teamHub.hubName,
locationAddress: sr.shift.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: s.status?.stringValue ?? 'OPEN',
description: s.description,
durationDays: s.durationDays,
requiredSlots: required,
filledSlots: filled,
status: status,
description: sr.shift.description,
durationDays: null,
requiredSlots: sr.count,
filledSlots: sr.assigned ?? 0,
hasApplied: hasApplied,
totalValue: sr.totalValue,
);
} catch (e) {
return null;
}
final fdc.QueryResult<dc.GetShiftByIdData, dc.GetShiftByIdVariables> result =
await executeProtected(() => _dataConnect.getShiftById(id: shiftId).execute());
final s = result.data.shift;
if (s == null) return null;
int? required;
int? filled;
try {
final rolesRes = await executeProtected(() =>
_dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute());
if (rolesRes.data.shiftRoles.isNotEmpty) {
required = 0;
filled = 0;
for (var r in rolesRes.data.shiftRoles) {
required = (required ?? 0) + r.count;
filled = (filled ?? 0) + (r.assigned ?? 0);
}
}
} catch (_) {}
final startDt = _toDateTime(s.startTime);
final endDt = _toDateTime(s.endTime);
final createdDt = _toDateTime(s.createdAt);
return Shift(
id: s.id,
title: s.title,
clientName: s.order.business.businessName,
logoUrl: null,
hourlyRate: s.cost ?? 0.0,
location: s.location ?? '',
locationAddress: s.locationAddress ?? '',
date: startDt?.toIso8601String() ?? '',
startTime: startDt != null ? DateFormat('HH:mm').format(startDt) : '',
endTime: endDt != null ? DateFormat('HH:mm').format(endDt) : '',
createdDate: createdDt?.toIso8601String() ?? '',
status: s.status?.stringValue ?? 'OPEN',
description: s.description,
durationDays: s.durationDays,
requiredSlots: required,
filledSlots: filled,
);
}
@override
@@ -445,14 +411,15 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
throw Exception('Missing role id.');
}
final roleResult = await _dataConnect
final roleResult = await executeProtected(() => _dataConnect
.getShiftRoleById(shiftId: shiftId, roleId: targetRoleId)
.execute();
.execute());
final role = roleResult.data.shiftRole;
if (role == null) {
throw Exception('Shift role not found');
}
final shiftResult = await _dataConnect.getShiftById(id: shiftId).execute();
final shiftResult =
await executeProtected(() => _dataConnect.getShiftById(id: shiftId).execute());
final shift = shiftResult.data.shift;
if (shift == null) {
throw Exception('Shift not found');
@@ -474,26 +441,23 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
999,
999,
);
print(
'Staff applyForShift: dayStartUtc=${_toTimestamp(dayStartUtc).toJson()} '
'dayEndUtc=${_toTimestamp(dayEndUtc).toJson()}',
);
final dayApplications = await _dataConnect
final dayApplications = await executeProtected(() => _dataConnect
.vaidateDayStaffApplication(staffId: staffId)
.dayStart(_toTimestamp(dayStartUtc))
.dayEnd(_toTimestamp(dayEndUtc))
.execute();
.execute());
if (dayApplications.data.applications.isNotEmpty) {
throw Exception('The user already has a shift that day.');
}
}
final existingApplicationResult = await _dataConnect
final existingApplicationResult = await executeProtected(() => _dataConnect
.getApplicationByStaffShiftAndRole(
staffId: staffId,
shiftId: shiftId,
roleId: targetRoleId,
)
.execute();
.execute());
if (existingApplicationResult.data.applications.isNotEmpty) {
throw Exception('Application already exists.');
}
@@ -508,7 +472,7 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
bool updatedRole = false;
bool updatedShift = false;
try {
final appResult = await _dataConnect
final appResult = await executeProtected(() => _dataConnect
.createApplication(
shiftId: shiftId,
staffId: staffId,
@@ -517,29 +481,36 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
origin: dc.ApplicationOrigin.STAFF,
)
// TODO: this should be PENDING so a vendor can accept it.
.execute();
.execute());
appId = appResult.data.application_insert.id;
await _dataConnect
await executeProtected(() => _dataConnect
.updateShiftRole(shiftId: shiftId, roleId: targetRoleId)
.assigned(assigned + 1)
.execute();
.execute());
updatedRole = true;
await _dataConnect.updateShift(id: shiftId).filled(filled + 1).execute();
await executeProtected(
() => _dataConnect.updateShift(id: shiftId).filled(filled + 1).execute());
updatedShift = true;
} catch (e) {
if (updatedShift) {
await _dataConnect.updateShift(id: shiftId).filled(filled).execute();
try {
await _dataConnect.updateShift(id: shiftId).filled(filled).execute();
} catch (_) {}
}
if (updatedRole) {
await _dataConnect
.updateShiftRole(shiftId: shiftId, roleId: targetRoleId)
.assigned(assigned)
.execute();
try {
await _dataConnect
.updateShiftRole(shiftId: shiftId, roleId: targetRoleId)
.assigned(assigned)
.execute();
} catch (_) {}
}
if (appId != null) {
await _dataConnect.deleteApplication(id: appId).execute();
try {
await _dataConnect.deleteApplication(id: appId).execute();
} catch (_) {}
}
rethrow;
}
@@ -573,9 +544,8 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
} else {
// Fallback fetch
final staffId = await _getStaffId();
final apps = await _dataConnect
.getApplicationsByStaffId(staffId: staffId)
.execute();
final apps = await executeProtected(() =>
_dataConnect.getApplicationsByStaffId(staffId: staffId).execute());
final app = apps.data.applications
.where((a) => a.shiftId == shiftId)
.firstOrNull;
@@ -588,13 +558,12 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
if (appId == null || roleId == null) {
// If we are rejecting and can't find an application, create one as rejected (declining an available shift)
if (newStatus == dc.ApplicationStatus.REJECTED) {
final rolesResult = await _dataConnect
.listShiftRolesByShiftId(shiftId: shiftId)
.execute();
final rolesResult = await executeProtected(() =>
_dataConnect.listShiftRolesByShiftId(shiftId: shiftId).execute());
if (rolesResult.data.shiftRoles.isNotEmpty) {
final role = rolesResult.data.shiftRoles.first;
final staffId = await _getStaffId();
await _dataConnect
await executeProtected(() => _dataConnect
.createApplication(
shiftId: shiftId,
staffId: staffId,
@@ -602,16 +571,16 @@ class ShiftsRepositoryImpl implements ShiftsRepositoryInterface {
status: dc.ApplicationStatus.REJECTED,
origin: dc.ApplicationOrigin.STAFF,
)
.execute();
.execute());
return;
}
}
throw Exception("Application not found for shift $shiftId");
}
await _dataConnect
.updateApplicationStatus(id: appId)
await executeProtected(() => _dataConnect
.updateApplicationStatus(id: appId!)
.status(newStatus)
.execute();
.execute());
}
}

View File

@@ -1,4 +1,3 @@
import 'package:krow_domain/krow_domain.dart';
import '../repositories/shifts_repository_interface.dart';
class AcceptShiftUseCase {

View File

@@ -1,4 +1,3 @@
import 'package:krow_domain/krow_domain.dart';
import '../repositories/shifts_repository_interface.dart';
class DeclineShiftUseCase {

View File

@@ -223,7 +223,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
const SizedBox(height: 8),
Row(
children: [
Container(
SizedBox(
width: 24,
height: 24,
child: displayShift.logoUrl != null
@@ -462,12 +462,12 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
),
],
const SizedBox(height: 20),
if (displayShift!.status != 'confirmed' &&
displayShift!.hasApplied != true &&
(displayShift!.requiredSlots == null ||
displayShift!.filledSlots == null ||
displayShift!.filledSlots! <
displayShift!.requiredSlots!))
if (displayShift.status != 'confirmed' &&
displayShift.hasApplied != true &&
(displayShift.requiredSlots == null ||
displayShift.filledSlots == null ||
displayShift.filledSlots! <
displayShift.requiredSlots!))
Row(
children: [
Expanded(

View File

@@ -22,12 +22,6 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
String _searchQuery = '';
String _jobType = 'all';
@override
void initState() {
super.initState();
print('FindShiftsTab init: tab entered, data pending');
}
Widget _buildFilterTab(String id, String label) {
final isSelected = _jobType == id;
return GestureDetector(
@@ -69,8 +63,9 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
if (_jobType == 'one-day') {
return s.durationDays == null || s.durationDays! <= 1;
}
if (_jobType == 'multi-day')
if (_jobType == 'multi-day') {
return s.durationDays != null && s.durationDays! > 1;
}
return true;
}).toList();
@@ -176,21 +171,8 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
...filteredJobs.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Debug shiftId: ${shift.id}',
style: const TextStyle(
fontSize: 10,
color: Color(0xFF94A3B8),
),
),
const SizedBox(height: 4),
MyShiftCard(
shift: shift,
),
],
child: MyShiftCard(
shift: shift,
),
),
),

View File

@@ -13,7 +13,6 @@ import 'domain/usecases/get_shift_details_usecase.dart';
import 'presentation/blocs/shifts/shifts_bloc.dart';
import 'presentation/blocs/shift_details/shift_details_bloc.dart';
import 'presentation/pages/shifts_page.dart';
import 'presentation/pages/shift_details_page.dart';
class StaffShiftsModule extends Module {
@override

View File

@@ -1,4 +1,4 @@
library staff_shifts;
library;
export 'src/staff_shifts_module.dart';
export 'src/shift_details_module.dart';