Skip to content

Commit 1aece3b

Browse files
authored
chore: migrate the React demo to NextJS (#17)
Migrates the React demo to NextJS.
1 parent 0c5ad5d commit 1aece3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+669
-459
lines changed

examples/react-chatbot/.gitignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files (can opt-in for committing if needed)
34+
.env*
35+
36+
# vercel
37+
.vercel
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts

examples/react-chatbot/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2+
3+
## Getting Started
4+
5+
First, run the development server:
6+
7+
```bash
8+
npm run dev
9+
# or
10+
yarn dev
11+
# or
12+
pnpm dev
13+
# or
14+
bun dev
15+
```
16+
17+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18+
19+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20+
21+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22+
23+
## Learn More
24+
25+
To learn more about Next.js, take a look at the following resources:
26+
27+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29+
30+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31+
32+
## Deploy on Vercel
33+
34+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35+
36+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
25.3 KB
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Metadata } from 'next';
2+
3+
export const metadata: Metadata = {
4+
title: 'Create Next App',
5+
description: 'AI Chat demo with Stream AI Components',
6+
};
7+
8+
export default function RootLayout({
9+
children,
10+
}: Readonly<{
11+
children: React.ReactNode;
12+
}>) {
13+
return (
14+
<html lang="en">
15+
<body>{children}</body>
16+
</html>
17+
);
18+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { ChannelFilters, ChannelOptions, ChannelSort } from 'stream-chat';
2+
import { StreamChat } from 'stream-chat';
3+
import { AIChatApp } from '@/components/AIChatApp';
4+
import { ThemeProvider } from '@/components/ThemeContext';
5+
6+
import '../components/index.scss';
7+
8+
const generateUserToken = (userId: string) => {
9+
const apiKey = process.env.STREAM_API_KEY as string | undefined;
10+
const secret = process.env.STREAM_API_SECRET as string | undefined;
11+
if (!apiKey || !secret) {
12+
throw new Error('Stream API key and secret are required');
13+
}
14+
15+
const client = new StreamChat(apiKey, secret);
16+
const token = client.createToken(userId);
17+
return { apiKey, token, userId };
18+
};
19+
20+
export default async function Home(props: {
21+
searchParams: Promise<{ conversation_id?: string; user_id?: string }>;
22+
}) {
23+
const { conversation_id, user_id = 'jane' } = await props.searchParams;
24+
const { apiKey, token, userId } = generateUserToken(user_id);
25+
26+
const filters: ChannelFilters = {
27+
members: { $in: [userId] },
28+
type: 'messaging',
29+
archived: false,
30+
};
31+
const options: ChannelOptions = { limit: 15, presence: true, state: true };
32+
const sort: ChannelSort = {
33+
pinned_at: 1,
34+
last_message_at: -1,
35+
updated_at: -1,
36+
};
37+
38+
return (
39+
<ThemeProvider>
40+
<AIChatApp
41+
apiKey={apiKey}
42+
userToken={token}
43+
userId={userId}
44+
filters={filters}
45+
options={options}
46+
sort={sort}
47+
initialChannelId={conversation_id}
48+
/>
49+
</ThemeProvider>
50+
);
51+
}

examples/react-example/src/components/AIChatApp/AIChatApp.scss renamed to examples/react-chatbot/components/AIChatApp/AIChatApp.scss

File renamed without changes.

examples/react-example/src/components/AIChatApp/AIChatApp.tsx renamed to examples/react-chatbot/components/AIChatApp/AIChatApp.tsx

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
'use client';
2+
13
import { useState, useEffect } from 'react';
4+
import { useRouter, useSearchParams } from 'next/navigation';
25
import type {
36
ChannelFilters,
47
ChannelOptions,
@@ -8,7 +11,7 @@ import type {
811
import { Chat, useCreateChatClient, useChatContext } from 'stream-chat-react';
912
import { Sidebar } from '../Sidebar';
1013
import { ChatContainer } from '../ChatContainer';
11-
import { summarizeConversation } from '../../api';
14+
import { summarizeConversation } from '@/components/api';
1215
import './AIChatApp.scss';
1316

1417
interface AIChatAppProps {
@@ -36,20 +39,22 @@ const ChatContent = ({
3639
}) => {
3740
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
3841
const { client, channel, setActiveChannel } = useChatContext();
42+
const router = useRouter();
43+
const searchParams = useSearchParams();
3944

40-
// Update URL when channel changes
45+
// Update URL when channel changes using Next.js router
4146
useEffect(() => {
4247
if (channel?.id) {
43-
const url = new URL(window.location.href);
44-
const currentConversationId = url.searchParams.get('conversation_id');
48+
const currentConversationId = searchParams.get('conversation_id');
4549

4650
// Only push if the conversation_id actually changed
4751
if (currentConversationId !== channel.id) {
48-
url.searchParams.set('conversation_id', channel.id);
49-
window.history.pushState({}, '', url.toString());
52+
const params = new URLSearchParams(searchParams.toString());
53+
params.set('conversation_id', channel.id);
54+
router.push(`?${params.toString()}`, { scroll: false });
5055
}
5156
}
52-
}, [channel?.id]);
57+
}, [channel?.id, searchParams, router]);
5358

5459
// Load initial channel from URL on mount
5560
useEffect(() => {
@@ -65,23 +70,6 @@ const ChatContent = ({
6570
}
6671
}, [initialChannelId, client, channel, setActiveChannel]);
6772

68-
// Handle browser back/forward navigation
69-
useEffect(() => {
70-
const handlePopState = async () => {
71-
const url = new URL(window.location.href);
72-
const conversationId = url.searchParams.get('conversation_id');
73-
74-
if (conversationId && client && conversationId !== channel?.id) {
75-
const targetChannel = client.channel('messaging', conversationId);
76-
await targetChannel.watch();
77-
setActiveChannel(targetChannel);
78-
}
79-
};
80-
81-
window.addEventListener('popstate', handlePopState);
82-
return () => window.removeEventListener('popstate', handlePopState);
83-
}, [client, channel?.id, setActiveChannel]);
84-
8573
// Watch for new messages and trigger summarization
8674
useEffect(() => {
8775
if (!channel) return;

examples/react-example/src/components/AIChatApp/index.ts renamed to examples/react-chatbot/components/AIChatApp/index.ts

File renamed without changes.

examples/react-example/src/components/AIStateIndicator/AIStateIndicator.scss renamed to examples/react-chatbot/components/AIStateIndicator/AIStateIndicator.scss

File renamed without changes.

examples/react-example/src/components/AIStateIndicator/AIStateIndicator.tsx renamed to examples/react-chatbot/components/AIStateIndicator/AIStateIndicator.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use client';
2+
13
import { useMemo } from 'react';
24
import {
35
AIStates,

0 commit comments

Comments
 (0)