Prohibited nav emblem, Assign to Myself, and obfuscated contact masking

Featurekamo-internal
Shipped
September 3, 2026 at 8:03 PM UTC
Author
Kamo
Commit
f774107

**The Leads nav icon says when you cannot accept.** A member who holds leads they have not worked gets a red block emblem over the Leads icon and a tooltip naming what is blocked, why, and what to clear. Fed by /leads/available-summary and kept live by a new accept-gate event on the credit/assignment socket — the payload carries only a member id, so each browser ignores everybody else's and re-asks the server for its own. Shown to any member who can see leads, not only credit holders: since a free-for-all lead can now be self-claimed, the gate governs them too. The availability dot stays credit-only, so the two statements remain separable — you can be blocked from accepting while leads sit there available, and those are different things to say. **Every status is named the way THIS org names it.** The tooltip, the /leads/available notice and the detail-page copy resolve New Lead / Farm Fresh through useStatusLabels: labels are replaceable on /settings/features/crm, and telling a member to move a lead off "New Lead" when their org calls it something else names a status they cannot find in the picker. **/leads/available's notice splits into its two reasons** — leads owed a note, leads owed a status change — because merged into one list they read as an undifferentiated pile and the member has to open each lead to learn what it wants. A lead failing both is listed once, badged. **Assign to Myself** sits under Hot Reassign on an unassigned lead. Offered on a free-for-all lead to anyone not currently barred, and on any unassigned lead to a holder of ASSIGN_LEADS. The response carries the lead back unmasked, so setting it into state flips assignedToMe, recomputes the mask decision to UNMASKED, and reveals the contact information with no reload. **The status control pulses** while the lead is mine and still at New Lead or Farm Fresh — that is the control that fixes it, and the header is read long before a nav tooltip. Honours prefers-reduced-motion. **Masked contact info is obfuscated, not blanked.** contactObfuscator.ts mirrors the server's ContactObfuscator exactly, asserting the same strings, because the realtime lead relay ships a full unmasked DTO to every subscriber in the org and the browser is the only thing standing in front of it there. A blank field reads as "this lead has no e-mail", which is a different and wrong statement. **The /leads Unassigned filter is offered to everyone.** Without VIEW_UNASSIGNED_LEADS it returns the unassigned free-for-all leads this member may claim, and the label says so rather than the option quietly meaning two different things. The client no longer forces assigned=ASSIGNED for those members — the server's floor is wider than that now, and sending ASSIGNED would clip exactly the rows this change exists to show.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing