# 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](/components/basic-usage.md) - Full component reference
* [ChannelFeed Props](/components/basic-usage/props-reference.md) - All available props
* [ChannelFeed Customization](/components/basic-usage/customization.md) - Styling guide
* [useDeva Hook](/hooks-api/use-deva.md) - Authentication hook reference
* [OAuth Integration](/authentication/oauth-integration.md) - Authentication details


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sdkdocs.deva.me/examples/feed-display.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
