[add] Jhipster base

This commit is contained in:
2018-08-06 21:49:34 -06:00
parent 1390427ec0
commit 11626e6efb
247 changed files with 145182 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
export const ACTION_TYPES = {
ACTIVATE_ACCOUNT: 'activate/ACTIVATE_ACCOUNT',
RESET: 'activate/RESET'
};
const initialState = {
activationSuccess: false,
activationFailure: false
};
export type ActivateState = Readonly<typeof initialState>;
// Reducer
export default (state: ActivateState = initialState, action): ActivateState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.ACTIVATE_ACCOUNT):
return {
...state
};
case FAILURE(ACTION_TYPES.ACTIVATE_ACCOUNT):
return {
...state,
activationFailure: true
};
case SUCCESS(ACTION_TYPES.ACTIVATE_ACCOUNT):
return {
...state,
activationSuccess: true
};
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
// Actions
export const activateAction = key => ({
type: ACTION_TYPES.ACTIVATE_ACCOUNT,
payload: axios.get('api/activate?key=' + key)
});
export const reset = () => ({
type: ACTION_TYPES.RESET
});

View File

@@ -0,0 +1,66 @@
import React from 'react';
import { connect } from 'react-redux';
import { Link, RouteComponentProps } from 'react-router-dom';
import { Row, Col, Alert } from 'reactstrap';
import { IRootState } from 'app/shared/reducers';
import { activateAction, reset } from './activate.reducer';
const successAlert = (
<Alert color="success">
<strong>Your user account has been activated.</strong> Please
<Link to="/login" className="alert-link">
sign in
</Link>.
</Alert>
);
const failureAlert = (
<Alert color="danger">
<strong>Your user could not be activated.</strong> Please use the registration form to sign up.
</Alert>
);
export interface IActivateProps extends StateProps, DispatchProps, RouteComponentProps<{ key: any }> {}
export class ActivatePage extends React.Component<IActivateProps> {
componentWillUnmount() {
this.props.reset();
}
componentDidMount() {
const { key } = this.props.match.params;
this.props.activateAction(key);
}
render() {
const { activationSuccess, activationFailure } = this.props;
return (
<div>
<Row className="justify-content-center">
<Col md="8">
<h1>Activation</h1>
{activationSuccess ? successAlert : undefined}
{activationFailure ? failureAlert : undefined}
</Col>
</Row>
</div>
);
}
}
const mapStateToProps = ({ activate }: IRootState) => ({
activationSuccess: activate.activationSuccess,
activationFailure: activate.activationFailure
});
const mapDispatchToProps = { activateAction, reset };
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(
mapStateToProps,
mapDispatchToProps
)(ActivatePage);

View File

@@ -0,0 +1,17 @@
import React from 'react';
import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
import Settings from './settings/settings';
import Password from './password/password';
import Sessions from './sessions/sessions';
const Routes = ({ match }) => (
<div>
<ErrorBoundaryRoute path={`${match.url}/settings`} component={Settings} />
<ErrorBoundaryRoute path={`${match.url}/password`} component={Password} />
<ErrorBoundaryRoute path={`${match.url}/sessions`} component={Sessions} />
</div>
);
export default Routes;

View File

@@ -0,0 +1,95 @@
import React from 'react';
import { connect } from 'react-redux';
import { Alert, Col, Row, Button } from 'reactstrap';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { RouteComponentProps } from 'react-router-dom';
import { IRootState } from 'app/shared/reducers';
import { handlePasswordResetFinish, reset } from '../password-reset.reducer';
import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
export interface IPasswordResetFinishProps extends DispatchProps, RouteComponentProps<{ key: string }> {}
export interface IPasswordResetFinishState {
password: string;
key: string;
}
export class PasswordResetFinishPage extends React.Component<IPasswordResetFinishProps, IPasswordResetFinishState> {
state: IPasswordResetFinishState = {
password: '',
key: this.props.match.params.key
};
componentWillUnmount() {
this.props.reset();
}
handleValidSubmit = (event, values) => {
this.props.handlePasswordResetFinish(this.state.key, values.newPassword);
};
updatePassword = event => {
this.setState({ password: event.target.value });
};
getResetForm() {
return (
<AvForm onValidSubmit={this.handleValidSubmit}>
<AvField
name="newPassword"
label="New password"
placeholder={'New password'}
type="password"
validate={{
required: { value: true, errorMessage: 'Your password is required.' },
minLength: { value: 4, errorMessage: 'Your password is required to be at least 4 characters.' },
maxLength: { value: 50, errorMessage: 'Your password cannot be longer than 50 characters.' }
}}
onChange={this.updatePassword}
/>
<PasswordStrengthBar password={this.state.password} />
<AvField
name="confirmPassword"
label="New password confirmation"
placeholder="Confirm the new password"
type="password"
validate={{
required: { value: true, errorMessage: 'Your confirmation password is required.' },
minLength: { value: 4, errorMessage: 'Your confirmation password is required to be at least 4 characters.' },
maxLength: { value: 50, errorMessage: 'Your confirmation password cannot be longer than 50 characters.' },
match: { value: 'newPassword', errorMessage: 'The password and its confirmation do not match!' }
}}
/>
<Button color="success" type="submit">
Validate new password
</Button>
</AvForm>
);
}
render() {
const { key } = this.state;
return (
<div>
<Row className="justify-content-center">
<Col md="4">
<h1>Reset password</h1>
<div>{key ? this.getResetForm() : null}</div>
</Col>
</Row>
</div>
);
}
}
const mapDispatchToProps = { handlePasswordResetFinish, reset };
type DispatchProps = typeof mapDispatchToProps;
export default connect(
null,
mapDispatchToProps
)(PasswordResetFinishPage);

View File

@@ -0,0 +1,61 @@
import React from 'react';
import { connect } from 'react-redux';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { Button, Alert, Col, Row } from 'reactstrap';
import { IRootState } from 'app/shared/reducers';
import { handlePasswordResetInit, reset } from '../password-reset.reducer';
export type IPasswordResetInitProps = DispatchProps;
export class PasswordResetInit extends React.Component<IPasswordResetInitProps> {
componentWillUnmount() {
this.props.reset();
}
handleValidSubmit = (event, values) => {
this.props.handlePasswordResetInit(values.email);
event.preventDefault();
};
render() {
return (
<div>
<Row className="justify-content-center">
<Col md="8">
<h1>Reset your password</h1>
<Alert color="warning">
<p>Enter the email address you used to register</p>
</Alert>
<AvForm onValidSubmit={this.handleValidSubmit}>
<AvField
name="email"
label="Email"
placeholder="Your email"
type="email"
validate={{
required: { value: true, errorMessage: 'Your email is required.' },
minLength: { value: 5, errorMessage: 'Your email is required to be at least 5 characters.' },
maxLength: { value: 254, errorMessage: 'Your email cannot be longer than 50 characters.' }
}}
/>
<Button color="primary" type="submit">
Reset password
</Button>
</AvForm>
</Col>
</Row>
</div>
);
}
}
const mapDispatchToProps = { handlePasswordResetInit, reset };
type DispatchProps = typeof mapDispatchToProps;
export default connect(
null,
mapDispatchToProps
)(PasswordResetInit);

View File

@@ -0,0 +1,74 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
export const ACTION_TYPES = {
RESET_PASSWORD_INIT: 'passwordReset/RESET_PASSWORD_INIT',
RESET_PASSWORD_FINISH: 'passwordReset/RESET_PASSWORD_FINISH',
RESET: 'passwordReset/RESET'
};
const initialState = {
loading: false,
resetPasswordSuccess: false,
resetPasswordFailure: false
};
export type PasswordResetState = Readonly<typeof initialState>;
// Reducer
export default (state: PasswordResetState = initialState, action): PasswordResetState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.RESET_PASSWORD_FINISH):
case REQUEST(ACTION_TYPES.RESET_PASSWORD_INIT):
return {
...state,
loading: true
};
case FAILURE(ACTION_TYPES.RESET_PASSWORD_FINISH):
case FAILURE(ACTION_TYPES.RESET_PASSWORD_INIT):
return {
...initialState,
loading: false,
resetPasswordFailure: true
};
case SUCCESS(ACTION_TYPES.RESET_PASSWORD_FINISH):
case SUCCESS(ACTION_TYPES.RESET_PASSWORD_INIT):
return {
...initialState,
loading: false,
resetPasswordSuccess: true
};
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
const apiUrl = 'api/account/reset-password';
// Actions
export const handlePasswordResetInit = mail => ({
type: ACTION_TYPES.RESET_PASSWORD_INIT,
// If the content-type isn't set that way, axios will try to encode the body and thus modify the data sent to the server.
payload: axios.post(`${apiUrl}/init`, mail, { headers: { ['Content-Type']: 'text/plain' } }),
meta: {
successMessage: 'Check your emails for details on how to reset your password.',
errorMessage: "<strong>Email address isn't registered!</strong> Please check and try again"
}
});
export const handlePasswordResetFinish = (key, newPassword) => ({
type: ACTION_TYPES.RESET_PASSWORD_FINISH,
payload: axios.post(`${apiUrl}/finish`, { key, newPassword }),
meta: {
successMessage: '<strong>Your password has been reset.</strong> Please '
}
});
export const reset = () => ({
type: ACTION_TYPES.RESET
});

View File

@@ -0,0 +1,66 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
export const ACTION_TYPES = {
UPDATE_PASSWORD: 'account/UPDATE_PASSWORD',
RESET: 'account/RESET'
};
const initialState = {
loading: false,
errorMessage: null,
updateSuccess: false,
updateFailure: false
};
export type PasswordState = Readonly<typeof initialState>;
// Reducer
export default (state: PasswordState = initialState, action): PasswordState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.UPDATE_PASSWORD):
return {
...initialState,
errorMessage: null,
updateSuccess: false,
loading: true
};
case FAILURE(ACTION_TYPES.UPDATE_PASSWORD):
return {
...initialState,
loading: false,
updateSuccess: false,
updateFailure: true
};
case SUCCESS(ACTION_TYPES.UPDATE_PASSWORD):
return {
...initialState,
loading: false,
updateSuccess: true,
updateFailure: false
};
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
// Actions
const apiUrl = 'api/account';
export const savePassword = (currentPassword, newPassword) => ({
type: ACTION_TYPES.UPDATE_PASSWORD,
payload: axios.post(`${apiUrl}/change-password`, { currentPassword, newPassword }),
meta: {
successMessage: '<strong>Password changed!</strong>',
errorMessage: '<strong>An error has occurred!</strong> The password could not be changed.'
}
});
export const reset = () => ({
type: ACTION_TYPES.RESET
});

View File

@@ -0,0 +1,119 @@
import React from 'react';
import { connect } from 'react-redux';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { Row, Col, Button } from 'reactstrap';
import { IRootState } from 'app/shared/reducers';
import { getSession } from 'app/shared/reducers/authentication';
import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
import { savePassword, reset } from './password.reducer';
export interface IUserPasswordProps extends StateProps, DispatchProps {}
export interface IUserPasswordState {
password: string;
}
export class PasswordPage extends React.Component<IUserPasswordProps, IUserPasswordState> {
state: IUserPasswordState = {
password: ''
};
componentDidMount() {
this.props.reset();
this.props.getSession();
}
componentWillUnmount() {
this.props.reset();
}
handleValidSubmit = (event, values) => {
this.props.savePassword(values.currentPassword, values.newPassword);
};
updatePassword = event => {
this.setState({ password: event.target.value });
};
render() {
const { account } = this.props;
return (
<div>
<Row className="justify-content-center">
<Col md="8">
<h2 id="password-title">Password for {account.login}</h2>
<AvForm id="password-form" onValidSubmit={this.handleValidSubmit}>
<AvField
name="currentPassword"
label="Current password"
placeholder="Current password"
type="password"
validate={{
required: { value: true, errorMessage: 'Your password is required.' }
}}
/>
<AvField
name="newPassword"
label="New password"
placeholder="New password"
type="password"
validate={{
required: { value: true, errorMessage: 'Your password is required.' },
minLength: { value: 4, errorMessage: 'Your password is required to be at least 4 characters.' },
maxLength: { value: 50, errorMessage: 'Your password cannot be longer than 50 characters.' }
}}
onChange={this.updatePassword}
/>
<PasswordStrengthBar password={this.state.password} />
<AvField
name="confirmPassword"
label="New password confirmation"
placeholder="Confirm the new password"
type="password"
validate={{
required: {
value: true,
errorMessage: 'Your confirmation password is required.'
},
minLength: {
value: 4,
errorMessage: 'Your confirmation password is required to be at least 4 characters.'
},
maxLength: {
value: 50,
errorMessage: 'Your confirmation password cannot be longer than 50 characters.'
},
match: {
value: 'newPassword',
errorMessage: 'The password and its confirmation do not match!'
}
}}
/>
<Button color="success" type="submit">
Save
</Button>
</AvForm>
</Col>
</Row>
</div>
);
}
}
const mapStateToProps = ({ authentication }: IRootState) => ({
account: authentication.account,
isAuthenticated: authentication.isAuthenticated
});
const mapDispatchToProps = { getSession, savePassword, reset };
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(
mapStateToProps,
mapDispatchToProps
)(PasswordPage);

View File

@@ -0,0 +1,58 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
export const ACTION_TYPES = {
CREATE_ACCOUNT: 'register/CREATE_ACCOUNT',
RESET: 'register/RESET'
};
const initialState = {
loading: false,
registrationSuccess: false,
registrationFailure: false,
errorMessage: null
};
export type RegisterState = Readonly<typeof initialState>;
// Reducer
export default (state: RegisterState = initialState, action): RegisterState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.CREATE_ACCOUNT):
return {
...state,
loading: true
};
case FAILURE(ACTION_TYPES.CREATE_ACCOUNT):
return {
...initialState,
registrationFailure: true,
errorMessage: action.payload.response.data.errorKey
};
case SUCCESS(ACTION_TYPES.CREATE_ACCOUNT):
return {
...initialState,
registrationSuccess: true
};
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
// Actions
export const handleRegister = (login, email, password, langKey = 'en') => ({
type: ACTION_TYPES.CREATE_ACCOUNT,
payload: axios.post('api/register', { login, email, password, langKey }),
meta: {
successMessage: '<strong>Registration saved!</strong> Please check your email for confirmation.'
}
});
export const reset = () => ({
type: ACTION_TYPES.RESET
});

View File

@@ -0,0 +1,120 @@
import React from 'react';
import { connect } from 'react-redux';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { Row, Col, Alert, Button } from 'reactstrap';
import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
import { IRootState } from 'app/shared/reducers';
import { handleRegister, reset } from './register.reducer';
export type IRegisterProps = DispatchProps;
export interface IRegisterState {
password: string;
}
export class RegisterPage extends React.Component<IRegisterProps, IRegisterState> {
state: IRegisterState = {
password: ''
};
componentWillUnmount() {
this.props.reset();
}
handleValidSubmit = (event, values) => {
this.props.handleRegister(values.username, values.email, values.firstPassword);
event.preventDefault();
};
updatePassword = event => {
this.setState({ password: event.target.value });
};
render() {
return (
<div>
<Row className="justify-content-center">
<Col md="8">
<h1 id="register-title">Registration</h1>
</Col>
</Row>
<Row className="justify-content-center">
<Col md="8">
<AvForm id="register-form" onValidSubmit={this.handleValidSubmit}>
<AvField
name="username"
label="Username"
placeholder="Your username"
validate={{
required: { value: true, errorMessage: 'Your username is required.' },
pattern: { value: '^[_.@A-Za-z0-9-]*$', errorMessage: 'Your username can only contain letters and digits.' },
minLength: { value: 1, errorMessage: 'Your username is required to be at least 1 character.' },
maxLength: { value: 50, errorMessage: 'Your username cannot be longer than 50 characters.' }
}}
/>
<AvField
name="email"
label="Email"
placeholder="Your email"
type="email"
validate={{
required: { value: true, errorMessage: 'Your email is required.' },
minLength: { value: 5, errorMessage: 'Your email is required to be at least 5 characters.' },
maxLength: { value: 254, errorMessage: 'Your email cannot be longer than 50 characters.' }
}}
/>
<AvField
name="firstPassword"
label="New password"
placeholder="New password"
type="password"
onChange={this.updatePassword}
validate={{
required: { value: true, errorMessage: 'Your password is required.' },
minLength: { value: 4, errorMessage: 'Your password is required to be at least 4 characters.' },
maxLength: { value: 50, errorMessage: 'Your password cannot be longer than 50 characters.' }
}}
/>
<PasswordStrengthBar password={this.state.password} />
<AvField
name="secondPassword"
label="New password confirmation"
placeholder="Confirm the new password"
type="password"
validate={{
required: { value: true, errorMessage: 'Your confirmation password is required.' },
minLength: { value: 4, errorMessage: 'Your confirmation password is required to be at least 4 characters.' },
maxLength: { value: 50, errorMessage: 'Your confirmation password cannot be longer than 50 characters.' },
match: { value: 'firstPassword', errorMessage: 'The password and its confirmation do not match!' }
}}
/>
<Button id="register-submit" color="primary" type="submit">
Register
</Button>
</AvForm>
<p>&nbsp;</p>
<Alert color="warning">
<span>If you want to</span>
<a className="alert-link"> sign in</a>
<span>
, you can try the default accounts:
<br />- Administrator (login="admin" and password="admin")
<br />- User (login="user" and password="user").
</span>
</Alert>
</Col>
</Row>
</div>
);
}
}
const mapDispatchToProps = { handleRegister, reset };
type DispatchProps = typeof mapDispatchToProps;
export default connect(
null,
mapDispatchToProps
)(RegisterPage);

View File

@@ -0,0 +1,67 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
export const ACTION_TYPES = {
FIND_ALL: 'sessions/FIND_ALL',
INVALIDATE: 'sessions/INVALIDATE'
};
const initialState = {
loading: false,
sessions: [],
updateSuccess: false,
updateFailure: false
};
export type SessionsState = Readonly<typeof initialState>;
// Reducer
export default (state: SessionsState = initialState, action): SessionsState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.FIND_ALL):
case REQUEST(ACTION_TYPES.INVALIDATE):
return {
...state,
loading: true
};
case FAILURE(ACTION_TYPES.FIND_ALL):
return {
...state,
loading: false
};
case FAILURE(ACTION_TYPES.INVALIDATE):
return {
...state,
loading: false,
updateFailure: true
};
case SUCCESS(ACTION_TYPES.FIND_ALL):
return {
...state,
loading: false,
sessions: action.payload.data
};
case SUCCESS(ACTION_TYPES.INVALIDATE):
return {
...state,
loading: false,
updateSuccess: true
};
default:
return state;
}
};
// Actions
const apiURL = '/api/account/sessions/';
export const findAll = () => ({
type: ACTION_TYPES.FIND_ALL,
payload: axios.get(apiURL)
});
export const invalidateSession = series => ({
type: ACTION_TYPES.INVALIDATE,
payload: axios.delete(`${apiURL}${series}`)
});

View File

@@ -0,0 +1,99 @@
import React from 'react';
import { connect } from 'react-redux';
import { Alert, Table, Button } from 'reactstrap';
import { getSession } from 'app/shared/reducers/authentication';
import { IRootState } from 'app/shared/reducers';
import { findAll, invalidateSession } from './sessions.reducer';
export interface ISessionsProps extends StateProps, DispatchProps {}
export class SessionsPage extends React.Component<ISessionsProps> {
componentDidMount() {
this.props.getSession();
this.props.findAll();
}
doSessionInvalidation = series => () => {
this.props.invalidateSession(series);
this.props.findAll();
};
refreshList = () => {
this.props.findAll();
};
render() {
const { account, sessions, updateSuccess, updateFailure } = this.props;
return (
<div>
<h2>
Active sessions for [<b>{account.login}</b>]
</h2>
{updateSuccess ? (
<Alert color="success">
<strong>Session invalidated!</strong>
</Alert>
) : null}
{updateFailure ? (
<Alert color="danger">
<span>
<strong>An error has occured!</strong> The session could not be invalidated.
</span>
</Alert>
) : null}
<Button color="primary" onClick={this.refreshList}>
Refresh
</Button>
<div className="table-responsive">
<Table className="table-striped">
<thead>
<tr>
<th>IP Address</th>
<th>User agent</th>
<th>Date</th>
<th />
</tr>
</thead>
<tbody>
{sessions.map(s => (
<tr>
<td>{s.ipAddress}</td>
<td>{s.userAgent}</td>
<td>{s.tokenDate}</td>
<td>
<Button color="primary" onClick={this.doSessionInvalidation(s.series)}>
Invalidate
</Button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
</div>
);
}
}
const mapStateToProps = ({ authentication, sessions }: IRootState) => ({
account: authentication.account,
sessions: sessions.sessions,
updateSuccess: sessions.updateSuccess,
updateFailure: sessions.updateFailure
});
const mapDispatchToProps = { getSession, findAll, invalidateSession };
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(
mapStateToProps,
mapDispatchToProps
)(SessionsPage);

View File

@@ -0,0 +1,69 @@
import axios from 'axios';
import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
import { getSession } from 'app/shared/reducers/authentication';
export const ACTION_TYPES = {
UPDATE_ACCOUNT: 'account/UPDATE_ACCOUNT',
RESET: 'account/RESET'
};
const initialState = {
loading: false,
errorMessage: null,
updateSuccess: false,
updateFailure: false
};
export type SettingsState = Readonly<typeof initialState>;
// Reducer
export default (state: SettingsState = initialState, action): SettingsState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.UPDATE_ACCOUNT):
return {
...state,
errorMessage: null,
updateSuccess: false,
loading: true
};
case FAILURE(ACTION_TYPES.UPDATE_ACCOUNT):
return {
...state,
loading: false,
updateSuccess: false,
updateFailure: true
};
case SUCCESS(ACTION_TYPES.UPDATE_ACCOUNT):
return {
...state,
loading: false,
updateSuccess: true,
updateFailure: false
};
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
// Actions
const apiUrl = 'api/account';
export const saveAccountSettings = account => async dispatch => {
await dispatch({
type: ACTION_TYPES.UPDATE_ACCOUNT,
payload: axios.post(apiUrl, account),
meta: {
successMessage: '<strong>Settings saved!</strong>'
}
});
dispatch(getSession());
};
export const reset = () => ({
type: ACTION_TYPES.RESET
});

View File

@@ -0,0 +1,110 @@
import React from 'react';
import { Button, Col, Alert, Row } from 'reactstrap';
import { connect } from 'react-redux';
import { AvForm, AvField } from 'availity-reactstrap-validation';
import { IRootState } from 'app/shared/reducers';
import { getSession } from 'app/shared/reducers/authentication';
import { saveAccountSettings, reset } from './settings.reducer';
export interface IUserSettingsProps extends StateProps, DispatchProps {}
export interface IUserSettingsState {
account: any;
}
export class SettingsPage extends React.Component<IUserSettingsProps, IUserSettingsState> {
componentDidMount() {
this.props.getSession();
}
componentWillUnmount() {
this.props.reset();
}
handleValidSubmit = (event, values) => {
const account = {
...this.props.account,
...values
};
this.props.saveAccountSettings(account);
event.persist();
};
render() {
const { account } = this.props;
return (
<div>
<Row className="justify-content-center">
<Col md="8">
<h2 id="settings-title">User settings for {account.login}</h2>
<AvForm id="settings-form" onValidSubmit={this.handleValidSubmit}>
{/* First name */}
<AvField
className="form-control"
name="firstName"
label="First Name"
id="firstName"
placeholder="Your first name"
validate={{
required: { value: true, errorMessage: 'Your first name is required.' },
minLength: { value: 1, errorMessage: 'Your first name is required to be at least 1 character' },
maxLength: { value: 50, errorMessage: 'Your first name cannot be longer than 50 characters' }
}}
value={account.firstName}
/>
{/* Last name */}
<AvField
className="form-control"
name="lastName"
label="Last Name"
id="lastName"
placeholder="Your last name"
validate={{
required: { value: true, errorMessage: 'Your last name is required.' },
minLength: { value: 1, errorMessage: 'Your last name is required to be at least 1 character' },
maxLength: { value: 50, errorMessage: 'Your last name cannot be longer than 50 characters' }
}}
value={account.lastName}
/>
{/* Email */}
<AvField
name="email"
label="Email"
placeholder="Your email"
type="email"
validate={{
required: { value: true, errorMessage: 'Your email is required.' },
minLength: { value: 5, errorMessage: 'Your email is required to be at least 5 characters.' },
maxLength: { value: 254, errorMessage: 'Your email cannot be longer than 50 characters.' }
}}
value={account.email}
/>
<Button color="primary" type="submit">
Save
</Button>
</AvForm>
</Col>
</Row>
</div>
);
}
}
const mapStateToProps = ({ authentication }: IRootState) => ({
account: authentication.account,
isAuthenticated: authentication.isAuthenticated
});
const mapDispatchToProps = { getSession, saveAccountSettings, reset };
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(
mapStateToProps,
mapDispatchToProps
)(SettingsPage);