v1.6.0/brand new chat ui

This commit is contained in:
2020-08-03 18:05:08 -04:00
parent 3e7494aef4
commit 9d0cb56cda
6 changed files with 1486 additions and 436 deletions
+1072 -265
View File
File diff suppressed because it is too large Load Diff
+69 -14
View File
@@ -35,6 +35,7 @@ import {
FormControlLabel, FormControlLabel,
Chip, Chip,
CircularProgress, CircularProgress,
Paper,
} from '@material-ui/core'; } from '@material-ui/core';
import Thread from './Thread'; import Thread from './Thread';
import { Carousel } from '@giphy/react-components'; import { Carousel } from '@giphy/react-components';
@@ -70,6 +71,7 @@ import {
Error, Error,
FullscreenExit, FullscreenExit,
Fullscreen, Fullscreen,
CancelRounded,
} from '@material-ui/icons'; } from '@material-ui/icons';
import Create from './Create'; import Create from './Create';
import { goTo } from 'route-lite'; import { goTo } from 'route-lite';
@@ -99,6 +101,7 @@ export default class Chat extends Component {
isFullscreen: document.fullscreen, isFullscreen: document.fullscreen,
allowAutoRejoin: allowAutoRejoin:
LocalData().allowAutoRejoin !== undefined ? LocalData().allowAutoRejoin : true, LocalData().allowAutoRejoin !== undefined ? LocalData().allowAutoRejoin : true,
replyTo: null,
}; };
this.port = null; this.port = null;
this.gifClick = this.gifClick.bind(this); this.gifClick = this.gifClick.bind(this);
@@ -107,9 +110,12 @@ export default class Chat extends Component {
this.leaveParty = this.leaveParty.bind(this); this.leaveParty = this.leaveParty.bind(this);
this.shareParty = this.shareParty.bind(this); this.shareParty = this.shareParty.bind(this);
this.syncPlayer = this.syncPlayer.bind(this); this.syncPlayer = this.syncPlayer.bind(this);
this.setReplyTo = this.setReplyTo.bind(this);
this.sendMessage = this.sendMessage.bind(this); this.sendMessage = this.sendMessage.bind(this);
this.getCarousel = this.getCarousel.bind(this); this.getCarousel = this.getCarousel.bind(this);
this.updateAdminOnly = this.updateAdminOnly.bind(this);
this.handlePhoneCall = this.handlePhoneCall.bind(this); this.handlePhoneCall = this.handlePhoneCall.bind(this);
this.getReplyToContent = this.getReplyToContent.bind(this);
this.callEventListener = this.callEventListener.bind(this); this.callEventListener = this.callEventListener.bind(this);
this.sendMessageInvoker = this.sendMessageInvoker.bind(this); this.sendMessageInvoker = this.sendMessageInvoker.bind(this);
this.videoEventListener = this.videoEventListener.bind(this); this.videoEventListener = this.videoEventListener.bind(this);
@@ -117,7 +123,6 @@ export default class Chat extends Component {
this.updateAllowAutoRejoin = this.updateAllowAutoRejoin.bind(this); this.updateAllowAutoRejoin = this.updateAllowAutoRejoin.bind(this);
this.updateAllowChatNotification = this.updateAllowChatNotification.bind(this); this.updateAllowChatNotification = this.updateAllowChatNotification.bind(this);
this.mCallManager = new CallManager(this.callEventListener, this.props.notify); this.mCallManager = new CallManager(this.callEventListener, this.props.notify);
this.updateAdminOnly = this.updateAdminOnly.bind(this);
} }
componentDidMount() { componentDidMount() {
// EVENT CAPTURE FOR ENTER TO SEND // EVENT CAPTURE FOR ENTER TO SEND
@@ -160,7 +165,7 @@ export default class Chat extends Component {
this.port.postMessage({ this.port.postMessage({
type: 'INIT', type: 'INIT',
roomId: LocalData().partyName, roomId: LocalData().partyName,
roomPin: LocalData().partyPin roomPin: LocalData().partyPin,
}); });
// Listener // Listener
this.port.onMessage.addListener((response) => { this.port.onMessage.addListener((response) => {
@@ -185,7 +190,7 @@ export default class Chat extends Component {
} }
this.setState(response); this.setState(response);
if (response.player) this.mVideoListener.doUpdate(response.player); if (response.player) this.mVideoListener.doUpdate(response.player);
const pcc = document.querySelector('.thread-container'); const pcc = document.querySelector('.thread-wrapper');
if (pcc) pcc.scrollTop = pcc.scrollHeight; if (pcc) pcc.scrollTop = pcc.scrollHeight;
}); });
@@ -235,7 +240,13 @@ export default class Chat extends Component {
const data = { const data = {
partyName: LocalData().partyName, partyName: LocalData().partyName,
}; };
if (this.state.onCall) this.mCallManager.toggleCall(this.state.onCall, this.state.conference, this.state.admin, this.state.adminOnly); if (this.state.onCall)
this.mCallManager.toggleCall(
this.state.onCall,
this.state.conference,
this.state.admin,
this.state.adminOnly
);
DeleteRoomApi(data) DeleteRoomApi(data)
.then((res) => { .then((res) => {
this.props.notify('Ended party'); this.props.notify('Ended party');
@@ -256,7 +267,13 @@ export default class Chat extends Component {
partyName: LocalData().partyName, partyName: LocalData().partyName,
userUid: LocalData().userUid, userUid: LocalData().userUid,
}; };
if (this.state.onCall) this.mCallManager.toggleCall(this.state.onCall, this.state.conference, this.state.admin, this.state.adminOnly); if (this.state.onCall)
this.mCallManager.toggleCall(
this.state.onCall,
this.state.conference,
this.state.admin,
this.state.adminOnly
);
LeaveRoomApi(data) LeaveRoomApi(data)
.then((res) => { .then((res) => {
this.props.notify('Left party'); this.props.notify('Left party');
@@ -291,10 +308,12 @@ export default class Chat extends Component {
type: '', type: '',
}; };
if (this.state.gif === true) data.type = 'giphy'; if (this.state.gif === true) data.type = 'giphy';
if (this.state.replyTo !== null) data.replyTo = this.state.replyTo.id;
SendMessageApi(data).catch((err) => { SendMessageApi(data).catch((err) => {
this.props.notify(err.message || err.statusText); this.props.notify(err.message || err.statusText);
console.error('Send Message API error', err); console.error('Send Message API error', err);
}); });
this.setState({ replyTo: null });
} }
sendMessageInvoker(overrideMessage) { sendMessageInvoker(overrideMessage) {
if (overrideMessage) this.sendMessage(overrideMessage); if (overrideMessage) this.sendMessage(overrideMessage);
@@ -376,6 +395,25 @@ export default class Chat extends Component {
console.error('Update Admin Only API error', err); console.error('Update Admin Only API error', err);
}); });
} }
setReplyTo(message) {
this.setState({
replyTo: message,
});
}
getReplyToContent() {
const { replyTo } = this.state;
if (replyTo) {
if (replyTo.type === 'giphy') {
return <img alt="gif" src={replyTo.text} />;
}
return (
<Typography variant="body2" gutterBottom>
{replyTo.text}
</Typography>
);
}
return null;
}
render() { render() {
const { const {
admin, admin,
@@ -394,6 +432,7 @@ export default class Chat extends Component {
isFullscreen, isFullscreen,
adminModeUpdate, adminModeUpdate,
adminOnly, adminOnly,
replyTo,
} = this.state; } = this.state;
const alerts = [ const alerts = [
{ {
@@ -411,8 +450,8 @@ export default class Chat extends Component {
}, },
{ {
condition: () => adminOnly, condition: () => adminOnly,
message: 'Party is currently in admin only mode.' message: 'Party is currently in admin only mode.',
} },
]; ];
return ( return (
<div className="party-chat-container"> <div className="party-chat-container">
@@ -530,8 +569,7 @@ export default class Chat extends Component {
} }
labelPlacement="end" labelPlacement="end"
/> />
{ {admin ? (
admin ?
<FormControlLabel <FormControlLabel
className="notification-switch" className="notification-switch"
control={ control={
@@ -548,13 +586,15 @@ export default class Chat extends Component {
Admin Only Mode (can be changed later) Admin Only Mode (can be changed later)
<br /> <br />
<span style={{ color: '#8a8a8a' }}> <span style={{ color: '#8a8a8a' }}>
{adminOnly ? 'Only admin can update player and start calls right now' : 'All party members can update player and start calls right now'} {adminOnly
? 'Only admin can update player and start calls right now'
: 'All party members can update player and start calls right now'}
</span> </span>
</span> </span>
} }
labelPlacement="end" labelPlacement="end"
/> : null />
} ) : null}
<Typography className="party-controls-users-title" variant="overline"> <Typography className="party-controls-users-title" variant="overline">
PARTY MEMBERS PARTY MEMBERS
</Typography> </Typography>
@@ -629,7 +669,7 @@ export default class Chat extends Component {
</Card> </Card>
) : null} ) : null}
</div> </div>
<div className="thread-container"> <div className="thread-wrapper">
<div className="alerts-container"> <div className="alerts-container">
{alerts.map((a) => { {alerts.map((a) => {
if (a.condition() === true) { if (a.condition() === true) {
@@ -644,8 +684,23 @@ export default class Chat extends Component {
} else return null; } else return null;
})} })}
</div> </div>
<Thread messages={messages} /> <Thread setReplyTo={this.setReplyTo} messages={messages} />
</div> </div>
<Paper
square
variant="outlined"
className={`replying-to-card ${replyTo !== null ? 'replying-to-card-up' : ''}`}
>
<div className="replying-to-content">
<Typography variant="overline" display="block" gutterBottom>
REPLYING TO
</Typography>
{this.getReplyToContent()}
</div>
<IconButton onClick={() => this.setReplyTo(null)}>
<CancelRounded />
</IconButton>
</Paper>
<div className="text-phone-panel"> <div className="text-phone-panel">
{gif || newMessage ? null : ( {gif || newMessage ? null : (
<Tooltip title="Fullscreen with Watch Party" aria-label="Fullscreen"> <Tooltip title="Fullscreen with Watch Party" aria-label="Fullscreen">
+204 -81
View File
@@ -16,95 +16,218 @@ YouTube logo is a trademark and intellectual property of Google, Inc.
Hulu logo is a trademark and intellectual property of Hulu, LLC. Hulu logo is a trademark and intellectual property of Hulu, LLC.
HBO Now and HBO Max logos are trademark and intellectual property of WarnerMedia Direct,LLC. HBO Now and HBO Max logos are trademark and intellectual property of WarnerMedia Direct,LLC.
************************************************************************/ ************************************************************************/
.thread-container * {
margin: 0;
padding: 0;
font-family: 'Roboto', sans-serif;
letter-spacing: 1.15px;
}
.thread-container {
max-height: none;
padding: 0 15px;
overflow: hidden;
}
.thread-item { .thread-item {
color: white;
width: fit-content;
margin: 10px 0;
width: 100%;
transition: all ease-in-out 0.5s;
}
.thread-item.highlight {
background-color: #111111;
border-radius: 26px 0px 0px 26px;
padding: 16px;
padding-right: 0px;
}
.thread-message {
width: 100%; width: 100%;
white-space: pre-wrap;
margin-top: 25px !important;
font-size: 12px !important;
position: relative; position: relative;
} }
.thread-item.no-space { .thread-message .thread-overline {
margin-top: 0 !important; height: 0;
} overflow-y: visible;
.system-message { font-size: 10px;
display: block;
text-align: center;
width: 100%;
text-align: center;
font-size: 12px;
margin-top: 7.5px !important;
color: rgba(147, 147, 147, 0.8) !important;
}
.system-message.alert {
background-color: black;
border-radius: 1rem;
color: white !important;
padding: 5px 10px;
position: sticky;
top: 2px;
z-index: 1;
}
.my-message {
display: block;
width: fit-content;
text-align: right;
margin-left: auto !important;
margin-right: 5px !important;
margin-top: 5px !important;
padding: 2.5px 10px !important;
border-radius: 13px;
max-width: 60%;
word-wrap: break-word;
background-color: rgb(49, 49, 49);
font-size: 14px !important;
}
img.my-message {
margin-right: 0 !important;
padding-right: 0 !important;
border-radius: 1rem;
max-width: 60%;
background: none;
border-radius: 2rem;
}
.party-message {
font-size: 14px !important;
display: block;
width: fit-content;
max-width: 60%;
word-wrap: break-word;
margin-top: 5px !important;
padding: 2.5px 10px !important;
border-radius: 13px;
background-color: rgb(88, 88, 88);
}
img.party-message {
border-radius: 1rem;
max-width: 60%;
background: none;
border-radius: 2rem;
margin-left: 0 !important;
padding-left: 0 !important;
}
.thread-item .name {
color: rgb(149, 149, 149);
font-size: 12px !important;
}
.time {
top: 0;
color: #3a3a3a;
position: absolute;
opacity: 0;
transition: all ease-in-out 0.3s; transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
white-space: nowrap;
display: flex;
align-items: center;
opacity: 0;
color: #9f9f9f;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row-reverse;
} }
.party-message ~ .time { .thread-message .thread-overline span {
right: 0; flex: 1;
text-align: center;
} }
.party-message:hover ~ .time { .thread-message .thread-overline .thread-reply-icon {
opacity: 1; position: absolute;
} display: flex;
.my-message ~ .time { justify-content: center;
align-items: center;
font-size: 20px;
border-radius: 26px;
z-index: 999 !important;
white-space: break-spaces;
left: 0; left: 0;
cursor: pointer;
bottom: 0;
transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
width: 25px;
height: 25px;
padding: 0;
padding-bottom: 7px;
} }
.my-message:hover ~ .time { .thread-item:hover .thread-message .thread-overline {
height: 24px;
margin-bottom: 7px;
opacity: 1; opacity: 1;
} }
.thread-message p {
max-width: 65%;
padding: 5px 15px;
background: #424242;
border-radius: 26px;
z-index: 9999 !important;
transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
width: fit-content;
min-height: 25px;
display: flex;
align-items: center;
line-height: 16px;
font-size: 13px;
font-weight: 100;
font-family: 'Roboto';
letter-spacing: 1.5px;
white-space: break-spaces;
word-break: break-all;
}
.thread-message img {
max-width: 55%;
border-radius: 26px;
transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
z-index: 999;
}
.thread-item:hover .thread-message p,
.thread-item:hover .thread-message img {
margin-left: 40px;
}
.thread-message .thread-overline .thread-reply-icon:hover {
opacity: 0.6;
}
.thread-name {
font-size: 11px;
margin-top: 15px;
margin-bottom: 7px;
color: #adadad;
}
.thread-reply {
font-size: 11px;
margin-bottom: -20px;
padding: 7.5px 15px;
padding-bottom: 25px;
border-radius: 13px;
background: #222222;
width: fit-content;
max-width: 45%;
z-index: 999 !important;
transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
cursor: pointer;
}
.thread-reply-name {
color: #8a8a8a;
font-size: 10px;
text-transform: uppercase;
margin-bottom: 5px !important;
}
.thread-reply p {
width: fit-content;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.thread-reply img {
max-height: 70px;
border-radius: 26px;
transition: all ease-in-out 0.3s;
transition-delay: 0.1s;
}
.thread-item:hover .thread-reply {
margin-bottom: 0;
padding-bottom: 7.5px;
}
.thread-reply:hover {
background: #111111;
}
.thread-item.continued-message .thread-name {
display: none;
}
/*
M Y
M E S S A G E S
*/
.thread-item.my-message {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.thread-item.thread-item.my-message.highlight {
padding-left: 0px;
}
.thread-item.my-message .thread-name {
display: none;
}
.thread-item.my-message .thread-message {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.thread-item.my-message .thread-message p {
text-align: right;
}
.thread-item.my-message .thread-message .thread-overline {
flex-direction: row;
}
.thread-item.my-message .thread-message .thread-overline .thread-reply-icon {
right: 0;
left: unset;
}
.thread-item.my-message:hover .thread-message p,
.thread-item.my-message:hover .thread-message img {
margin-left: 0;
margin-right: 40px;
}
/*
S Y S T E M
M E S S A G E S
*/
.thread-item.system-message .thread-name,
.thread-item.system-message .thread-reply,
.thread-item.system-message img,
.thread-item.system-message .thread-overline .thread-reply-icon {
display: none;
}
.thread-item.system-message .thread-message p {
width: 100%;
margin: 0 auto;
background: none;
font-size: 12px;
color: #555;
text-align: center;
display: block;
}
.thread-item.system-message:hover .thread-message p {
margin: 0 auto;
}
+68 -53
View File
@@ -16,63 +16,78 @@ YouTube logo is a trademark and intellectual property of Google, Inc.
Hulu logo is a trademark and intellectual property of Hulu, LLC. Hulu logo is a trademark and intellectual property of Hulu, LLC.
HBO Now and HBO Max logos are trademark and intellectual property of WarnerMedia Direct,LLC. HBO Now and HBO Max logos are trademark and intellectual property of WarnerMedia Direct,LLC.
************************************************************************/ ************************************************************************/
import React from 'react'; import React, { Component } from 'react';
import { Typography } from '@material-ui/core'; import { Typography, IconButton } from '@material-ui/core';
import { Reply } from '@material-ui/icons';
import './Thread.css'; import './Thread.css';
import { LocalData } from './Api'; import { LocalData } from './Api';
const Thread = (props) => export default class Thread extends Component {
props.messages.map((m, midx) => { constructor(props) {
var { userUid } = LocalData(); super(props);
if (m.uid === '<system>') { this.getReplyMessage = this.getReplyMessage.bind(this);
// SYSTEM MESSAGES }
scrollToMessage(id) {
const pcc = document.querySelector('.thread-wrapper');
const msg = document.getElementById(id);
pcc.scrollTop = msg.offsetTop - pcc.offsetTop;
msg.classList.add('highlight');
setTimeout(() => msg.classList.remove('highlight'), 500);
}
getItemClassNames(uid, userUid, msgIdx) {
const lastUid = msgIdx >= 1 ? this.props.messages[msgIdx - 1].uid : '';
return `thread-item ${uid === userUid ? 'my-message' : ''} ${
uid === '<system>' ? 'system-message' : ''
} ${lastUid === uid ? 'continued-message' : ''}`;
}
getMessageTextOrImage(msg) {
if (msg.type === 'giphy') {
return <img alt="gif" src={msg.text} />;
}
return <p>{msg.text}</p>;
}
getTimeString(time) {
return new Date(time.seconds * 1000).toLocaleTimeString();
}
getReplyMessage(rT, messages) {
if (rT !== undefined && rT !== null) {
const replyMessage = messages.filter((m) => m.id === rT)[0];
return ( return (
<Typography variant="body2" className="thread-item system-message" key={m.id} disabled> <div className="thread-reply" onClick={() => this.scrollToMessage(replyMessage.id)}>
{m.text} <p className="thread-reply-name">Reply to {replyMessage.name}:</p>
</Typography> {this.getMessageTextOrImage(replyMessage)}
);
} else if (m.uid === userUid) {
// OWN MESSAGE
return (
<div
className={`thread-item ${
midx > 0 ? (props.messages[midx - 1].uid !== m.uid ? '' : 'no-space') : ''
}`}
key={m.id}
>
{m.type === 'giphy' ? (
<img className="my-message" alt="giphy gif" src={m.text} />
) : (
<Typography variant="body1" className="my-message">
{m.text}
</Typography>
)}
<span className="time">{new Date(m.time.seconds * 1000).toLocaleTimeString()}</span>
</div>
);
} else {
// OTHER USER MESSAGE
return (
<div
className={`thread-item ${
midx > 0 ? (props.messages[midx - 1].uid !== m.uid ? '' : 'no-space') : ''
}`}
key={m.id}
>
<Typography variant="caption" className="name">
{midx > 0 ? (props.messages[midx - 1].uid !== m.uid ? m.name : '') : m.name}
</Typography>
{m.type === 'giphy' ? (
<img className="party-message" alt="giphy gif" src={m.text} />
) : (
<Typography variant="body1" className="party-message">
{m.text}
</Typography>
)}
<span className="time">{new Date(m.time.seconds * 1000).toLocaleTimeString()}</span>
</div> </div>
); );
} }
}); return null;
}
export default Thread; render() {
const { messages, setReplyTo } = this.props;
const { userUid } = LocalData();
return (
<div className="thread-container">
{messages.map((msg, msgIdx) => (
<div
id={msg.id}
key={`msg-${msgIdx}`}
className={this.getItemClassNames(msg.uid, userUid, msgIdx)}
>
<div className="thread-name">{msg.name}</div>
{this.getReplyMessage(msg.replyTo, messages)}
<div className="thread-message">
<div className="thread-overline">
<span>{this.getTimeString(msg.time)}</span>
<div className="thread-reply-icon">
<IconButton onClick={() => setReplyTo(msg)}>
<Reply />
</IconButton>
</div>
</div>
{this.getMessageTextOrImage(msg)}
</div>
</div>
))}
</div>
);
}
}
+71 -22
View File
@@ -159,14 +159,35 @@ body.googleplay.visible {
body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div.mjANdc.eEPege { body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div.mjANdc.eEPege {
padding: 0 !important; padding: 0 !important;
} }
body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div.mjANdc.eEPege > div.LhXUod.XL54pf.J9Nfi.iWO5td, body.googleplay.visible
body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div > div.LhXUod.XL54pf.J9Nfi.iWO5td > span > div > div > iframe { div.llhEMd.bYEzqc.LAhoGb.iWO5td
> div.mjANdc.eEPege
> div.LhXUod.XL54pf.J9Nfi.iWO5td,
body.googleplay.visible
div.llhEMd.bYEzqc.LAhoGb.iWO5td
> div
> div.LhXUod.XL54pf.J9Nfi.iWO5td
> span
> div
> div
> iframe {
min-height: 100%; min-height: 100%;
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
} }
body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div > div.LhXUod.XL54pf.J9Nfi.iWO5td > span > div, body.googleplay.visible
body.googleplay.visible div.llhEMd.bYEzqc.LAhoGb.iWO5td > div > div.LhXUod.XL54pf.J9Nfi.iWO5td > span > div > div { div.llhEMd.bYEzqc.LAhoGb.iWO5td
> div
> div.LhXUod.XL54pf.J9Nfi.iWO5td
> span
> div,
body.googleplay.visible
div.llhEMd.bYEzqc.LAhoGb.iWO5td
> div
> div.LhXUod.XL54pf.J9Nfi.iWO5td
> span
> div
> div {
height: 100%; height: 100%;
} }
/* CRUNCHYROLL STYLING */ /* CRUNCHYROLL STYLING */
@@ -194,18 +215,6 @@ body.crunchyroll.visible #vilos-player {
max-height: 42vw !important; max-height: 42vw !important;
} }
/*
FULL SCREEN BUTTON REMOVER
*/
body.netflix
.touchable.PlayerControls--control-element.nfp-button-control.default-control-button.button-nfplayerFullscreen,
body.hulu .controls__view-mode-button-normal-icon.player-svgicon,
body.disney .control-icon-btn.fullscreen-icon,
body.amazon .fyysciv.f1lobqlo.fk0j80b {
display: none;
}
#party-loading { #party-loading {
position: absolute; position: absolute;
width: 100%; width: 100%;
@@ -354,12 +363,12 @@ body.amazon .fyysciv.f1lobqlo.fk0j80b {
.create-bottom-card a:hover { .create-bottom-card a:hover {
color: #c0f300; color: #c0f300;
} }
.thread-container { .thread-wrapper {
max-height: 100%; max-height: 100%;
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
margin-bottom: 1rem; margin-bottom: 1rem;
padding: 0 15px; padding: 0;
margin-top: 1rem; margin-top: 1rem;
} }
.room-title { .room-title {
@@ -369,14 +378,14 @@ body.amazon .fyysciv.f1lobqlo.fk0j80b {
padding-right: 1rem !important; padding-right: 1rem !important;
font-size: 18px !important; font-size: 18px !important;
} }
.thread-container::-webkit-scrollbar { .thread-wrapper::-webkit-scrollbar {
width: 5px; width: 5px;
} }
.thread-container::-webkit-scrollbar-track { .thread-wrapper::-webkit-scrollbar-track {
background-color: rgb(90, 90, 90); background-color: rgb(90, 90, 90);
border-radius: 1rem; border-radius: 1rem;
} }
.thread-container::-webkit-scrollbar-thumb { .thread-wrapper::-webkit-scrollbar-thumb {
background-color: rgb(180, 180, 180); background-color: rgb(180, 180, 180);
border-radius: 13px; border-radius: 13px;
} }
@@ -614,6 +623,8 @@ body.amazon-prime .notification-switch .MuiSwitch-thumb {
align-items: center; align-items: center;
font-size: 11px; font-size: 11px;
text-transform: uppercase; text-transform: uppercase;
flex: 1;
justify-content: center;
} }
#mic-permission-overlay { #mic-permission-overlay {
@@ -665,4 +676,42 @@ body.amazon-prime .notification-switch .MuiSwitch-thumb {
.admin-only-switch { .admin-only-switch {
margin-bottom: 20px !important; margin-bottom: 20px !important;
} }
.replying-to-card {
display: flex !important;
padding: 15px 20px 500px 20px !important;
border: none !important;
border-top-left-radius: 26px !important;
border-top-right-radius: 26px !important;
margin-bottom: -554px !important;
opacity: 0 !important;
transition: all ease-in-out 0.3s !important;
}
.replying-to-card.replying-to-card-up {
margin-bottom: -480px !important;
opacity: 1 !important;
}
.replying-to-content {
flex: 1;
overflow: hidden;
}
.replying-to-content img {
max-height: 75px;
border-radius: 26px;
}
.replying-to-content p {
font-size: 11px;
letter-spacing: 1.2px;
font-weight: 100;
overflow: hidden;
position: relative;
white-space: nowrap;
max-width: 100%;
text-overflow: ellipsis;
}
.replying-to-card button {
align-self: flex-start;
}
+2 -1
View File
@@ -1,7 +1,7 @@
const admin = require('firebase-admin'); const admin = require('firebase-admin');
module.exports = async (req, res) => { module.exports = async (req, res) => {
const { name, text, uid, roomId, type } = JSON.parse(req.body); const { name, text, uid, roomId, type, replyTo } = JSON.parse(req.body);
const roomExists = await admin const roomExists = await admin
.firestore() .firestore()
@@ -21,6 +21,7 @@ module.exports = async (req, res) => {
time: new Date(), time: new Date(),
uid, uid,
type: type || '', type: type || '',
replyTo: replyTo || null,
}) })
.catch((err) => { .catch((err) => {
console.error(`Failed to send message to party : \n\t Room: ${roomId} \n\t ${uid}`, err); console.error(`Failed to send message to party : \n\t Room: ${roomId} \n\t ${uid}`, err);