- {
- isConnected
- ? (
)
- : (
-
-
- {
- register
- ? ( )
- : ( )
- }
-
-
- )
- }
- {
- !isConnected && this.showDescription(state, description) && (
-
- {description}
-
- )
- }
+
+
+
+
+ )}
+
+ bottom={(
+
+
+
+ )}
+
+ side={(
+
+
+ Users connected to server: {users.length}
+
+ users[index].name }
+ items={ users.map(user => (
+
+
+
+ ) ) }
+ />
+
+ )}
+ />
);
}
}
-const ServerRooms = ({ rooms, joinedRooms, history, message, users}) => (
-
-
-
-
- )}
-
- bottom={(
-
-
-
- )}
-
- side={(
-
-
- Users connected to server: {users.length}
-
- users[index].name }
- items={ users.map(user => (
-
-
-
- ) ) }
- />
-
- )}
- />
-
-);
-
-const Connect = ({register}) => (
-
-
-
-
-);
-
-const Register = ({ connect }) => (
-
-
-
-
-);
-
interface ServerProps {
message: string;
- state: number;
- description: string;
rooms: Room[];
joinedRooms: Room[];
users: User[];
@@ -139,16 +63,14 @@ interface ServerProps {
}
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));
\ No newline at end of file
+export default withRouter(connect(mapStateToProps)(Server));
diff --git a/webclient/src/containers/index.ts b/webclient/src/containers/index.ts
index f39d3725b..e9efbd6fe 100644
--- a/webclient/src/containers/index.ts
+++ b/webclient/src/containers/index.ts
@@ -5,4 +5,5 @@ 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";
\ No newline at end of file
+export { default as Logs } from "./Logs/Logs";
+export { default as Login } from "./Login/Login";
diff --git a/webclient/src/forms/LoginForm/LoginForm.css b/webclient/src/forms/LoginForm/LoginForm.css
new file mode 100644
index 000000000..4b176476f
--- /dev/null
+++ b/webclient/src/forms/LoginForm/LoginForm.css
@@ -0,0 +1,20 @@
+.loginForm {
+ width: 100%;
+}
+
+.loginForm-item {
+ margin-bottom: 20px;
+}
+
+.loginForm-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: -20px;
+ margin-bottom: 20px;
+ font-weight: bold;
+}
+
+.loginForm-submit {
+ width: 100%;
+}
diff --git a/webclient/src/forms/LoginForm/LoginForm.tsx b/webclient/src/forms/LoginForm/LoginForm.tsx
new file mode 100644
index 000000000..0ce753665
--- /dev/null
+++ b/webclient/src/forms/LoginForm/LoginForm.tsx
@@ -0,0 +1,73 @@
+// eslint-disable-next-line
+import React from "react";
+import { connect } from "react-redux";
+import { Form, Field, reduxForm, change } from "redux-form"
+
+import Button from "@material-ui/core/Button";
+
+import { InputField, KnownHosts } from "components";
+// import { ServerDispatch } from "store";
+import { FormKey } from 'types';
+
+import "./LoginForm.css";
+
+const LoginForm = (props) => {
+ const { dispatch, handleSubmit } = props;
+
+ const forgotPassword = () => {
+ console.log('LoginForm.forgotPassword->openForgotPasswordDialog');
+ };
+
+ const onHostChange = ({ host, port }) => {
+ dispatch(change(FormKey.LOGIN, 'host', host));
+ dispatch(change(FormKey.LOGIN, 'port', port));
+ }
+
+ return (
+
+ );
+}
+
+const propsMap = {
+ form: FormKey.LOGIN,
+ validate: values => {
+ const errors: any = {};
+
+ if (!values.user) errors.user = 'Required';
+ if (!values.pass) errors.pass = 'Required';
+ if (!values.host) errors.host = 'Required';
+ if (!values.port) errors.port = 'Required';
+
+ return errors;
+ }
+};
+
+const mapStateToProps = () => ({
+ initialValues: {
+ // host: "mtg.tetrarch.co/servatrice",
+ // port: "443"
+ // host: "server.cockatrice.us",
+ // port: "4748"
+ }
+});
+
+export default connect(mapStateToProps)(reduxForm(propsMap)(LoginForm));
diff --git a/webclient/src/forms/index.ts b/webclient/src/forms/index.ts
index 72fa688ec..141ff1bed 100644
--- a/webclient/src/forms/index.ts
+++ b/webclient/src/forms/index.ts
@@ -1,4 +1,5 @@
export { default as CardImportForm } from './CardImportForm/CardImportForm';
export { default as ConnectForm } from './ConnectForm/ConnectForm';
+export { default as LoginForm } from './LoginForm/LoginForm';
export { default as RegisterForm } from './RegisterForm/RegisterForm';
export { default as SearchForm } from './SearchForm/SearchForm';
diff --git a/webclient/src/images/logo.png b/webclient/src/images/logo.png
new file mode 100644
index 000000000..7ce83bd20
Binary files /dev/null and b/webclient/src/images/logo.png differ
diff --git a/webclient/src/index.css b/webclient/src/index.css
index 3dc46340d..015c037cd 100644
--- a/webclient/src/index.css
+++ b/webclient/src/index.css
@@ -1,3 +1,5 @@
+@import url('https://fonts.googleapis.com/css2?family=Teko&display=swap');
+
:root {
}
diff --git a/webclient/src/material-theme.ts b/webclient/src/material-theme.ts
index 472c27d58..d2a373450 100644
--- a/webclient/src/material-theme.ts
+++ b/webclient/src/material-theme.ts
@@ -1,69 +1,157 @@
import { createMuiTheme } from '@material-ui/core';
+const palette = {
+ background: {
+ default: 'dimgrey',
+ paper: '#FFFFFF',
+ },
+ primary: {
+ main: '#7033DB',
+ light: 'rgba(112, 51, 219, .3)',
+ dark: '#401C7F',
+ contrastText: '#FFFFFF',
+ },
+ // secondary: {
+ // main: '',
+ // light: '',
+ // dark: '',
+ // contrastText: '',
+ // },
+ // error: {
+ // main: '',
+ // light: '',
+ // dark: '',
+ // contrastText: '',
+ // },
+ // warning: {
+ // main: '',
+ // light: '',
+ // dark: '',
+ // contrastText: '',
+ // },
+ // info: {
+ // main: '',
+ // light: '',
+ // dark: '',
+ // contrastText: '',
+ // },
+ success: {
+ main: '#6CDF39',
+ light: '#6CDF39',
+ // dark: '',
+ // contrastText: '',
+ },
+};
+
export const materialTheme = createMuiTheme({
- // overrides: {
+ palette,
+
+ overrides: {
// MuiCssBaseline: {
// '@global': {
// '@font-face': [],
// },
// },
- // MuiButton: {
- // text: {
- // color: 'white',
- // },
- // },
- // },
+ MuiButton: {
+ root: {
+ fontWeight: 'bold',
+ textTransform: 'none',
- palette: {
- primary: {
- main: '#7033DB',
- light: 'rgba(112, 51, 219, .3)',
- dark: '#401C7F',
- contrastText: '#FFFFFF',
+ '&.rounded': {
+ // 'border-radius': '50px',
+ },
+
+ '&.tall': {
+ 'height': '40px',
+ },
+ },
+ },
+
+ MuiList: {
+ root: {
+ padding: '8px',
+
+ '&.MuiList-padding': {
+ paddingBottom: '4px',
+ },
+
+ '& .MuiButton-root': {
+ width: '100%',
+ },
+
+ '& > .MuiButtonBase-root': {
+ padding: '8px 16px',
+ marginBottom: '4px',
+ borderRadius: 0,
+ justifyContent: 'space-between',
+ },
+
+ '& .MuiButtonBase-root.Mui-selected, & .MuiButtonBase-root.Mui-selected:hover, & .MuiButtonBase-root:hover': {
+ background: palette.primary.light
+ },
+
+ [[
+ '& .MuiButtonBase-root.Mui-selected',
+ '& .MuiButtonBase-root.Mui-selected:hover',
+ '& .MuiButtonBase-root:hover'
+ ].join(', ')]: {
+ background: palette.primary.light
+ },
+ },
+ },
+
+ MuiListItem: {
+ root: {
+ },
+ },
+
+ MuiInputBase: {
+ formControl: {
+ '& .MuiSelect-root svg': {
+ display: 'none',
+ },
+ },
+ },
+
+ MuiOutlinedInput: {
+ root: {
+ '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
+ borderWidth: '1px',
+ },
+
+ '.rounded &': {
+ // 'border-radius': '50px',
+ },
+
+ '.tall &': {
+ height: '40px',
+ },
+ },
},
- // secondary: {
- // main: '',
- // light: '',
- // dark: '',
- // contrastText: '',
- // },
- // error: {
- // main: '',
- // light: '',
- // dark: '',
- // contrastText: '',
- // },
- // warning: {
- // main: '',
- // light: '',
- // dark: '',
- // contrastText: '',
- // },
- // info: {
- // main: '',
- // light: '',
- // dark: '',
- // contrastText: '',
- // },
- // success: {
- // main: '',
- // light: '',
- // dark: '',
- // contrastText: '',
- // },
},
typography: {
fontSize: 12,
- // h1: {},
+ h1: {
+ fontSize: 28,
+ fontWeight: 'bold',
+ },
// h2: {},
// h3: {},
// h4: {},
// h5: {},
// h6: {},
- // subtitle1: {},
- // subtitle2: {},
+ subtitle1: {
+ fontSize: 14,
+ fontWeight: 'bold',
+ lineHeight: 1.4,
+ color: '#9E9E9E',
+ },
+ subtitle2: {
+ lineHeight: 1.4,
+ color: '#9E9E9E',
+ },
// body1: {},
// body2: {},
// button: {},
diff --git a/webclient/src/services/DexieDTOs/HostDTO.ts b/webclient/src/services/DexieDTOs/HostDTO.ts
new file mode 100644
index 000000000..e58c82313
--- /dev/null
+++ b/webclient/src/services/DexieDTOs/HostDTO.ts
@@ -0,0 +1,28 @@
+import { IndexableType } from 'dexie';
+import { Host } from 'types';
+
+import { dexieService } from '../DexieService';
+
+export class HostDTO extends Host {
+ save() {
+ return dexieService.hosts.put(this);
+ }
+
+ static add(host: HostDTO): Promise
{
+ return dexieService.hosts.add(host);
+ }
+
+ static get(id): Promise {
+ return dexieService.hosts.where('id').equals(id).first();
+ }
+
+ static getAll(): Promise {
+ return dexieService.hosts.toArray();
+ }
+
+ static bulkAdd(hosts: Host[]): Promise {
+ return dexieService.hosts.bulkAdd(hosts);
+ }
+};
+
+dexieService.hosts.mapToClass(HostDTO);
diff --git a/webclient/src/services/DexieDTOs/index.ts b/webclient/src/services/DexieDTOs/index.ts
index 2ec930169..f95954c55 100644
--- a/webclient/src/services/DexieDTOs/index.ts
+++ b/webclient/src/services/DexieDTOs/index.ts
@@ -1,3 +1,4 @@
export * from './CardDTO';
export * from './SetDTO';
export * from './TokenDTO';
+export * from './HostDTO';
diff --git a/webclient/src/services/DexieService.ts b/webclient/src/services/DexieService.ts
index 2429481b8..b9141ddb7 100644
--- a/webclient/src/services/DexieService.ts
+++ b/webclient/src/services/DexieService.ts
@@ -4,12 +4,14 @@ enum Stores {
CARDS = 'cards',
SETS = 'sets',
TOKENS = 'tokens',
+ HOSTS = 'hosts',
}
const StoreKeyIndexes = {
- [Stores.CARDS]: "name",
- [Stores.SETS]: "code",
- [Stores.TOKENS]: "name.value",
+ [Stores.CARDS]: 'name',
+ [Stores.SETS]: 'code',
+ [Stores.TOKENS]: 'name.value',
+ [Stores.HOSTS]: '++id,name',
};
class DexieService {
@@ -30,6 +32,10 @@ class DexieService {
get tokens() {
return this.db.table(Stores.TOKENS);
}
+
+ get hosts() {
+ return this.db.table(Stores.HOSTS);
+ }
}
export const dexieService = new DexieService();
diff --git a/webclient/src/types/forms.ts b/webclient/src/types/forms.ts
index 753885ead..32cf7e408 100644
--- a/webclient/src/types/forms.ts
+++ b/webclient/src/types/forms.ts
@@ -3,6 +3,7 @@ export enum FormKey {
ADD_TO_IGNORE = "ADD_TO_IGNORE",
CARD_IMPORT = "CARD_IMPORT",
CONNECT = "CONNECT",
+ LOGIN = "LOGIN",
REGISTER = "REGISTER",
SEARCH_LOGS = "SEARCH_LOGS",
}
diff --git a/webclient/src/types/routes.tsx b/webclient/src/types/routes.tsx
index e5e1bf63d..0dd3bba6f 100644
--- a/webclient/src/types/routes.tsx
+++ b/webclient/src/types/routes.tsx
@@ -1,10 +1,11 @@
export enum RouteEnum {
- PLAYER = "/player/:name",
- SERVER = "/server",
- ROOM = "/room/:roomId",
- LOGS = "/logs",
- GAME = "/game",
- DECKS = "/decks",
- DECK = "/deck",
- ACCOUNT = "/account",
+ PLAYER = '/player/:name',
+ SERVER = '/server',
+ ROOM = '/room/:roomId',
+ LOGIN = '/',
+ LOGS = '/logs',
+ GAME = '/game',
+ DECKS = '/decks',
+ DECK = '/deck',
+ ACCOUNT = '/account',
}
diff --git a/webclient/src/types/server.tsx b/webclient/src/types/server.tsx
index 23a70d25a..d3a158811 100644
--- a/webclient/src/types/server.tsx
+++ b/webclient/src/types/server.tsx
@@ -31,6 +31,48 @@ export enum StatusEnumLabel {
"Disconnecting" = 99
}
+export class Host {
+ id?: number;
+ name: string;
+ host: string;
+ port: string;
+ localHost?: string;
+ localPort?: string;
+ editable: boolean;
+}
+
+export const DefaultHosts: Host[] = [
+ {
+ name: 'Rooster',
+ host: 'server.cockatrice.us/servatrice',
+ port: '4748',
+ localHost: 'server.cockatrice.us',
+ editable: false,
+ },
+ {
+ name: 'Tetrarch',
+ host: 'mtg.tetrarch.co/servatrice',
+ port: '4748',
+ editable: false,
+ },
+];
+
+export const getHostPort = (host: Host): { host: string, port: string } => {
+ const isLocal = window.location.hostname === 'localhost';
+
+ if (!host) {
+ return {
+ host: '',
+ port: ''
+ };
+ }
+
+ return {
+ host: !isLocal ? host.host : host.localHost || host.host,
+ port: !isLocal ? host.port : host.localPort || host.port,
+ }
+};
+
export enum KnownHost {
ROOSTER = 'Rooster',
TETRARCH = 'Tetrarch',