From 0e6f9d885baea0fac1b80667b64b982672b64f5b Mon Sep 17 00:00:00 2001 From: Simon Huang Date: Fri, 2 Oct 2020 21:11:33 -0400 Subject: [PATCH] added 'join room' option --- src/components/Messages.css | 4 +++ src/pages/Home.css | 35 +++++++++++++++--- src/pages/Home.tsx | 71 ++++++++++++++++++++++++++++++++++--- src/pages/Room.tsx | 7 ++-- src/services/utilities.ts | 8 +++++ 5 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/components/Messages.css b/src/components/Messages.css index 6fa4ad0..a4028cc 100644 --- a/src/components/Messages.css +++ b/src/components/Messages.css @@ -40,6 +40,10 @@ padding-top: 5px; } +ion-footer ion-toolbar:last-of-type { + padding-bottom: 10px; +} + .message-input { width: 100%; height: 100%; diff --git a/src/pages/Home.css b/src/pages/Home.css index ef8971f..64d425c 100644 --- a/src/pages/Home.css +++ b/src/pages/Home.css @@ -24,15 +24,42 @@ ion-title { } .first-step-col { - margin-top: 20%; - margin-bottom: 10px; + margin-top: 15%; } .create-col { - margin-bottom: 50px; + margin-bottom: 20px; } .share-col { - margin-top: 8px; + margin-top: 2px; font-size: 20px; + margin-bottom: 50px; +} + +.join-col { + font-size: 20px; +} + +.paste-col { + padding: 0; +} + +.paste-toolbar { + max-width: 300px; + --background: none; + margin: auto; +} + +.paste-input { + margin-left: 2px; + text-align: left; + font-size: 14px; + border: 1px solid var(--ion-color-secondary); + border-radius: 5px; +} + +.paste-button { + margin-right: 2px; + --box-shadow: 0 3px 2px -1px rgba(0, 0, 0, 0.2), 0 2px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 5e73cd7..d408ef7 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,13 +1,29 @@ -import { IonButton, IonContent, IonGrid, IonHeader, IonPage, IonRow, IonTitle, IonToolbar, IonCol } from '@ionic/react'; +import { + IonButton, + IonCol, + IonContent, + IonFabButton, + IonGrid, + IonHeader, + IonIcon, + IonInput, + IonPage, + IonRow, + IonTitle, + IonToolbar, +} from '@ionic/react'; +import { enterOutline } from 'ionicons/icons'; import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router'; import { auth, db, rtdb, timestamp } from '../services/firebase'; -import { generateAnonName } from '../services/utilities'; +import { generateAnonName, matchRoomUrl } from '../services/utilities'; import './Home.css'; const Home: React.FC = () => { const [loading, setLoading] = useState(true); const [userId, setUserId] = useState(''); + const [roomLink, setRoomLink] = useState(''); + const [valid, setValid] = useState(true); let history = useHistory(); @@ -30,7 +46,7 @@ const Home: React.FC = () => { }; }, []); - // Populate both Firestore and RealTimeDB before navigating to room + // Populate both Firestore and RealTimeDB before navigating to room on create const createRoom = async () => { // Firestore preparations const roomId = await db.collection('rooms').add({ @@ -53,7 +69,25 @@ const Home: React.FC = () => { await rtdb.ref('/available/' + roomId.id).set({ name: 'Room Name', createdAt: new Date().toISOString() }); const path = '/room/' + roomId.id; - return history.push(path); + return history.push(path); // Navigate to room + }; + + const showError = () => { + return
Invalid link
; + }; + + // Validate URL and join the room + const joinRoom = async () => { + if (matchRoomUrl(roomLink)) { + const roomId = roomLink.split('/')[roomLink.split('/').length - 1]; + const doc = await db.collection('rooms').doc(roomId).get(); + if (doc.exists) { + setValid(true); + return history.push('/room/' + roomId); + } + } + + setValid(false); }; return ( @@ -88,6 +122,35 @@ const Home: React.FC = () => { Share the link with friends! + + OR + + + + Join a room: + + + + + + setRoomLink(e.detail.value!)} + placeholder="Paste room link" + class="paste-input" + > + + + + + {valid ? <> : showError()} + + )} diff --git a/src/pages/Room.tsx b/src/pages/Room.tsx index 6b4dff8..0175577 100644 --- a/src/pages/Room.tsx +++ b/src/pages/Room.tsx @@ -2,8 +2,8 @@ import { IonCol, IonContent, IonGrid, IonHeader, IonPage, IonRow } from '@ionic/ import React, { useEffect, useState } from 'react'; import { RouteComponentProps, useHistory } from 'react-router'; import Frame from '../components/Frame'; -import RoomHeader from '../components/RoomHeader'; import VideoPlayer from '../components/Player/VideoPlayer'; +import RoomHeader from '../components/RoomHeader'; import { auth, db, decrement, increment, rtdb } from '../services/firebase'; import { generateAnonName } from '../services/utilities'; import './Room.css'; @@ -83,12 +83,13 @@ const Room: React.FC> = ({ match }) => { } }); - // Manage user count + // Manage user count and maintain room availability rtdb.ref('.info/connected').on('value', async (snapshot) => { if (snapshot.val() === true) { try { await roomRef.update({ userCount: increment }); - await roomRef.onDisconnect().update({ userCount: decrement }); + roomRef.onDisconnect().update({ userCount: decrement }); + availableRef.child(roomId).set({ name: 'Room Name', createdAt: new Date().toISOString() }); } catch (err) { console.log(err); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 9f42b86..0583b4c 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -88,6 +88,7 @@ const animals = [ // MATCH_URL_VIDYARD: /vidyard.com\/(?:watch\/)?([a-zA-Z0-9-]+)/, // }; +const MATCH_URL_ROOM = /((^(http:\/\/)?localhost:3000)|(^(https?:\/\/(www\.)?)?turtletv\.app))\/room\/([-a-zA-Z0-9]*)/; const MATCH_URL_NETFLIX = /https?:\/\/(www\.)?netflix\.com\/watch\/([-a-zA-Z0-9()@:%_+.~#?&//=]*)/; export const matchUrl = (url: string) => { @@ -98,6 +99,13 @@ export const matchUrl = (url: string) => { } }; +export const matchRoomUrl = (url: string) => { + if (url.match(MATCH_URL_ROOM)) { + return true; + } + return false; +}; + export const generateAnonName = (): string => { const adj: string = adjectives[Math.floor(Math.random() * 40)]; const animal: string = animals[Math.floor(Math.random() * 30)];