Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/tutorial/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
VITE_API_KEY=REPLACE_WITH_API_KEY
VITE_USER_ID=REPLACE_WITH_USER_ID
VITE_USER_NAME=REPLACE_WITH_USER_NAME
VITE_USER_TOKEN=REPLACE_WITH_USER_TOKEN
27 changes: 27 additions & 0 deletions examples/tutorial/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.env
!env.example

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
19 changes: 19 additions & 0 deletions examples/tutorial/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
This folder contains the source code for [Chat React tutorial](https://github.com/GetStream/getstream.io-tutorials/blob/main/chat/tutorials/react-tutorial.mdx). It contains multiple versions of apps representing the tutorial steps.

## Setup

1. Copy create a `.env` file next to the `.env.example` file.
2. Copy the contents of `.env.example` file into `.env` file and populate the credentials

## Run individual app examples

```shell
yarn dev:client-setup
yarn dev:client-setup
yarn dev:core-component-setup
yarn dev:channel-list
yarn dev:custom-ui-components
yarn dev:custom-attachment-type
yarn dev:emoji-picker
yarn dev:livestream
```
25 changes: 25 additions & 0 deletions examples/tutorial/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
},
);
13 changes: 13 additions & 0 deletions examples/tutorial/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions examples/tutorial/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "tutorial",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev:client-setup": "vite --mode 1-client-setup",
"dev:core-component-setup": "vite --mode 2-core-component-setup",
"dev:channel-list": "vite --mode 3-channel-list",
"dev:custom-ui-components": "vite --mode 4-custom-ui-components",
"dev:custom-attachment-type": "vite --mode 5-custom-attachment-type",
"dev:emoji-picker": "vite --mode 6-emoji-picker",
"dev:livestream": "vite --mode 7-livestream",
"build:client-setup": "vite build --mode 1-client-setup",
"build:core-component-setup": "vite build --mode 2-core-component-setup",
"build:channel-list": "vite build --mode 3-channel-list",
"build:custom-ui-components": "vite build --mode 4-custom-ui-components",
"build:custom-attachment-type": "vite build --mode 5-custom-attachment-type",
"build:emoji-picker": "vite build --mode 6-emoji-picker",
"build:livestream": "vite build --mode 7-livestream",
"build:all": "concurrently \"npm run build:client-setup\" \"npm run build:core-component-setup\" \"npm run build:channel-list\" \"npm run build:custom-ui-components\" \"npm run build:custom-attachment-type\" \"npm run build:emoji-picker\" \"npm run build:livestream\"",
"lint": "eslint ."
},
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0",
"stream-chat": "^9.0.0",
"stream-chat-react": "^13.0.0"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@vitejs/plugin-react": "^4.4.1",
"concurrently": "^9.1.2",
"eslint": "^9.25.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.30.1",
"vite": "^6.3.5"
}
}
1 change: 1 addition & 0 deletions examples/tutorial/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions examples/tutorial/src/1-client-setup/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Chat, useCreateChatClient } from 'stream-chat-react';

// your Stream app information
const apiKey = 'REPLACE_WITH_API_KEY';
const userId = 'REPLACE_WITH_USER_ID';
const userName = 'REPLACE_WITH_USER_NAME';
const userToken = 'REPLACE_WITH_USER_TOKEN';

const App = () => {
const client = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: { id: userId, name: userName },
});

if (!client) return <div>Setting up client & connection...</div>;

return <Chat client={client}>Chat with client is ready!</Chat>;
};

export default App;
5 changes: 5 additions & 0 deletions examples/tutorial/src/1-client-setup/credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// your Stream app information
export const apiKey = import.meta.env.VITE_API_KEY;
export const userId = import.meta.env.VITE_USER_ID;
export const userName = import.meta.env.VITE_USER_NAME;
export const userToken = import.meta.env.VITE_USER_TOKEN;
13 changes: 13 additions & 0 deletions examples/tutorial/src/1-client-setup/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
9 changes: 9 additions & 0 deletions examples/tutorial/src/1-client-setup/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
65 changes: 65 additions & 0 deletions examples/tutorial/src/2-core-component-setup/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useState, useEffect } from 'react';
import type { User, Channel as StreamChannel } from 'stream-chat';
import {
useCreateChatClient,
Chat,
Channel,
ChannelHeader,
MessageInput,
MessageList,
Thread,
Window,
} from 'stream-chat-react';

import 'stream-chat-react/dist/css/v2/index.css';
// additionally
import './layout.css';

const apiKey = 'REPLACE_WITH_API_KEY';
const userId = 'REPLACE_WITH_USER_ID';
const userName = 'REPLACE_WITH_USER_NAME';
const userToken = 'REPLACE_WITH_USER_TOKEN';

const user: User = {
id: userId,
name: userName,
image: `https://getstream.io/random_png/?name=${userName}`,
};

const App = () => {
const [channel, setChannel] = useState<StreamChannel>();
const client = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: user,
});

useEffect(() => {
if (!client) return;

const channel = client.channel('messaging', 'custom_channel_id', {
image: 'https://getstream.io/random_png/?name=react',
name: 'Talk about React',
members: [userId],
});

setChannel(channel);
}, [client]);

if (!client) return <div>Setting up client & connection...</div>;

return (
<Chat client={client} theme='str-chat__theme-custom'>
<Channel channel={channel}>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</Chat>
);
};

export default App;
13 changes: 13 additions & 0 deletions examples/tutorial/src/2-core-component-setup/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
21 changes: 21 additions & 0 deletions examples/tutorial/src/2-core-component-setup/layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
html,
body,
#root {
height: 100%;
}
body {
margin: 0;
}
#root {
display: flex;
}

.str-chat__channel-list {
width: 30%;
}
.str-chat__channel {
width: 100%;
}
.str-chat__thread {
width: 45%;
}
9 changes: 9 additions & 0 deletions examples/tutorial/src/2-core-component-setup/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { DefaultChannelData } from 'stream-chat-react';

declare module 'stream-chat' {
interface CustomChannelData extends DefaultChannelData {
image?: string;
}
}
61 changes: 61 additions & 0 deletions examples/tutorial/src/3-channel-list/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { User, ChannelSort, ChannelFilters, ChannelOptions } from 'stream-chat';
import {
useCreateChatClient,
Chat,
Channel,
ChannelHeader,
ChannelList,
MessageInput,
MessageList,
Thread,
Window,
} from 'stream-chat-react';

import 'stream-chat-react/dist/css/v2/index.css';
import './layout.css';

const apiKey = 'REPLACE_WITH_API_KEY';
const userId = 'REPLACE_WITH_USER_ID';
const userName = 'REPLACE_WITH_USER_NAME';
const userToken = 'REPLACE_WITH_USER_TOKEN';

const user: User = {
id: userId,
name: userName,
image: `https://getstream.io/random_png/?name=${userName}`,
};

const sort: ChannelSort = { last_message_at: -1 };
const filters: ChannelFilters = {
type: 'messaging',
members: { $in: [userId] },
};
const options: ChannelOptions = {
limit: 10,
};

const App = () => {
const client = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: user,
});

if (!client) return <div>Setting up client & connection...</div>;

return (
<Chat client={client}>
<ChannelList filters={filters} sort={sort} options={options} />
<Channel>
<Window>
<ChannelHeader />
<MessageList />
<MessageInput />
</Window>
<Thread />
</Channel>
</Chat>
);
};

export default App;
13 changes: 13 additions & 0 deletions examples/tutorial/src/3-channel-list/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
Loading