diff --git a/frontend/src/actions/message.actions.js b/frontend/src/actions/message.actions.js
new file mode 100644
index 0000000..0a87dcc
--- /dev/null
+++ b/frontend/src/actions/message.actions.js
@@ -0,0 +1,11 @@
+export const ADD_MESSAGE = 'ADD_MESSAGE'
+
+export function addMessage(type, text) {
+ return { type: ADD_MESSAGE, text, messageType: type };
+}
+
+export const REMOVE_OLDEST_MESSAGE = 'REMOVE_OLDEST_MESSAGE'
+
+export function removeOldestMessage() {
+ return { type: REMOVE_OLDEST_MESSAGE }
+}
\ No newline at end of file
diff --git a/frontend/src/components/message-list.js b/frontend/src/components/message-list.js
new file mode 100644
index 0000000..23cd435
--- /dev/null
+++ b/frontend/src/components/message-list.js
@@ -0,0 +1,23 @@
+export function MessageList({ messages }) {
+ if (!Array.isArray(messages)) return null;
+
+ return (
+
+
+
+ {
+ messages.map((m, i) => {
+ return (
+
+ )
+ })
+ }
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/pages/login.js b/frontend/src/pages/login.js
index 99c0b4e..45044bb 100644
--- a/frontend/src/pages/login.js
+++ b/frontend/src/pages/login.js
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react'
-import Page from './page';
+import { ConnectedPage as Page } from './page';
import { login } from '../actions/auth.actions';
import { connect } from 'react-redux';
diff --git a/frontend/src/pages/page.js b/frontend/src/pages/page.js
index fb32593..186c8a1 100644
--- a/frontend/src/pages/page.js
+++ b/frontend/src/pages/page.js
@@ -1,13 +1,33 @@
import React, { useEffect } from 'react'
+import { MessageList } from '../components/message-list';
+import { connect } from 'react-redux';
+import { removeOldestMessage } from '../actions/message.actions';
-export default function Page({ title, children }) {
+export default function Page({ title, messages, dispatch, children }) {
useEffect(() => {
document.title = title ? `${title } - PleaseWait` : 'PleaseWait';
});
+ useEffect(() => {
+ if (!Array.isArray(messages) || messages.length === 0) return;
+
+ let timeoutId = setTimeout(() => {
+ dispatch(removeOldestMessage());
+ }, 5000);
+
+ return () => clearTimeout(timeoutId);
+ }, [messages])
+
return (
+
{ children }
);
-}
\ No newline at end of file
+}
+
+function mapStateToProps(state) {
+ return { messages: state.messages.sortedByTimestamp };
+}
+
+export const ConnectedPage = connect(mapStateToProps)(Page);
\ No newline at end of file
diff --git a/frontend/src/reducers/messages.reducers.js b/frontend/src/reducers/messages.reducers.js
new file mode 100644
index 0000000..59a87db
--- /dev/null
+++ b/frontend/src/reducers/messages.reducers.js
@@ -0,0 +1,32 @@
+import { ADD_MESSAGE, REMOVE_OLDEST_MESSAGE } from "../actions/message.actions";
+
+const initialState = {
+ sortedByTimestamp: []
+};
+
+export function messagesReducer(state = initialState, action) {
+ switch(action.type) {
+ case ADD_MESSAGE:
+ return handleAddMessage(state, action);
+ case REMOVE_OLDEST_MESSAGE:
+ return handleRemoveOldestMessage(state, action);
+ };
+ return state;
+}
+
+function handleAddMessage(state, action) {
+ return {
+ ...state,
+ sortedByTimestamp: [
+ { ts: Date.now(), text: action.text, type: action.messageType },
+ ...state.sortedByTimestamp
+ ]
+ }
+};
+
+function handleRemoveOldestMessage(state, action) {
+ return {
+ ...state,
+ sortedByTimestamp: state.sortedByTimestamp.slice(0, -1)
+ }
+};
\ No newline at end of file
diff --git a/frontend/src/reducers/session.reducers.js b/frontend/src/reducers/session.reducers.js
index eeb15a8..2d245a7 100644
--- a/frontend/src/reducers/session.reducers.js
+++ b/frontend/src/reducers/session.reducers.js
@@ -15,7 +15,7 @@ export function sessionReducer(state = initialState, action) {
function handleLoginSuccess(state, action) {
return {
- ...state.user,
+ ...state,
isLoggedIn: true,
user: {
username: action.username,
diff --git a/frontend/src/sagas/auth.sagas.js b/frontend/src/sagas/auth.sagas.js
index f7d6435..f42bea7 100644
--- a/frontend/src/sagas/auth.sagas.js
+++ b/frontend/src/sagas/auth.sagas.js
@@ -1,5 +1,6 @@
import { call, put } from 'redux-saga/effects';
import { loginFailure, loginSuccess } from '../actions/auth.actions';
+import { addMessage } from '../actions/message.actions';
export function* loginSaga(action) {
let result;
@@ -7,10 +8,13 @@ export function* loginSaga(action) {
result = yield call(doLogin, action.username, action.password);
} catch(err) {
yield put(loginFailure(action.username, err));
+ yield put(addMessage('danger', "Une erreur inconnue bloque le fonctionnement normal de l'application. Veuillez réessayer plus tard."));
}
if ('error' in result) {
yield put(loginFailure(action.username, result.error));
+ const message = result.error.message ? result.error.message : result.error.toString();
+ yield put(addMessage('danger', message));
return
}
diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js
index 71b924b..dc8cbd6 100644
--- a/frontend/src/store/store.js
+++ b/frontend/src/store/store.js
@@ -2,11 +2,13 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootSaga from '../sagas/root'
import { sessionReducer } from '../reducers/session.reducers';
+import { messagesReducer } from '../reducers/messages.reducers';
const sagaMiddleware = createSagaMiddleware()
const rootReducer = combineReducers({
session: sessionReducer,
+ messages: messagesReducer,
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;