feat: architecture overhaul, launchpad-style reports, and uber-style locations

- Strengthened Buffer Layer architecture to decouple Data Connect from Domain
- Rewired Coverage, Performance, and Forecast reports to match Launchpad logic
- Implemented Uber-style Preferred Locations search using Google Places API
- Added session recovery logic to prevent crashes on app restart
- Synchronized backend schemas & SDK for ShiftStatus enums
- Fixed various build/compilation errors and localization duplicates
This commit is contained in:
2026-02-20 17:20:06 +05:30
parent e6c4b51e84
commit 8849bf2273
60 changed files with 3804 additions and 2397 deletions

View File

@@ -0,0 +1,8 @@
/// Defines the period for billing calculations.
enum BillingPeriod {
/// Weekly billing period.
week,
/// Monthly billing period.
month,
}

View File

@@ -0,0 +1,35 @@
import 'package:equatable/equatable.dart';
class CoverageReport extends Equatable {
final double overallCoverage;
final int totalNeeded;
final int totalFilled;
final List<CoverageDay> dailyCoverage;
const CoverageReport({
required this.overallCoverage,
required this.totalNeeded,
required this.totalFilled,
required this.dailyCoverage,
});
@override
List<Object?> get props => [overallCoverage, totalNeeded, totalFilled, dailyCoverage];
}
class CoverageDay extends Equatable {
final DateTime date;
final int needed;
final int filled;
final double percentage;
const CoverageDay({
required this.date,
required this.needed,
required this.filled,
required this.percentage,
});
@override
List<Object?> get props => [date, needed, filled, percentage];
}

View File

@@ -0,0 +1,63 @@
import 'package:equatable/equatable.dart';
class DailyOpsReport extends Equatable {
final int scheduledShifts;
final int workersConfirmed;
final int inProgressShifts;
final int completedShifts;
final List<DailyOpsShift> shifts;
const DailyOpsReport({
required this.scheduledShifts,
required this.workersConfirmed,
required this.inProgressShifts,
required this.completedShifts,
required this.shifts,
});
@override
List<Object?> get props => [
scheduledShifts,
workersConfirmed,
inProgressShifts,
completedShifts,
shifts,
];
}
class DailyOpsShift extends Equatable {
final String id;
final String title;
final String location;
final DateTime startTime;
final DateTime endTime;
final int workersNeeded;
final int filled;
final String status;
final double? hourlyRate;
const DailyOpsShift({
required this.id,
required this.title,
required this.location,
required this.startTime,
required this.endTime,
required this.workersNeeded,
required this.filled,
required this.status,
this.hourlyRate,
});
@override
List<Object?> get props => [
id,
title,
location,
startTime,
endTime,
workersNeeded,
filled,
status,
hourlyRate,
];
}

View File

@@ -0,0 +1,77 @@
import 'package:equatable/equatable.dart';
class ForecastReport extends Equatable {
final double projectedSpend;
final int projectedWorkers;
final double averageLaborCost;
final List<ForecastPoint> chartData;
// New fields for the updated design
final int totalShifts;
final double totalHours;
final double avgWeeklySpend;
final List<ForecastWeek> weeklyBreakdown;
const ForecastReport({
required this.projectedSpend,
required this.projectedWorkers,
required this.averageLaborCost,
required this.chartData,
this.totalShifts = 0,
this.totalHours = 0.0,
this.avgWeeklySpend = 0.0,
this.weeklyBreakdown = const [],
});
@override
List<Object?> get props => [
projectedSpend,
projectedWorkers,
averageLaborCost,
chartData,
totalShifts,
totalHours,
avgWeeklySpend,
weeklyBreakdown,
];
}
class ForecastPoint extends Equatable {
final DateTime date;
final double projectedCost;
final int workersNeeded;
const ForecastPoint({
required this.date,
required this.projectedCost,
required this.workersNeeded,
});
@override
List<Object?> get props => [date, projectedCost, workersNeeded];
}
class ForecastWeek extends Equatable {
final int weekNumber;
final double totalCost;
final int shiftsCount;
final double hoursCount;
final double avgCostPerShift;
const ForecastWeek({
required this.weekNumber,
required this.totalCost,
required this.shiftsCount,
required this.hoursCount,
required this.avgCostPerShift,
});
@override
List<Object?> get props => [
weekNumber,
totalCost,
shiftsCount,
hoursCount,
avgCostPerShift,
];
}

View File

@@ -0,0 +1,33 @@
import 'package:equatable/equatable.dart';
class NoShowReport extends Equatable {
final int totalNoShows;
final double noShowRate;
final List<NoShowWorker> flaggedWorkers;
const NoShowReport({
required this.totalNoShows,
required this.noShowRate,
required this.flaggedWorkers,
});
@override
List<Object?> get props => [totalNoShows, noShowRate, flaggedWorkers];
}
class NoShowWorker extends Equatable {
final String id;
final String fullName;
final int noShowCount;
final double reliabilityScore;
const NoShowWorker({
required this.id,
required this.fullName,
required this.noShowCount,
required this.reliabilityScore,
});
@override
List<Object?> get props => [id, fullName, noShowCount, reliabilityScore];
}

View File

@@ -0,0 +1,35 @@
import 'package:equatable/equatable.dart';
class PerformanceReport extends Equatable {
final double fillRate;
final double completionRate;
final double onTimeRate;
final double avgFillTimeHours; // in hours
final List<PerformanceMetric> keyPerformanceIndicators;
const PerformanceReport({
required this.fillRate,
required this.completionRate,
required this.onTimeRate,
required this.avgFillTimeHours,
required this.keyPerformanceIndicators,
});
@override
List<Object?> get props => [fillRate, completionRate, onTimeRate, avgFillTimeHours, keyPerformanceIndicators];
}
class PerformanceMetric extends Equatable {
final String label;
final String value;
final double trend; // e.g. 0.05 for +5%
const PerformanceMetric({
required this.label,
required this.value,
required this.trend,
});
@override
List<Object?> get props => [label, value, trend];
}

View File

@@ -0,0 +1,29 @@
import 'package:equatable/equatable.dart';
class ReportsSummary extends Equatable {
final double totalHours;
final double otHours;
final double totalSpend;
final double fillRate;
final double avgFillTimeHours;
final double noShowRate;
const ReportsSummary({
required this.totalHours,
required this.otHours,
required this.totalSpend,
required this.fillRate,
required this.avgFillTimeHours,
required this.noShowRate,
});
@override
List<Object?> get props => [
totalHours,
otHours,
totalSpend,
fillRate,
avgFillTimeHours,
noShowRate,
];
}

View File

@@ -0,0 +1,83 @@
import 'package:equatable/equatable.dart';
class SpendReport extends Equatable {
final double totalSpend;
final double averageCost;
final int paidInvoices;
final int pendingInvoices;
final int overdueInvoices;
final List<SpendInvoice> invoices;
final List<SpendChartPoint> chartData;
final List<SpendIndustryCategory> industryBreakdown;
const SpendReport({
required this.totalSpend,
required this.averageCost,
required this.paidInvoices,
required this.pendingInvoices,
required this.overdueInvoices,
required this.invoices,
required this.chartData,
required this.industryBreakdown,
});
@override
List<Object?> get props => [
totalSpend,
averageCost,
paidInvoices,
pendingInvoices,
overdueInvoices,
invoices,
chartData,
industryBreakdown,
];
}
class SpendIndustryCategory extends Equatable {
final String name;
final double amount;
final double percentage;
const SpendIndustryCategory({
required this.name,
required this.amount,
required this.percentage,
});
@override
List<Object?> get props => [name, amount, percentage];
}
class SpendInvoice extends Equatable {
final String id;
final String invoiceNumber;
final DateTime issueDate;
final double amount;
final String status;
final String vendorName;
final String? industry;
const SpendInvoice({
required this.id,
required this.invoiceNumber,
required this.issueDate,
required this.amount,
required this.status,
required this.vendorName,
this.industry,
});
@override
List<Object?> get props => [id, invoiceNumber, issueDate, amount, status, vendorName, industry];
}
class SpendChartPoint extends Equatable {
final DateTime date;
final double amount;
const SpendChartPoint({required this.date, required this.amount});
@override
List<Object?> get props => [date, amount];
}