feat(friends): always-visible Direct-Add row with resolved-form display

The Send-Friend-Request action row in the Add Friend tab previously
appeared only when the typed query contained a non-edge @, leaving
no way to fire a blind request for a bare local handle. Widen the
gate to allow non-empty bare handles, keep the malformed @ shapes
(@, @bob, bob@) hidden. When the typed query has no @, display the
resolved form <query>@<window.location.host> so the user sees which
instance the request will hit. Submission string is unchanged.

Updates FriendsPage.test.tsx: inverts the now-stale 'does not show
Direct Add row for plain usernames' test into the new positive
assertion, and adds a separate test for the malformed @ shapes.
This commit is contained in:
Jannis Braun
2026-04-25 19:32:03 +02:00
parent 781e293cf7
commit da98d78489
2 changed files with 36 additions and 5 deletions
@@ -462,9 +462,15 @@ function AddFriendTab({
});
}, [rawSearchResults, friends, requests, selfIds, isSearchMode]);
// Direct Add detection (synchronous, not debounced)
const atIndex = query.lastIndexOf('@');
const showDirectAdd = atIndex > 0 && atIndex < query.length - 1;
const trimmedQuery = query.trim();
const directAt = trimmedQuery.lastIndexOf('@');
const showDirectAdd = trimmedQuery.length > 0
&& (directAt === -1 || (directAt > 0 && directAt < trimmedQuery.length - 1));
// Bare handle gets the home host appended for display only — submission
// still uses the raw trimmed query.
const directAddDisplay = trimmedQuery.includes('@')
? trimmedQuery
: `${trimmedQuery}@${window.location.host}`;
// Direct Add handler
const handleDirectAdd = async () => {
@@ -552,7 +558,7 @@ function AddFriendTab({
<path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
</svg>
<div className="flex-1 min-w-0 text-sm text-txt-secondary">
Send friend request to <span className="font-semibold text-txt-primary">{query.trim()}</span>
Send friend request to <span className="font-semibold text-txt-primary">{directAddDisplay}</span>
</div>
<button
onClick={handleDirectAdd}