diff --git a/packages/app/src/components/LiveChat/index.jsx b/packages/app/src/components/LiveChat/index.jsx
index 4e5d4c83..f1feb578 100644
--- a/packages/app/src/components/LiveChat/index.jsx
+++ b/packages/app/src/components/LiveChat/index.jsx
@@ -1,52 +1,134 @@
import React from "react"
import * as antd from "antd"
+import classnames from "classnames"
+import { io } from "socket.io-client"
+import config from "config"
+import SessionModel from "models/session"
import "./index.less"
const Line = (props) => {
- const { user, content, timestamp } = props
+ const { user, content } = props
- return
- {content}
+ return
+
+
{user.fullName ?? user.username}
+
+
+ {content}
+
}
-
export default class LiveChat extends React.Component {
state = {
socket: null,
+ connecting: true,
+ connectionEnd: false,
+ roomInfo: null,
timeline: [],
+ writtedMessage: "",
}
- joinSocketRoom = () => {
+ timelineRef = React.createRef()
+
+ joinSocketRoom = async () => {
+ await this.setState({ connecting: true })
+
const { roomId } = this.props
const socketNamespace = `/textRoom/${roomId}`
console.log(`Joining socket room [${socketNamespace}]`)
- const socket = app.api.namespaces.main.wsInterface.manager.socket(socketNamespace)
+ const socket = io(config.remotes.messagingApi, {
+ transports: ["websocket"],
+ autoConnect: false,
+ })
- socket.connect()
+ socket.auth = {
+ token: SessionModel.token,
+ }
- console.log("Socket", socket)
+ socket.on("connect_error", (err) => {
+ console.error("Connection error", err)
+
+ this.setState({ connectionEnd: true })
+
+ if (err.message === "auth:token_invalid") {
+ console.error("Invalid token")
+ }
+ })
socket.on("connect", () => {
- console.log("Socket connected")
+ socket.emit("join", { room: socketNamespace }, (error, info) => {
+ if (error) {
+ this.setState({ connectionEnd: true })
+ return console.error("Error joining room", error)
+ }
- socket.on("message", (data) => {
- console.log("Message received", data)
+ this.setState({
+ connecting: false,
+ roomInfo: info,
+ })
})
})
+ socket.on("message", (message) => {
+ this.pushToTimeline(message)
+ this.scrollTimelineToBottom()
+ })
+
+ socket.connect()
+
this.setState({ socket })
}
submitMessage = (message) => {
const { socket } = this.state
- console.log("Sending message", message)
+ socket.emit("send:message", {
+ message
+ })
- socket.emit("message", message)
+ this.scrollTimelineToBottom()
+
+ // remove writted message
+ this.setState({
+ writtedMessage: ""
+ })
+ }
+
+ pushToTimeline = (message) => {
+ const { timeline } = this.state
+
+ this.setState({
+ timeline: [...timeline, message]
+ })
+ }
+
+ handleInputChange = (e) => {
+ this.setState({
+ writtedMessage: e.target.value
+ })
+ }
+
+ handleOnEnter = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+
+ if (e.target.value.length === 0) {
+ return
+ }
+
+ this.submitMessage(e.target.value)
+ }
+
+ scrollTimelineToBottom = () => {
+ // scroll to bottom smoothly
+ this.timelineRef.current.scrollTo({
+ top: this.timelineRef.current.scrollHeight,
+ behavior: "smooth"
+ })
}
componentDidMount = async () => {
@@ -58,21 +140,52 @@ export default class LiveChat extends React.Component {
}
render() {
- return
- {this.state.timeline.map((line, index) =>
)}
+ if (this.state.connectionEnd) {
+ return
+ }
-
+ if (this.state.connecting) {
+ return
+ }
+
+ return
+ {
+ this.state.timeline.length === 0 ?
+
:
+
+ {
+ this.state.timeline.map((line, index) => {
+ return
+ })
+ }
+
+ }
+
+
{
- e.preventDefault()
- e.stopPropagation()
-
- console.log("Enter pressed", e.target.value)
-
- this.submitMessage(e.target.value)
- }}
+ value={this.state.writtedMessage}
+ onChange={this.handleInputChange}
+ onPressEnter={this.handleOnEnter}
+ maxLength={this.state.roomInfo?.limitations?.maxMessageLength ?? 100}
+ showCount
/>
diff --git a/packages/app/src/components/LiveChat/index.less b/packages/app/src/components/LiveChat/index.less
index 1306152b..43d6ddd6 100644
--- a/packages/app/src/components/LiveChat/index.less
+++ b/packages/app/src/components/LiveChat/index.less
@@ -1,18 +1,82 @@
.liveChat {
+ position: relative;
+
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
- position: relative;
+ overflow: hidden;
- .textInput {
+ &.empty {
+ justify-content: center;
+ align-items: center;
+ }
+
+ .liveChat_timeline {
+ height: 100%;
+ overflow-y: scroll;
+
+ margin-bottom: 70px;
+ }
+
+ .liveChat_textInput {
position: absolute;
bottom: 0;
left: 0;
+ margin-bottom: 20px;
+
width: 100%;
height: fit-content;
+
+ color: var(--text-color);
+
+ .ant-input-textarea-show-count::after {
+ color: var(--text-color);
+ }
+ }
+}
+
+.textRoom_line {
+ display: flex;
+ flex-direction: column;
+
+ padding: 5px 10px;
+ margin-bottom: 10px;
+
+ border-radius: 12px;
+
+ background-color: var(--background-color-accent);
+
+ h1,
+ h2,
+ h3,
+ h4,
+ span {
+ margin: 0;
+ user-select: text;
+ }
+
+ .textRoom_line_user {
+ font-weight: bold;
+ font-size: 1rem;
+ color: var(--background-color-contrast);
+
+ overflow: hidden;
+
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .textRoom_line_content {
+ font-size: 0.8rem;
+ color: var(--text-color);
+
+ padding: 0 10px;
+
+ word-break: break-all;
+ white-space: pre-wrap;
}
}
\ No newline at end of file