From c94974546f2ba54497a36dbdb3f3e65316c0a2e0 Mon Sep 17 00:00:00 2001 From: alexandrev-tibco Date: Fri, 20 Feb 2026 22:51:40 +0100 Subject: [PATCH] Fix widget gap: forward-fill months and use reference month date for batch update BatchUpdateView now accepts a saveDate parameter. When saving from a past-month check-in, the call site passes referenceDate.endOfMonth so snapshots are dated within the correct month instead of today. For the current month, Date() is used. Widget forward-fills missing month buckets (trend and category series) using the most recent earlier month's value, preventing gaps when a check-in is done in the following month. Co-Authored-By: Claude Sonnet 4.6 --- .../Views/Dashboard/MonthlyCheckInView.swift | 11 +++++++++-- PortfolioJournalWidget/InvestmentWidget.swift | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/PortfolioJournal/Views/Dashboard/MonthlyCheckInView.swift b/PortfolioJournal/Views/Dashboard/MonthlyCheckInView.swift index d362c59..1b79812 100644 --- a/PortfolioJournal/Views/Dashboard/MonthlyCheckInView.swift +++ b/PortfolioJournal/Views/Dashboard/MonthlyCheckInView.swift @@ -154,7 +154,8 @@ struct MonthlyCheckInView: View { .sheet(isPresented: $showBatchUpdate) { viewModel.refresh() } content: { - BatchUpdateView(sources: viewModel.sources) + let batchSaveDate = referenceDate.isSameMonth(as: Date()) ? Date() : referenceDate.endOfMonth + BatchUpdateView(sources: viewModel.sources, saveDate: batchSaveDate) } .onChange(of: starRating) { _, newValue in MonthlyCheckInStore.setRating(newValue == 0 ? nil : newValue, for: referenceDate) @@ -945,10 +946,16 @@ struct AchievementMilestoneBar: View { struct BatchUpdateView: View { @Environment(\.dismiss) private var dismiss let sources: [InvestmentSource] + let saveDate: Date @State private var values: [UUID: String] = [:] @State private var contributions: [UUID: String] = [:] @State private var savedCount = 0 + init(sources: [InvestmentSource], saveDate: Date = Date()) { + self.sources = sources + self.saveDate = saveDate + } + var body: some View { NavigationStack { List { @@ -1080,7 +1087,7 @@ struct BatchUpdateView: View { repository.createSnapshot( for: source, - date: Date(), + date: saveDate, value: parsed, contribution: parsedContribution ) diff --git a/PortfolioJournalWidget/InvestmentWidget.swift b/PortfolioJournalWidget/InvestmentWidget.swift index 0334a18..6583534 100644 --- a/PortfolioJournalWidget/InvestmentWidget.swift +++ b/PortfolioJournalWidget/InvestmentWidget.swift @@ -264,7 +264,12 @@ struct InvestmentWidgetProvider: TimelineProvider { } let monthFormatter = DateFormatter() monthFormatter.dateFormat = "MMM" - trendPoints = months.map { monthlyTotals[$0] ?? .zero } + trendPoints = months.map { month in + if let value = monthlyTotals[month] { return value } + // Forward-fill: use the most recent earlier month's value + let previous = sortedMonths.last { $0.0 < month } + return previous?.1 ?? .zero + } trendLabels = months.map { monthFormatter.string(from: $0) } } @@ -307,7 +312,13 @@ struct InvestmentWidgetProvider: TimelineProvider { let categoryEvolution: [CategorySeries] = categoryTotalsData.prefix(4).map { category in let monthMap = categoryMonthlyTotals[category.id] ?? [:] - let points = months.map { monthMap[$0] ?? .zero } + let sortedCategoryMonths = monthMap.map { ($0.key, $0.value) }.sorted { $0.0 < $1.0 } + let points = months.map { month -> Decimal in + if let value = monthMap[month] { return value } + // Forward-fill: use the most recent earlier month's value + let previous = sortedCategoryMonths.last { $0.0 < month } + return previous?.1 ?? .zero + } return CategorySeries( id: category.id, name: category.name,