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:
Jeremy Letto 2021-05-18 22:06:41 -05:00 committed by GitHub
parent 294229622d
commit 8db9475804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 127 additions and 76 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -1,3 +0,0 @@
.log-results {
margin-bottom: 20px;
}

View file

@ -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;

View file

@ -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%;
}

View file

@ -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));

View file

@ -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;

View file

@ -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%;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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));

View file

@ -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));

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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));

View file

@ -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%;
}

View file

@ -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>

View file

@ -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';