# @opchan/react React hooks and providers for building decentralized forum applications on top of `@opchan/core`. ## Overview `@opchan/react` provides a complete React integration layer for the OpChan protocol, featuring: - 🔐 **Flexible Authentication** - Wallet-based (Ethereum) or anonymous sessions - 🔑 **Key Delegation** - Browser-based signing to reduce wallet prompts - 📝 **Content Management** - Cells, posts, comments, and votes - 👤 **Identity System** - ENS resolution, call signs, and user profiles - ⚖️ **Permission Management** - Role-based access control - 🌐 **Network State** - Waku connection monitoring - 💾 **Local-First** - IndexedDB caching with network sync ## Installation ```bash npm install @opchan/react @opchan/core react react-dom ``` ## Quick Start ### 1. Setup Provider The `OpChanProvider` wraps WagmiProvider and QueryClientProvider internally: ```tsx import React from 'react'; import { createRoot } from 'react-dom/client'; import { OpChanProvider } from '@opchan/react'; import { Buffer } from 'buffer'; import App from './App'; // Required polyfill for crypto libraries if (!(window as any).Buffer) { (window as any).Buffer = Buffer; } createRoot(document.getElementById('root')!).render( ); ``` ### 2. Use Hooks in Your App ```tsx import { useForum } from '@opchan/react'; export function MyComponent() { const { user, content, permissions, network } = useForum(); return (

Cells: {content.cells.length}

Network: {network.isConnected ? 'Connected' : 'Disconnected'}

{permissions.canPost && }
); } ``` ## Core Concepts ### Authentication Modes OpChan supports three authentication modes: 1. **Anonymous** (`ANONYMOUS`) - Browser-only session, no wallet required - Can post, comment, and vote - Cannot create cells - Optional call sign for identity 2. **Wallet Connected** (`WALLET_CONNECTED`) - Ethereum wallet connected - Full interaction capabilities - Can create posts, comment, vote - Cannot create cells (requires ENS verification) 3. **ENS Verified** (`ENS_VERIFIED`) - Wallet + ENS ownership verified - Full platform access - Can create cells (becomes cell admin) - Enhanced relevance scoring for content ### Key Delegation To reduce wallet signature prompts, OpChan uses browser-based key delegation: - **For Wallet Users**: Wallet signs authorization for browser keys (7 or 30 days) - **For Anonymous Users**: Browser keys generated automatically (no wallet signature) This enables one-time wallet interaction with subsequent actions signed by browser keys. ## API Reference ### Hooks #### `useForum()` Convenience hook that bundles all core hooks: ```tsx const { user, content, permissions, network } = useForum(); ``` Equivalent to: ```tsx const user = useAuth(); const content = useContent(); const permissions = usePermissions(); const network = useNetwork(); ``` --- #### `useAuth()` Manages user session, authentication, and identity. **Data:** - `currentUser: User | null` - Current authenticated user - `verificationStatus: EVerificationStatus` - Authentication level - `isAuthenticated: boolean` - Whether user is logged in (wallet or anonymous) - `delegationInfo: { hasDelegation, isValid, timeRemaining?, expiresAt? }` - Delegation status **Actions:** - `connect()` - Open wallet connection modal - `disconnect()` - Disconnect wallet or exit anonymous session - `startAnonymous(): Promise` - Start anonymous session, returns sessionId - `verifyOwnership(): Promise` - Verify ENS ownership - `delegate(duration: '7days' | '30days'): Promise` - Create wallet delegation - `delegationStatus(): Promise` - Check delegation status - `clearDelegation(): Promise` - Clear stored delegation - `updateProfile({ callSign?, displayPreference? }): Promise` - Update user profile **Example:** ```tsx function AuthButton() { const { currentUser, connect, startAnonymous, disconnect } = useAuth(); if (currentUser) { return ; } return ( <> ); } ``` --- #### `useContent()` Access forum content and perform content actions. **Data:** - `cells: Cell[]` - All cells - `posts: Post[]` - All posts - `comments: Comment[]` - All comments - `bookmarks: Bookmark[]` - User's bookmarks - `postsByCell: Record` - Posts grouped by cell - `commentsByPost: Record` - Comments grouped by post - `cellsWithStats: Cell[]` - Cells with computed stats (activeMembers, relevance) - `userVerificationStatus: Record` - Verification cache - `lastSync: number | null` - Last network sync timestamp - `pending: { isPending(id), onChange(callback) }` - Pending operations tracking **Actions:** - `createCell({ name, description, icon? }): Promise` - `createPost({ cellId, title, content }): Promise` - `createComment({ postId, content }): Promise` - `vote({ targetId, isUpvote }): Promise` - `moderate.post(cellId, postId, reason?)` - Moderate a post - `moderate.unpost(cellId, postId)` - Unmoderate a post - `moderate.comment(cellId, commentId, reason?)` - Moderate a comment - `moderate.uncomment(cellId, commentId)` - Unmoderate a comment - `moderate.user(cellId, userAddress, reason?)` - Moderate a user - `moderate.unuser(cellId, userAddress)` - Unmoderate a user - `togglePostBookmark(post, cellId?): Promise` - Toggle post bookmark - `toggleCommentBookmark(comment, postId?): Promise` - Toggle comment bookmark - `removeBookmark(bookmarkId): Promise` - Remove specific bookmark - `clearAllBookmarks(): Promise` - Clear all bookmarks - `refresh(): Promise` - Refresh content from cache **Example:** ```tsx function CreatePostForm({ cellId }: { cellId: string }) { const { createPost } = useContent(); const [title, setTitle] = useState(''); const [content, setContent] = useState(''); const handleSubmit = async () => { const post = await createPost({ cellId, title, content }); if (post) { setTitle(''); setContent(''); } }; return (
{ e.preventDefault(); handleSubmit(); }}> setTitle(e.target.value)} />