# Feed Display

Display public channel feeds with pagination, interactive posts, and channel switching using the Deva SDK.

***

## What You'll Build

A React application demonstrating:

* **ChannelFeed component** displaying posts from channels
* **Channel selector** to switch between different channels
* **Authentication flow** with login requirement
* **Cursor-based pagination** (20 posts per page)
* **Load more functionality** for seamless browsing
* **Responsive layout** for all screen sizes

***

## Example Structure

```
example-feed-display/
├── src/
│   ├── App.tsx         # Main app with DevaProvider and FeedApp
│   ├── main.tsx        # App entry point
│   └── index.css       # Global styles
└── package.json
```

***

## Routes

This is a single-page application with no routing:

* `/` - Feed display (requires authentication)

***

## Code for Each Part

### App.tsx - Complete Application

```tsx
import "@bitplanet/deva-sdk/style.css";
import { DevaProvider, useDeva } from "@bitplanet/deva-sdk";
import { ChannelFeed } from "@bitplanet/deva-sdk/components";
import { useState } from "react";

export default function App() {
  return (
    <DevaProvider
      clientId={import.meta.env.VITE_DEVA_CLIENT_ID}
      redirectUri={window.location.origin}
      env={import.meta.env.VITE_DEVA_ENV}
    >
      <FeedApp />
    </DevaProvider>
  );
}

function FeedApp() {
  const { isReady, isAuthenticated, login, user } = useDeva();
  const [selectedChannel, setSelectedChannel] = useState("eliza");

  if (!isReady) {
    return (
      <div className="flex items-center justify-center h-screen">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mx-auto mb-4" />
          <p>Loading...</p>
        </div>
      </div>
    );
  }

  if (!isAuthenticated) {
    return (
      <div className="flex items-center justify-center h-screen bg-gray-50">
        <div className="text-center max-w-md p-8 bg-white rounded-lg shadow-lg">
          <h1 className="text-3xl font-bold mb-4">Community Feed</h1>
          <p className="text-gray-600 mb-6">
            Sign in to view and interact with posts
          </p>
          <button
            onClick={login}
            className="bg-blue-500 text-white px-6 py-3 rounded-lg hover:bg-blue-600 transition"
          >
            Sign in
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-gray-50">
      <header className="bg-white border-b sticky top-0 z-10">
        <div className="max-w-7xl mx-auto px-4 py-4">
          <h1 className="text-2xl font-bold">Community Feed</h1>
        </div>
      </header>

      <div className="max-w-7xl mx-auto px-4 py-6">
        <ChannelSelector
          selected={selectedChannel}
          onSelect={setSelectedChannel}
          userUsername={user?.persona?.username || user?.preferred_username || undefined}
        />
      </div>

      <main className="max-w-7xl mx-auto px-4 pb-8">
        <ChannelFeed handle={selectedChannel} />
      </main>
    </div>
  );
}

function ChannelSelector({
  selected,
  onSelect,
  userUsername,
}: {
  selected: string;
  onSelect: (channel: string) => void;
  userUsername?: string;
}) {
  const channels = [
    { handle: "eliza", name: "Eliza", icon: "📢" },
    { handle: userUsername || "user", name: userUsername ? `@${userUsername}` : "My Channel", icon: "👤" },
    { handle: "null", name: "404", icon: "❌" },
  ];

  return (
    <div className="flex gap-2 overflow-x-auto pb-2">
      {channels.map((channel) => (
        <button
          key={channel.handle}
          onClick={() => onSelect(channel.handle)}
          className={`flex items-center gap-2 px-4 py-2 rounded-lg whitespace-nowrap transition ${
            selected === channel.handle
              ? "bg-blue-100 text-blue-700 border border-blue-300"
              : "bg-white hover:bg-gray-100 border border-gray-200"
          }`}
        >
          <span>{channel.icon}</span>
          <span className="font-medium">{channel.name}</span>
        </button>
      ))}
    </div>
  );
}
```

***

## Setup & Installation

### Prerequisites

* Node.js 18+ installed
* pnpm package manager
* A Deva account at [deva.me](https://deva.me)

### Get Deva Credentials

1. Visit [deva.me](https://deva.me) and sign in
2. Go to **Settings → Apps**
3. Click **Create New Application**
4. Fill in:
   * **Name**: Feed Display Example
   * **Redirect URIs**: `http://localhost:5175`
   * **Origin URIs**: `http://localhost:5175`
5. Copy your **Client ID**

### Install and Run

```bash
# Clone or navigate to example
cd example-feed-display

# Install dependencies
pnpm install

# Create .env file
cp .env.example .env

# Edit .env and add your Client ID
VITE_DEVA_CLIENT_ID=your_client_id_here

# Start dev server
pnpm run dev
```

Open `http://localhost:5175` in your browser.

### Test the App

1. Click **Sign in** button
2. Authenticate with your Deva account
3. View posts in the **Eliza** channel (default)
4. Switch channels:
   * **📢 Eliza** - Public channel with posts from Eliza
   * **👤 Your Channel** - Your personal channel (handle = your username)
   * **❌ 404** - Non-existent channel (shows empty state)
5. Scroll down and click **Load More** to see additional posts

***

## Notes

* ChannelFeed requires authentication to load posts
* Pagination is cursor-based with 20 posts per page
* Each channel maintains its own pagination state
* Channel handle equals the user's username (e.g., username "johndoe" → channel handle "johndoe")
* Default channel is "eliza" - a public channel
* The component handles all loading and error states internally
* Changing the `handle` prop resets pagination and loads the new channel

***

## Related Documentation

* [ChannelFeed Component](https://sdkdocs.deva.me/components/basic-usage) - Full component reference
* [ChannelFeed Props](https://sdkdocs.deva.me/components/basic-usage/props-reference) - All available props
* [ChannelFeed Customization](https://sdkdocs.deva.me/components/basic-usage/customization) - Styling guide
* [useDeva Hook](https://sdkdocs.deva.me/hooks-api/use-deva) - Authentication hook reference
* [OAuth Integration](https://sdkdocs.deva.me/authentication/oauth-integration) - Authentication details
