Skip to content

Commit fff6699

Browse files
committed
Add ability to link to youtube videos and show embedded video in chat
1 parent cd097ff commit fff6699

File tree

6 files changed

+103
-9
lines changed

6 files changed

+103
-9
lines changed

streams-react/src/components/ChatContainer/ChatContainer.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import {ChatContext} from "../../context/ChatContext";
44
import styles from "./ChatContainer.module.css";
55

66
const ChatContainer = () => {
7-
const {isChatOpen, setIsChatOpen, setChatDimensions} = useContext(ChatContext);
7+
const {isChatOpen, setIsChatOpen, chatDimensions, setChatDimensions} = useContext(ChatContext);
88
const containerRef = useRef(null);
99

1010
useEffect(() => {
1111
const handleResize = () => {
1212
const width = containerRef.current.getBoundingClientRect()?.width;
1313

14-
setChatDimensions(dimensions => ({...dimensions, width}));
14+
if(width !== chatDimensions.width) {
15+
setChatDimensions(dimensions => ({...dimensions, width}));
16+
}
1517
};
1618

1719
window.addEventListener("resize", handleResize);
@@ -20,7 +22,19 @@ const ChatContainer = () => {
2022
return () => {
2123
window.removeEventListener("resize", handleResize);
2224
};
23-
}, [setChatDimensions]);
25+
}, [chatDimensions, setChatDimensions]);
26+
27+
useEffect(() => {
28+
if(!isChatOpen) handleVideosReset();
29+
}, [isChatOpen]);
30+
31+
const handleVideosReset = () => {
32+
let videos = document.querySelectorAll(".embedded__video");
33+
if(!videos.length) return;
34+
videos.forEach(video => {
35+
video.contentWindow.postMessage(`{"event":"command","func":"stopVideo","args":""}`, "*");
36+
});
37+
};
2438

2539
const handleClick = () => {
2640
setIsChatOpen(!isChatOpen);

streams-react/src/components/ChatMessages/ChatMessages.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {useRef, useContext, useEffect} from "react";
22
import ChatUser from "../ChatUser/ChatUser";
33
import {ChatContext} from "../../context/ChatContext";
4-
import {v4 as uuidv4} from "uuid";
54
import styles from "./ChatMessages.module.css";
65

76
const ChatMessages = () => {
@@ -67,16 +66,19 @@ const ChatMessages = () => {
6766
let newMessages = [];
6867
let currentUser = messages[0];
6968
currentUser.message = [currentUser.message];
69+
currentUser.id = [currentUser.id];
7070

7171
for(let i = 1; i < messages.length; i++) {
7272
if(!Array.isArray(currentUser.message)) currentUser.message = [currentUser.message];
7373
if(messages[i].streamID === currentUser.streamID) {
7474
currentUser.message = [...currentUser.message, messages[i].message];
75+
currentUser.id = [...currentUser.id, messages[i].id];
7576
}
7677
else {
7778
newMessages.push(currentUser);
7879
currentUser = messages[i];
7980
currentUser.message = [currentUser.message];
81+
currentUser.id = [currentUser.id];
8082
}
8183
}
8284

@@ -87,7 +89,7 @@ const ChatMessages = () => {
8789
const renderMessages = () => {
8890
const messages = combineMessages(messageList);
8991
return messages.map((msg)=> {
90-
return <ChatUser key={uuidv4()} messageData={msg} />;
92+
return <ChatUser key={msg.id[0]} messageData={msg} />;
9193
});
9294
};
9395

streams-react/src/components/ChatMessages/ChatMessages.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
flex: 1;
33
width: 100%;
44
overflow-y: auto;
5+
overflow-x: hidden;
56
}
67
.header {
78
display: flex;

streams-react/src/components/ChatUser/ChatUser.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import Identicon from "../Identicon/Identicon";
22
import ChatUserHeader from "../ChatUserHeader/ChatUserHeader";
33
import ChatUserMessage from "../ChatUserMessage/ChatUserMessage";
4-
import {v4 as uuidv4} from "uuid";
54
import styles from "./ChatUser.module.css";
65

76
const ChatUser = ({messageData}) => {
87

98
const renderMessage = () => {
10-
return messageData.message.map((message) => {
11-
return <ChatUserMessage key={uuidv4()} message={message} />
9+
return messageData.message.map((message, i) => {
10+
return <ChatUserMessage key={messageData.id[i]} message={message} />
1211
});
1312
};
1413

streams-react/src/components/ChatUserMessage/ChatUserMessage.js

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,70 @@
1+
import {useState, useEffect} from "react";
12
import styles from "./ChatUserMessage.module.css";
23

34
const ChatUserMessage = ({message}) => {
5+
const [hasURL, setHasURL] = useState(false);
6+
const [srcURL, setSrcURL] = useState("");
7+
const [messageURL, setMessageURL] = useState("");
8+
9+
useEffect(() => {
10+
const checkMessagesForURL = () => {
11+
let regExp = null;
12+
let match = null;
13+
// https://stackoverflow.com/questions/28735459/how-to-validate-youtube-url-in-client-side-in-text-box
14+
if (message !== undefined || message !== "") {
15+
regExp = /^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
16+
}
17+
let messages = message.replace(/\n/g, " ").split(" ");
18+
for(const value of messages) {
19+
match = value.match(regExp);
20+
if(match && match[1].length === 11) {
21+
setHasURL(true);
22+
setMessageURL(match[0]);
23+
setSrcURL(match[1]);
24+
return;
25+
}
26+
}
27+
};
28+
29+
if(message.length) {
30+
checkMessagesForURL();
31+
}
32+
}, [message]);
33+
34+
const handleStringToURL = () => {
35+
if(!hasURL) return message;
36+
37+
let newMessage = message;
38+
let startIndex = message.indexOf(messageURL);
39+
let beginningString = newMessage.slice(0, startIndex);
40+
let link = <a href={messageURL}>{messageURL}</a>;
41+
let endString = newMessage.substring(startIndex + messageURL.length);
42+
newMessage = beginningString + link + endString;
43+
return (
44+
<>
45+
{beginningString}
46+
<a href={messageURL} className={styles.link} target="_blank" rel="noopener noreferrer" >{messageURL}</a>
47+
{endString}
48+
</>
49+
);
50+
};
51+
452
return (
553
<div className={styles.container}>
6-
<p className={styles.message}>{message}</p>
54+
<p className={styles.message}>{handleStringToURL()}</p>
55+
{hasURL &&
56+
<div className={styles.iframe__container}>
57+
<iframe
58+
className={`embedded__video ${styles.iframe}`}
59+
title="video"
60+
type="text/html"
61+
frameBorder="0"
62+
height="200"
63+
allowFullScreen
64+
src={`https://www.youtube.com/embed/${srcURL}?autoplay=1&enablejsapi=1&rel=0&version=3`}
65+
></iframe>
66+
</div>
67+
}
768
</div>
869
);
970
};

streams-react/src/components/ChatUserMessage/ChatUserMessage.module.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,21 @@
99
padding: 5px;
1010
white-space: pre-wrap;
1111
overflow-wrap: break-word;
12+
}
13+
.link {
14+
color: #2962FF;
15+
text-decoration: underline;
16+
}
17+
.link:hover {
18+
color: #0091EA;
19+
}
20+
.iframe__container {
21+
display: flex;
22+
justify-content: center;
23+
align-items: center;
24+
padding: 5px;
25+
width: 100%;
26+
}
27+
iframe {
28+
width: 100%;
1229
}

0 commit comments

Comments
 (0)