Skip to main content

useUserLookup

Location: src/hooks/useUserLookup.js

Overview

Provides exact username lookup functionality. Searches for a single user by their exact username (no partial matching, no discovery). The lookup is performed via the lookup_user_by_username Supabase RPC function and includes rate limit detection.

Use this hook in friend-search or user-search UI components where exact username matching is required.

Signature

function useUserLookup(): {
lookup: (username: string) => Promise<object | null>,
isLoading: boolean,
error: string | null,
rateLimitError: boolean,
result: object | null,
reset: () => void
}

Parameters

This hook takes no parameters.

Return Value

PropertyTypeDescription
lookup(username: string) => Promise<object | null>Performs exact username lookup. Normalizes input to lowercase and validates format (a-z0-9_, 3-30 chars). Returns the user object or null.
isLoadingbooleanWhether a lookup is currently in progress
errorstring | nullError message if the lookup failed
rateLimitErrorbooleanWhether the lookup was rejected due to rate limiting
resultobject | nullThe most recent lookup result (user object or null)
reset() => voidClears result, error, and rate limit error state

Usage

import { useUserLookup } from '../hooks/useUserLookup';

function UserSearch() {
const { lookup, isLoading, error, rateLimitError, result, reset } = useUserLookup();
const [username, setUsername] = useState('');

const handleSearch = async () => {
const user = await lookup(username);
if (user) {
console.log('Found user:', user.display_name);
}
};

return (
<div>
<input
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter exact username"
/>
<button onClick={handleSearch} disabled={isLoading}>
Search
</button>
{rateLimitError && <p>Too many searches. Please wait an hour.</p>}
{error && <p>{error}</p>}
{result && <UserCard user={result} />}
</div>
);
}

Notes

  • Usernames are validated against the regex /^[a-z0-9_]{3,30}$/ before any database call.
  • If rate limited by the server, the hook sets rateLimitError to true and provides a user-friendly error message.
  • No partial matching or discovery is supported -- this is intentional for privacy (Invariant #14).

Last updated: 2026-02-07