stitch-ui
Version:
365 lines (349 loc) • 11.8 kB
JavaScript
import React from "react"; // eslint-disable-line no-unused-vars
import PropTypes from "prop-types";
import { Map } from "immutable";
import { Route, Switch, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import { appPropType } from "../../core/proptypes";
import MessageEditor from "./MessageEditor";
import MessageList from "./MessageList";
import * as actions from "../actions";
import * as serviceActions from "../../services/actions";
import { NavItem, Confirm, Banner, Button } from "../../core";
import { addAlert, AlertContainer } from "../../alert";
import { EditConfig, EditRules } from "../../service";
import {
PUSH_SAVE_ALERTKEY,
SAVE_TYPE_SENT,
SAVE_TYPE_DRAFT
} from "../constants";
export class PushNotifications extends React.Component {
constructor(props) {
super(props);
this.state = { newMessageModalOpen: false };
this.getMessageOptions = this.getMessageOptions.bind(this);
this.editMessage = this.editMessage.bind(this);
this.duplicateMessage = this.duplicateMessage.bind(this);
this.deleteMessage = this.deleteMessage.bind(this);
}
componentDidMount() {
const { app: { groupId, _id }, hasGcm } = this.props;
if (hasGcm) {
this.props.loadSvc(groupId, _id, "gcm");
}
}
getMessageOptions(message) {
if (message.type === SAVE_TYPE_SENT) {
return (
<span>
<li>
<a onClick={() => this.duplicateMessage(message)}>Duplicate</a>
</li>
<li>
<a onClick={() => this.deleteMessage(message._id)}>Delete</a>
</li>
</span>
);
} else if (message.type === SAVE_TYPE_DRAFT) {
return (
<span>
<li>
<a onClick={() => this.duplicateMessage(message)}>Duplicate</a>
</li>
<li>
<a onClick={() => this.editMessage(message)}>Edit</a>
</li>
<li>
<a onClick={() => this.deleteMessage(message._id)}>Delete</a>
</li>
</span>
);
}
return null;
}
deleteMessage(messageId) {
return Confirm.confirm("Are you sure you want to delete this message?")
.then(() => this.props.deleteMessage(messageId))
.then(() => this.messageList.load());
}
duplicateMessage(message) {
this.props.setNewMessageError(null);
this.props.setNewMessageTopic(message.topic);
this.props.setNewMessageLabel(message.label);
this.props.setNewMessageText(message.message);
this.setState({ newMessageModalOpen: true });
}
editMessage(message) {
this.props.setNewMessageError(null);
this.props.setNewMessageTopic(message.topic);
this.props.setNewMessageLabel(message.label);
this.props.setNewMessageText(message.message);
this.setState({ newMessageModalOpen: true, editingMessageId: message._id });
}
render() {
const {
app,
client,
loadSvc,
match,
executePushPipeline,
modalError,
messages,
saveMessage,
createMessage,
setMessageStatus,
newMessage,
loadMessages,
setNewMessageText,
setNewMessageTopic,
setNewMessageLabel,
addAlertFunc,
loadingMessages,
loadingMessagesError,
sendMessage,
hasGcm,
gcmConfigured
} = this.props;
const configProps = {
app,
client,
svcname: "gcm",
service: { ...app.services.gcm, name: "gcm" },
onUpdate: loadSvc
};
const banner = gcmConfigured
? <span />
: <Banner
message="You must configure a GCM service before sending push notifications."
warning
clearable={false}
/>;
return (
<div>
<MessageEditor
error={modalError}
editingMessageId={this.state.editingMessageId}
executePushPipeline={executePushPipeline}
addAlert={addAlertFunc}
newMessage={newMessage}
saveMessage={saveMessage}
createMessage={createMessage}
setNewMessageTopic={setNewMessageTopic}
setNewMessageText={setNewMessageText}
setNewMessageLabel={setNewMessageLabel}
setMessageStatus={setMessageStatus}
sendMessage={sendMessage}
open={this.state.newMessageModalOpen}
reloadList={() => this.messageList.load()}
onClose={() => this.setState({ newMessageModalOpen: false })}
/>
{banner}
<div className="section-header section-header-has-tabs">
<div className="section-header-title">
<div className="section-header-title-text">
{"Push Notifications"}
</div>
<AlertContainer alertKey={PUSH_SAVE_ALERTKEY} />
<div className="section-header-title-controls">
<Button
primary
onClick={() => {
this.props.setNewMessageError(null);
this.props.setNewMessageText("");
this.props.setNewMessageTopic("");
this.props.setNewMessageLabel("");
this.setState({
newMessageModalOpen: true,
editingMessageId: null
});
}}
>
Send New Notification
</Button>
</div>
</div>
<ul className="section-header-tabs">
<NavItem
to={`/groups/${app.groupId}/apps/${app._id}/push/sent`}
className="section-header-tab apptabs-services section-header-tab-is-left"
activeClassName="section-header-tab-is-active"
linkClassName="section-header-tab-link"
>
Sent
</NavItem>
<NavItem
to={`/groups/${app.groupId}/apps/${app._id}/push/drafts`}
className="section-header-tab apptabs-services section-header-tab-is-right"
activeClassName="section-header-tab-is-active"
linkClassName="section-header-tab-link"
>
Drafts
</NavItem>
<NavItem
to={`/groups/${app.groupId}/apps/${app._id}/push/config`}
className="section-header-tab apptabs-services section-header-tab-is-right"
activeClassName="section-header-tab-is-active"
linkClassName="section-header-tab-link"
>
Config
</NavItem>
<NavItem
to={`/groups/${app.groupId}/apps/${app._id}/push/rules`}
className="section-header-tab apptabs-services section-header-tab-is-right"
activeClassName="section-header-tab-is-active"
linkClassName="section-header-tab-link"
>
Rules
</NavItem>
</ul>
</div>
<div className="tabs-content" />
<Switch>
<Redirect exact from={`${match.url}`} to={`${match.url}/sent`} />
<Route
path={`${match.url}/drafts`}
render={() =>
<MessageList
ref={x => (this.messageList = x)}
getMessageOptions={this.getMessageOptions}
messages={messages}
messageType={SAVE_TYPE_DRAFT}
loadMessages={loadMessages}
loadingMessages={loadingMessages}
loadingMessagesError={loadingMessagesError}
/>}
/>
<Route
path={`${match.url}/sent`}
render={() =>
<MessageList
ref={x => (this.messageList = x)}
getMessageOptions={this.getMessageOptions}
messageType={SAVE_TYPE_SENT}
messages={messages}
loadMessages={loadMessages}
loadingMessages={loadingMessages}
loadingMessagesError={loadingMessagesError}
/>}
/>
<Route
path={`${match.url}/config`}
render={() =>
hasGcm
? <EditConfig {...configProps} />
: <span>
{"Please create GCM service to continue."}
</span>}
/>
<Route
path={`${match.url}/rules`}
render={() =>
hasGcm
? <EditRules {...configProps} />
: <span>
{"Please create GCM service to continue."}
</span>}
/>
</Switch>
</div>
);
}
}
const mapStateToProps = state => {
const {
modalError,
newMessage,
messages,
loadingMessages,
loadingMessagesError
} = state.push;
const hasGcm = !!state.app.root.services.gcm;
const service = state.service.base;
const gcmConfigured =
hasGcm &&
service.serviceName === "gcm" &&
service.configInput.get("apiKey") !== "API-KEY" &&
service.configInput.get("senderId") !== "SENDER-ID";
return {
modalError,
newMessage,
messages,
loadingMessages,
loadingMessagesError,
hasGcm,
gcmConfigured
};
};
const mapDispatchToProps = (dispatch, ownProps) => ({
addAlertFunc: (key, message, options) =>
dispatch(addAlert(key, message, options)),
executePushPipeline: pipeline =>
dispatch(
actions.executePushPipeline(
ownProps.app.groupId,
ownProps.app._id,
pipeline
)
),
loadMessages: query =>
dispatch(
actions.loadMessages(ownProps.app.groupId, ownProps.app._id, query)
),
saveMessage: (messageId, message) =>
dispatch(
actions.saveMessage(
ownProps.app.groupId,
ownProps.app._id,
messageId,
message
)
),
createMessage: message =>
dispatch(
actions.createMessage(ownProps.app.groupId, ownProps.app._id, message)
),
deleteMessage: messageId =>
dispatch(
actions.deleteMessage(ownProps.app.groupId, ownProps.app._id, messageId)
),
setMessageStatus: (messageId, type) =>
dispatch(
actions.setMessageStatus(
ownProps.app.groupId,
ownProps.app._id,
messageId,
type
)
),
setNewMessageError: error => dispatch(actions.setNewMessageError({ error })),
setNewMessageTopic: input => dispatch(actions.setNewMessageTopic({ input })),
setNewMessageText: input => dispatch(actions.setNewMessageText({ input })),
setNewMessageLabel: input => dispatch(actions.setNewMessageLabel({ input })),
sendMessage: message => dispatch(actions.sendMessage({ message })),
loadSvc: (groupId, appId, svcName, switching) =>
dispatch(serviceActions.loadSvc(groupId, appId, svcName, { switching }))
});
PushNotifications.propTypes = {
...appPropType,
addAlertFunc: PropTypes.func.isRequired,
executePushPipeline: PropTypes.func.isRequired,
loadMessages: PropTypes.func.isRequired,
saveMessage: PropTypes.func.isRequired,
createMessage: PropTypes.func.isRequired,
deleteMessage: PropTypes.func.isRequired,
setMessageStatus: PropTypes.func.isRequired,
setNewMessageError: PropTypes.func.isRequired,
setNewMessageTopic: PropTypes.func.isRequired,
setNewMessageText: PropTypes.func.isRequired,
setNewMessageLabel: PropTypes.func.isRequired,
sendMessage: PropTypes.func.isRequired,
modalError: PropTypes.string,
newMessage: PropTypes.instanceOf(Map).isRequired,
messages: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
loadingMessages: PropTypes.bool.isRequired,
loadingMessagesError: PropTypes.string
};
PushNotifications.defaultProps = {
modalError: null,
loadingMessagesError: null
};
export default connect(mapStateToProps, mapDispatchToProps)(PushNotifications);