- Video Listener Optimizations - Auto Leave Fix - Edge support - Admin Dashboard Update - Vimeo & Dailymotion
673 lines
21 KiB
JavaScript
673 lines
21 KiB
JavaScript
/************************************************************************
|
|
Copyright (C) Ayushya Amitabh - All Rights Reserved
|
|
Unauthorized copying of this file, via any medium is strictly prohibited
|
|
Proprietary and confidential
|
|
Written by Ayushya Amitabh <admin@chromewatchparty.com>, 2020
|
|
https://www.chromewatchparty.com/copyright
|
|
=========================================================================
|
|
ALL CONTENT ON WATCH PARTY'S WEBSITE OR IN WATCH PARTY'S CHROME EXTENSION APP, UNLESS OTHERWISE
|
|
CITED ARE THE SOLE INTELLECTUAL PROPERTY OF AYUSHYA AMITABH, AND MAY NOT BE
|
|
COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION.
|
|
************************************************************************/
|
|
/*global chrome */
|
|
import React, { Component } from "react";
|
|
import {
|
|
Button,
|
|
FormControlLabel,
|
|
Switch,
|
|
TextField,
|
|
Typography,
|
|
Paper,
|
|
ButtonGroup,
|
|
ExpansionPanel,
|
|
ExpansionPanelSummary,
|
|
ExpansionPanelDetails,
|
|
MobileStepper,
|
|
IconButton,
|
|
Card,
|
|
CardContent,
|
|
CardActions,
|
|
} from "@material-ui/core";
|
|
import {
|
|
JoinRoomApi,
|
|
CreateRoomApi,
|
|
PLAYER_STATUS,
|
|
getPlayerSource,
|
|
LocalData,
|
|
updateLocalData,
|
|
getUserUid,
|
|
emptyLocalData,
|
|
setTutorialStatus,
|
|
} from "./Api";
|
|
import { goTo } from "route-lite";
|
|
import Chat from "./Chat";
|
|
import {
|
|
ChevronRight,
|
|
InfoRounded,
|
|
MonetizationOnRounded,
|
|
RateReviewRounded,
|
|
Settings,
|
|
ExpandLess,
|
|
KeyboardArrowLeft,
|
|
KeyboardArrowRight,
|
|
Notifications,
|
|
} from "@material-ui/icons";
|
|
import { Autocomplete } from "@material-ui/lab";
|
|
|
|
const CONSTANTS = {
|
|
USER_NAME_LENGTH: 12,
|
|
NAME_LENGTH: 24,
|
|
PIN_LENGTH: 9,
|
|
};
|
|
export default class Create extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
const defaultMode = LocalData().partyName ? "join" : "create";
|
|
this.state = {
|
|
userName: LocalData().userName || "",
|
|
name: LocalData().partyName || "",
|
|
pin: LocalData().partyPin || "",
|
|
mode: defaultMode,
|
|
parties: [],
|
|
adminOnly: false,
|
|
publicParty: false,
|
|
alertStep:
|
|
this.props.status && this.props.status.importantAlert
|
|
? this.props.status.importantAlert
|
|
: 0,
|
|
allowAutoRejoin:
|
|
LocalData().allowAutoRejoin !== undefined
|
|
? LocalData().allowAutoRejoin
|
|
: true,
|
|
allowChatNotification:
|
|
LocalData().allowChatNotification !== undefined
|
|
? LocalData().allowChatNotification
|
|
: true,
|
|
allowAutoFollow: LocalData().allowAutoFollow || false,
|
|
expanded: "alerts",
|
|
};
|
|
this.createCall = this.createCall.bind(this);
|
|
this.joinCall = this.joinCall.bind(this);
|
|
this.success = this.success.bind(this);
|
|
this.partyNameAutocompleteProcessor = this.partyNameAutocompleteProcessor.bind(
|
|
this
|
|
);
|
|
this.updateAllowAutoRejoin = this.updateAllowAutoRejoin.bind(this);
|
|
this.updateAllowAutoFollow = this.updateAllowAutoFollow.bind(this);
|
|
this.updateAllowChatNotification = this.updateAllowChatNotification.bind(
|
|
this
|
|
);
|
|
this.clearPartyHistory = this.clearPartyHistory.bind(this);
|
|
this.handleSteps = this.handleSteps.bind(this);
|
|
}
|
|
componentDidMount() {
|
|
const {
|
|
lastActive,
|
|
userName,
|
|
partyName,
|
|
partyPin,
|
|
allowAutoRejoin,
|
|
} = LocalData();
|
|
// CONTINUE TUTORIAL
|
|
if (this.props.tutorialComplete === false) {
|
|
this.props.resetTutorial();
|
|
}
|
|
if (
|
|
this.props.showFab === true &&
|
|
allowAutoRejoin === true &&
|
|
lastActive &&
|
|
userName &&
|
|
partyName &&
|
|
partyPin
|
|
) {
|
|
if (
|
|
Math.abs(new Date(parseInt(lastActive)) - new Date().getTime()) <= 60000
|
|
) {
|
|
this.props.updateLoading(true);
|
|
this.props.setVisible(true);
|
|
this.joinCall(userName, partyName, partyPin);
|
|
}
|
|
}
|
|
chrome.runtime.sendMessage(
|
|
{
|
|
type: "GET_PARTIES",
|
|
},
|
|
(response) => {
|
|
this.setState({ parties: response });
|
|
}
|
|
);
|
|
}
|
|
partyNameChange(value) {
|
|
if (value.length <= CONSTANTS.NAME_LENGTH) this.setState({ name: value });
|
|
}
|
|
partyPinChange(value) {
|
|
if (value.length <= CONSTANTS.PIN_LENGTH) this.setState({ pin: value });
|
|
}
|
|
userNameChange(value) {
|
|
if (value.length <= CONSTANTS.USER_NAME_LENGTH)
|
|
this.setState({ userName: value });
|
|
}
|
|
createOrJoin() {
|
|
this.props.updateLoading(true);
|
|
getUserUid();
|
|
const { userName, name, pin, mode } = this.state;
|
|
if (!userName.replace(/\s+/g, "")) {
|
|
this.props.notify("Missing user name");
|
|
this.props.updateLoading(false);
|
|
return;
|
|
}
|
|
if (!name.replace(/\s+/g, "")) {
|
|
this.props.notify("Missing party name");
|
|
this.props.updateLoading(false);
|
|
return;
|
|
}
|
|
if (!pin.replace(/\s+/g, "")) {
|
|
this.props.notify("Missing party pin");
|
|
this.props.updateLoading(false);
|
|
return;
|
|
}
|
|
if (userName && name && pin) {
|
|
switch (mode) {
|
|
case "create":
|
|
this.createCall(userName.trim(), name.trim(), pin);
|
|
break;
|
|
case "join":
|
|
this.joinCall(userName.trim(), name.trim(), pin);
|
|
break;
|
|
default:
|
|
this.props.updateLoading(false);
|
|
break;
|
|
}
|
|
} else {
|
|
this.props.notify("Double check your inputs");
|
|
}
|
|
}
|
|
createCall(userName, partyName, partyPin) {
|
|
this.props.updateLoading(true);
|
|
getUserUid();
|
|
const apidata = {
|
|
userName,
|
|
partyName,
|
|
partyPin,
|
|
player: {
|
|
source: getPlayerSource(),
|
|
status: PLAYER_STATUS.PAUSED,
|
|
time: 0,
|
|
url: window.location.href,
|
|
},
|
|
adminOnly: this.state.adminOnly || this.state.publicParty,
|
|
publicParty: this.state.publicParty,
|
|
};
|
|
CreateRoomApi(apidata)
|
|
.then((res) => res.json())
|
|
.then((createResult) => {
|
|
if (createResult.status <= 299) {
|
|
this.success(userName, partyName, partyPin);
|
|
} else {
|
|
this.props.updateLoading(false);
|
|
this.props.notify(createResult.message || createResult.statusText);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error("Create Party API Error", err);
|
|
this.props.notify(err.message || "Something went wrong");
|
|
this.props.updateLoading(false);
|
|
});
|
|
}
|
|
joinCall(userName, partyName, partyPin) {
|
|
const apidata = {
|
|
userName,
|
|
partyName,
|
|
partyPin,
|
|
source: getPlayerSource(),
|
|
};
|
|
getUserUid();
|
|
JoinRoomApi(apidata)
|
|
.then((res) => res.json())
|
|
.then((joinResult) => {
|
|
if (joinResult.status <= 299) {
|
|
this.success(userName, partyName, partyPin);
|
|
} else {
|
|
this.props.updateLoading(false);
|
|
this.props.notify(joinResult.message || joinResult.statusText);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
emptyLocalData();
|
|
console.error("Join Party API Error", err);
|
|
this.props.notify(err.message || "Something went wrong");
|
|
this.props.updateLoading(false);
|
|
});
|
|
}
|
|
success(userName, partyName, partyPin) {
|
|
updateLocalData({ userName, partyName, partyPin });
|
|
this.props.updateLoading(false);
|
|
goTo(Chat, this.props);
|
|
}
|
|
partyNameAutocompleteProcessor(v) {
|
|
if (v !== null && v !== undefined && typeof v === "object") {
|
|
if (v.name) this.partyNameChange(v.name);
|
|
else this.partyNameChange("");
|
|
if (v.pin) this.partyPinChange(v.pin);
|
|
else this.partyPinChange("");
|
|
} else if (typeof v === "object" && (v === null || v === undefined)) {
|
|
this.partyNameChange("");
|
|
this.partyPinChange("");
|
|
} else if (v !== undefined && v !== null && typeof v === "string") {
|
|
this.partyNameChange(v);
|
|
}
|
|
}
|
|
updateAllowChatNotification() {
|
|
updateLocalData({
|
|
allowChatNotification: !this.state.allowChatNotification,
|
|
});
|
|
this.setState({ allowChatNotification: !this.state.allowChatNotification });
|
|
}
|
|
updateAllowAutoRejoin() {
|
|
updateLocalData({ allowAutoRejoin: !this.state.allowAutoRejoin });
|
|
this.setState({ allowAutoRejoin: !this.state.allowAutoRejoin });
|
|
}
|
|
updateAllowAutoFollow() {
|
|
updateLocalData({ allowAutoFollow: !this.state.allowAutoFollow });
|
|
this.setState({ allowAutoFollow: !this.state.allowAutoFollow });
|
|
}
|
|
clearPartyHistory() {
|
|
this.setState({
|
|
parties: [],
|
|
});
|
|
chrome.runtime.sendMessage({ type: "EMPTY_PARTIES" });
|
|
}
|
|
handleSteps(direction) {
|
|
const { alertStep } = this.state;
|
|
if (alertStep + direction < 0) return;
|
|
if (alertStep + direction >= this.props.status.alerts.length) return;
|
|
this.setState({ alertStep: alertStep + direction });
|
|
}
|
|
handleExpanders(e) {
|
|
const { expanded } = this.state;
|
|
if (e === expanded) this.setState({ expanded: "" });
|
|
else this.setState({ expanded: e });
|
|
}
|
|
render() {
|
|
const {
|
|
mode,
|
|
name,
|
|
pin,
|
|
userName,
|
|
parties,
|
|
adminOnly,
|
|
publicParty,
|
|
allowAutoRejoin,
|
|
allowAutoFollow,
|
|
allowChatNotification,
|
|
alertStep,
|
|
expanded,
|
|
} = this.state;
|
|
const { status, resetTutorial } = this.props;
|
|
return (
|
|
<div className="party-create-container">
|
|
<Typography
|
|
color="secondary"
|
|
className="brand-title"
|
|
variant="h6"
|
|
display="block"
|
|
gutterBottom
|
|
>
|
|
WATCH PARTY
|
|
</Typography>
|
|
<Paper className="create-input-card" elevation={3}>
|
|
<ButtonGroup className="create-mode-select" size="small" fullWidth>
|
|
<Button
|
|
id="mode-select-left"
|
|
variant={mode === "create" ? "contained" : null}
|
|
color={mode === "create" ? "secondary" : null}
|
|
disableElevation={mode === "create"}
|
|
onClick={() => this.setState({ mode: "create" })}
|
|
>
|
|
Create
|
|
</Button>
|
|
<Button
|
|
id="mode-select-right"
|
|
variant={mode === "join" ? "contained" : null}
|
|
color={mode === "join" ? "secondary" : null}
|
|
disableElevation={mode === "join"}
|
|
onClick={() => this.setState({ mode: "join" })}
|
|
>
|
|
Join
|
|
</Button>
|
|
</ButtonGroup>
|
|
<TextField
|
|
color="secondary"
|
|
size="small"
|
|
className="create-name addFocus"
|
|
label="Name"
|
|
variant="outlined"
|
|
value={userName}
|
|
onChange={(e) => this.userNameChange(e.target.value)}
|
|
helperText={
|
|
userName
|
|
? `${userName.length}/${CONSTANTS.USER_NAME_LENGTH} Characters`
|
|
: null
|
|
}
|
|
/>
|
|
<Autocomplete
|
|
color="secondary"
|
|
options={parties}
|
|
getOptionLabel={(o) => o.name}
|
|
autoComplete
|
|
freeSolo
|
|
value={{ name: name, pin: pin }}
|
|
onInputChange={(e, v, r) =>
|
|
this.partyNameAutocompleteProcessor({ name: v, pin: pin })
|
|
}
|
|
onChange={(e, v) => this.partyNameAutocompleteProcessor(v)}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
color="secondary"
|
|
size="small"
|
|
{...params}
|
|
className="create-name addFocus"
|
|
label="Party Name"
|
|
variant="outlined"
|
|
helperText={
|
|
name
|
|
? `${name.length}/${CONSTANTS.NAME_LENGTH} Characters`
|
|
: null
|
|
}
|
|
/>
|
|
)}
|
|
/>
|
|
<TextField
|
|
color="secondary"
|
|
size="small"
|
|
className="create-pin addFocus"
|
|
label="Party Pin"
|
|
variant="outlined"
|
|
type="number"
|
|
value={pin}
|
|
onChange={(e) => this.partyPinChange(e.target.value)}
|
|
helperText={
|
|
pin ? `${pin.length}/${CONSTANTS.PIN_LENGTH} Digits` : null
|
|
}
|
|
/>
|
|
<FormControlLabel
|
|
className={`notification-switch admin-only-switch ${
|
|
mode !== "create" ? "admin-only-switch-hidden" : ""
|
|
}`}
|
|
control={
|
|
<Switch
|
|
checked={adminOnly || publicParty}
|
|
onChange={() => this.setState({ adminOnly: !adminOnly })}
|
|
name="adminOnly"
|
|
color={adminOnly || publicParty ? "secondary" : "primary"}
|
|
/>
|
|
}
|
|
label={
|
|
<span>
|
|
Admin Only Mode (can be changed later)
|
|
<br />
|
|
<span style={{ color: "#8a8a8a" }}>
|
|
{adminOnly || publicParty
|
|
? "Only admin will update currently playing and start calls"
|
|
: "All members will update currently playing and start calls"}
|
|
</span>
|
|
</span>
|
|
}
|
|
labelPlacement="end"
|
|
/>
|
|
{/* <FormControlLabel
|
|
className={`notification-switch admin-only-switch ${
|
|
mode !== "create" ? "admin-only-switch-hidden" : ""
|
|
}`}
|
|
control={
|
|
<Switch
|
|
checked={publicParty}
|
|
onChange={() => this.setState({ publicParty: !publicParty })}
|
|
name="publicParty"
|
|
color={publicParty ? "secondary" : "primary"}
|
|
/>
|
|
}
|
|
label={
|
|
<span>
|
|
Public Party (can be changed later)
|
|
<br />
|
|
<span style={{ color: "#8a8a8a" }}>
|
|
{publicParty
|
|
? "Party will be listed and available to join from Watch Party website"
|
|
: "Only people you share with can join"}
|
|
</span>
|
|
</span>
|
|
}
|
|
labelPlacement="end"
|
|
/> */}
|
|
<Button
|
|
size="small"
|
|
variant="contained"
|
|
color="secondary"
|
|
onClick={() => this.createOrJoin()}
|
|
>
|
|
<span>{mode === "create" ? "Start Party" : "Join Party"}</span>{" "}
|
|
<ChevronRight />
|
|
</Button>
|
|
</Paper>
|
|
<ExpansionPanel
|
|
expanded={expanded === "alerts"}
|
|
className="create-settings-card create-alerts-card"
|
|
>
|
|
<ExpansionPanelSummary
|
|
onClick={() => this.handleExpanders("alerts")}
|
|
expandIcon={<ExpandLess />}
|
|
>
|
|
<Notifications />
|
|
<Typography className="create-settings-title" variant="button">
|
|
Alerts
|
|
</Typography>
|
|
</ExpansionPanelSummary>
|
|
<ExpansionPanelDetails>
|
|
{status ? (
|
|
<div className="alerts-stepper-container">
|
|
<Card className="alerts-stepper-card" elevation={10}>
|
|
<CardContent>
|
|
<Typography
|
|
color="textSecondary"
|
|
gutterBottom
|
|
variant="overline"
|
|
>
|
|
{status.alerts[alertStep].title}
|
|
</Typography>
|
|
<Typography variant="body2" component="p">
|
|
{status.alerts[alertStep].description}
|
|
</Typography>
|
|
</CardContent>
|
|
{status.alerts[alertStep].link &&
|
|
status.alerts[alertStep].linkText && (
|
|
<CardActions>
|
|
<Button
|
|
href={status.alerts[alertStep].link}
|
|
target="_blank"
|
|
size="small"
|
|
>
|
|
{status.alerts[alertStep].linkText}
|
|
</Button>
|
|
</CardActions>
|
|
)}
|
|
</Card>
|
|
<MobileStepper
|
|
className="alerts-stepper-controls"
|
|
variant="dots"
|
|
color="secondary"
|
|
activeStep={alertStep}
|
|
backButton={
|
|
<IconButton
|
|
disabled={alertStep === 0}
|
|
onClick={() => this.handleSteps(-1)}
|
|
>
|
|
<KeyboardArrowLeft />
|
|
</IconButton>
|
|
}
|
|
nextButton={
|
|
<IconButton
|
|
disabled={alertStep === status.alerts.length - 1}
|
|
onClick={() => this.handleSteps(1)}
|
|
>
|
|
<KeyboardArrowRight />
|
|
</IconButton>
|
|
}
|
|
steps={status.alerts ? status.alerts.length : 0}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<Typography color="textSecondary" gutterBottom variant="overline">
|
|
No alerts right now
|
|
</Typography>
|
|
)}
|
|
</ExpansionPanelDetails>
|
|
</ExpansionPanel>
|
|
<ExpansionPanel
|
|
expanded={expanded === "settings"}
|
|
className="create-settings-card create-settings-expander"
|
|
>
|
|
<ExpansionPanelSummary
|
|
onClick={() => this.handleExpanders("settings")}
|
|
expandIcon={<ExpandLess />}
|
|
>
|
|
<Settings />
|
|
<Typography className="create-settings-title" variant="button">
|
|
Settings
|
|
</Typography>
|
|
</ExpansionPanelSummary>
|
|
<ExpansionPanelDetails>
|
|
<FormControlLabel
|
|
className="notification-switch"
|
|
control={
|
|
<Switch
|
|
checked={allowChatNotification}
|
|
onChange={this.updateAllowChatNotification}
|
|
name="allowChatNotification"
|
|
/>
|
|
}
|
|
label={
|
|
<span>
|
|
Allow chat notification when side panel is closed
|
|
<br />
|
|
<span style={{ color: "#8a8a8a" }}>
|
|
{allowChatNotification
|
|
? "Notifications Enabled"
|
|
: "Notifications Disabled"}
|
|
</span>
|
|
</span>
|
|
}
|
|
labelPlacement="end"
|
|
/>
|
|
<FormControlLabel
|
|
className="notification-switch"
|
|
control={
|
|
<Switch
|
|
checked={allowAutoRejoin}
|
|
onChange={this.updateAllowAutoRejoin}
|
|
name="allowAutoRejoin"
|
|
/>
|
|
}
|
|
label={
|
|
<span>
|
|
Allow Watch Party to auto rejoin (within 1 minute)
|
|
<br />
|
|
<span style={{ color: "#8a8a8a" }}>
|
|
{allowAutoRejoin
|
|
? "Auto Rejoin Enabled"
|
|
: "Auto Rejoin Disabled"}
|
|
</span>
|
|
</span>
|
|
}
|
|
labelPlacement="end"
|
|
/>
|
|
<FormControlLabel
|
|
className="notification-switch"
|
|
control={
|
|
<Switch
|
|
checked={allowAutoFollow}
|
|
onChange={this.updateAllowAutoFollow}
|
|
name="allowAutoFollow"
|
|
/>
|
|
}
|
|
label={
|
|
<span>
|
|
Allow Watch Party to change to the currently playing show
|
|
<br />
|
|
<span style={{ color: "#8a8a8a" }}>
|
|
{allowAutoFollow
|
|
? "Auto Follow Enabled"
|
|
: "Auto Follow Disabled"}
|
|
</span>
|
|
</span>
|
|
}
|
|
labelPlacement="end"
|
|
/>
|
|
<Button
|
|
color="secondary"
|
|
fullWidth
|
|
variant="contained"
|
|
onClick={() => {
|
|
setTutorialStatus(false);
|
|
resetTutorial();
|
|
}}
|
|
size="small"
|
|
>
|
|
START TUTORIAL
|
|
</Button>
|
|
<Button
|
|
color="secondary"
|
|
fullWidth
|
|
variant="contained"
|
|
onClick={this.clearPartyHistory}
|
|
size="small"
|
|
>
|
|
CLEAR SAVED PARTY DETAILS
|
|
</Button>
|
|
</ExpansionPanelDetails>
|
|
</ExpansionPanel>
|
|
<Button
|
|
target="_blank"
|
|
href={`http://www.chromewatchparty.com/changes/v${this.props.appVersion}`}
|
|
fullWidth
|
|
color="secondary"
|
|
variant="contained"
|
|
size="small"
|
|
className="whats-new-button"
|
|
>
|
|
See what's new in V{this.props.appVersion}
|
|
</Button>
|
|
<div className="create-bottom-card">
|
|
<Button
|
|
color="secondary"
|
|
target="_blank"
|
|
startIcon={<InfoRounded />}
|
|
size="small"
|
|
href="https://www.chromewatchparty.com/welcome/#tips"
|
|
>
|
|
FAQ
|
|
</Button>
|
|
<Button
|
|
color="secondary"
|
|
target="_blank"
|
|
startIcon={<RateReviewRounded />}
|
|
size="small"
|
|
href="https://get.chromewatchparty.com"
|
|
>
|
|
Review
|
|
</Button>
|
|
<Button
|
|
color="secondary"
|
|
target="_blank"
|
|
startIcon={<MonetizationOnRounded />}
|
|
size="small"
|
|
href="https://www.chromewatchparty.com/donate"
|
|
>
|
|
Donate
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|