feat(healthchat): show default contacts while approval is pending

An unapproved account only gets the server's default contacts, which are
its way to reach support — list them instead of discarding them, and hide
the search field that cannot return anything.
This commit is contained in:
Sedat Qaja
2026-10-09 14:23:39 +02:00
parent 57570df8dd
commit 181c518dc7
8 changed files with 121 additions and 26 deletions
@@ -31,19 +31,46 @@ final class HealthChatMemberDirectoryScreenViewModelTests {
}
@Test
func showsPendingApprovalMessage() async throws {
apiService.membersSearchQueryReturnValue = .success(.init(users: [],
isApproved: false,
pendingMessage: "Ihr Konto wird geprüft"))
func showsPendingApprovalMessageWithTheDefaultContacts() async throws {
apiService.membersSearchQueryReturnValue = try .success(makeResponse(userIDs: ["@natascha.katumba:healthchat.ch"],
isApproved: false,
pendingMessage: "Ihr Konto wird geprüft"))
let viewModel = makeViewModel()
let deferred = deferFulfillment(viewModel.context.observe(\.viewState.content)) { content in
content == .pendingApproval(message: "Ihr Konto wird geprüft")
guard case .pendingApproval(let message, let members) = content else { return false }
return message == "Ihr Konto wird geprüft" && members.map(\.userID) == ["@natascha.katumba:healthchat.ch"]
}
try await deferred.fulfill()
}
@Test
func refreshPicksUpAnApprovalWithoutClearingTheList() async throws {
apiService.membersSearchQueryReturnValue = try .success(makeResponse(userIDs: ["@natascha.katumba:healthchat.ch"],
isApproved: false,
pendingMessage: "Ihr Konto wird geprüft"))
let viewModel = makeViewModel()
let deferredPending = deferFulfillment(viewModel.context.observe(\.viewState.content)) { content in
guard case .pendingApproval = content else { return false }
return true
}
try await deferredPending.fulfill()
apiService.membersSearchQueryReturnValue = try .success(makeResponse(userIDs: ["@alice:healthchat.ch"]))
let deferredMembers = deferFulfillment(viewModel.context.observe(\.viewState.content)) { content in
guard case .members(let members) = content else { return false }
return members.map(\.userID) == ["@alice:healthchat.ch"]
}
viewModel.context.send(viewAction: .refresh)
try await deferredMembers.fulfill()
#expect(viewModel.context.viewState.isApproved)
}
@Test
func showsFailureAndRecoversOnRetry() async throws {
apiService.membersSearchQueryReturnValue = .failure(.networkFailure)
@@ -160,10 +187,10 @@ final class HealthChatMemberDirectoryScreenViewModelTests {
}
@Test
func pendingApprovalDisablesInviting() async throws {
apiService.membersSearchQueryReturnValue = .success(.init(users: [],
isApproved: false,
pendingMessage: "Ihr Konto wird geprüft"))
func pendingApprovalDisablesSearchingAndInviting() async throws {
apiService.membersSearchQueryReturnValue = try .success(makeResponse(userIDs: [],
isApproved: false,
pendingMessage: "Ihr Konto wird geprüft"))
let viewModel = makeViewModel()
@@ -220,8 +247,10 @@ final class HealthChatMemberDirectoryScreenViewModelTests {
userIndicatorController: UserIndicatorControllerMock())
}
private func makeResponse(userIDs: [String]) throws -> HealthChatMembersResponse {
try .init(users: userIDs.map(makeMember(userID:)), isApproved: true, pendingMessage: nil)
private func makeResponse(userIDs: [String],
isApproved: Bool = true,
pendingMessage: String? = nil) throws -> HealthChatMembersResponse {
try .init(users: userIDs.map(makeMember(userID:)), isApproved: isApproved, pendingMessage: pendingMessage)
}
private func makeMember(userID: String) throws -> HealthChatMember {