Fixed validation and added toasts

This commit is contained in:
Ildar Kamalov 2019-01-21 11:55:39 +03:00 committed by Eugene Bujak
parent 2bd4840ba5
commit a7416f9c34
9 changed files with 68 additions and 34 deletions

View File

@ -179,13 +179,14 @@
"install_devices_desc": "In order for AdGuard Home to start working, you need to configure your devices to use it.", "install_devices_desc": "In order for AdGuard Home to start working, you need to configure your devices to use it.",
"install_submit_title": "Congratulations!", "install_submit_title": "Congratulations!",
"install_submit_desc": "The setup procedure is finished and you are ready to start using AdGuard Home.", "install_submit_desc": "The setup procedure is finished and you are ready to start using AdGuard Home.",
"install_decices_router": "Router", "install_devices_router": "Router",
"install_decices_router_desc": "This setup will automatically cover all the devices connected to your home router and you will not need to configure each of them manually.", "install_devices_router_desc": "This setup will automatically cover all the devices connected to your home router and you will not need to configure each of them manually.",
"install_decices_router_list_1": "Open the preferences for your router. Usually, you can access it from your browser via a URL (like http://192.168.0.1/ or http://192.168.1.1/). You may be asked to enter the password. If you don't remember it, you can often reset the password by pressing a button on the router itself. Some routers require a specific application, which in that case should be already installed on your computer/phone.", "install_devices_router_list_1": "Open the preferences for your router. Usually, you can access it from your browser via a URL (like http://192.168.0.1/ or http://192.168.1.1/). You may be asked to enter the password. If you don't remember it, you can often reset the password by pressing a button on the router itself. Some routers require a specific application, which in that case should be already installed on your computer/phone.",
"install_decices_router_list_2": "Find the DHCP/DNS settings. Look for the DNS letters next to a field which allows two or three sets of numbers, each broken into four groups of one to three digits.", "install_devices_router_list_2": "Find the DHCP/DNS settings. Look for the DNS letters next to a field which allows two or three sets of numbers, each broken into four groups of one to three digits.",
"install_decices_router_list_3": "Enter your AdGuard Home server addresses there.", "install_devices_router_list_3": "Enter your AdGuard Home server addresses there.",
"get_started": "Get Started", "get_started": "Get Started",
"next": "Next", "next": "Next",
"open_dashboard": "Open Dashboard", "open_dashboard": "Open Dashboard",
"install_saved": "All settings saved" "install_saved": "All settings saved",
"form_error_password": "Password mismatched"
} }

View File

@ -5,6 +5,7 @@ const apiClient = new Api();
export const addErrorToast = createAction('ADD_ERROR_TOAST'); export const addErrorToast = createAction('ADD_ERROR_TOAST');
export const addSuccessToast = createAction('ADD_SUCCESS_TOAST'); export const addSuccessToast = createAction('ADD_SUCCESS_TOAST');
export const removeToast = createAction('REMOVE_TOAST');
export const nextStep = createAction('NEXT_STEP'); export const nextStep = createAction('NEXT_STEP');
export const prevStep = createAction('PREV_STEP'); export const prevStep = createAction('PREV_STEP');

View File

@ -4,8 +4,8 @@ import { Field, reduxForm } from 'redux-form';
import { withNamespaces, Trans } from 'react-i18next'; import { withNamespaces, Trans } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import i18n from '../../i18n';
import Controls from './Controls'; import Controls from './Controls';
import validate from './validate';
import renderField from './renderField'; import renderField from './renderField';
const required = (value) => { const required = (value) => {
@ -15,11 +15,21 @@ const required = (value) => {
return <Trans>form_error_required</Trans>; return <Trans>form_error_required</Trans>;
}; };
const validate = (values) => {
const errors = {};
if (values.confirm_password !== values.password) {
errors.confirm_password = i18n.t('form_error_password');
}
return errors;
};
const Auth = (props) => { const Auth = (props) => {
const { const {
handleSubmit, handleSubmit,
submitting,
pristine, pristine,
invalid,
t, t,
} = props; } = props;
@ -75,7 +85,7 @@ const Auth = (props) => {
/> />
</div> </div>
</div> </div>
<Controls submitting={submitting} pristine={pristine} /> <Controls pristine={pristine} invalid={invalid} />
</form> </form>
); );
}; };
@ -83,7 +93,7 @@ const Auth = (props) => {
Auth.propTypes = { Auth.propTypes = {
handleSubmit: PropTypes.func.isRequired, handleSubmit: PropTypes.func.isRequired,
pristine: PropTypes.bool.isRequired, pristine: PropTypes.bool.isRequired,
submitting: PropTypes.bool.isRequired, invalid: PropTypes.bool.isRequired,
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };

View File

@ -45,7 +45,7 @@ class Controls extends Component {
<button <button
type="submit" type="submit"
className="btn btn-success btn-standard btn-lg" className="btn btn-success btn-standard btn-lg"
disabled={this.props.submitting || this.props.pristine} disabled={this.props.invalid || this.props.pristine}
> >
<Trans>next</Trans> <Trans>next</Trans>
</button> </button>
@ -65,7 +65,6 @@ class Controls extends Component {
type="button" type="button"
className="btn btn-success btn-standard btn-lg" className="btn btn-success btn-standard btn-lg"
onClick={this.props.nextStep} onClick={this.props.nextStep}
disabled={this.props.submitting || this.props.pristine}
> >
<Trans>next</Trans> <Trans>next</Trans>
</button> </button>
@ -101,6 +100,7 @@ Controls.propTypes = {
prevStep: PropTypes.func, prevStep: PropTypes.func,
pristine: PropTypes.bool, pristine: PropTypes.bool,
submitting: PropTypes.bool, submitting: PropTypes.bool,
invalid: PropTypes.bool,
}; };
const mapStateToProps = (state) => { const mapStateToProps = (state) => {

View File

@ -18,19 +18,19 @@ const Devices = () => (
<Tabs> <Tabs>
<div label="Router"> <div label="Router">
<div className="tab__title"> <div className="tab__title">
<Trans>install_decices_router</Trans> <Trans>install_devices_router</Trans>
</div> </div>
<div className="tab__text"> <div className="tab__text">
<Trans>install_decices_router_desc</Trans> <Trans>install_devices_router_desc</Trans>
<ol> <ol>
<li> <li>
<Trans>install_decices_router_list_1</Trans> <Trans>install_devices_router_list_1</Trans>
</li> </li>
<li> <li>
<Trans>install_decices_router_list_2</Trans> <Trans>install_devices_router_list_2</Trans>
</li> </li>
<li> <li>
<Trans>install_decices_router_list_3</Trans> <Trans>install_devices_router_list_3</Trans>
</li> </li>
</ol> </ol>
</div> </div>

View File

@ -36,6 +36,7 @@ let Settings = (props) => {
handleSubmit, handleSubmit,
interfaceIp, interfaceIp,
dnsIp, dnsIp,
invalid,
} = props; } = props;
return ( return (
@ -122,7 +123,7 @@ let Settings = (props) => {
<Trans>install_settings_dns_desc</Trans> <strong>{dnsIp}</strong> <Trans>install_settings_dns_desc</Trans> <strong>{dnsIp}</strong>
</p> </p>
</div> </div>
<Controls /> <Controls invalid={invalid} />
</form> </form>
); );
}; };
@ -131,8 +132,7 @@ Settings.propTypes = {
handleSubmit: PropTypes.func.isRequired, handleSubmit: PropTypes.func.isRequired,
interfaceIp: PropTypes.string.isRequired, interfaceIp: PropTypes.string.isRequired,
dnsIp: PropTypes.string.isRequired, dnsIp: PropTypes.string.isRequired,
pristine: PropTypes.bool.isRequired, invalid: PropTypes.bool.isRequired,
submitting: PropTypes.bool.isRequired,
initialValues: PropTypes.object, initialValues: PropTypes.object,
}; };

View File

@ -13,6 +13,7 @@ import Devices from './Devices';
import Submit from './Submit'; import Submit from './Submit';
import Progress from './Progress'; import Progress from './Progress';
import Toasts from '../../components/Toasts';
import Footer from '../../components/ui/Footer'; import Footer from '../../components/ui/Footer';
import logo from '../../components/ui/svg/logo.svg'; import logo from '../../components/ui/svg/logo.svg';
@ -85,6 +86,7 @@ class Setup extends Component {
</div> </div>
</div> </div>
<Footer /> <Footer />
<Toasts />
</Fragment> </Fragment>
} }
</Fragment> </Fragment>
@ -104,8 +106,8 @@ Setup.propTypes = {
}; };
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const { install } = state; const { install, toasts } = state;
const props = { install }; const props = { install, toasts };
return props; return props;
}; };

View File

@ -1,11 +0,0 @@
const validate = (values) => {
const errors = {};
if (values.confirm_password !== values.password) {
errors.confirm_password = 'Password mismatched';
}
return errors;
};
export default validate;

View File

@ -1,8 +1,10 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import { handleActions } from 'redux-actions'; import { handleActions } from 'redux-actions';
import { reducer as formReducer } from 'redux-form'; import { reducer as formReducer } from 'redux-form';
import nanoid from 'nanoid';
import * as actions from '../actions/install'; import * as actions from '../actions/install';
import { INSTALL_FIRST_STEP } from '../helpers/constants';
const install = handleActions({ const install = handleActions({
[actions.getDefaultAddressesRequest]: state => ({ ...state, processingDefault: true }), [actions.getDefaultAddressesRequest]: state => ({ ...state, processingDefault: true }),
@ -19,11 +21,40 @@ const install = handleActions({
[actions.setAllSettingsFailure]: state => ({ ...state, processingSubmit: false }), [actions.setAllSettingsFailure]: state => ({ ...state, processingSubmit: false }),
[actions.setAllSettingsSuccess]: state => ({ ...state, processingSubmit: false }), [actions.setAllSettingsSuccess]: state => ({ ...state, processingSubmit: false }),
}, { }, {
step: 1, step: INSTALL_FIRST_STEP,
processingDefault: true, processingDefault: true,
}); });
const toasts = handleActions({
[actions.addErrorToast]: (state, { payload }) => {
const errorToast = {
id: nanoid(),
message: payload.error.toString(),
type: 'error',
};
const newState = { ...state, notices: [...state.notices, errorToast] };
return newState;
},
[actions.addSuccessToast]: (state, { payload }) => {
const successToast = {
id: nanoid(),
message: payload,
type: 'success',
};
const newState = { ...state, notices: [...state.notices, successToast] };
return newState;
},
[actions.removeToast]: (state, { payload }) => {
const filtered = state.notices.filter(notice => notice.id !== payload);
const newState = { ...state, notices: filtered };
return newState;
},
}, { notices: [] });
export default combineReducers({ export default combineReducers({
install, install,
toasts,
form: formReducer, form: formReducer,
}); });