chore: update README

This commit is contained in:
Danish Arora 2025-10-29 18:28:40 +05:30
parent 0e01533ade
commit 028a464412
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
5 changed files with 456 additions and 4 deletions

View File

@ -543,6 +543,72 @@ const popular = [...posts].sort((a, b) =>
}
```
### Critical Setup Requirements
**⚠️ IMPORTANT: Provider Configuration**
The `OpChanProvider` must be properly configured to avoid the "useClient must be used within ClientProvider" error:
```tsx
// ✅ CORRECT - Complete setup
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(
<OpChanProvider
config={{
wakuConfig: {
contentTopic: '/opchan/1/messages/proto',
reliableChannelId: 'opchan-messages'
},
reownProjectId: 'your-reown-project-id' // ⚠️ REQUIRED for WalletConnect
}}
>
<App />
</OpChanProvider>
);
```
**Common Setup Mistakes:**
1. **Missing reownProjectId** - Causes wallet connection failures
2. **Missing Buffer polyfill** - Causes crypto library errors
3. **Provider not wrapping all components** - Causes "useClient must be used within ClientProvider" error
4. **Using hooks outside provider** - All `@opchan/react` hooks must be inside `OpChanProvider`
**Environment Variables:**
```bash
# .env
VITE_REOWN_SECRET=your_reown_project_id_here
```
**Vite Configuration (if using Vite):**
```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
define: {
global: 'globalThis',
},
optimizeDeps: {
include: ['buffer'],
},
});
```
### Recommended UI Libraries
- **shadcn/ui** - Accessible component primitives
@ -743,6 +809,79 @@ export function PostDetail({ postId }: { postId: string }) {
}
```
## Troubleshooting Common Issues
### Error: "useClient must be used within ClientProvider"
**Root Cause:** Components using `@opchan/react` hooks are not wrapped by `OpChanProvider`.
**Solution:**
```tsx
// ❌ WRONG - Hooks used outside provider
function App() {
const { currentUser } = useAuth(); // This will fail
return <div>Hello</div>;
}
// ✅ CORRECT - All hooks inside provider
function App() {
return (
<OpChanProvider config={config}>
<MainApp />
</OpChanProvider>
);
}
function MainApp() {
const { currentUser } = useAuth(); // This works
return <div>Hello</div>;
}
```
### Error: Wallet Connection Fails
**Root Cause:** Missing or invalid `reownProjectId` in provider config.
**Solution:**
```tsx
// ❌ WRONG - Missing reownProjectId
<OpChanProvider config={{ wakuConfig: {...} }}>
// ✅ CORRECT - Include reownProjectId
<OpChanProvider config={{
wakuConfig: {...},
reownProjectId: 'your-project-id'
}}>
```
### Error: "Buffer is not defined"
**Root Cause:** Missing Buffer polyfill for crypto libraries.
**Solution:**
```tsx
import { Buffer } from 'buffer';
// Add before rendering
if (!(window as any).Buffer) {
(window as any).Buffer = Buffer;
}
```
### Error: Anonymous users can't interact after setting call sign
**Root Cause:** Verification status not preserved during profile updates.
**Solution:**
```tsx
// In updateProfile function
const updated: User = {
...user,
...identity,
verificationStatus: user.verificationStatus, // Preserve!
};
```
## Testing Your Implementation
### Manual Test Checklist

View File

@ -42,7 +42,7 @@ export * from './lib/waku/network';
// Export wallet functionality
export { EthereumWallet, EthereumWalletHelpers } from './lib/wallet';
export { wagmiConfig, config } from './lib/wallet/config';
export { wagmiConfig, config, createWagmiConfig } from './lib/wallet/config';
export * from './lib/wallet/types';
// Primary client API

View File

@ -618,6 +618,262 @@ interface OpChanProviderProps {
}
```
## Complete Example App
Here's a minimal working example that demonstrates all the key patterns:
### 1. Main Entry Point (`main.tsx`)
```tsx
import { createRoot } from 'react-dom/client';
import { OpChanProvider } from '@opchan/react';
import { Buffer } from 'buffer';
import App from './App';
// Required polyfill
if (!(window as any).Buffer) {
(window as any).Buffer = Buffer;
}
createRoot(document.getElementById('root')!).render(
<OpChanProvider
config={{
wakuConfig: {
contentTopic: '/opchan/1/messages/proto',
reliableChannelId: 'opchan-messages'
},
reownProjectId: import.meta.env.VITE_REOWN_SECRET || '2ead96ea166a03e5ab50e5c190532e72'
}}
>
<App />
</OpChanProvider>
);
```
### 2. App Component (`App.tsx`)
```tsx
import { useForum } from '@opchan/react';
export default function App() {
const { user, content, permissions, network } = useForum();
// Wait for initial data load
if (!network.isHydrated) {
return <div>Loading...</div>;
}
return (
<div className="min-h-screen bg-gray-900 text-white">
<Header />
<main className="container mx-auto p-4">
{!user.currentUser ? (
<AuthPrompt />
) : (
<ForumInterface />
)}
</main>
</div>
);
}
```
### 3. Authentication Component (`AuthPrompt.tsx`)
```tsx
import { useAuth } from '@opchan/react';
export function AuthPrompt() {
const { connect, startAnonymous } = useAuth();
return (
<div className="text-center space-y-4">
<h1 className="text-2xl font-bold">Welcome to OpChan</h1>
<p className="text-gray-400">Choose how you'd like to participate:</p>
<div className="space-y-2">
<button
onClick={connect}
className="w-full bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded"
>
Connect Wallet
</button>
<button
onClick={startAnonymous}
className="w-full bg-gray-600 hover:bg-gray-700 px-4 py-2 rounded"
>
Continue Anonymously
</button>
</div>
</div>
);
}
```
### 4. Header Component (`Header.tsx`)
```tsx
import { useAuth } from '@opchan/react';
export function Header() {
const { currentUser, disconnect, verificationStatus } = useAuth();
return (
<header className="bg-gray-800 p-4">
<div className="flex justify-between items-center">
<h1 className="text-xl font-bold">OpChan</h1>
{currentUser ? (
<div className="flex items-center space-x-4">
<span className="text-sm">
{currentUser.displayName}
{verificationStatus === 'anonymous' && ' (Anonymous)'}
{verificationStatus === 'ens-verified' && ' (ENS)'}
</span>
<button
onClick={disconnect}
className="text-sm text-gray-400 hover:text-white"
>
Disconnect
</button>
</div>
) : null}
</div>
</header>
);
}
```
### 5. Forum Interface (`ForumInterface.tsx`)
```tsx
import { useContent, usePermissions } from '@opchan/react';
export function ForumInterface() {
const { cells, posts, createPost } = useContent();
const { canPost, canCreateCell } = usePermissions();
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<h2 className="text-xl font-semibold">Cells</h2>
{canCreateCell && (
<button className="bg-green-600 hover:bg-green-700 px-4 py-2 rounded">
Create Cell
</button>
)}
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{cells.map(cell => (
<CellCard key={cell.id} cell={cell} />
))}
</div>
<div>
<h3 className="text-lg font-semibold mb-4">Recent Posts</h3>
<div className="space-y-2">
{posts.slice(0, 10).map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
</div>
</div>
);
}
```
### 6. Cell Card Component (`CellCard.tsx`)
```tsx
import { useContent } from '@opchan/react';
export function CellCard({ cell }) {
const { postsByCell } = useContent();
const cellPosts = postsByCell[cell.id] || [];
return (
<div className="bg-gray-800 p-4 rounded-lg">
<h3 className="font-semibold">{cell.name}</h3>
<p className="text-sm text-gray-400 mb-2">{cell.description}</p>
<div className="text-xs text-gray-500">
{cellPosts.length} posts
</div>
</div>
);
}
```
### 7. Post Card Component (`PostCard.tsx`)
```tsx
import { useUserDisplay } from '@opchan/react';
export function PostCard({ post }) {
const { displayName, callSign, ensName } = useUserDisplay(post.author);
return (
<div className="bg-gray-800 p-3 rounded">
<div className="flex justify-between items-start mb-2">
<span className="text-sm font-medium">
{displayName}
{callSign && ` (#${callSign})`}
{ensName && ` (${ensName})`}
</span>
<span className="text-xs text-gray-500">
{new Date(post.timestamp).toLocaleDateString()}
</span>
</div>
<h4 className="font-medium">{post.title}</h4>
<p className="text-sm text-gray-400 mt-1">{post.content}</p>
</div>
);
}
```
### 8. Package.json Dependencies
```json
{
"dependencies": {
"@opchan/react": "^1.1.0",
"@opchan/core": "^1.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"buffer": "^6.0.3"
},
"devDependencies": {
"@types/react": "^18.3.0",
"typescript": "^5.3.0",
"vite": "^5.0.0",
"@vitejs/plugin-react": "^4.0.0"
}
}
```
### 9. Vite Configuration (`vite.config.ts`)
```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
define: {
global: 'globalThis',
},
optimizeDeps: {
include: ['buffer'],
},
});
```
### 10. Environment Variables (`.env`)
```bash
VITE_REOWN_SECRET=your_reown_project_id_here
```
## Best Practices
1. **Use `useForum()` for most cases** - Cleaner than importing individual hooks
@ -647,6 +903,63 @@ interface OpChanProviderProps {
## Troubleshooting
### Error: "useClient must be used within ClientProvider"
**Root Cause:** Components using `@opchan/react` hooks are not wrapped by `OpChanProvider`.
**Solution:**
```tsx
// ❌ WRONG - Hooks used outside provider
function App() {
const { currentUser } = useAuth(); // This will fail
return <div>Hello</div>;
}
// ✅ CORRECT - All hooks inside provider
function App() {
return (
<OpChanProvider config={config}>
<MainApp />
</OpChanProvider>
);
}
function MainApp() {
const { currentUser } = useAuth(); // This works
return <div>Hello</div>;
}
```
### Error: Wallet Connection Fails
**Root Cause:** Missing or invalid `reownProjectId` in provider config.
**Solution:**
```tsx
// ❌ WRONG - Missing reownProjectId
<OpChanProvider config={{ wakuConfig: {...} }}>
// ✅ CORRECT - Include reownProjectId
<OpChanProvider config={{
wakuConfig: {...},
reownProjectId: 'your-project-id'
}}>
```
### Error: "Buffer is not defined"
**Root Cause:** Missing Buffer polyfill for crypto libraries.
**Solution:**
```tsx
import { Buffer } from 'buffer';
// Add before rendering
if (!(window as any).Buffer) {
(window as any).Buffer = Buffer;
}
```
### Anonymous users can't interact after setting call sign
- Ensure `mapVerificationStatus` includes `ANONYMOUS` case
- Check that `updateProfile` preserves `verificationStatus`

View File

@ -1,6 +1,6 @@
{
"name": "@opchan/react",
"version": "1.1.2",
"version": "1.1.2",
"private": false,
"description": "React contexts and hooks for OpChan built on @opchan/core",
"main": "dist/index.js",

View File

@ -1,10 +1,9 @@
import React from "react";
import { OpChanClient, type OpChanClientConfig } from "@opchan/core";
import { OpChanClient, type OpChanClientConfig, createWagmiConfig } from "@opchan/core";
import { ClientProvider } from "../context/ClientContext";
import { StoreWiring } from "./StoreWiring";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { wagmiConfig } from "@opchan/core";
export interface OpChanProviderProps {
config: OpChanClientConfig;
@ -30,6 +29,7 @@ export const OpChanProvider: React.FC<OpChanProviderProps> = ({
children,
}) => {
const [client] = React.useState(() => new OpChanClient(config));
const [wagmiConfig] = React.useState(() => createWagmiConfig(config.reownProjectId));
return (
<WagmiProvider config={wagmiConfig}>