mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-10 00:04:48 -07:00
Webclient: Handle firing an event once (#4499)
* draft: handle firing an event once * lint * Prevent rapid double-click on sending messages * no rest spread on single primative when sibling components exist * clear message instead of using a fireOnce handler. * fix tests * remove unnecessary validate mock
This commit is contained in:
parent
4bb13677c8
commit
513fcb0908
16 changed files with 21467 additions and 161 deletions
|
|
@ -1,19 +1,16 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, reduxForm } from 'redux-form'
|
||||
import React from 'react';
|
||||
import { Form } from 'react-final-form'
|
||||
|
||||
import { InputAction } from 'components';
|
||||
import { FormKey } from 'types';
|
||||
|
||||
const AddToBuddies = ({ handleSubmit }) => (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<InputAction action="Add" label="Add to Buddies" name="userName" />
|
||||
const AddToBuddies = ({ onSubmit }) => (
|
||||
<Form onSubmit={values => onSubmit(values)}>
|
||||
{({ handleSubmit }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<InputAction action="Add" label="Add to Buddies" name="userName" />
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.ADD_TO_BUDDIES
|
||||
};
|
||||
|
||||
export default connect()(reduxForm(propsMap)(AddToBuddies));
|
||||
export default AddToBuddies;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, reduxForm } from 'redux-form'
|
||||
import React from 'react';
|
||||
import { Form } from 'react-final-form'
|
||||
|
||||
import { InputAction } from 'components';
|
||||
import { FormKey } from 'types';
|
||||
|
||||
const AddToIgnore = ({ handleSubmit }) => (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<InputAction action="Add" label="Add to Ignore" name="userName" />
|
||||
const AddToIgnore = ({ onSubmit }) => (
|
||||
<Form onSubmit={values => onSubmit(values)}>
|
||||
{({ handleSubmit }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<InputAction action="Add" label="Add to Ignore" name="userName" />
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.ADD_TO_IGNORE,
|
||||
};
|
||||
|
||||
export default connect()(reduxForm(propsMap)(AddToIgnore));
|
||||
export default AddToIgnore;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import Typography from '@material-ui/core/Typography';
|
|||
import { AuthenticationService } from 'api';
|
||||
import { RegistrationDialog, RequestPasswordResetDialog, ResetPasswordDialog } from 'dialogs';
|
||||
import { LoginForm } from 'forms';
|
||||
import { useReduxEffect } from 'hooks';
|
||||
import { useReduxEffect, useFireOnce } from 'hooks';
|
||||
import { Images } from 'images';
|
||||
import { HostDTO } from 'services';
|
||||
import { RouteEnum, WebSocketConnectOptions, getHostPort } from 'types';
|
||||
|
|
@ -77,15 +77,6 @@ const Login = ({ state, description }: LoginProps) => {
|
|||
closeResetPasswordDialog();
|
||||
}, ServerTypes.RESET_PASSWORD_SUCCESS, []);
|
||||
|
||||
useReduxEffect(({ options: { hashedPassword } }) => {
|
||||
if (hostIdToRemember) {
|
||||
HostDTO.get(hostIdToRemember).then(host => {
|
||||
host.hashedPassword = hashedPassword;
|
||||
host.save();
|
||||
});
|
||||
}
|
||||
}, ServerTypes.LOGIN_SUCCESSFUL, [hostIdToRemember]);
|
||||
|
||||
const showDescription = () => {
|
||||
return !isConnected && description?.length;
|
||||
};
|
||||
|
|
@ -121,6 +112,19 @@ const Login = ({ state, description }: LoginProps) => {
|
|||
AuthenticationService.login(options as WebSocketConnectOptions);
|
||||
}, []);
|
||||
|
||||
const [submitButtonDisabled, resetSubmitButton, handleLogin] = useFireOnce(onSubmitLogin)
|
||||
|
||||
useReduxEffect(({ options: { hashedPassword } }) => {
|
||||
if (hostIdToRemember) {
|
||||
HostDTO.get(hostIdToRemember).then(host => {
|
||||
host.hashedPassword = hashedPassword;
|
||||
host.save();
|
||||
});
|
||||
}
|
||||
resetSubmitButton()
|
||||
}, ServerTypes.LOGIN_SUCCESSFUL, [hostIdToRemember]);
|
||||
|
||||
|
||||
const updateHost = ({ selectedHost, userName, hashedPassword, remember }) => {
|
||||
HostDTO.get(selectedHost.id).then(hostDTO => {
|
||||
hostDTO.remember = remember;
|
||||
|
|
@ -208,7 +212,11 @@ const Login = ({ state, description }: LoginProps) => {
|
|||
<Typography variant="h1">Login</Typography>
|
||||
<Typography variant="subtitle1">A cross-platform virtual tabletop for multiplayer card games.</Typography>
|
||||
<div className="login-form">
|
||||
<LoginForm onSubmit={onSubmitLogin} onResetPassword={openRequestPasswordResetDialog} />
|
||||
<LoginForm
|
||||
onSubmit={handleLogin}
|
||||
onResetPassword={openRequestPasswordResetDialog}
|
||||
disableSubmitButton={submitButtonDisabled}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from "react";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter, generatePath } from 'react-router-dom';
|
||||
|
||||
|
|
@ -8,7 +7,7 @@ import Paper from '@material-ui/core/Paper';
|
|||
|
||||
import { RoomsService } from 'api';
|
||||
import { ScrollToBottomOnChanges, ThreePaneLayout, UserDisplay, VirtualList, AuthGuard } from 'components';
|
||||
import { RoomsStateMessages, RoomsStateRooms, JoinedRooms, RoomsSelectors } from 'store';
|
||||
import { RoomsStateMessages, RoomsStateRooms, JoinedRooms, RoomsSelectors, RoomsTypes } from 'store';
|
||||
import { RouteEnum } from 'types';
|
||||
|
||||
import OpenGames from './OpenGames';
|
||||
|
|
@ -18,86 +17,73 @@ import SayMessage from './SayMessage';
|
|||
import './Room.css';
|
||||
|
||||
// @TODO (3)
|
||||
class Room extends Component<any> {
|
||||
componentDidUpdate() {
|
||||
const { joined, match, history } = this.props;
|
||||
let { roomId } = match.params;
|
||||
function Room(props) {
|
||||
|
||||
roomId = parseInt(roomId, 0);
|
||||
const { joined, match, history, rooms, messages } = props;
|
||||
const roomId = parseInt(match.params.roomId, 0);
|
||||
|
||||
if (!joined.find(({ roomId: id }) => id === roomId)) {
|
||||
history.push(generatePath(RouteEnum.SERVER));
|
||||
}
|
||||
if (!joined.find(({ roomId: id }) => id === roomId)) {
|
||||
history.push(generatePath(RouteEnum.SERVER));
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleRoomSay = this.handleRoomSay.bind(this);
|
||||
}
|
||||
|
||||
handleRoomSay({ message }) {
|
||||
function 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 room = rooms[roomId];
|
||||
|
||||
const messages = this.props.messages[roomId];
|
||||
const users = room.userList;
|
||||
const roomMessages = messages[roomId];
|
||||
const users = room.userList;
|
||||
|
||||
return (
|
||||
<div className="room-view">
|
||||
<AuthGuard />
|
||||
return (
|
||||
<div className="room-view">
|
||||
<AuthGuard />
|
||||
|
||||
<div className="room-view__main">
|
||||
<ThreePaneLayout
|
||||
fixedHeight
|
||||
<div className="room-view__main">
|
||||
<ThreePaneLayout
|
||||
fixedHeight
|
||||
|
||||
top={(
|
||||
<Paper className="room-view__games overflow-scroll">
|
||||
<OpenGames room={room} />
|
||||
top={(
|
||||
<Paper className="room-view__games overflow-scroll">
|
||||
<OpenGames room={room} />
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
bottom={(
|
||||
<div className="room-view__messages">
|
||||
<Paper className="room-view__messages-content overflow-scroll">
|
||||
<ScrollToBottomOnChanges changes={roomMessages} content={(
|
||||
<Messages messages={roomMessages} />
|
||||
)} />
|
||||
</Paper>
|
||||
)}
|
||||
<Paper className="room-view__messages-sayMessage">
|
||||
<SayMessage onSubmit={handleRoomSay} />
|
||||
</Paper>
|
||||
</div>
|
||||
)}
|
||||
|
||||
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">
|
||||
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>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface RoomProps {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
// eslint-disable-next-line
|
||||
import React from "react";
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, reduxForm } from 'redux-form'
|
||||
import React from 'react';
|
||||
import { Form } from 'react-final-form'
|
||||
|
||||
import { InputAction } from 'components';
|
||||
|
||||
const SayMessage = ({ handleSubmit }) => (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<InputAction action="Send" label="Chat" name="message" />
|
||||
</Form>
|
||||
);
|
||||
const required = (value) => (value ? undefined : 'Required');
|
||||
|
||||
const propsMap = {
|
||||
form: 'sayMessage'
|
||||
};
|
||||
const SayMessage = (props) => {
|
||||
const { onSubmit } = props
|
||||
return (
|
||||
<Form onSubmit={values => onSubmit(values)}>
|
||||
{({ handleSubmit, form }) => (
|
||||
<form onSubmit={e => {
|
||||
handleSubmit(e)
|
||||
form.restart()
|
||||
}}>
|
||||
<InputAction action="Send" label="Chat" name="message" validate={required}/>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect()(reduxForm(propsMap)(SayMessage));
|
||||
export default SayMessage;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue