Skip to content

Commit 4e3e405

Browse files
yewreekaclaude
andcommitted
Run welcome-outcome state writes even when the pairing banner wins
A welcome push that carries both a pairing join request and a join result / new group used to return the pairing notification before the other cases' state writes ran; a later push would no longer see either event as new, losing them entirely. The join-result / new-group handling is factored into welcomeOutcomeNotification and always runs; only the banner is superseded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f839d0a commit 4e3e405

1 file changed

Lines changed: 44 additions & 6 deletions

File tree

ConvosCore/Sources/ConvosCore/Inboxes/MessagingService+PushNotifications.swift

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,18 +151,56 @@ extension MessagingService {
151151
)
152152

153153
if let pairingRequest {
154-
// Only let a genuinely surfaced pairing request short-circuit.
155-
// The scan spans all recent DMs, not just this push's topic, so
156-
// a deduped duplicate (.droppedMessage) might belong to an
157-
// earlier push - returning it here would suppress a join-result
158-
// or new-group notification this same push legitimately carries.
159-
// On a duplicate, fall through to those checks instead.
154+
// Only let a genuinely surfaced pairing request take the
155+
// banner. The scan spans all recent DMs, not just this push's
156+
// topic, so a deduped duplicate (.droppedMessage) might belong
157+
// to an earlier push - returning it here would suppress a
158+
// join-result or new-group notification this same push
159+
// legitimately carries. On a duplicate, fall through instead.
160160
let notification = pairingRequestNotification(pairingRequest, userInfo: userInfo)
161161
if !notification.isDroppedMessage {
162+
// The join-result / new-group handling still must run to
163+
// completion: its state writes (setLastWelcomeProcessed,
164+
// the GRDB bridge for a new group) can't be deferred to a
165+
// later push, which would no longer see either event as
166+
// new. Only the banner is superseded. A failure in that
167+
// pass shouldn't cost the pairing banner, hence the catch.
168+
do {
169+
_ = try await welcomeOutcomeNotification(
170+
joinRequestOutcomes: joinRequestOutcomes,
171+
existingGroupIds: existingGroupIds,
172+
processTime: processTime,
173+
client: client,
174+
userInfo: userInfo
175+
)
176+
} catch {
177+
Log.error("Welcome outcome handling failed after pairing detection: \(error.localizedDescription)")
178+
}
162179
return notification
163180
}
164181
}
165182

183+
return try await welcomeOutcomeNotification(
184+
joinRequestOutcomes: joinRequestOutcomes,
185+
existingGroupIds: existingGroupIds,
186+
processTime: processTime,
187+
client: client,
188+
userInfo: userInfo
189+
)
190+
}
191+
192+
/// The join-result ("accepted your invite") or new-group ("invite was
193+
/// verified") notification for this welcome push, running the state
194+
/// writes that go with each. Factored out of `handleWelcomeMessage` so
195+
/// the pairing-request path can run it for its side effects while
196+
/// keeping the pairing banner.
197+
private func welcomeOutcomeNotification(
198+
joinRequestOutcomes: [InviteJoinRequestOutcome],
199+
existingGroupIds: Set<String>,
200+
processTime: Date,
201+
client: any XMTPClientProvider,
202+
userInfo: [AnyHashable: Any]
203+
) async throws -> DecodedNotificationContent? {
166204
if let result = joinRequestOutcomes.compactMap(\.result).first {
167205
setLastWelcomeProcessed(processTime, for: client.inboxId)
168206

0 commit comments

Comments
 (0)