frontend-session & message-for-author
parent
423f79f04b
commit
432efcffe3
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export const INITIALIZE_FRONTEND_SESSION_STARTED =
|
||||
"INITIALIZE_FRONTEND_SESSION_STARTED";
|
||||
|
||||
export const INITIALIZE_FRONTEND_SESSION_SUCCESS =
|
||||
"INITIALIZE_FRONTEND_SESSION_SUCCESS";
|
|
@ -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
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export const SAVE_MESSAGE_FOR_AUTHOR_SUCCESS =
|
||||
"SAVE_MESSAGE_FOR_AUTHOR_SUCCESS";
|
|
@ -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
|
||||
};
|
|
@ -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 (
|
||||
<MessageForAuthorDialog
|
||||
open={open}
|
||||
handleClose={handleClose}
|
||||
messageForAuthor={messageForAuthor}
|
||||
onMessageForAuthorChanged={onMessageForAuthorChanged}
|
||||
saveMessage={saveMessage}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
MessageForAuthorContainer.propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
handleClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({ saveMessageForAuthor }, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(MessageForAuthorContainer);
|
|
@ -0,0 +1,69 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
IconButton,
|
||||
Grid,
|
||||
Tooltip
|
||||
} from "@material-ui/core";
|
||||
import SendRoundedIcon from "@material-ui/icons/SendRounded";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const MessageForAuthorDialog = ({
|
||||
open,
|
||||
handleClose,
|
||||
messageForAuthor,
|
||||
onMessageForAuthorChanged,
|
||||
saveMessage
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={11} sm={11} md={11}>
|
||||
<TextField
|
||||
autoFocus
|
||||
id="message-for-author"
|
||||
label={t("Server.MessageForAuthor")}
|
||||
fullWidth
|
||||
value={messageForAuthor}
|
||||
onChange={onMessageForAuthorChanged}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1} sm={1} md={1}>
|
||||
<Tooltip title={t("General.Send")}>
|
||||
<IconButton
|
||||
aria-label="send message"
|
||||
onClick={saveMessage}
|
||||
color="primary"
|
||||
>
|
||||
<SendRoundedIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
MessageForAuthorDialog.propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
handleClose: PropTypes.func.isRequired,
|
||||
messageForAuthor: PropTypes.string.isRequired,
|
||||
onMessageForAuthorChanged: PropTypes.func.isRequired,
|
||||
saveMessage: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default MessageForAuthorDialog;
|
|
@ -10,13 +10,14 @@ import {
|
|||
Collapse,
|
||||
Avatar,
|
||||
IconButton,
|
||||
Typography
|
||||
Typography,
|
||||
Tooltip
|
||||
} from "@material-ui/core";
|
||||
import FavoriteIcon from "@material-ui/icons/Favorite";
|
||||
import ShareIcon from "@material-ui/icons/Share";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import MoreVertIcon from "@material-ui/icons/MoreVert";
|
||||
import DnsRoundedIcon from "@material-ui/icons/DnsRounded";
|
||||
import MessageRoundedIcon from "@material-ui/icons/MessageRounded";
|
||||
import styles from "../../../components/common/styles/expandableCardStyles";
|
||||
import ServerSummary from "./ServerSummary";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -27,7 +28,8 @@ const ServerComponent = ({
|
|||
data,
|
||||
serverHost,
|
||||
openAbout,
|
||||
handleOpenInNewTab
|
||||
handleOpenInNewTab,
|
||||
showMessageForAuthor
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
@ -65,9 +67,11 @@ const ServerComponent = ({
|
|||
)}
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton aria-label="add to favorites">
|
||||
<FavoriteIcon />
|
||||
<Tooltip title={t("Server.Actions.SendMessageToAuthor")}>
|
||||
<IconButton aria-label="sent message" onClick={showMessageForAuthor}>
|
||||
<MessageRoundedIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton aria-label="share">
|
||||
<ShareIcon />
|
||||
</IconButton>
|
||||
|
@ -121,7 +125,8 @@ ServerComponent.propTypes = {
|
|||
data: PropTypes.object.isRequired,
|
||||
serverHost: PropTypes.string,
|
||||
openAbout: PropTypes.func.isRequired,
|
||||
handleOpenInNewTab: PropTypes.func.isRequired
|
||||
handleOpenInNewTab: PropTypes.func.isRequired,
|
||||
showMessageForAuthor: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ServerComponent;
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { bindActionCreators } from "redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { loadServerData, loadSystemVersion } from "../actionCreators";
|
||||
import ServerComponent from "./ServerComponent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import MessageForAuthorContainer from "../../messageForAuthor/components/MessageForAuthorContainer";
|
||||
|
||||
const ServerContainer = ({ actions, data, serverHost, history }) => {
|
||||
const [openMessageForAuthor, setOpenMessageForAuthor] = useState(false);
|
||||
|
||||
const closeMessageForAuthor = () => {
|
||||
setOpenMessageForAuthor(false);
|
||||
};
|
||||
|
||||
const showMessageForAuthor = () => {
|
||||
setOpenMessageForAuthor(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
actions.loadServerData();
|
||||
actions.loadSystemVersion();
|
||||
|
@ -23,12 +34,19 @@ const ServerContainer = ({ actions, data, serverHost, history }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ServerComponent
|
||||
data={data}
|
||||
serverHost={serverHost}
|
||||
openAbout={openAbout}
|
||||
handleOpenInNewTab={handleOpenInNewTab}
|
||||
showMessageForAuthor={showMessageForAuthor}
|
||||
/>
|
||||
<MessageForAuthorContainer
|
||||
open={openMessageForAuthor}
|
||||
handleClose={closeMessageForAuthor}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,8 +6,10 @@ import {
|
|||
forwardsReducer
|
||||
} from "../../features/session/reducers";
|
||||
import releaseNotesReducer from "../../features/releaseNotes/reducer";
|
||||
import frontendSessionReducer from "../../features/frontendSession/reducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
frontendSession: frontendSessionReducer,
|
||||
server: serverReducer,
|
||||
sessions: sessionsReducer,
|
||||
forwards: forwardsReducer,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export default {
|
||||
frontendSession: { loading: false, loaded: false },
|
||||
server: {
|
||||
data: { loading: false, loaded: false },
|
||||
activeSession: { loading: false, loaded: false }
|
||||
|
|
Loading…
Reference in New Issue