add functions, create and join room
This commit is contained in:
+65
@@ -0,0 +1,65 @@
|
||||
import React, { Component } from 'react';
|
||||
import firebase from 'firebase/app';
|
||||
import Chat from './Chat';
|
||||
import Create from './Create';
|
||||
import Loading from './Loading';
|
||||
|
||||
export default class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: false,
|
||||
loggedIn: false,
|
||||
page: 'create',
|
||||
};
|
||||
this.updateLoading = this.updateLoading.bind(this);
|
||||
this.changePage = this.changePage.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
firebase.auth().onAuthStateChanged(user => {
|
||||
const roomId = window.localStorage.getItem('roomId');
|
||||
if (user) {
|
||||
this.setState({
|
||||
loggedIn: true,
|
||||
});
|
||||
if (roomId)
|
||||
this.setState({
|
||||
page: 'chat',
|
||||
});
|
||||
} else {
|
||||
if (roomId) {
|
||||
window.localStorage.removeItem('roomId');
|
||||
window.localStorage.removeItem('watchPartyUserName');
|
||||
window.localStorage.removeItem('watchPartyUser');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
changePage(page) {
|
||||
this.setState({
|
||||
page,
|
||||
});
|
||||
}
|
||||
updateLoading(loading) {
|
||||
this.setState({
|
||||
loading,
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const { loading, loggedIn, page } = this.state;
|
||||
return (
|
||||
<div className="party-content-wrapper">
|
||||
{loading && <Loading />}
|
||||
{page === 'chat' ? (
|
||||
<Chat changePage={this.changePage} updateLoading={this.updateLoading} />
|
||||
) : page === 'create' ? (
|
||||
<Create
|
||||
changePage={this.changePage}
|
||||
loggedIn={loggedIn}
|
||||
updateLoading={this.updateLoading}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Typography, Input, message } from 'antd';
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/firestore';
|
||||
import { RightCircleFilled } from '@ant-design/icons';
|
||||
import Thread from './Thread';
|
||||
|
||||
export default class Chat extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
messages: []
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
firebase.firestore()
|
||||
.collection('rooms')
|
||||
.doc(window.localStorage.getItem('roomId'))
|
||||
.onSnapshot(snap => {
|
||||
this.setState(snap.data());
|
||||
}, err => {
|
||||
this.props.updateLoading(true);
|
||||
if (err.code === 'permission-denied') {
|
||||
message.error('Couldn\'t join old party');
|
||||
this.props.changePage('create');
|
||||
this.props.updateLoading(false);
|
||||
}
|
||||
})
|
||||
firebase.firestore()
|
||||
.collection('rooms')
|
||||
.doc(window.localStorage.getItem('roomId'))
|
||||
.collection('messages')
|
||||
.onSnapshot(snap => {
|
||||
this.setState({messages: snap.docs.map(v => ({ ...v.data(), id: v.id}) )});
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const {messages, name} = this.state;
|
||||
return (
|
||||
<div className="content__wrapper">
|
||||
<div>
|
||||
<Typography.Title level={3}>{name}</Typography.Title>
|
||||
<Typography.Text underline>Watch Party</Typography.Text>
|
||||
</div>
|
||||
<div className="party_chat_container">
|
||||
<Thread messages={messages} />
|
||||
</div>
|
||||
<div className="party_chat_input">
|
||||
<Input.TextArea
|
||||
autoSize={{
|
||||
maxRows:3,
|
||||
minRows:1,
|
||||
}}
|
||||
id="chat_input"
|
||||
placeholder="Begin typing..."
|
||||
/>
|
||||
<RightCircleFilled id="chat_send" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
import React, { useState } from 'react';
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/auth';
|
||||
import { Button, Input, Divider, Typography, message } from 'antd';
|
||||
import { PlusCircleFilled, PlayCircleFilled } from '@ant-design/icons';
|
||||
|
||||
const login = async () => firebase.auth().signInAnonymously();
|
||||
|
||||
const Create = props => {
|
||||
const [userName, setUserName] = useState(window.localStorage.getItem('watchPartyUserName') || '');
|
||||
const [roomName, setRoomName] = useState('');
|
||||
const [roomCode, setRoomCode] = useState(window.localStorage.getItem('roomId') || '');
|
||||
|
||||
const requestCreateRoom = async () => {
|
||||
props.updateLoading(true);
|
||||
if (userName === '') {
|
||||
message.error('You forgot your name');
|
||||
props.updateLoading(false);
|
||||
return;
|
||||
}
|
||||
if (roomName === '') {
|
||||
message.error('You forgot to give a party name');
|
||||
props.updateLoading(false);
|
||||
return;
|
||||
}
|
||||
if (!props.loggedIn) await login();
|
||||
firebase
|
||||
.auth()
|
||||
.currentUser.getIdToken()
|
||||
.then(idToken => {
|
||||
fetch('http://localhost:5001/watch-party-crx/us-central1/widgets/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Token ${idToken}:${firebase.auth().currentUser.uid}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
roomName,
|
||||
userName,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
res.roomId && window.localStorage.setItem('roomId', res.roomId);
|
||||
window.localStorage.setItem('watchPartyUserName', userName);
|
||||
window.localStorage.setItem('watchPartyUser', firebase.auth().currentUser.uid);
|
||||
props.changePage('chat');
|
||||
props.updateLoading(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const requestJoinRoom = async () => {
|
||||
props.updateLoading(true);
|
||||
if (userName === '') {
|
||||
message.error('You forgot your name');
|
||||
props.updateLoading(false);
|
||||
return;
|
||||
}
|
||||
if (roomCode === '') {
|
||||
message.error('Please enter a party code');
|
||||
props.updateLoading(false);
|
||||
return;
|
||||
}
|
||||
if (!props.loggedIn) await login();
|
||||
firebase
|
||||
.auth()
|
||||
.currentUser.getIdToken()
|
||||
.then(idToken => {
|
||||
fetch(`http://localhost:5001/watch-party-crx/us-central1/widgets/join`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Token ${idToken}:${firebase.auth().currentUser.uid}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
roomId: roomCode.trim(),
|
||||
userName,
|
||||
}),
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status === 200) return res.json();
|
||||
if (res.status === 404) message.error("That party doesn't exist");
|
||||
return {};
|
||||
})
|
||||
.then(res => {
|
||||
res.roomId && window.localStorage.setItem('roomId', res.roomId);
|
||||
window.localStorage.setItem('watchPartyUserName', userName);
|
||||
window.localStorage.setItem('watchPartyUser', firebase.auth().currentUser.uid);
|
||||
props.changePage('chat');
|
||||
props.updateLoading(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: 20,
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<Typography.Title style={{ position: 'absolute', top: 20, left: 20 }} level={3}>
|
||||
Watch Party
|
||||
</Typography.Title>
|
||||
|
||||
<Input
|
||||
style={{ borderRadius: 23, marginBottom: 15 }}
|
||||
value={userName}
|
||||
onChange={e => setUserName(e.target.value)}
|
||||
placeholder="Your Name"
|
||||
size="large"
|
||||
/>
|
||||
<Divider />
|
||||
<Input
|
||||
style={{ borderRadius: 23, marginBottom: 15 }}
|
||||
value={roomName}
|
||||
onChange={e => setRoomName(e.target.value)}
|
||||
placeholder="Room Name"
|
||||
size="large"
|
||||
/>
|
||||
<Button onClick={requestCreateRoom} block size="large" type="primary" shape="round">
|
||||
<PlusCircleFilled style={{ color: 'white' }} />
|
||||
Start Watch Party
|
||||
</Button>
|
||||
<Divider />
|
||||
<Input
|
||||
style={{ borderRadius: 23, marginBottom: 15 }}
|
||||
value={roomCode}
|
||||
onChange={e => setRoomCode(e.target.value)}
|
||||
placeholder="Room Code"
|
||||
size="large"
|
||||
/>
|
||||
<Button onClick={requestJoinRoom} block size="large" shape="round">
|
||||
<PlayCircleFilled />
|
||||
Join Watch Party
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Create;
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
|
||||
const Loading = () => (
|
||||
<div id="loading_container">
|
||||
<LoadingOutlined />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Loading;
|
||||
@@ -1,19 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import './netflix.css';
|
||||
|
||||
export default class Netflix extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="content__wrapper">
|
||||
<h3>WATCH PARTY</h3>
|
||||
<div className="party_chat_container">CHAT WINDOW HERE</div>
|
||||
<div className="party_chat_input">
|
||||
<textarea
|
||||
placeholder={`Write a message...\nPress Ctrl+Enter to send`}
|
||||
onChange={e => console.log(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.thread-item {
|
||||
width: 100%;
|
||||
}
|
||||
.system-message {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: rgba(100,100,100,0.8) !important;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Typography } from 'antd';
|
||||
import './Thread.css';
|
||||
|
||||
const Thread = props =>
|
||||
props.messages.map(m => {
|
||||
console.log(m);
|
||||
if (m.uid === '<system>') {
|
||||
return <Typography.Text className="thread-item system-message" key={m.id} disabled>{m.text}</Typography.Text>
|
||||
}
|
||||
});
|
||||
|
||||
export default Thread;
|
||||
@@ -0,0 +1,7 @@
|
||||
@import '~antd/dist/antd.css';
|
||||
.party-content-wrapper {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
+19
-8
@@ -1,7 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Netflix from './Netflix';
|
||||
import firebase from 'firebase/app';
|
||||
import 'antd/dist/antd.css';
|
||||
import './netflix.css';
|
||||
import './hulu.css';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: 'AIzaSyCJLuYpzXLDRmu2ttzFuSGmYcpFxqToWFU',
|
||||
@@ -20,17 +24,24 @@ const PartyWrapper = document.createElement('div');
|
||||
PartyWrapper.id = 'party_wrapper';
|
||||
document.body.appendChild(PartyWrapper);
|
||||
|
||||
// STYLINGS
|
||||
if (window.location.href.startsWith('https://www.hulu.com')) {
|
||||
// HULU
|
||||
} else if (window.location.href.startsWith('https://www.netflix.com')) {
|
||||
// NETFLIX
|
||||
PartyWrapper.classList.add('netflix');
|
||||
document.body.classList.add('netflix');
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Netflix />
|
||||
</React.StrictMode>,
|
||||
PartyWrapper
|
||||
);
|
||||
} else if (window.location.href.includes('amazon.com')) {
|
||||
// PRIME VIDEO
|
||||
} else {
|
||||
ReactDOM.render(<div>Watch Party not supported on this site</div>, PartyWrapper);
|
||||
// LOCAL HOST
|
||||
PartyWrapper.classList.add('netflix');
|
||||
document.body.classList.add('netflix');
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
PartyWrapper
|
||||
);
|
||||
|
||||
+42
-11
@@ -25,6 +25,7 @@ body.netflix #appMountPoint {
|
||||
position: relative !important;
|
||||
}
|
||||
#party_wrapper.netflix {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
flex-shrink: 3;
|
||||
flex-basis: 1;
|
||||
@@ -42,15 +43,45 @@ body.netflix #appMountPoint {
|
||||
#party_wrapper.netflix .party_chat_container {
|
||||
flex: 1;
|
||||
}
|
||||
#party_wrapper.netflix .party_chat_input > textarea {
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
height: 4rem;
|
||||
max-height: 4rem;
|
||||
resize: none;
|
||||
color: black;
|
||||
border-radius: 13px;
|
||||
padding: 5px;
|
||||
outline: none;
|
||||
border: none;
|
||||
#party_wrapper.netflix h3{
|
||||
color: white;
|
||||
}
|
||||
.party_chat_input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
.party_chat_input #chat_input {
|
||||
resize: none;
|
||||
max-height: 100px;
|
||||
border-radius: 13px;
|
||||
}
|
||||
.party_chat_input ::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.party_chat_input #chat_send {
|
||||
align-self: flex-end;
|
||||
margin-left: 5px;
|
||||
margin-bottom: 5px;
|
||||
color: white;
|
||||
}
|
||||
.party_chat_input #chat_send svg {
|
||||
height: 1.8rem;
|
||||
width: 1.8rem;
|
||||
}
|
||||
#loading_container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
background-color: rgba(80, 80, 80, 0.9);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
#loading_container svg{
|
||||
color: wheat;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
Reference in New Issue
Block a user