added ionic segment

pull/3/head
Simon Huang 5 years ago
parent 4052296a19
commit 9abcfd4015

@ -1,5 +1,5 @@
import React from 'react';
import { Route } from 'react-router-dom';
import { Route } from 'react-router';
import { IonApp, IonRouterOutlet } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Home from './pages/Home';

@ -1,52 +0,0 @@
ion-textarea {
border: solid 1px #999;
}
.chat-card {
background: var(--ion-color-light);
height: 100%;
width: 100%;
float: right;
margin: 0;
}
.message-toolbar {
padding-left: 5px;
--background: var(--ion-color-light);
}
.footer-ios ion-toolbar:first-of-type {
padding-top: 5px;
}
.send-msg {
padding-left: 0;
}
.send-button {
align-self: center;
margin: 0 2px 0 5px;
--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);
}
.message-input {
width: 100%;
height: 100%;
border: 1px solid #999;
border-radius: 5px;
text-align: left;
}
@media (max-width: 576px) {
.message-input {
border-radius: 10px;
}
.send-msg {
display: none;
}
.native-input.sc-ion-input-ios {
padding-inline-start: 5px;
}
}

@ -1,62 +0,0 @@
import { IonCard, IonFabButton, IonFooter, IonIcon, IonInput, IonToolbar } from '@ionic/react';
import { sendOutline } from 'ionicons/icons';
import React, { useState } from 'react';
import { rtdb } from '../services/firebase';
import './Chatbox.css';
import Messages from './Messages';
import OnlineList from './OnlineList';
type ChatboxProps = {
ownerId: string;
roomId: string;
userId: string;
userList: Map<string, string>;
};
const Chat: React.FC<ChatboxProps> = ({ ownerId, roomId, userId, userList }) => {
const [message, setMessage] = useState(''); // Message to be sent
// Send message to database
const sendMessage = async () => {
if (message !== '') {
await rtdb.ref('/chats/' + roomId).push({
content: message,
createdAt: Date.now(),
senderId: userId,
});
// Reset textarea field
setMessage('');
}
};
const onEnter = (e: React.KeyboardEvent<HTMLIonInputElement>) => {
if (e.key === 'Enter') {
sendMessage();
}
};
return (
<IonCard class="chat-card">
<Messages ownerId={ownerId} roomId={roomId} userId={userId} userList={userList}></Messages>
<IonFooter>
<IonToolbar class="message-toolbar">
<IonInput
onIonChange={(e) => setMessage(e.detail.value!)}
onKeyDown={(e) => onEnter(e)}
value={message}
placeholder="Send message"
enterkeyhint="send"
class="message-input"
></IonInput>
<IonFabButton slot="end" size="small" onClick={sendMessage} class="send-button">
<IonIcon icon={sendOutline}></IonIcon>
</IonFabButton>
<OnlineList userList={userList}></OnlineList>
</IonToolbar>
</IonFooter>
</IonCard>
);
};
export default Chat;

@ -0,0 +1,12 @@
.frame-card {
background: var(--ion-color-light);
height: 100%;
width: 100%;
float: right;
margin: 0;
}
ion-segment-button {
--indicator-transition: transform 100ms cubic-bezier(0.4, 0, 0.2, 1);
max-height: 40px;
}

@ -0,0 +1,38 @@
import { IonCard, IonIcon, IonSegment, IonSegmentButton } from '@ionic/react';
import { chatboxOutline, informationCircleOutline, peopleOutline } from 'ionicons/icons';
import React, { useState } from 'react';
import './Frame.css';
import Messages from './Messages';
import OnlineList from './OnlineList';
type FrameProps = {
ownerId: string;
roomId: string;
userId: string;
userList: Map<string, string>;
};
const Frame: React.FC<FrameProps> = ({ ownerId, roomId, userId, userList }) => {
const [pane, setPane] = useState('chat');
return (
<IonCard class="frame-card">
<IonSegment value={pane}>
<IonSegmentButton value="chat" onClick={() => setPane('chat')}>
<IonIcon icon={chatboxOutline}></IonIcon>
</IonSegmentButton>
<IonSegmentButton value="online" onClick={() => setPane('online')}>
<IonIcon icon={peopleOutline}></IonIcon>
</IonSegmentButton>
<IonSegmentButton value="about" onClick={() => setPane('about')}>
<IonIcon icon={informationCircleOutline}></IonIcon>
</IonSegmentButton>
</IonSegment>
<Messages pane={pane} ownerId={ownerId} roomId={roomId} userId={userId} userList={userList}></Messages>
<OnlineList pane={pane} userList={userList}></OnlineList>
</IonCard>
);
};
export default Frame;

@ -1,6 +1,6 @@
.message-card {
.message-content {
overflow-y: auto;
height: calc(100% - 125px);
height: calc(100% - 160px);
padding: 0;
}
@ -31,3 +31,40 @@
background: var(--ion-color-secondary);
color: #fff;
}
.message-toolbar {
padding-left: 5px;
--background: var(--ion-color-light);
}
.footer-ios ion-toolbar:first-of-type {
padding-top: 5px;
}
ion-textarea {
border: solid 1px #999;
}
.message-input {
width: 100%;
height: 100%;
border: 1px solid #999;
border-radius: 5px;
text-align: left;
}
.send-button {
align-self: center;
margin: 0 5px 0 5px;
--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);
}
@media (max-width: 576px) {
.message-input {
border-radius: 10px;
}
.native-input.sc-ion-input-ios {
padding-inline-start: 5px;
}
}

@ -1,10 +1,22 @@
import { IonCol, IonContent, IonGrid, IonRow } from '@ionic/react';
import {
IonCol,
IonContent,
IonFabButton,
IonFooter,
IonGrid,
IonIcon,
IonInput,
IonRow,
IonToolbar,
} from '@ionic/react';
import { sendOutline } from 'ionicons/icons';
import React, { useEffect, useRef, useState } from 'react';
import { db, arrayUnion, rtdb } from '../services/firebase';
import './Messages.css';
import { arrayUnion, db, rtdb } from '../services/firebase';
import { secondsToTimestamp } from '../services/utilities';
import './Messages.css';
type MessagesProps = {
pane: string;
ownerId: string;
roomId: string;
userId: string;
@ -18,12 +30,13 @@ type Message = {
senderId: string;
};
const Messages: React.FC<MessagesProps> = ({ ownerId, roomId, userId, userList }) => {
const Messages: React.FC<MessagesProps> = ({ pane, ownerId, roomId, userId, userList }) => {
const [joinTime] = useState(Date.now()); // Time at mounting of the component
const [chats, setChats] = useState<Message[]>([]); // All processed chat messages
const [systemMessages, setSystemMessages] = useState<Message[]>([]); // All processed system messages
const [allMessages, setAllMessages] = useState<Message[]>([]); // Combined array of chat and system messages
const [userHistory] = useState<Map<string, string>>(new Map<string, string>()); // All users who are/were in the room
const [message, setMessage] = useState(''); // Message to be sent
const contentRef = useRef<HTMLIonContentElement>(null);
// Send 'joined room' message on component mount
@ -41,12 +54,14 @@ const Messages: React.FC<MessagesProps> = ({ ownerId, roomId, userId, userList }
let arr: Message[] = [];
snapshot.forEach((child) => {
const msg = child.val();
arr.push({
content: msg.content,
createdAt: msg.createdAt,
id: msg.senderId + msg.createdAt,
senderId: msg.senderId,
});
if (msg.createdAt > joinTime) {
arr.push({
content: msg.content,
createdAt: msg.createdAt,
id: msg.senderId + msg.createdAt,
senderId: msg.senderId,
});
}
});
setChats(arr);
});
@ -133,6 +148,26 @@ const Messages: React.FC<MessagesProps> = ({ ownerId, roomId, userId, userList }
return name;
};
// Send message to database
const sendMessage = async () => {
if (message !== '') {
await rtdb.ref('/chats/' + roomId).push({
content: message,
createdAt: Date.now(),
senderId: userId,
});
// Reset textarea field
setMessage('');
}
};
const onEnter = (e: React.KeyboardEvent<HTMLIonInputElement>) => {
if (e.key === 'Enter') {
sendMessage();
}
};
const renderMessages = () => {
return allMessages
.sort((msg1, msg2) => msg1.createdAt - msg2.createdAt)
@ -153,9 +188,26 @@ const Messages: React.FC<MessagesProps> = ({ ownerId, roomId, userId, userList }
};
return (
<IonContent class="message-card" ref={contentRef}>
<IonGrid class="message-grid">{userList.size === 0 ? <span>Loading...</span> : renderMessages()}</IonGrid>
</IonContent>
<>
<IonContent style={{ display: pane === 'chat' ? null : 'none' }} class="message-content" ref={contentRef}>
<IonGrid class="message-grid">{userList.size === 0 ? <span>Loading...</span> : renderMessages()}</IonGrid>
</IonContent>
<IonFooter style={{ display: pane === 'chat' ? null : 'none' }}>
<IonToolbar class="message-toolbar">
<IonInput
onIonChange={(e) => setMessage(e.detail.value!)}
onKeyDown={(e) => onEnter(e)}
value={message}
placeholder="Send message"
enterkeyhint="send"
class="message-input"
></IonInput>
<IonFabButton slot="end" size="small" onClick={sendMessage} class="send-button">
<IonIcon icon={sendOutline}></IonIcon>
</IonFabButton>
</IonToolbar>
</IonFooter>
</>
);
};

@ -1,22 +1,16 @@
.online-button {
margin: 0 4px 0 0;
align-self: center;
--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);
.online-content {
height: calc(100% - 160px);
padding: 0;
}
.popover-list {
.online-list {
padding-top: 2px;
}
.list-header {
font-size: 24px;
color: var(--ion-color-primary);
border-bottom: 1px solid #999;
}
.online-item {
--padding-start: 12px;
--min-height: 0;
color: var(--ion-color-primary);
}
.online-label {

@ -1,47 +1,25 @@
import React, { useState } from 'react';
import { IonPopover, IonFabButton, IonIcon, IonList, IonListHeader, IonItem, IonLabel } from '@ionic/react';
import { peopleOutline } from 'ionicons/icons';
import { IonContent, IonItem, IonLabel, IonList } from '@ionic/react';
import React from 'react';
import './OnlineList.css';
type OnlineListProps = {
pane: string;
userList: Map<string, string>;
};
const OnlineList: React.FC<OnlineListProps> = ({ userList }) => {
const [showPopover, setShowPopover] = useState<{ open: boolean; event: Event | undefined }>({
open: false,
event: undefined,
});
const OnlineList: React.FC<OnlineListProps> = ({ pane, userList }) => {
return (
<>
<IonPopover
cssClass="online-popover"
isOpen={showPopover.open}
event={showPopover.event}
showBackdrop={false}
onDidDismiss={(e) => setShowPopover({ open: false, event: undefined })}
>
<IonList class="popover-list">
<IonListHeader class="list-header">Online</IonListHeader>
{Array.from(userList.values()).map((user) => {
return (
<IonItem key={user} class="online-item" lines="none">
<IonLabel class="online-label">{user}</IonLabel>
</IonItem>
);
})}
</IonList>
</IonPopover>
<IonFabButton
slot="end"
size="small"
class="online-button"
onClick={(e) => setShowPopover({ open: true, event: e.nativeEvent })}
>
<IonIcon icon={peopleOutline}></IonIcon>
</IonFabButton>
</>
<IonContent style={{ display: pane === 'online' ? null : 'none' }} class="online-content">
<IonList class="online-list">
{Array.from(userList.values()).map((user) => {
return (
<IonItem key={user} class="online-item" lines="none">
<IonLabel class="online-label">{user}</IonLabel>
</IonItem>
);
})}
</IonList>
</IonContent>
);
};

@ -22,7 +22,7 @@ const Home: React.FC = () => {
});
await db.collection('playlists').doc(roomId.id).set({
createdAt: timestamp,
url: 'https://www.youtube.com/watch?v=XEfDYMngJeE',
url: 'https://www.youtube.com/watch?v=DGQwd1_dpuc',
});
await db.collection('states').doc(roomId.id).set({
isPlaying: false,
@ -32,7 +32,6 @@ const Home: React.FC = () => {
// RealTimeDB preparations
await rtdb.ref('/rooms/' + roomId.id).set({ userCount: 0 });
await rtdb.ref('/available/' + roomId.id).set({ name: 'Room Name', createdAt: new Date().toISOString() });
await rtdb.ref('/chats/' + roomId.id).push({ content: 'created a room.', createdAt: Date.now(), senderId: userId });
const path = '/room/' + roomId.id;
return history.push(path);

@ -23,12 +23,12 @@
height: 100%;
}
.chat-col {
.frame-col {
padding: 0;
}
@media (max-width: 992px) {
.chat-col {
.frame-col {
height: 65%;
}
}

@ -1,7 +1,7 @@
import { IonCol, IonContent, IonGrid, IonHeader, IonPage, IonRow } from '@ionic/react';
import React, { useEffect, useState } from 'react';
import { RouteComponentProps, useHistory } from 'react-router';
import Chat from '../components/Chatbox';
import Frame from '../components/Frame';
import RoomHeader from '../components/RoomHeader';
import VideoPlayer from '../components/VideoPlayer';
import { auth, db, decrement, increment, rtdb } from '../services/firebase';
@ -155,8 +155,8 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
<IonCol size="12" sizeLg="9" class="player-col">
<VideoPlayer ownerId={ownerId} userId={userId} roomId={roomId}></VideoPlayer>
</IonCol>
<IonCol size="12" sizeLg="3" class="chat-col">
<Chat ownerId={ownerId} roomId={roomId} userId={userId} userList={userList}></Chat>
<IonCol size="12" sizeLg="3" class="frame-col">
<Frame ownerId={ownerId} roomId={roomId} userId={userId} userList={userList}></Frame>
</IonCol>
</IonRow>
</IonGrid>

Loading…
Cancel
Save