mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-11 00:24:47 -07:00
Cleanup and refactor (#4361)
* fix three panel layout height issue * rename websocket/services to websocket/persistence, implement LeaveRoom * cleanup * add new line eof * move route components from /components to /containers * remove duplicate style Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
This commit is contained in:
parent
294229622d
commit
8db9475804
47 changed files with 127 additions and 76 deletions
|
|
@ -1,19 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { AuthGuard } from "components/index";
|
||||
|
||||
import "./Decks.css";
|
||||
|
||||
class Decks extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<AuthGuard />
|
||||
<span>"Decks"</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Decks;
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { AuthGuard } from "../index";
|
||||
|
||||
import "./Game.css";
|
||||
|
||||
class Game extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<AuthGuard />
|
||||
<span>"Game"</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Game;
|
||||
|
|
@ -6,7 +6,7 @@ import Chip from "@material-ui/core/Chip";
|
|||
import Toolbar from "@material-ui/core/Toolbar";
|
||||
import * as _ from "lodash";
|
||||
|
||||
import { AuthenticationService } from "api";
|
||||
import { AuthenticationService, RoomsService } from "api";
|
||||
import { RoomsSelectors, ServerSelectors } from "store";
|
||||
import { Room, RouteEnum, User } from "types";
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ class Header extends Component<HeaderProps> {
|
|||
this.props.history.push(generatePath(RouteEnum.ROOM, { roomId }));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { joinedRooms, server, state, user } = this.props;
|
||||
|
||||
|
|
@ -82,21 +83,27 @@ class Header extends Component<HeaderProps> {
|
|||
}
|
||||
}
|
||||
|
||||
const Rooms = props => (
|
||||
<div className="temp-subnav__rooms">
|
||||
const Rooms = props => {
|
||||
|
||||
const onLeaveRoom = (event, roomId) => {
|
||||
event.preventDefault();
|
||||
RoomsService.leaveRoom(roomId);
|
||||
};
|
||||
|
||||
return <div className="temp-subnav__rooms">
|
||||
<span>Rooms: </span>
|
||||
{
|
||||
_.reduce(props.rooms, (rooms, { name, roomId}) => {
|
||||
rooms.push(
|
||||
<NavLink to={generatePath(RouteEnum.ROOM, { roomId })} className="temp-chip" key={roomId}>
|
||||
<Chip label={name} color="primary" />
|
||||
<Chip label={name} color="primary" onDelete={(event) => onLeaveRoom(event, roomId)} />
|
||||
</NavLink>
|
||||
);
|
||||
return rooms;
|
||||
}, [])
|
||||
}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
interface HeaderProps {
|
||||
state: number;
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
.log-results {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
import React from "react";
|
||||
import * as _ from "lodash";
|
||||
|
||||
import AppBar from "@material-ui/core/AppBar";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
||||
import "./LogResults.css";
|
||||
|
||||
const LogResults = (props) => {
|
||||
const { logs } = props;
|
||||
|
||||
const hasRoomLogs = logs.room && logs.room.length;
|
||||
const hasGameLogs = logs.game && logs.game.length;
|
||||
const hasChatLogs = logs.chat && logs.chat.length;
|
||||
|
||||
const [value, setValue] = React.useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const headerCells = [
|
||||
{
|
||||
label: "Time"
|
||||
},
|
||||
{
|
||||
label: "Sender Name"
|
||||
},
|
||||
{
|
||||
label: "Sender IP"
|
||||
},
|
||||
{
|
||||
label: "Message"
|
||||
},
|
||||
{
|
||||
label: "Target ID"
|
||||
},
|
||||
{
|
||||
label: "Target Name"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AppBar position="static">
|
||||
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
|
||||
<Tab label={"Rooms" + (hasRoomLogs ? ` [${logs.room.length}]` : "")} {...a11yProps(0)} />
|
||||
<Tab label={"Games" + (hasGameLogs ? ` [${logs.game.length}]` : "")} {...a11yProps(1)} />
|
||||
<Tab label={"Chats" + (hasChatLogs ? ` [${logs.chat.length}]` : "")} {...a11yProps(2)} />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={value} index={0}>
|
||||
<Results logs={logs.room} headerCells={headerCells} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<Results logs={logs.game} headerCells={headerCells} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={2}>
|
||||
<Results logs={logs.chat} headerCells={headerCells} />
|
||||
</TabPanel>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
const a11yProps = index => {
|
||||
return {
|
||||
id: `simple-tab-${index}`,
|
||||
"aria-controls": `simple-tabpanel-${index}`,
|
||||
};
|
||||
};
|
||||
|
||||
const TabPanel = ({ children, value, index, ...other }) => {
|
||||
return (
|
||||
<Typography
|
||||
component="div"
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
id={`simple-tabpanel-${index}`}
|
||||
aria-labelledby={`simple-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
<Box>{children}</Box>
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
const Results = ({headerCells, logs}) => (
|
||||
<Paper className="log-results">
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{ _.map(headerCells, ({ label }) => (
|
||||
<TableCell key={label}>{label}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{ _.map(logs, ({ time, senderName, senderIp, message, targetId, targetName }, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{time}</TableCell>
|
||||
<TableCell>{senderName}</TableCell>
|
||||
<TableCell>{senderIp}</TableCell>
|
||||
<TableCell>{message}</TableCell>
|
||||
<TableCell>{targetId}</TableCell>
|
||||
<TableCell>{targetName}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
export default LogResults;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
.moderator-logs {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.moderator-logs__form {
|
||||
width: 40%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.moderator-logs__results {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import * as _ from "lodash";
|
||||
|
||||
import { ServerDispatch, ServerSelectors, ServerStateLogs } from "store";
|
||||
|
||||
import { ModeratorService } from "api";
|
||||
|
||||
import { AuthGuard, ModGuard} from "components";
|
||||
import LogResults from "./LogResults";
|
||||
import { SearchForm } from "forms";
|
||||
|
||||
import "./Logs.css";
|
||||
|
||||
class Logs extends Component<LogsTypes> {
|
||||
MAXIMUM_RESULTS = 1000;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onSubmit = this.onSubmit.bind(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ServerDispatch.clearLogs();
|
||||
}
|
||||
|
||||
onSubmit(fields) {
|
||||
const trimmedFields: any = this.trimFields(fields);
|
||||
|
||||
const { userName, ipAddress, gameName, gameId, message, logLocation } = trimmedFields;
|
||||
|
||||
const required = _.filter({
|
||||
userName, ipAddress, gameName, gameId, message
|
||||
}, field => field);
|
||||
|
||||
if (logLocation) {
|
||||
trimmedFields.logLocation = this.flattenLogLocations(logLocation);
|
||||
}
|
||||
|
||||
trimmedFields.maximumResults = this.MAXIMUM_RESULTS;
|
||||
|
||||
if (_.size(required)) {
|
||||
ModeratorService.viewLogHistory(trimmedFields);
|
||||
} else {
|
||||
// @TODO use yet-to-be-implemented banner/alert
|
||||
}
|
||||
}
|
||||
|
||||
private trimFields(fields) {
|
||||
return _.reduce(fields, (obj, field, key) => {
|
||||
if (typeof field === "string") {
|
||||
const trimmed = _.trim(field);
|
||||
|
||||
if (!!trimmed) {
|
||||
obj[key] = trimmed;
|
||||
}
|
||||
} else {
|
||||
obj[key] = field;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
|
||||
private flattenLogLocations(logLocations) {
|
||||
return _.reduce(logLocations, (arr, loc, key) => {
|
||||
arr.push(key);
|
||||
return arr;
|
||||
}, [])
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="moderator-logs overflow-scroll">
|
||||
<AuthGuard />
|
||||
<ModGuard />
|
||||
|
||||
<div className="moderator-logs__form">
|
||||
<SearchForm onSubmit={this.onSubmit} />
|
||||
</div>
|
||||
|
||||
<div className="moderator-logs__results">
|
||||
<LogResults logs={this.props.logs} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface LogsTypes {
|
||||
logs: ServerStateLogs
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
logs: ServerSelectors.getLogs(state)
|
||||
});
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(Logs));
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { AuthGuard } from "components";
|
||||
|
||||
class Player extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<AuthGuard />
|
||||
<span>"Player"</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Player;
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
.games {
|
||||
}
|
||||
|
||||
.games-header,
|
||||
.game {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
.games-header__cell {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.games-header__label,
|
||||
.game__detail {
|
||||
width: 10%;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.games-header__label.description,
|
||||
.game__detail.description {
|
||||
width: 20%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.games-header__label.creator,
|
||||
.game__detail.creator {
|
||||
width: 20%;
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import * as _ from "lodash";
|
||||
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import TableSortLabel from "@material-ui/core/TableSortLabel";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
|
||||
// import { RoomsService } from "AppShell/common/services";
|
||||
|
||||
import { SortUtil, RoomsDispatch, RoomsSelectors } from "store";
|
||||
import { UserDisplay } from "components";
|
||||
|
||||
import "./Games.css";
|
||||
|
||||
// @TODO run interval to update timeSinceCreated
|
||||
class Games extends Component<GamesProps> {
|
||||
private headerCells = [
|
||||
{
|
||||
label: "Age",
|
||||
field: "startTime"
|
||||
},
|
||||
{
|
||||
label: "Description",
|
||||
field: "description"
|
||||
},
|
||||
{
|
||||
label: "Creator",
|
||||
field: "creatorInfo.name"
|
||||
},
|
||||
{
|
||||
label: "Type",
|
||||
field: "gameType"
|
||||
},
|
||||
{
|
||||
label: "Restrictions",
|
||||
// field: "?"
|
||||
},
|
||||
{
|
||||
label: "Players",
|
||||
// field: ["maxPlayers", "playerCount"]
|
||||
},
|
||||
{
|
||||
label: "Spectators",
|
||||
field: "spectatorsCount"
|
||||
},
|
||||
];
|
||||
|
||||
handleSort(sortByField) {
|
||||
const { room: { roomId }, sortBy } = this.props;
|
||||
const { field, order } = SortUtil.toggleSortBy(sortByField, sortBy);
|
||||
RoomsDispatch.sortGames(roomId, field, order);
|
||||
}
|
||||
|
||||
private isUnavailableGame({ started, maxPlayers, playerCount }) {
|
||||
return !started && playerCount < maxPlayers;
|
||||
}
|
||||
|
||||
private isPasswordProtectedGame({ withPassword }) {
|
||||
return !withPassword;
|
||||
}
|
||||
|
||||
private isBuddiesOnlyGame({ onlyBuddies }) {
|
||||
return !onlyBuddies;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { room, sortBy } = this.props;
|
||||
|
||||
const games = room.gameList.filter(game => (
|
||||
this.isUnavailableGame(game) &&
|
||||
this.isPasswordProtectedGame(game) &&
|
||||
this.isBuddiesOnlyGame(game)
|
||||
));
|
||||
|
||||
return (
|
||||
<div className="games">
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{ _.map(this.headerCells, ({ label, field }) => {
|
||||
const active = field === sortBy.field;
|
||||
const order = sortBy.order.toLowerCase();
|
||||
const sortDirection = active ? order : false;
|
||||
|
||||
return (
|
||||
<TableCell sortDirection={sortDirection} key={label}>
|
||||
{!field ? label : (
|
||||
<TableSortLabel
|
||||
active={active}
|
||||
direction={order}
|
||||
onClick={() => this.handleSort(field)}
|
||||
>
|
||||
{label}
|
||||
</TableSortLabel>
|
||||
)}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{ _.map(games, ({ description, gameId, gameType, creatorInfo, maxPlayers, playerCount, spectatorsCount, startTime }) => (
|
||||
<TableRow key={gameId}>
|
||||
<TableCell className="games-header__cell single-line-ellipsis">{startTime}</TableCell>
|
||||
<TableCell className="games-header__cell">
|
||||
<Tooltip title={description} placement="bottom-start" enterDelay={500}>
|
||||
<div className="single-line-ellipsis">
|
||||
{description}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell className="games-header__cell">
|
||||
<UserDisplay user={ creatorInfo } />
|
||||
</TableCell>
|
||||
<TableCell className="games-header__cell single-line-ellipsis">{gameType}</TableCell>
|
||||
<TableCell className="games-header__cell single-line-ellipsis">?</TableCell>
|
||||
<TableCell className="games-header__cell single-line-ellipsis">{`${playerCount}/${maxPlayers}`}</TableCell>
|
||||
<TableCell className="games-header__cell single-line-ellipsis">{spectatorsCount}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface GamesProps {
|
||||
room: any;
|
||||
sortBy: any;
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
sortBy: RoomsSelectors.getSortGamesBy(state)
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(Games);
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
.messages {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 5px 0;
|
||||
margin: 2px 0;
|
||||
border-bottom: 1px dashed rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.message:last-of-type {
|
||||
border: 0;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
|
||||
import "./Messages.css";
|
||||
|
||||
const Messages = ({ messages }) => (
|
||||
<div className="messages">
|
||||
{
|
||||
messages && messages.map(({ message, messageType, timeOf, timeReceived }) => (
|
||||
<div className="message" key={timeReceived}>
|
||||
<div className="message__detail">{ParsedMessage(message)}</div>
|
||||
</div>
|
||||
) )
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
const ParsedMessage = (message) => {
|
||||
const name = message.match("^[^:]+:");
|
||||
|
||||
if (name && name.length) {
|
||||
message = message.slice(name[0].length, message.length);
|
||||
}
|
||||
|
||||
return <div>
|
||||
<strong>{name}</strong>
|
||||
{message}
|
||||
</div>
|
||||
};
|
||||
|
||||
export default Messages;
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
.room-view,
|
||||
.room-view__games,
|
||||
.room-view__messages,
|
||||
.room-view__messages-content,
|
||||
.room-view__side {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.room-view__messages,
|
||||
.room-view__side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.room-view__messages-sayMessage {
|
||||
width: 100%;
|
||||
margin: 10px auto 2px;
|
||||
}
|
||||
|
||||
.room-view__side-label {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.room-view__side-list,
|
||||
.room-view__side-list .room-view__side-list__item {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.room-view__side-list .room-view__side-list__item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.room-view__side-list .room-view__side-list__item .user-display__details {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter /*, RouteComponentProps */ } from "react-router-dom";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
|
||||
import { RoomsService } from "api";
|
||||
import { ScrollToBottomOnChanges, ThreePaneLayout, UserDisplay, VirtualList, AuthGuard} from "components";
|
||||
import { RoomsStateMessages, RoomsStateRooms, RoomsSelectors } from "store";
|
||||
|
||||
|
||||
|
||||
import Games from "./Games";
|
||||
import Messages from "./Messages";
|
||||
import SayMessage from "./SayMessage";
|
||||
|
||||
import "./Room.css";
|
||||
|
||||
// @TODO (3)
|
||||
class Room extends Component<any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleRoomSay = this.handleRoomSay.bind(this);
|
||||
}
|
||||
|
||||
handleRoomSay({ message }) {
|
||||
if (message) {
|
||||
const { roomId } = this.props.match.params;
|
||||
RoomsService.roomSay(roomId, message);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, rooms} = this.props;
|
||||
const { roomId } = match.params;
|
||||
const room = rooms[roomId];
|
||||
|
||||
const messages = this.props.messages[roomId];
|
||||
const users = room.userList;
|
||||
|
||||
return (
|
||||
<div className="room-view">
|
||||
<AuthGuard />
|
||||
<ThreePaneLayout
|
||||
fixedHeight
|
||||
|
||||
top={(
|
||||
<Paper className="room-view__games overflow-scroll">
|
||||
<Games room={room} />
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
bottom={(
|
||||
<div className="room-view__messages">
|
||||
<Paper className="room-view__messages-content overflow-scroll">
|
||||
<ScrollToBottomOnChanges changes={messages} content={(
|
||||
<Messages messages={messages} />
|
||||
)} />
|
||||
</Paper>
|
||||
<Paper className="room-view__messages-sayMessage">
|
||||
<SayMessage onSubmit={this.handleRoomSay} />
|
||||
</Paper>
|
||||
</div>
|
||||
)}
|
||||
|
||||
side={(
|
||||
<Paper className="room-view__side overflow-scroll">
|
||||
<div className="room-view__side-label">
|
||||
Users in this room: {users.length}
|
||||
</div>
|
||||
<VirtualList
|
||||
className="room-view__side-list"
|
||||
itemKey={(index, data) => users[index].name }
|
||||
items={ users.map(user => (
|
||||
<ListItem button className="room-view__side-list__item">
|
||||
<UserDisplay user={user} />
|
||||
</ListItem>
|
||||
) ) }
|
||||
/>
|
||||
</Paper>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface RoomProps {
|
||||
messages: RoomsStateMessages;
|
||||
rooms: RoomsStateRooms;
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
messages: RoomsSelectors.getMessages(state),
|
||||
rooms: RoomsSelectors.getRooms(state)
|
||||
});
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(Room));
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Form, reduxForm } from "redux-form"
|
||||
|
||||
import { InputAction } from 'components';
|
||||
|
||||
const SayMessage = ({ handleSubmit }) => (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<InputAction action="Say" label="Chat" name="message" />
|
||||
</Form>
|
||||
);
|
||||
|
||||
const propsMap = {
|
||||
form: "sayMessage"
|
||||
};
|
||||
|
||||
export default connect()(reduxForm(propsMap)(SayMessage));
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
.rooms {
|
||||
}
|
||||
|
||||
.rooms-header,
|
||||
.room {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
.rooms-header__label,
|
||||
.room__detail {
|
||||
width: 10%;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.rooms-header__label.name,
|
||||
.room__detail.name {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.rooms-header__label.description,
|
||||
.room__detail.description {
|
||||
width: 30%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
import { generatePath } from "react-router-dom";
|
||||
import * as _ from "lodash";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
|
||||
|
||||
import { RoomsService } from "api";
|
||||
import { RouteEnum } from "types";
|
||||
|
||||
import "./Rooms.css";
|
||||
|
||||
const Rooms = ({ rooms, joinedRooms, history }) => {
|
||||
function onClick(roomId) {
|
||||
if (_.find(joinedRooms, room => room.roomId === roomId)) {
|
||||
history.push(generatePath(RouteEnum.ROOM, { roomId }));
|
||||
} else {
|
||||
RoomsService.joinRoom(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rooms">
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Name</TableCell>
|
||||
<TableCell>Description</TableCell>
|
||||
<TableCell>Permissions</TableCell>
|
||||
<TableCell>Players</TableCell>
|
||||
<TableCell>Games</TableCell>
|
||||
<TableCell></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{ _.map(rooms, ({ description, gameCount, name, permissionlevel, playerCount, roomId }) => (
|
||||
<TableRow key={roomId}>
|
||||
<TableCell>{name}</TableCell>
|
||||
<TableCell>{description}</TableCell>
|
||||
<TableCell>{permissionlevel}</TableCell>
|
||||
<TableCell>{playerCount}</TableCell>
|
||||
<TableCell>{gameCount}</TableCell>
|
||||
<TableCell>
|
||||
<Button size="small" color="primary" variant="contained" onClick={() => onClick(roomId)}>
|
||||
Join
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Rooms;
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
.server,
|
||||
.server-rooms,
|
||||
.server-rooms__side {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.server {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.server .form-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.server-connect {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.server-connect__form,
|
||||
.server-connect__description {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.server-connect__form {
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
.server-connect__description {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.serverRoomWrapper {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.serverMessage {
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.server-rooms {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.server-rooms__side-label {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
|
||||
import { RoomsSelectors, ServerSelectors } from "store";
|
||||
|
||||
import { AuthenticationService } from "api";
|
||||
|
||||
import { ThreePaneLayout, UserDisplay, VirtualList } from "components";
|
||||
import { ConnectForm, RegisterForm } from "forms";
|
||||
import { Room, StatusEnum, User } from "types";
|
||||
import Rooms from './Rooms';
|
||||
|
||||
import "./Server.css";
|
||||
|
||||
class Server extends Component<ServerProps, ServerState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.showDescription = this.showDescription.bind(this);
|
||||
this.showRegisterForm = this.showRegisterForm.bind(this);
|
||||
this.hideRegisterForm = this.hideRegisterForm.bind(this);
|
||||
this.onRegister = this.onRegister.bind(this);
|
||||
|
||||
this.state = {
|
||||
register: false
|
||||
};
|
||||
}
|
||||
|
||||
showDescription(state, description) {
|
||||
const isDisconnected = state === StatusEnum.DISCONNECTED;
|
||||
const hasDescription = description && !!description.length;
|
||||
|
||||
return isDisconnected && hasDescription;
|
||||
}
|
||||
|
||||
showRegisterForm() {
|
||||
this.setState({register: true});
|
||||
}
|
||||
|
||||
hideRegisterForm() {
|
||||
this.setState({register: false});
|
||||
}
|
||||
|
||||
onRegister(fields) {
|
||||
console.log("register", fields);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { message, rooms, joinedRooms, history, state, description, users } = this.props;
|
||||
const { register } = this.state;
|
||||
const isConnected = AuthenticationService.isConnected(state);
|
||||
|
||||
return (
|
||||
<div className="server">
|
||||
{
|
||||
isConnected
|
||||
? ( <ServerRooms rooms={rooms} joinedRooms={joinedRooms} history={history} message={message} users={users} /> )
|
||||
: (
|
||||
<div className="server-connect">
|
||||
<Paper className="server-connect__form">
|
||||
{
|
||||
register
|
||||
? ( <Register connect={this.hideRegisterForm} onRegister={this.onRegister} /> )
|
||||
: ( <Connect register={this.showRegisterForm} /> )
|
||||
}
|
||||
</Paper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isConnected && this.showDescription(state, description) && (
|
||||
<Paper className="server-connect__description">
|
||||
{description}
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ServerRooms = ({ rooms, joinedRooms, history, message, users}) => (
|
||||
<div className="server-rooms">
|
||||
<ThreePaneLayout
|
||||
top={(
|
||||
<Paper className="serverRoomWrapper overflow-scroll">
|
||||
<Rooms rooms={rooms} joinedRooms={joinedRooms} history={history} />
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
bottom={(
|
||||
<Paper className="serverMessage overflow-scroll" dangerouslySetInnerHTML={{ __html: message }} />
|
||||
)}
|
||||
|
||||
side={(
|
||||
<Paper className="server-rooms__side overflow-scroll">
|
||||
<div className="server-rooms__side-label">
|
||||
Users connected to server: {users.length}
|
||||
</div>
|
||||
<VirtualList
|
||||
itemKey={(index, data) => users[index].name }
|
||||
items={ users.map(user => (
|
||||
<ListItem button dense>
|
||||
<UserDisplay user={user} />
|
||||
</ListItem>
|
||||
) ) }
|
||||
/>
|
||||
</Paper>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Connect = ({register}) => (
|
||||
<div className="form-wrapper">
|
||||
<ConnectForm onSubmit={AuthenticationService.connect} />
|
||||
{/*{<Button variant="outlined" onClick={register}>Register</Button>}*/}
|
||||
</div>
|
||||
);
|
||||
|
||||
const Register = ({ onRegister, connect }) => (
|
||||
<div className="form-wrapper">
|
||||
<RegisterForm onSubmit={event => onRegister(event)} />
|
||||
<Button variant="outlined" onClick={connect}>Connect</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
interface ServerProps {
|
||||
message: string;
|
||||
state: number;
|
||||
description: string;
|
||||
rooms: Room[];
|
||||
joinedRooms: Room[];
|
||||
users: User[];
|
||||
history: any;
|
||||
}
|
||||
|
||||
interface ServerState {
|
||||
register: boolean;
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
message: ServerSelectors.getMessage(state),
|
||||
state: ServerSelectors.getState(state),
|
||||
description: ServerSelectors.getDescription(state),
|
||||
rooms: RoomsSelectors.getRooms(state),
|
||||
joinedRooms: RoomsSelectors.getJoinedRooms(state),
|
||||
users: ServerSelectors.getUsers(state)
|
||||
});
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(Server));
|
||||
|
|
@ -22,12 +22,13 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.three-pane-layout .grid-main__top.fixedHeight {
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.three-pane-layout .grid-main__bottom {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.three-pane-layout .grid-main__top.fixedHeight,
|
||||
.three-pane-layout .grid-main__bottom.fixedHeight {
|
||||
height: 50%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ class ThreePaneLayout extends Component<ThreePaneLayoutProps> {
|
|||
}>
|
||||
{this.props.top}
|
||||
</Grid>
|
||||
<Grid item className="grid-main__bottom">
|
||||
<Grid item className={
|
||||
"grid-main__bottom"
|
||||
+ (this.props.fixedHeight ? " fixedHeight" : "")
|
||||
}>
|
||||
{this.props.bottom}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
// Common components
|
||||
export { default as Header } from './Header/Header';
|
||||
export { default as InputField } from './InputField/InputField';
|
||||
|
|
@ -11,14 +9,6 @@ export { default as CheckboxField } from './CheckboxField/CheckboxField';
|
|||
export { default as SelectField } from './SelectField/SelectField';
|
||||
export { default as ScrollToBottomOnChanges } from './ScrollToBottomOnChanges/ScrollToBottomOnChanges';
|
||||
|
||||
// Major components
|
||||
export { default as Game } from './Game/Game';
|
||||
export { default as Decks } from './Decks/Decks';
|
||||
export { default as Room } from "./Room/Room";
|
||||
export { default as Player } from "./Player/Player";
|
||||
export { default as Server } from "./Server/Server";
|
||||
export { default as Logs } from "./Logs/Logs";
|
||||
|
||||
// Guards
|
||||
export { default as AuthGuard } from './Guard/AuthGuard';
|
||||
export { default as ModGuard} from './Guard/ModGuard';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue