Skip to main content

useCircles

Location: src/hooks/useCircles.js

Overview

Provides a comprehensive set of hooks for managing circles (private friend groups). Includes useCircles for listing and creating circles, useCircle for managing a single circle's members and settings, useAvailableFriends for finding friends to invite, and useCirclePosts for fetching posts within a circle.

All circle creation and invitation actions are protected by tier-aware rate limiting.

Exported Hooks

useCircles

Manages the user's circle list, including active memberships and pending invites.

function useCircles(): {
loading: boolean,
error: string | null,
rateLimitError: string | null,
myCircles: Circle[],
pendingInvites: Circle[],
createCircle: (name: string, description?: string | null) => Promise<Result>,
createDynamicCircle: (name: string, description?: string | null, rules?: Rule[]) => Promise<Result>,
acceptInvite: (circleId: string) => Promise<Result>,
declineInvite: (circleId: string) => Promise<Result>,
refetch: () => Promise<void>
}
PropertyTypeDescription
myCirclesCircle[]Active circle memberships with member counts and user roles
pendingInvitesCircle[]Pending circle invitations with inviter info
createCircle(name, description?) => Promise<Result>Create a static circle via create_circle RPC. Rate-limited and tier-restricted.
createDynamicCircle(name, description?, rules?) => Promise<Result>Create a dynamic circle with view rules
acceptInvite(circleId) => Promise<Result>Accept a circle invitation
declineInvite(circleId) => Promise<Result>Decline and remove a circle invitation

useCircle

Manages a single circle's details, members, invitations, and settings.

function useCircle(circleId: string): {
loading: boolean,
error: string | null,
rateLimitError: string | null,
circle: Circle | null,
members: Member[],
pendingInvites: Member[],
viewRules: Rule[],
userMembership: { id, role, status } | null,
// Derived state
isAdmin: boolean,
isMember: boolean,
isInvited: boolean,
isDynamic: boolean,
memberCount: number,
isOnlyAdmin: boolean,
// Actions
updateCircle: (updates: object) => Promise<Result>,
updateViewRules: (newRules: Rule[]) => Promise<Result>,
inviteFriend: (friendId: string) => Promise<Result>,
cancelInvite: (userId: string) => Promise<Result>,
removeMember: (userId: string) => Promise<Result>,
updateMemberRole: (userId: string, newRole: string) => Promise<Result>,
leaveCircle: () => Promise<Result>,
deleteCircle: () => Promise<Result>,
refetch: () => Promise<void>
}

useAvailableFriends

Fetches friends eligible to be invited to a circle (excludes existing members and blocked users).

function useAvailableFriends(circleId: string): {
loading: boolean,
error: string | null,
friends: Profile[],
refetch: () => Promise<void>
}

useCirclePosts

Fetches posts shared to a specific circle, filtering out blocked users.

function useCirclePosts(circleId: string): {
loading: boolean,
error: string | null,
posts: Post[],
hasMore: boolean,
loadMore: () => void,
refetch: () => void
}
PropertyTypeDescription
postsPost[]Posts in this circle with profiles, comments, images, and shared post data
hasMorebooleanWhether more posts are available to load
loadMore() => voidLoad the next page (20 posts per page)

Usage

import { useCircles, useCircle } from '../hooks/useCircles';

function CirclesList() {
const { myCircles, pendingInvites, createCircle, loading } = useCircles();

if (loading) return <Skeleton />;

return (
<div>
{pendingInvites.map(c => <InviteCard key={c.id} circle={c} />)}
{myCircles.map(c => <CircleCard key={c.id} circle={c} />)}
<button onClick={() => createCircle('My Circle')}>New Circle</button>
</div>
);
}

function CircleDetail({ circleId }) {
const { circle, members, isAdmin, inviteFriend, removeMember } = useCircle(circleId);

return (
<div>
<h2>{circle?.name}</h2>
<MemberList members={members} onRemove={isAdmin ? removeMember : null} />
</div>
);
}

Notes

  • Circle creation uses a SECURITY DEFINER RPC function that handles both circle creation and adding the creator as admin.
  • Dynamic circles support circle_view_rules for automatic membership based on rules.
  • useAvailableFriends filters out both existing members/invitees and blocked users in either direction.
  • useCirclePosts attempts to use the get_circle_posts_excluding_blocked RPC for block filtering, with a fallback to a direct query if the RPC is not available.
  • Post images are sorted by position in the result.

Last updated: 2026-02-07