Browse Source

Finalize register view

develop
Apostolos Fanakis 4 years ago
parent
commit
d7a98ef562
  1. 7
      packages/concordia-app/.eslintrc.js
  2. 1
      packages/concordia-app/package.json
  3. 13
      packages/concordia-app/public/locales/en/translation.json
  4. 4
      packages/concordia-app/src/assets/css/app.css
  5. 144
      packages/concordia-app/src/components/SignUpForm.jsx
  6. 2
      packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx
  7. 2
      packages/concordia-app/src/layouts/RegisterLayout/index.jsx
  8. 0
      packages/concordia-app/src/layouts/RegisterLayout/styles.css
  9. 172
      packages/concordia-app/src/views/Register/index.jsx
  10. 10
      packages/concordia-app/src/views/Register/styles.css

7
packages/concordia-app/.eslintrc.js

@ -43,7 +43,12 @@ module.exports = {
'no-unused-vars': 'warn', 'no-unused-vars': 'warn',
'no-console': 'warn', 'no-console': 'warn',
'no-shadow': 'warn', 'no-shadow': 'warn',
"no-multi-str": "warn" "no-multi-str": "warn",
"jsx-a11y/label-has-associated-control": [ 2, {
"labelAttributes": ["label"],
"controlComponents": ["Input"],
"depth": 3,
}],
}, },
'settings': { 'settings': {
'import/resolver': { 'import/resolver': {

1
packages/concordia-app/package.json

@ -32,6 +32,7 @@
"i18next-browser-languagedetector": "^6.0.1", "i18next-browser-languagedetector": "^6.0.1",
"i18next-http-backend": "^1.0.21", "i18next-http-backend": "^1.0.21",
"level": "~6.0.1", "level": "~6.0.1",
"lodash": "^4.17.20",
"orbit-db-identity-provider": "~0.3.1", "orbit-db-identity-provider": "~0.3.1",
"prop-types": "~15.7.2", "prop-types": "~15.7.2",
"react": "~16.13.1", "react": "~16.13.1",

13
packages/concordia-app/public/locales/en/translation.json

@ -1,4 +1,13 @@
{ {
"topbar.button.signup": "Sign Up", "register.card.header": "Sign Up",
"signup.form.button.submit": "Sign Up" "register.form.button.back": "Back",
"register.form.button.guest": "Continue as guest",
"register.form.button.submit": "Sign Up",
"register.form.error.message.header": "Form contains errors",
"register.form.error.username.taken.message": "The username {{username}} is already taken.",
"register.form.header.already.member.message": "There is already an account for this address.\nIf you want to create another account please change your address.",
"register.form.username.field.label": "Username",
"register.form.username.field.placeholder": "Username",
"register.p.account.address": "Account address:",
"topbar.button.register": "Sign Up"
} }

4
packages/concordia-app/src/assets/css/app.css

@ -1,3 +1,7 @@
body { body {
margin: 1em !important; margin: 1em !important;
} }
.i18next-newlines {
white-space: pre-line !important;
}

144
packages/concordia-app/src/components/SignUpForm.jsx

@ -1,144 +0,0 @@
import React, { Component } from 'react';
import {
Button, Form, Menu, Message, Modal,
} from 'semantic-ui-react';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import AppContext from './AppContext';
const contractName = 'Forum';
const checkUsernameTakenMethod = 'isUserNameTaken';
const signUpMethod = 'signUp';
class SignUpForm extends Component {
constructor(props, context) {
super(props, context);
// For quick access
this.contract = this.context.drizzle.contracts[contractName];
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.completeAction = this.completeAction.bind(this);
this.checkedUsernames = [];
this.state = {
usernameInput: '',
error: false,
errorHeader: '',
errorMessage: '',
signingUp: false,
};
}
componentDidUpdate() {
// TODO
}
handleSubmit() {
const { usernameInput, error } = this.state;
if (usernameInput === '') {
this.setState({
error: true,
errorHeader: 'Data Incomplete',
errorMessage: 'You need to provide a username',
});
} else if (!error) {
// TODO
// // Makes sure current input username has been checked for availability
// if (this.checkedUsernames.some((e) => e.usernameChecked === usernameInput)) {
// this.completeAction();
// }
this.completeAction();
}
}
handleInputChange(e, { name, value }) {
this.setState({
[name]: value,
error: false,
});
if (value !== '') {
if (this.checkedUsernames.length > 0) {
if (this.checkedUsernames.some((e) => e.usernameChecked === value)) {
return;
}
}
this.contract.methods[checkUsernameTakenMethod].cacheCall(
value,
);
}
}
completeAction() {
const { usernameInput } = this.state;
const { user, account } = this.props;
if (user.hasSignedUp) {
this.contract.methods.signUp.cacheSend(usernameInput);
} else {
this.setState({
signingUp: true,
});
this.contract.methods[signUpMethod].cacheSend(
...[usernameInput], { from: account },
);
}
this.setState({
usernameInput: '',
});
}
render() {
const {
error, usernameInput, errorHeader, errorMessage, signingUp,
} = this.state;
const { t } = this.props;
return (
<Modal
as={Form}
onSubmit={(e) => this.handleSubmit(e)}
trigger={(
<Menu.Item
name="signup"
position="right"
content={t('topbar.button.signup')}
/>
)}
>
<Modal.Header>Sign Up</Modal.Header>
<Modal.Content>
<Form.Field required>
<label>Username</label>
<Form.Input
placeholder="Username"
name="usernameInput"
value={usernameInput}
onChange={this.handleInputChange}
/>
</Form.Field>
<Message
error
header={errorHeader}
content={errorMessage}
/>
<Button type="submit" color="black" content={t('signup.form.button.submit')} />
</Modal.Content>
</Modal>
);
}
}
SignUpForm.contextType = AppContext.Context;
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(withTranslation()(SignUpForm));

2
packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx

@ -29,7 +29,7 @@ const MainLayoutMenu = (props) => {
onClick={() => { push('/auth/register'); }} onClick={() => { push('/auth/register'); }}
position="right" position="right"
> >
{t('topbar.button.signup')} {t('topbar.button.register')}
</Menu.Item> </Menu.Item>
</Menu> </Menu>
</div> </div>

2
packages/concordia-app/src/layouts/RegisterLayout/index.jsx

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Particles from 'react-particles-js'; import Particles from 'react-particles-js';
import particlesOptions from '../../assets/particles'; import particlesOptions from '../../assets/particles';
import '../../assets/css/register-layout.css'; import './styles.css';
const RegisterLayout = (props) => { const RegisterLayout = (props) => {
const { children } = props; const { children } = props;

0
packages/concordia-app/src/assets/css/register-layout.css → packages/concordia-app/src/layouts/RegisterLayout/styles.css

172
packages/concordia-app/src/views/Register/index.jsx

@ -0,0 +1,172 @@
import React, {
useCallback, useContext, useEffect, useMemo, useState,
} from 'react';
import {
Button, Card, Form, Header, Input, Message,
} from 'semantic-ui-react';
import throttle from 'lodash/throttle';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { useHistory } from 'react-router';
import AppContext from '../../components/AppContext';
import './styles.css';
const Register = (props) => {
const { user, account, isUserNameTakenResults } = props;
const {
drizzle: {
contracts: {
Forum: {
methods: { isUserNameTaken, signUp },
},
},
},
} = useContext(AppContext.Context);
const [usernameInput, setUsernameInput] = useState('');
const [usernameIsChecked, setUsernameIsChecked] = useState(true);
const [usernameIsTaken, setUsernameIsTaken] = useState(true);
const [error, setError] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [signingUp, setSigningUp] = useState(false);
const history = useHistory();
const { t } = useTranslation();
useEffect(() => {
if (usernameInput.length > 0) {
const checkedUsernames = Object
.values(isUserNameTakenResults)
.map((callCompleted) => ({
checkedUsername: callCompleted.args[0],
isTaken: callCompleted.value,
}));
const checkedUsername = checkedUsernames
.find((callCompleted) => callCompleted.checkedUsername === usernameInput);
setUsernameIsChecked(checkedUsername !== undefined);
if (checkedUsername && checkedUsername.isTaken) {
setUsernameIsTaken(true);
setError(true);
setErrorMessage(t('register.form.error.username.taken.message', { username: usernameInput }));
} else {
setUsernameIsTaken(false);
setError(false);
}
}
}, [isUserNameTakenResults, t, usernameInput]);
const checkUsernameTaken = useMemo(() => throttle(
(username) => {
isUserNameTaken.cacheCall(username);
}, 200,
), [isUserNameTaken]);
const handleInputChange = useCallback((event, { value }) => {
setUsernameInput(value);
if (value.length > 0) {
checkUsernameTaken(value);
}
}, [checkUsernameTaken]);
const handleSubmit = useCallback(() => {
if (user.hasSignedUp) {
signUp.cacheSend(usernameInput);
} else {
setSigningUp(true);
signUp.cacheSend(
...[usernameInput], { from: account },
);
}
}, [account, signUp, user.hasSignedUp, usernameInput]);
const goToHomePage = React.useCallback(() => history.push('/'), [history]);
return (
<div className="centered form-card-container">
<Card fluid>
<Card.Content>
<Card.Header>Sign Up</Card.Header>
<Card.Description>
<p>
<strong>{t('register.p.account.address')}</strong>
&nbsp;
{user.address}
</p>
{user.hasSignedUp
? (
<div>
<Header as="h4" className="i18next-newlines">
{t('register.form.header.already.member.message')}
</Header>
</div>
)
: (
<Form loading={signingUp}>
<Form.Field required>
<label htmlFor="form-register-field-username">
{t('register.form.username.field.label')}
</label>
<Input
id="form-register-field-username"
placeholder={t('register.form.username.field.placeholder')}
name="usernameInput"
className="form-input"
value={usernameInput}
onChange={handleInputChange}
/>
</Form.Field>
</Form>
)}
</Card.Description>
</Card.Content>
{error === true && (
<Card.Content extra>
<Message
error
header={t('register.form.error.message.header')}
content={errorMessage}
/>
</Card.Content>
)}
<Card.Content extra>
{user.hasSignedUp
? (
<Button
color="black"
floated="right"
content={t('register.form.button.back')}
onClick={goToHomePage}
/>
)
: (
<>
<Button
color="green"
floated="right"
content={t('register.form.button.submit')}
onClick={handleSubmit}
disabled={usernameIsTaken || signingUp}
loading={!usernameIsChecked}
/>
<Button
color="violet"
floated="right"
basic
content={t('register.form.button.guest')}
onClick={goToHomePage}
/>
</>
)}
</Card.Content>
</Card>
</div>
);
};
const mapStateToProps = (state) => ({
user: state.user,
isUserNameTakenResults: state.contracts.Forum.isUserNameTaken,
});
export default connect(mapStateToProps)(Register);

10
packages/concordia-app/src/views/Register/styles.css

@ -0,0 +1,10 @@
.centered {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.form-card-container {
min-width: 15vw;
}
Loading…
Cancel
Save