Skip to main content

useFriendship

Location: src/hooks/useFriendship.js

Overview

Manages the complete friendship lifecycle between the current user and another user. Handles sending, canceling, accepting, declining friend requests, and removing existing friends. Integrates rate limiting for friend request spam prevention. Automatically reactivates canceled requests instead of creating duplicates.

Signature

function useFriendship(
otherUserId: string
): {
// State
loading: boolean,
error: string | null,
rateLimitError: string | null,
friendship: Friendship | null,
friendshipStatus: string | null,
isRequester: boolean,
isAddressee: boolean,
// Derived booleans
isFriend: boolean,
isPendingSent: boolean,
isPendingReceived: boolean,
hasNoRelationship: boolean,
// Actions
sendRequest: () => Promise<Result>,
cancelRequest: () => Promise<Result>,
acceptRequest: () => Promise<Result>,
declineRequest: () => Promise<Result>,
removeFriend: () => Promise<Result>,
refetch: () => Promise<void>,
clearError: () => void
}

Parameters

ParameterTypeRequiredDescription
otherUserIdstringYesThe ID of the other user to manage friendship with

Return Value

State

PropertyTypeDescription
loadingbooleanWhether a friendship operation is in progress
errorstring | nullError message from the last failed operation
rateLimitErrorstring | nullRate limit error message (from useRateLimit)
friendshipobject | nullThe raw friendship record from the database
friendshipStatusstring | nullThe friendship status: 'pending', 'accepted', 'declined', 'canceled', or null
isRequesterbooleanWhether the current user sent the request
isAddresseebooleanWhether the current user received the request

Derived Booleans

PropertyTypeDescription
isFriendbooleantrue if friendship status is 'accepted'
isPendingSentbooleantrue if status is 'pending' and current user is the requester
isPendingReceivedbooleantrue if status is 'pending' and current user is the addressee
hasNoRelationshipbooleantrue if no friendship record exists

Actions

PropertyTypeDescription
sendRequest() => Promise<Result>Send a friend request. Rate-limited. Returns { success: true } or { error, rateLimited? }. Reactivates canceled requests automatically.
cancelRequest() => Promise<Result>Cancel a pending request (requester only). Sets status to 'canceled'.
acceptRequest() => Promise<Result>Accept a pending request (addressee only). Sets status to 'accepted'.
declineRequest() => Promise<Result>Decline a pending request (addressee only). Sets status to 'declined'.
removeFriend() => Promise<Result>Remove an accepted friendship (either user). Deletes the record.
refetch() => Promise<void>Re-fetch the friendship state from the database
clearError() => voidClear error and rate limit error states

Usage

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

function FriendButton({ userId }) {
const {
loading,
isFriend,
isPendingSent,
isPendingReceived,
hasNoRelationship,
sendRequest,
cancelRequest,
acceptRequest,
removeFriend
} = useFriendship(userId);

if (loading) return <span>Loading...</span>;

if (isFriend) {
return <button onClick={removeFriend}>Remove Friend</button>;
}
if (isPendingSent) {
return <button onClick={cancelRequest}>Cancel Request</button>;
}
if (isPendingReceived) {
return <button onClick={acceptRequest}>Accept Request</button>;
}
if (hasNoRelationship) {
return <button onClick={sendRequest}>Add Friend</button>;
}
return null;
}

Notes

  • Friendship queries check both directions (requester_id/addressee_id) and exclude declined/canceled records.
  • Rate limiting uses RATE_LIMIT_ACTIONS.FRIEND_REQUEST from useRateLimit.
  • When sending a request to someone whose previous request was canceled, the hook reactivates the existing record instead of creating a duplicate.

Last updated: 2026-02-07