Unify task stats calculation and update UI labels

- Create shared TaskStatsCalculator for consistent date bucket logic
- Fix widget stats to use exclusive buckets (overdue | 7 days | 30 days)
- Update labels: "This Week" → "Next 7 Days" / "7 Days"
- Large widget now shows Overdue, 7 Days, 30 Days (removed Total)
- Rename "Pros" tab to "Contractors"
- Remove red pulsing ring from residence card icons

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-17 12:07:35 -06:00
parent bcd8b36a9b
commit 44c7b23cc2
6 changed files with 139 additions and 117 deletions

View File

@@ -204,78 +204,32 @@ private struct ResidencesContent: View {
return tasks
}
/// Compute total summary from task data using date logic
/// Compute total summary from task data using shared TaskStatsCalculator
private var computedSummary: TotalSummary {
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
let in7Days = calendar.date(byAdding: .day, value: 7, to: today) ?? today
let in30Days = calendar.date(byAdding: .day, value: 30, to: today) ?? today
var overdueCount: Int32 = 0
var dueThisWeekCount: Int32 = 0
var dueNext30DaysCount: Int32 = 0
for task in activeTasks {
guard let dueDateStr = task.effectiveDueDate,
let dueDate = DateUtils.parseDate(dueDateStr) else {
continue
}
let taskDate = calendar.startOfDay(for: dueDate)
if taskDate < today {
overdueCount += 1
} else if taskDate <= in7Days {
dueThisWeekCount += 1
} else if taskDate <= in30Days {
dueNext30DaysCount += 1
}
}
let dueDates = activeTasks.map { $0.effectiveDueDate }
let stats = TaskStatsCalculator.calculate(from: dueDates)
return TotalSummary(
totalResidences: Int32(residences.count),
totalTasks: Int32(activeTasks.count),
totalPending: 0,
totalOverdue: overdueCount,
tasksDueNextWeek: dueThisWeekCount,
tasksDueNextMonth: dueNext30DaysCount
totalOverdue: Int32(stats.overdueCount),
tasksDueNextWeek: Int32(stats.next7DaysCount),
tasksDueNextMonth: Int32(stats.next30DaysCount)
)
}
/// Get task stats for a specific residence
/// Get task stats for a specific residence using shared TaskStatsCalculator
private func taskStats(for residenceId: Int32) -> ResidenceTaskStats {
let residenceTasks = activeTasks.filter { $0.residenceId == residenceId }
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
let in7Days = calendar.date(byAdding: .day, value: 7, to: today) ?? today
let in30Days = calendar.date(byAdding: .day, value: 30, to: today) ?? today
var overdueCount = 0
var dueThisWeekCount = 0
var dueNext30DaysCount = 0
for task in residenceTasks {
guard let dueDateStr = task.effectiveDueDate,
let dueDate = DateUtils.parseDate(dueDateStr) else {
continue
}
let taskDate = calendar.startOfDay(for: dueDate)
if taskDate < today {
overdueCount += 1
} else if taskDate <= in7Days {
dueThisWeekCount += 1
} else if taskDate <= in30Days {
dueNext30DaysCount += 1
}
}
let dueDates = residenceTasks.map { $0.effectiveDueDate }
let stats = TaskStatsCalculator.calculate(from: dueDates)
return ResidenceTaskStats(
totalCount: residenceTasks.count,
overdueCount: overdueCount,
dueThisWeekCount: dueThisWeekCount,
dueNext30DaysCount: dueNext30DaysCount
overdueCount: stats.overdueCount,
dueThisWeekCount: stats.next7DaysCount,
dueNext30DaysCount: stats.next30DaysCount
)
}