Fixed validation and added toasts
This commit is contained in:
parent
2bd4840ba5
commit
a7416f9c34
|
@ -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"
|
||||||
}
|
}
|
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue