diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json
index 02220f0..920996b 100644
--- a/public/locales/en/translations.json
+++ b/public/locales/en/translations.json
@@ -20,7 +20,8 @@
"About": "About"
},
"General": {
- "Close": "Close"
+ "Close": "Close",
+ "Send": "Send"
},
"Session": {
"Title": "Sessions",
@@ -59,6 +60,10 @@
"Domain": "Domain",
"ActiveSession": "Active session",
"ActiveSessionSubtitle": "Expand to see forwards",
- "DDNSProvider": "Dynamic DNS Provider"
+ "DDNSProvider": "Dynamic DNS Provider",
+ "Actions": {
+ "SendMessageToAuthor": "Send message to author"
+ },
+ "MessageForAuthor": "Message for author"
}
}
diff --git a/public/locales/ro/translations.json b/public/locales/ro/translations.json
index 37e323f..586381d 100644
--- a/public/locales/ro/translations.json
+++ b/public/locales/ro/translations.json
@@ -11,7 +11,8 @@
"About": "Despre"
},
"General": {
- "Close": "Închide"
+ "Close": "Închide",
+ "Send": "Trimite"
},
"Session": {
"Title": "Sesiuni",
@@ -50,6 +51,10 @@
"Domain": "Domeniu",
"ActiveSession": "Sesiune activă",
"ActiveSessionSubtitle": "Extindeţi pentru a vedea redirectările",
- "DDNSProvider": "Furnizor DNS dinamic"
+ "DDNSProvider": "Furnizor DNS dinamic",
+ "Actions": {
+ "SendMessageToAuthor": "Trimite mesaj către autor"
+ },
+ "MessageForAuthor": "Mesaj pentru autor"
}
}
diff --git a/src/components/App.js b/src/components/App.js
index d41ba35..37c40f3 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -1,4 +1,5 @@
-import React, { Suspense } from "react";
+import React, { Suspense, useEffect } from "react";
+import PropTypes from "prop-types";
import { Route, Switch } from "react-router-dom";
import HomePage from "./home/HomePage";
import Header from "./layout/Header";
@@ -8,8 +9,15 @@ import "react-toastify/dist/ReactToastify.css";
import SessionContainer from "../features/session/components/SessionContainer";
import ReleaseNotesContainer from "../features/releaseNotes/components/ReleaseNotesContainer";
import AboutContainer from "../features/about/components/AboutContainer";
+import { connect } from "react-redux";
+import { bindActionCreators } from "redux";
+import { loadFrontendSession } from "../features/frontendSession/actionCreators";
+
+function App({ actions }) {
+ useEffect(() => {
+ actions.loadFrontendSession();
+ }, []);
-function App() {
const contentStyle = {
paddingLeft: "30px",
paddingRight: "30px"
@@ -33,4 +41,18 @@ function App() {
);
}
-export default App;
+App.propTypes = {
+ actions: PropTypes.object.isRequired
+};
+
+function mapStateToProps() {
+ return {};
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({ loadFrontendSession }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/src/features/frontendSession/actionCreators.js b/src/features/frontendSession/actionCreators.js
new file mode 100644
index 0000000..8bc5654
--- /dev/null
+++ b/src/features/frontendSession/actionCreators.js
@@ -0,0 +1,18 @@
+import * as types from "./actionTypes";
+import api from "./api";
+import { sendHttpRequest } from "../../redux/actions/httpActions";
+
+export function loadFrontendSession() {
+ return async function (dispatch) {
+ try {
+ dispatch({ type: types.INITIALIZE_FRONTEND_SESSION_STARTED });
+ const data = await dispatch(sendHttpRequest(api.getFrontendSession()));
+ dispatch({
+ type: types.INITIALIZE_FRONTEND_SESSION_SUCCESS,
+ payload: data
+ });
+ } catch (error) {
+ throw error;
+ }
+ };
+}
diff --git a/src/features/frontendSession/actionTypes.js b/src/features/frontendSession/actionTypes.js
new file mode 100644
index 0000000..81a6c6f
--- /dev/null
+++ b/src/features/frontendSession/actionTypes.js
@@ -0,0 +1,5 @@
+export const INITIALIZE_FRONTEND_SESSION_STARTED =
+ "INITIALIZE_FRONTEND_SESSION_STARTED";
+
+export const INITIALIZE_FRONTEND_SESSION_SUCCESS =
+ "INITIALIZE_FRONTEND_SESSION_SUCCESS";
diff --git a/src/features/frontendSession/api.js b/src/features/frontendSession/api.js
new file mode 100644
index 0000000..2e1f8ab
--- /dev/null
+++ b/src/features/frontendSession/api.js
@@ -0,0 +1,8 @@
+import { get } from "../../api/axiosApi";
+const baseUrl = process.env.REVERSE_PROXY_API_URL;
+
+const getFrontendSession = () => get(`${baseUrl}/system/frontend-session`);
+
+export default {
+ getFrontendSession
+};
diff --git a/src/features/frontendSession/reducer.js b/src/features/frontendSession/reducer.js
new file mode 100644
index 0000000..1f42d0f
--- /dev/null
+++ b/src/features/frontendSession/reducer.js
@@ -0,0 +1,26 @@
+import * as types from "./actionTypes";
+import initialState from "../../redux/reducers/initialState";
+
+export default function frontendSessionReducer(
+ state = initialState.frontendSession,
+ action
+) {
+ switch (action.type) {
+ case types.INITIALIZE_FRONTEND_SESSION_STARTED:
+ return {
+ loading: true,
+ loaded: false
+ };
+
+ case types.INITIALIZE_FRONTEND_SESSION_SUCCESS:
+ return {
+ ...state,
+ ...action.payload,
+ loading: false,
+ loaded: true
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/src/features/messageForAuthor/actionCreators.js b/src/features/messageForAuthor/actionCreators.js
new file mode 100644
index 0000000..d7dd6df
--- /dev/null
+++ b/src/features/messageForAuthor/actionCreators.js
@@ -0,0 +1,17 @@
+import * as types from "./actionTypes";
+import api from "./api";
+import { sendHttpRequest } from "../../redux/actions/httpActions";
+
+export function saveMessageForAuthor(messageContent) {
+ return async function (dispatch, getState) {
+ try {
+ const sessionId = getState().frontendSession.sessionId;
+ const data = await dispatch(
+ sendHttpRequest(api.saveMessageForAuthor(sessionId, messageContent))
+ );
+ dispatch({ type: types.SAVE_MESSAGE_FOR_AUTHOR_SUCCESS, payload: data });
+ } catch (error) {
+ throw error;
+ }
+ };
+}
diff --git a/src/features/messageForAuthor/actionTypes.js b/src/features/messageForAuthor/actionTypes.js
new file mode 100644
index 0000000..71d7550
--- /dev/null
+++ b/src/features/messageForAuthor/actionTypes.js
@@ -0,0 +1,2 @@
+export const SAVE_MESSAGE_FOR_AUTHOR_SUCCESS =
+ "SAVE_MESSAGE_FOR_AUTHOR_SUCCESS";
diff --git a/src/features/messageForAuthor/api.js b/src/features/messageForAuthor/api.js
new file mode 100644
index 0000000..734599c
--- /dev/null
+++ b/src/features/messageForAuthor/api.js
@@ -0,0 +1,9 @@
+import { post } from "../../api/axiosApi";
+const baseUrl = process.env.REVERSE_PROXY_API_URL;
+
+const saveMessageForAuthor = (sessionId, messageContent) =>
+ post(`${baseUrl}/system/message-for-author`, { sessionId, messageContent });
+
+export default {
+ saveMessageForAuthor
+};
diff --git a/src/features/messageForAuthor/components/MessageForAuthorContainer.js b/src/features/messageForAuthor/components/MessageForAuthorContainer.js
new file mode 100644
index 0000000..440a0cd
--- /dev/null
+++ b/src/features/messageForAuthor/components/MessageForAuthorContainer.js
@@ -0,0 +1,52 @@
+import React, { useState } from "react";
+import { connect } from "react-redux";
+import { bindActionCreators } from "redux";
+import PropTypes from "prop-types";
+import MessageForAuthorDialog from "./MessageForAuthorDialog";
+import { saveMessageForAuthor } from "../actionCreators";
+
+const MessageForAuthorContainer = ({ actions, open, handleClose }) => {
+ const [messageForAuthor, setMessageForAuthor] = useState("");
+
+ const onMessageForAuthorChanged = (event) => {
+ const value = event.target.value;
+ setMessageForAuthor(value);
+ };
+
+ const saveMessage = () => {
+ actions.saveMessageForAuthor(messageForAuthor);
+ setMessageForAuthor("");
+ handleClose();
+ };
+
+ return (
+