UserForm: ajout retour de validation d'API
This commit is contained in:
parent
de6832e94f
commit
67732aa00a
|
@ -0,0 +1,15 @@
|
|||
export const CREATE_USER_REQUEST = 'CREATE_USER_REQUEST';
|
||||
export const CREATE_USER_SUCCESS = 'CREATE_USER_SUCCESS';
|
||||
export const CREATE_USER_FAILURE = 'CREATE_USER_FAILURE';
|
||||
|
||||
export function createUser(username, password) {
|
||||
return { type: CREATE_USER_REQUEST, username, password}
|
||||
}
|
||||
|
||||
export function createUserSuccess(user) {
|
||||
return { type: CREATE_USER_SUCCESS, user }
|
||||
}
|
||||
|
||||
export function createUserFailure(error) {
|
||||
return { type: CREATE_USER_FAILURE, error }
|
||||
}
|
|
@ -4,7 +4,6 @@ import { WithForm } from './WithForm';
|
|||
export function UserForm({ form, onSubmit }) {
|
||||
|
||||
useEffect(() => {
|
||||
console.log(form.valid, form.submitted);
|
||||
if (form.valid && form.submitted) onSubmit(form.data);
|
||||
}, [form.valid, form.submitted]);
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ export function WithForm(validators) {
|
|||
|
||||
return function(Component) {
|
||||
|
||||
return function WithFormWrapper(props) {
|
||||
|
||||
return function WithFormWrapper({ errors, ...props }) {
|
||||
|
||||
const [ formData, setFormData ] = useState({});
|
||||
const [ formErrors, setFormErrors ] = useState({});
|
||||
const [ formErrors, setFormErrors ] = useState(errors || {});
|
||||
const [ submitted, setSubmitted ] = useState(false);
|
||||
|
||||
const validateField = (name) => {
|
||||
|
@ -27,6 +27,10 @@ export function WithForm(validators) {
|
|||
setSubmitted(false);
|
||||
}, [submitted]);
|
||||
|
||||
useEffect(() => {
|
||||
setFormErrors(errors || {});
|
||||
}, [errors]);
|
||||
|
||||
const form = {
|
||||
field: (name, defaultValue) => {
|
||||
return name in formData ? formData[name] : defaultValue;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
export class APIError extends Error {
|
||||
constructor(endpoint, code, message, data) {
|
||||
super(`APIError: ${message}`);
|
||||
this.endpoint = endpoint;
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
Error.captureStackTrace(this, APIError);
|
||||
}
|
||||
|
||||
getEndpoint() {
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.data;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,50 @@
|
|||
import React from 'react'
|
||||
import Page from './page';
|
||||
import { ExtendedUserForm as UserForm } from '../components/UserForm';
|
||||
import { connect } from 'react-redux';
|
||||
import { createUser } from '../actions/user.actions';
|
||||
|
||||
export default class HomePage extends React.PureComponent {
|
||||
|
||||
export class HomePage extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const onUserFormSubmit = formData => {
|
||||
console.log(formData);
|
||||
};
|
||||
|
||||
const { createUserFormError } = this.props;
|
||||
|
||||
const onUserFormSubmit = ({ username, password }) => {
|
||||
this.props.dispatch(createUser(username, password));
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title="home">
|
||||
<div className="section">
|
||||
<h1 className="title">Bienvenue sur PleaseWait !</h1>
|
||||
<h2 className="subtitle">Le gestionnaire de ticket simplifié.</h2>
|
||||
<a href="#/logout">Se déconnecter</a>
|
||||
<UserForm onSubmit={onUserFormSubmit} />
|
||||
<UserForm onSubmit={onUserFormSubmit} errors={createUserFormError} />
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function transformErrorCode(code) {
|
||||
switch (code) {
|
||||
case 0:
|
||||
return {
|
||||
username: {
|
||||
hasError: true,
|
||||
message: "Le nom d'utilisateur ne peut pas être vide. (API)"
|
||||
}
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps({ users }) {
|
||||
return {
|
||||
createUserFormError: transformErrorCode(users.createUserForm.errorCode),
|
||||
}
|
||||
}
|
||||
|
||||
export const ConnectedHomePage = connect(mapStateToProps)(HomePage)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { CREATE_USER_FAILURE } from "../actions/user.actions";
|
||||
|
||||
const initialState = {
|
||||
byId: {},
|
||||
createUserForm: { errorCode: null },
|
||||
};
|
||||
|
||||
export function usersReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case CREATE_USER_FAILURE:
|
||||
return handleCreateUserFailure(state, action);
|
||||
};
|
||||
return state;
|
||||
}
|
||||
|
||||
function handleCreateUserFailure(state, { error }) {
|
||||
return {
|
||||
...state,
|
||||
createUserForm: {
|
||||
...state.createUserForm,
|
||||
errorCode: error.code,
|
||||
}
|
||||
};
|
||||
}
|
|
@ -2,11 +2,13 @@ import { all } from 'redux-saga/effects';
|
|||
import { rootSaga as authRootSaga } from './auth/root.saga';
|
||||
import { rootSaga as failureRootSaga } from './failure/root.saga';
|
||||
import { rootSaga as initRootSaga } from './init/root.saga';
|
||||
import { rootSaga as userRootSaga } from './user/root.saga';
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([
|
||||
initRootSaga(),
|
||||
authRootSaga(),
|
||||
failureRootSaga(),
|
||||
userRootSaga()
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { all, takeLatest } from 'redux-saga/effects';
|
||||
import { CREATE_USER_REQUEST } from '../../actions/user.actions';
|
||||
import { createUserSaga } from './user.saga';
|
||||
|
||||
export function* rootSaga() {
|
||||
yield all([
|
||||
takeLatest(CREATE_USER_REQUEST, createUserSaga),
|
||||
]);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { call, put } from 'redux-saga/effects';
|
||||
import { APIClient } from '../../services/api-client.service';
|
||||
import { createUserFailure, createUserSuccess } from '../../actions/user.actions';
|
||||
|
||||
export function* createUserSaga({username, password}) {
|
||||
const client = new APIClient();
|
||||
let user;
|
||||
try {
|
||||
user = yield call(client.createUser, username, password);
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
yield put(createUserFailure(err));
|
||||
return
|
||||
}
|
||||
|
||||
yield put(createUserSuccess(user));
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { UnauthorizedError } from '../errors/unauthorized.error.js';
|
||||
import { APIError } from '../errors/api.error.js';
|
||||
|
||||
export const UnauthorizedStatusCode = 401;
|
||||
|
||||
|
@ -10,10 +11,12 @@ export class APIClient {
|
|||
this.retrieveSessionUser = this.retrieveSessionUser.bind(this);
|
||||
this.listUsers = this.listUsers.bind(this);
|
||||
this.listRequests = this.listRequests.bind(this);
|
||||
this.createUser = this.createUser.bind(this);
|
||||
}
|
||||
|
||||
login(username, password) {
|
||||
return this._callAPI('/login', { username, password }, 'POST')
|
||||
return this._callAPI('/login', { username, password }, 'POST')
|
||||
.then(result => result.data);
|
||||
}
|
||||
|
||||
logout() {
|
||||
|
@ -21,7 +24,8 @@ export class APIClient {
|
|||
}
|
||||
|
||||
retrieveSessionUser() {
|
||||
return this._callAPI('/me')
|
||||
return this._callAPI('/me')
|
||||
.then(result => result.data);
|
||||
}
|
||||
|
||||
listUsers() {
|
||||
|
@ -36,6 +40,12 @@ export class APIClient {
|
|||
|
||||
}
|
||||
|
||||
createUser(username, password) {
|
||||
return this._callAPI('/users', { username, password }, 'POST')
|
||||
.then(this._withAPIErrorMiddleware('create_user'))
|
||||
.then(result => result.data);
|
||||
}
|
||||
|
||||
updateRequestStatus(reqID, newStatus) {
|
||||
|
||||
}
|
||||
|
@ -50,13 +60,27 @@ export class APIClient {
|
|||
credentials: 'include',
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status === UnauthorizedStatusCode) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.then(this._withUnauthorizedErrorMiddleware())
|
||||
.then(res => res.json())
|
||||
}
|
||||
|
||||
_withUnauthorizedErrorMiddleware() {
|
||||
return res => {
|
||||
if (res.status === UnauthorizedStatusCode) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
_withAPIErrorMiddleware(endpoint) {
|
||||
return result => {
|
||||
if (result.error) {
|
||||
const { code, message, data } = result.error;
|
||||
throw new APIError(endpoint, code, message, data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ import rootSaga from '../sagas/root'
|
|||
import { sessionReducer } from '../reducers/session.reducers';
|
||||
import { messagesReducer } from '../reducers/messages.reducers';
|
||||
import project from '../reducers/project'
|
||||
import { usersReducer } from '../reducers/users.reducers';
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
session: sessionReducer,
|
||||
messages: messagesReducer,
|
||||
project
|
||||
project,
|
||||
users: usersReducer,
|
||||
});
|
||||
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
|
|
Loading…
Reference in New Issue