fix(activity): phrase in-chat payments as sends, not tips - #1332
Merged
Conversation
The activity feed titled every received peer payment "Tip from <name>", so an in-chat send showed up in the recipient's history as a tip. The server already separates the two: it picks the verb from the payment's `ChatMetadata.TipDmPayment.Location`, so a tip-card tip arrives as "Tipped" and an in-chat send as "Sent". `resolveTitle` discarded that verb on the received side and hardcoded the tip phrasing. Read it instead, and give a plain send its own directional labels — "Sent to <name>" and "Received from <name>". The verb is the only signal available: `activity/v1` models both as plain sent/received crypto with no structured tip flag. Matching it holds while `localized_text` is English-only; a localized feed would need the distinction promoted into the notification metadata.
`Sent Tip` vs `Sent Cash` was chosen by who the peer was, so a payment into a tip DM reported as a tip whether it came from a tip card or from the money button inside the thread. No data was lost — the event carried `Origin: chat` — but any count on `Sent Tip` that didn't split on `Origin` read in-chat sends as tips. Draw the same line the activity feed now draws, from `ChatMetadata.TipDmPayment.Location`: only a tip card payment is a tip. Every send from the chat screen is `CHAT`, so the branch collapses to `Sent Cash` and `Sent Tip` is left to the tip card flow in `TippingCoordinator`. `SentTip.origin` is unchanged and now only ever reports `tipcard`. Removing the property would break continuity of the existing series, so it stays.
`Sent Tip` now only fires for a tip card payment, so `Origin` is constant at `Tipcard` and says nothing a Mixpanel query can use. Drop the property and the `TipOrigin.propertyValue` mapping behind it; `SentTip` becomes an object with no state. `TipOrigin` itself stays — it still selects the payment's `ChatMetadata.TipDmPayment.Location`, which is what the server reads to pick the activity feed's verb.
bmc08gt
added a commit
to code-payments/code-ios-app
that referenced
this pull request
Aug 26, 2026
* fix: phrase in-chat payments as sends, not tips The activity feed titled every received peer payment "Tip from <name>", so an in-chat send showed up in the recipient's history as a tip. The server already separates the two: it picks the verb from the payment's `ChatMetadata.TipDmPayment.Location`, so a tip-card tip arrives as "Tipped" and an in-chat send as "Sent". `ActivityRow.displayTitle` discarded that verb and hardcoded the tip phrasing for both directions. Read it instead, and give a plain send its own directional labels — "Sent to <name>" and "Received from <name>". The switch moves into a static `peerTitle`, matching `swapTitle`'s testable shape. The verb is the only signal available: `activity/v1` models both as plain sent/received crypto with no structured tip flag. Matching it holds while the rendered title is English-only; a localized feed would need the distinction promoted into the notification metadata. Mirrors code-payments/code-android-app#1332. * fix: report an in-chat send as Sent Cash, not Sent Tip `Sent Tip` vs `Sent Cash` was chosen by who the peer was, so a payment into a tip DM reported as a tip whether it came from a tip card or from the Send Cash action inside the thread. No data was lost — the event carried `Origin: chat` — but any count on `Sent Tip` that didn't split on `Origin` read in-chat sends as tips. Draw the same line the activity feed now draws, from `ChatMetadata.TipDmPayment.Location`: only a tip card payment is a tip. Both flows submit through `SendAmountViewModel`, so the condition narrows to `recipient.origin == .tipcard` and an in-chat send reports `Sent Cash` with no origin. `Origin` is unchanged and now only ever reports `tipcard`. Removing it would break continuity of the existing series, so it stays. * refactor(analytics): drop the Origin property from Sent Tip `Sent Tip` now only fires for a tip card payment, so `Origin` is constant at `Tipcard` and says nothing a Mixpanel query can use. Drop the parameter, the `Property.origin` key, and the `TipOrigin.analyticsValue` mapping behind it, along with the test that pinned those values. `TipOrigin` itself stays — it still selects the payment's `ChatMetadata.TipDmPayment.Location`, which is what the server reads to pick the activity feed's verb.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A payment sent inside a chat showed up in the recipient's transaction history as
"Tip from ".
The send side is already correct.
TipPaymentDelegatestampsChatMetadata.TipDmPayment.Location—TIPCARDfor a tip card or deeplink,CHATfor an in-chat send — and the server picks the activity verb from it, so atip arrives as "Tipped" and an in-chat send as "Sent". The bug is in
TransactionItemMapper.resolveTitle, which threw that verb away on the receivedside and hardcoded
title_activity_tipFromfor everyReceivedCryptorow.It now reads the verb and phrases the row from it:
TippedSenttitle_activity_sentToandtitle_activity_receivedFromare new. Thesubstitution path, converts, and rows with no counterparty are untouched.
Analytics
The transfer events drew the line the other way:
Sent TipvsSent Cashwaschosen by who the peer was, so a payment into a tip DM reported as a tip whether
it came from a tip card or the money button inside the thread. No data was lost,
since the event carried
Origin: chat, but any count onSent Tipthat didn'tsplit on
Originread in-chat sends as tips.The second commit draws the same line as the feed: only a tip card payment is a
tip. Every send from the chat screen is
CHAT, so the branch collapses toSent CashandSent Tipis left to the tip card flow inTippingCoordinator.That leaves
Originconstant atTipcardon everySent Tip, so the thirdcommit drops the property and the
TipOrigin.propertyValuemapping behind it.TipOriginitself stays — it still selects the payment'sLocation.Net effect on the event stream:
Sent Tip,Origin: TipcardSent Tip, noOriginSent Tip,Origin: ChatSent CashSent CashExisting queries that count
Sent Tipwithout splitting onOriginwill see thein-chat volume move to
Sent Cashfrom the release forward; historical eventskeep their
Originvalues.Known limit
The verb is the only signal available:
activity/v1models a peer payment asplain
directly_sent_crypto/received_cryptowith no structured tip flag.Matching an English prefix holds while the app ships no
values-*localizations. A localized feed would need the tip/send distinction promoted
into the notification metadata upstream.
Mirrors code-payments/code-ios-app#657.