Skip to content

fix: phrase in-chat payments as sends, not tips - #657

Merged
bmc08gt merged 3 commits into
mainfrom
fix/activity-row-send-labels
Aug 26, 2026
Merged

fix: phrase in-chat payments as sends, not tips#657
bmc08gt merged 3 commits into
mainfrom
fix/activity-row-send-labels

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

A payment sent inside a chat showed up in the recipient's activity history as
"Tip from ".

The send side is already correct. The payment stamps
ChatMetadata.TipDmPayment.LocationTIPCARD for a tip card or deeplink,
CHAT for an in-chat send — and the server picks the activity verb from it, so a
tip arrives as "Tipped" and an in-chat send as "Sent". ActivityRow.displayTitle
discarded that verb and hardcoded the tip phrasing for both .gave and
.received.

It now reads the verb and phrases the row from it:

server verb .gave .received
Tipped Tipped Sally Tip from Sally
Sent Sent to Sally Received from Sally

The switch moves out of displayTitle into a static peerTitle(kind:name:serverTitle:),
matching swapTitle's testable shape, and returns nil for a non-peer row or an
unresolved counterparty so the caller keeps its existing fallback to the
server-rendered title. Swaps and every other row are untouched.

activity.title arrives already substitution-rendered on iOS, so it can read
"Tipped Bob" rather than a bare verb; the prefix match covers both, and there's
a test for it.

Analytics

The transfer events drew the line the other way: Sent Tip vs Sent Cash was
chosen by whether the target was a tip recipient, 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
on Sent Tip that didn't split on Origin read in-chat sends as tips.

The second commit draws the same line as the feed: only a .tipcard origin is a
tip, so a send from inside a tip thread reports Sent Cash.

That leaves Origin constant at Tipcard on every Sent Tip, so the third
commit drops the parameter, the Property.origin key, and the
TipOrigin.analyticsValue mapping behind it. TipOrigin itself stays — it still
selects the payment's Location.

Net effect on the event stream:

payment before after
tip card / deeplink Sent Tip, Origin: Tipcard Sent Tip, no Origin
in-chat send to a tip peer Sent Tip, Origin: Chat Sent Cash
in-chat send to a contact Sent Cash unchanged

Existing queries that count Sent Tip without splitting on Origin will see the
in-chat volume move to Sent Cash from the release forward; historical events
keep their Origin values.

Known limit

The verb is the only signal available: activity/v1 models a peer payment as
plain directly_sent_crypto / received_crypto with no structured tip flag.
Matching an English prefix holds while the rendered title is English-only. A
localized feed would need the tip/send distinction promoted into the
notification metadata upstream.

Mirrors code-payments/code-android-app#1332.

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.
`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.
`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.
@bmc08gt
bmc08gt merged commit bec251e into main Aug 26, 2026
@bmc08gt
bmc08gt deleted the fix/activity-row-send-labels branch August 26, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant