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:
@@ -254,7 +254,7 @@ describe('FriendsPage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('does not show Direct Add row for plain usernames', async () => {
|
||||
it('shows Direct Add row with resolved-form display for plain usernames', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderFriendsPage();
|
||||
await user.click(screen.getByText('Add Friend'));
|
||||
@@ -262,6 +262,31 @@ describe('FriendsPage', () => {
|
||||
const input = screen.getByPlaceholderText(/Search or add by username/);
|
||||
await user.type(input, 'marc');
|
||||
|
||||
// Direct Add row appears with the resolved form `marc@<window.location.host>`.
|
||||
// The exact host depends on jsdom (localhost:3000 by default), so match by prefix.
|
||||
expect(screen.getByText(/Send friend request to/)).toBeInTheDocument();
|
||||
expect(screen.getByText(new RegExp(`marc@${window.location.host.replace(/[.+?^${}()|[\]\\]/g, '\\$&')}`))).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show Direct Add row for malformed @ shapes', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderFriendsPage();
|
||||
await user.click(screen.getByText('Add Friend'));
|
||||
|
||||
const input = screen.getByPlaceholderText(/Search or add by username/);
|
||||
|
||||
// Lone @
|
||||
await user.type(input, '@');
|
||||
expect(screen.queryByText(/Send friend request to/)).not.toBeInTheDocument();
|
||||
await user.clear(input);
|
||||
|
||||
// Leading @ — only domain, no baseName
|
||||
await user.type(input, '@bob');
|
||||
expect(screen.queryByText(/Send friend request to/)).not.toBeInTheDocument();
|
||||
await user.clear(input);
|
||||
|
||||
// Trailing @ — only baseName, no domain
|
||||
await user.type(input, 'bob@');
|
||||
expect(screen.queryByText(/Send friend request to/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user