@infloapi/react-social
v0.1.0
Published
React components for the Inflo social graph — connections, groups, and the CirclesPickerDialog
Maintainers
Readme
@infloapi/react-social
React components for the Inflo social graph layer — connection discovery, group browsing, and the shareable CirclesPickerDialog.
This package is the UI counterpart to the @infloapi/node SDK's connections and groups resources, and complements @infloapp/share-react (which handles CLP content sharing) by covering the social graph selection step that always precedes a share.
Installation
npm install @infloapi/react-socialPeer dependencies:
npm install react react-domQuick start
1. Wrap your app with ConnectionsProvider
ConnectionsProvider accepts two async adapter functions — fetchConnections and fetchGroups — so you can route calls through your own server proxy (recommended) or call Inflo directly.
import { ConnectionsProvider } from "@infloapi/react-social";
function App() {
return (
<ConnectionsProvider
fetchConnections={async (opts) => {
// IMPORTANT: always forward limit and offset so the provider can
// paginate through all connections when has_more is true.
const params = new URLSearchParams();
if (opts?.limit !== undefined) params.set("limit", String(opts.limit));
if (opts?.offset !== undefined) params.set("offset", String(opts.offset));
const res = await fetch(`/api/social/connections?${params}`);
return res.json();
// Expected shape: { connections: ConnectionItem[], total: number, has_more: boolean }
}}
fetchGroups={async () => {
const res = await fetch("/api/social/groups");
return res.json();
// Expected shape: { groups: GroupItem[] }
// total and has_more are optional and ignored if absent.
}}
>
<YourApp />
</ConnectionsProvider>
);
}The provider:
- Loads the full connection list on mount (search filters it client-side, with no extra network request).
- Loads groups on mount.
- Exposes everything to child components via context.
Why client-side search? Inflo's
GET /api/v1/users/me/connectionsendpoint does not support aqorsearchparameter. The provider caches all connections and filters them in-memory when the user types — this is instant and requires no additional requests.
2. Use hooks inside the provider
import { useConnections, useGroups } from "@infloapi/react-social";
function ConnectionsList() {
const { connections, loading, error, search } = useConnections();
const { groups } = useGroups();
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<>
<input
placeholder="Search…"
onChange={(e) => search(e.target.value)}
/>
{/* connections is already filtered by the current search query */}
<ul>
{connections.map((c) => (
<li key={c.uid ?? c.inflo_user_id}>{c.display_name}</li>
))}
</ul>
</>
);
}3. Open the CirclesPickerDialog
import { useState } from "react";
import { CirclesPickerDialog } from "@infloapi/react-social";
import type { CirclesSelection } from "@infloapi/react-social";
function ShareButton({ alreadySharedUids }: { alreadySharedUids: string[] }) {
const [open, setOpen] = useState(false);
function handleSelect(selection: CirclesSelection) {
console.log("Selected UIDs:", selection.connections);
console.log("Selected group IDs:", selection.groups);
// → call your share API here
}
return (
<>
<button onClick={() => setOpen(true)}>Share…</button>
<CirclesPickerDialog
open={open}
onOpenChange={setOpen}
onSelect={handleSelect}
maxConnections={10}
disabledUids={alreadySharedUids}
title="Share with circles"
/>
</>
);
}CirclesPickerDialog features:
- Instant client-side search — filters the locally-loaded connection list as the user types; no extra network request.
- Groups section — shown above connections when there's no active search query.
- Multi-select — each row is checkable; a checkmark appears on selected items.
- Already-connected indicator — UIDs in
disabledUidsrender with a "Connected" badge and cannot be selected. - Connection limit — pass
maxConnectionsto cap individual connection picks (does not limit group selection). - Keyboard / accessibility —
Escapecloses the dialog;role="dialog"andaria-selectedattributes included.
Components
ConnectionCard
Renders an Inflo user row: avatar, display name, username, optional status badge, and a checkmark when selected.
import { ConnectionCard } from "@infloapi/react-social";
<ConnectionCard
connection={conn}
status="connected" // "connected" | "pending" | "not_connected"
selected={isSelected}
disabled={false}
onClick={(c) => toggleUid(c.uid)}
theme={{ primaryColor: "#7c3aed" }}
/>InvitationStatusBadge
Renders an invitation status as a colour-coded pill.
| Status | Colour |
|-------------|--------|
| pending | Yellow |
| accepted | Green |
| declined | Red |
| cancelled | Grey |
| expired | Grey |
import { InvitationStatusBadge } from "@infloapi/react-social";
<InvitationStatusBadge status={invitation.status} />Theming
Every component accepts a theme prop for inline style-based overrides — no extra CSS required.
const theme = {
primaryColor: "#7c3aed", // accent / selected state
primaryForeground: "#ffffff", // text on primary button
dialogBackground: "#1e1e2e", // dialog background
border: "#3f3f5c",
mutedText: "#a0a0c0",
radius: "12px",
fontFamily: "'Inter', sans-serif",
};
<CirclesPickerDialog theme={theme} ... />Wiring fetch adapters to your server proxy
The adapter functions should call your backend, which in turn calls Inflo using a server-side token. Never expose Inflo API keys or PATs to the browser.
Browser → /api/social/connections → Your server → Inflo /api/v1/users/me/connections
Browser → /api/social/groups → Your server → Inflo /api/v1/groupsA minimal Next.js example using @infloapi/node:
// pages/api/social/connections.ts
import { InfloClient } from "@infloapi/node";
const inflo = new InfloClient({ pat: process.env.INFLO_PAT! });
export default async function handler(req, res) {
// Forward limit + offset so ConnectionsProvider can paginate all pages.
const limit = Number(req.query.limit ?? 200);
const offset = Number(req.query.offset ?? 0);
const result = await inflo.connections.list({
userToken: req.headers["x-user-token"] as string,
limit,
offset,
});
res.json(result);
// returns { connections: [...], total, has_more }
}// pages/api/social/groups.ts
export default async function handler(req, res) {
const result = await fetch(
"https://infloapp.com/api/v1/groups",
{ headers: { Authorization: `Bearer ${process.env.INFLO_PAT}` } },
);
const data = await result.json();
res.json(data);
// returns { groups: [...] }
}API reference
ConnectionsProvider props
| Prop | Type | Description |
|------|------|-------------|
| fetchConnections | FetchConnectionsFn | Async adapter. Returns { connections, total, has_more }. Called on mount and on refresh. |
| fetchGroups | FetchGroupsFn | Async adapter. Returns { groups }. Called on mount and on refreshGroups. |
| children | ReactNode | — |
useConnections() return value
| Key | Type | Description |
|-----|------|-------------|
| connections | ConnectionItem[] | Client-side filtered list matching the current searchQuery. |
| loading | boolean | true during initial fetch or refresh. |
| error | Error \| null | Last fetch error. |
| refresh | () => Promise<void> | Re-fetch all connections from the server. |
| search | (query: string) => void | Update the search query (client-side filter, no network call). |
| searchQuery | string | Current search query string. |
| total | number | Total count from the server. |
useGroups() return value
| Key | Type | Description |
|-----|------|-------------|
| groups | GroupItem[] | Loaded groups. |
| loading | boolean | true during fetch. |
| error | Error \| null | Last fetch error. |
| refresh | () => Promise<void> | Re-fetch groups. |
CirclesPickerDialog props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| open | boolean | — | Controls dialog visibility. |
| onOpenChange | (open: boolean) => void | — | Called on close request. |
| onSelect | (selection: CirclesSelection) => void | — | Called on confirm. |
| maxConnections | number | undefined | Cap on selectable connections. |
| disabledUids | string[] | [] | UIDs shown as "already connected". |
| title | string | "Share with circles" | Dialog title. |
| theme | SocialTheme | {} | Visual overrides. |
Related packages
| Package | Purpose |
|---------|---------|
| @infloapi/react | React auth layer — InfloProvider, AuthGuard, PKCE SSO. Required before users have a valid token to pass to your server proxy. |
| @infloapi/node | Node.js SDK — implement the fetchConnections / fetchGroups adapter on your server using inflo.connections.list(). |
License
MIT © Inflo
