dev/chat
Lei OT 2 years ago
parent c0f1f7b369
commit 1d8c12ef66

@ -0,0 +1,9 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}

@ -15,7 +15,8 @@
"mobx-react": "^9.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1"
"react-router-dom": "^6.21.1",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@types/react": "^18.2.15",

@ -1,21 +1,23 @@
// websocketLib.js
import { WebSocketSubject } from 'rxjs/webSocket';
import { retryWhen, delay, take, catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
class WebSocketLib {
constructor(url, authToken) {
constructor(url, authToken, protocol) {
this.url = url;
this.authToken = authToken;
this.protocol = protocol;
}
connect() {
this.socket$ = new WebSocketSubject({
url: this.url,
protocol: this.authToken, // Using the protocol parameter for authentication
protocol: this.protocol, // Use protocol for message type
openObserver: {
next: () => {
console.log('Connection established');
// Send authentication message as soon as connection is established
this.socket$.next({ type: 'authenticate', token: this.authToken });
},
},
closeObserver: {
@ -31,7 +33,7 @@ class WebSocketLib {
errors.pipe(
delay(1000), // Retry connection every 1 second
take(10), // Maximum of 10 retries
catchError(error => throwError(`Failed to reconnect: ${error}`)) // Throw error after 10 failed retries
catchError(error => new Error(`Failed to reconnect: ${error}`)) // Throw error after 10 failed retries
)
)
)

@ -16,6 +16,8 @@ import DingdingQRCode from '@/views/DingdingQRCode'
import DingdingCallbak from '@/views/DingdingCallbak'
import ErrorPage from '@/views/ErrorPage'
import Conversations from '@/views/Conversations/Components/ChatWindow';
configure({
useProxies: 'ifavailable',
enforceActions: 'observed',
@ -30,18 +32,19 @@ const router = createBrowserRouter([
path: '/',
element: <App />,
errorElement: <ErrorPage />,
children: [
children: [
{ index: true, element: <OrderFollow /> },
]
},
{
path: '/s',
element: <App />,
children: [
children: [
{ index: true, element: <OrderFollow /> },
{ path: 'order/follow', element: <OrderFollow />},
{ path: 'chat/history', element: <ChatHistory />},
{ path: 'sales/management', element: <SalesManagement />},
{ path: 'order/chat', element: <Conversations />},
]
},
{

@ -0,0 +1,12 @@
import Chat from './Index';
// import 'antd/dist/reset.css';
function App() {
return (
<div className="App">
<Chat />
</div>
);
}
export default App;

@ -0,0 +1,57 @@
import { useState } from 'react';
import { List, Input, Avatar, Button } from 'antd';
const messages = [
{
sender: 'John Doe',
message: 'Hey!',
},
{
sender: 'Jane Doe',
message: 'Hi John!',
},
];
function App() {
const [message, setMessage] = useState('');
const sendMessage = () => {
// Update messages with new message data
const newMessage = {
sender: 'You',
message,
};
messages.push(newMessage);
setMessage('');
};
return (
<div className="App">
<List
itemLayout="horizontal"
dataSource={messages}
renderItem={(message) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar icon="user" />}
title={message.sender}
description={message.message}
/>
</List.Item>
)}
/>
<Input.Group compact>
<Input
placeholder="Type your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<Button type="primary" onClick={sendMessage}>
Send
</Button>
</Input.Group>
</div>
);
}
export default App;

@ -0,0 +1,28 @@
.chat-layout {
height: 100vh;
}
.chat-sider {
overflow: auto;
}
.chat-content {
padding: 24px;
overflow: auto;
}
.chat-input {
position: fixed;
bottom: 0;
width: calc(100% - 300px);
display: flex;
padding: 24px;
}
.chat-input .ant-input {
margin-right: 24px;
}
.chat-button {
height: 40px;
}

@ -0,0 +1,38 @@
import { Layout } from 'antd';
import Messages from './Messages';
import InputBox from './InputBox';
import Conversations from './Conversations';
import CustomerProfile from './CustomerProfile';
const {Sider, Content } = Layout;
const CList = [
{ name: 'Customer_1', label: 'Customer_1', key: 'Customer_1', value: 'Customer_1' },
{ name: 'Customer_2', label: 'Customer_2', key: 'Customer_2', value: 'Customer_2' },
{ name: 'Customer_3', label: 'Customer_3', key: 'Customer_3', value: 'Customer_3' },
{ name: 'Customer_4', label: 'Customer_4', key: 'Customer_4', value: 'Customer_4' },
];
function ChatWindow() {
return (
<Layout>
<Sider width={300} theme={'light'}>
<Conversations conversations={CList} />
</Sider>
<Content>
<Layout>
<Messages />
<InputBox />
</Layout>
</Content>
<Sider width={300} theme={'light'}>
<CustomerProfile customer={{}}/>
</Sider>
</Layout>
);
}
export default ChatWindow;

@ -0,0 +1,31 @@
import { List, Avatar } from 'antd';
import PropTypes from 'prop-types';
const ColorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
function Conversations({ conversations }) {
return (
<List
dataSource={conversations}
renderItem={(item, ii) => (
<List.Item>
<List.Item.Meta
avatar={
<Avatar
style={{
backgroundColor: ColorList[ii],
verticalAlign: 'middle',
}}>
{item.name}
</Avatar>
}
title={item.name}
/>
</List.Item>
)}
/>
);
}
Conversations.propTypes = {
conversations: PropTypes.string.isRequired,
};
export default Conversations;

@ -0,0 +1,8 @@
import { Card } from 'antd';
function CustomerProfile({ customer }) {
return <Card title={customer.name}>{/* other profile details */}</Card>;
}
CustomerProfile.propTypes = {
};
export default CustomerProfile;

@ -0,0 +1,22 @@
import { Input, Button } from 'antd';
function InputBox({ onSend }) {
function handleSend() {
// Logic to get message and call onSend
}
return (
<div>
<Input.Search
placeholder="Type message here"
enterButton="Send"
size="large"
onSearch={handleSend}
/>
</div>
);
}
export default InputBox;

@ -0,0 +1,21 @@
import { List, Avatar } from 'antd';
function Messages({ messages }) {
return (
<List
dataSource={messages}
renderItem={message => (
<List.Item>
<List.Item.Meta
avatar={<Avatar>{message.sender[0]}</Avatar>}
title={message.sender}
/>
<div>{message.text}</div>
</List.Item>
)}
/>
);
}
export default Messages;

@ -0,0 +1,54 @@
import { Layout, List, Input, Button } from 'antd';
import './Chat.css';
const { Sider, Content } = Layout;
const { TextArea } = Input;
const Chat = () => {
const channels = ['Channel 1', 'Channel 2'];
const messages = [
{ user: 'User 1', text: 'Hello!' },
{ user: 'User 2', text: 'Hi!' },
];
return (
<Layout className="chat-layout">
<Sider theme="light" width={300} className="chat-sider">
<List
header={<div>Channels</div>}
bordered
dataSource={channels}
renderItem={item => (
<List.Item>
{item}
</List.Item>
)}
/>
</Sider>
<Layout>
<Content className="chat-content">
<List
itemLayout="horizontal"
dataSource={messages}
renderItem={item => (
<List.Item>
<List.Item.Meta
title={item.user}
description={item.text}
/>
</List.Item>
)}
/>
<div className="chat-input">
<TextArea rows={4} />
<Button type="primary" className="chat-button">
Send
</Button>
</div>
</Content>
</Layout>
</Layout>
);
}
export default Chat;

@ -0,0 +1,35 @@
import { useContext } from 'react';
import { observer } from 'mobx-react';
import { Table } from 'antd';
import WebSocketLib from '@/lib/websocketLib';
const CList = [
{ name: 'Customer_1', label: 'Customer_1', key: 'Customer_1', value: 'Customer_1' },
{ name: 'Customer_2', label: 'Customer_2', key: 'Customer_2', value: 'Customer_2' },
{ name: 'Customer_3', label: 'Customer_3', key: 'Customer_3', value: 'Customer_3' },
{ name: 'Customer_4', label: 'Customer_4', key: 'Customer_4', value: 'Customer_4' },
];
// Assume we have an array of customer URLs and their corresponding auth tokens
const customers = [
{ url: 'ws://202.103.68.144:8888/whatever/', authToken: 'customer1Token' },
];
// Create a WebSocketLib instance for each customer
const connections = customers.map(customer => {
const wsLib = new WebSocketLib(customer.url, customer.authToken, 'WhatApp');
wsLib.connect();
return wsLib;
});
// Now, the agent can send a message to a specific customer like this:
connections[0].sendMessage('Hello, customer 1! '+ Date.now().toString(36));
// Or broadcast a message to all customers like this:
// connections.forEach(conn => conn.sendMessage('Hello, all customers!'));
export default observer((props) => {
// const { } = useContext(stores_Context);
return <></>;
});
Loading…
Cancel
Save