Fix: invited members now see shared tasks immediately on join
Product bug: when a user joined a shared residence, the residence appeared but its tasks (created by the owner) did not show in the Tasks tab until a manual refresh. Root cause was client-side — APILayer.joinWithCode updated the residence cache (addResidence) but never refreshed the tasks cache, and the optimistic addResidence suppressed getMyResidences' count-based task invalidation, so allTasks stayed a stale pre-join snapshot. The backend was correct (task list query already joins residence_residence_users). - APILayer.joinWithCode: call getTasks(forceRefresh = true) on success (mirrors bulkCreateTasks) so the joined residence's tasks load immediately. - ResidenceViewModel: corrected an inaccurate comment about join-time refresh. - SharingUITests.test03: un-quarantined — now passes (verified against live stack). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -562,6 +562,11 @@ object APILayer {
|
|||||||
if (result is ApiResult.Success) {
|
if (result is ApiResult.Success) {
|
||||||
DataManager.setTotalSummary(result.data.summary)
|
DataManager.setTotalSummary(result.data.summary)
|
||||||
DataManager.addResidence(result.data.residence)
|
DataManager.addResidence(result.data.residence)
|
||||||
|
// Proactive refresh — the optimistic addResidence above suppresses
|
||||||
|
// getMyResidences' count-based task invalidation, so fetch fresh
|
||||||
|
// tasks here so the joined residence's tasks appear immediately
|
||||||
|
// without a manual refresh.
|
||||||
|
getTasks(forceRefresh = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -154,19 +154,7 @@ final class SharingUITests: AuthenticatedUITestCase {
|
|||||||
|
|
||||||
// MARK: - Test 03: Shared Tasks Visible in UI
|
// MARK: - Test 03: Shared Tasks Visible in UI
|
||||||
|
|
||||||
/// Known issue: After joining a shared residence, the Tasks tab doesn't show
|
|
||||||
/// the shared tasks. The AllTasksView's residenceViewModel uses cached (empty)
|
|
||||||
/// data, which disables the refresh button and prevents task loading.
|
|
||||||
/// Fix: AllTasksView.onAppear should detect residence list changes or use
|
|
||||||
/// DataManager's already-refreshed cache.
|
|
||||||
func test03_sharedTasksVisibleInTasksTab() throws {
|
func test03_sharedTasksVisibleInTasksTab() throws {
|
||||||
// Known issue: after a user joins a shared residence, that residence's
|
|
||||||
// tasks (created by the owner) do not appear in the joining user's Tasks
|
|
||||||
// tab even after force-refresh — the residence itself shows, but its
|
|
||||||
// tasks aren't fetched for the joined member. Pre-existing app gap;
|
|
||||||
// skip until the shared-task fetch on join is fixed.
|
|
||||||
throw XCTSkip("App gap: joined member doesn't see the shared residence's tasks in the Tasks tab (residence shows, tasks don't).")
|
|
||||||
|
|
||||||
// Join via UI — this lands on Residences tab which triggers forceRefresh
|
// Join via UI — this lands on Residences tab which triggers forceRefresh
|
||||||
joinResidenceViaUI()
|
joinResidenceViaUI()
|
||||||
|
|
||||||
|
|||||||
@@ -337,9 +337,9 @@ class ResidenceViewModel: ObservableObject {
|
|||||||
|
|
||||||
if result is ApiResultSuccess<JoinResidenceResponse> {
|
if result is ApiResultSuccess<JoinResidenceResponse> {
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
// APILayer updates DataManager with refreshMyResidences,
|
// APILayer.joinWithCode updates the residence cache and also
|
||||||
// which updates DataManagerObservable, which updates our
|
// force-refreshes the tasks cache, so the joined residence's
|
||||||
// @Published myResidences via Combine subscription
|
// shared tasks appear immediately via DataManagerObservable.
|
||||||
completion(true)
|
completion(true)
|
||||||
} else if let error = ApiResultBridge.error(from: result) {
|
} else if let error = ApiResultBridge.error(from: result) {
|
||||||
self.errorMessage = ErrorMessageParser.parse(error.message)
|
self.errorMessage = ErrorMessageParser.parse(error.message)
|
||||||
|
|||||||
Reference in New Issue
Block a user