Adding a notification stack for error messages
This commit is contained in:
parent
05b0c985b4
commit
d6a64f45fd
17 changed files with 115 additions and 45 deletions
|
@ -19,20 +19,20 @@ export function changeCompose(text) {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
text: text
|
text: text
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function replyCompose(status) {
|
export function replyCompose(status) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_REPLY,
|
type: COMPOSE_REPLY,
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function cancelReplyCompose() {
|
export function cancelReplyCompose() {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_REPLY_CANCEL
|
type: COMPOSE_REPLY_CANCEL
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitCompose() {
|
export function submitCompose() {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
@ -48,27 +48,27 @@ export function submitCompose() {
|
||||||
dispatch(submitComposeFail(error));
|
dispatch(submitComposeFail(error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitComposeRequest() {
|
export function submitComposeRequest() {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_SUBMIT_REQUEST
|
type: COMPOSE_SUBMIT_REQUEST
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitComposeSuccess(status) {
|
export function submitComposeSuccess(status) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_SUBMIT_SUCCESS,
|
type: COMPOSE_SUBMIT_SUCCESS,
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitComposeFail(error) {
|
export function submitComposeFail(error) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_SUBMIT_FAIL,
|
type: COMPOSE_SUBMIT_FAIL,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function uploadCompose(files) {
|
export function uploadCompose(files) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
@ -87,13 +87,13 @@ export function uploadCompose(files) {
|
||||||
dispatch(uploadComposeFail(error));
|
dispatch(uploadComposeFail(error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function uploadComposeRequest() {
|
export function uploadComposeRequest() {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_REQUEST
|
type: COMPOSE_UPLOAD_REQUEST
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function uploadComposeProgress(loaded, total) {
|
export function uploadComposeProgress(loaded, total) {
|
||||||
return {
|
return {
|
||||||
|
@ -101,25 +101,25 @@ export function uploadComposeProgress(loaded, total) {
|
||||||
loaded: loaded,
|
loaded: loaded,
|
||||||
total: total
|
total: total
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function uploadComposeSuccess(media) {
|
export function uploadComposeSuccess(media) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_SUCCESS,
|
type: COMPOSE_UPLOAD_SUCCESS,
|
||||||
media: media
|
media: media
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function uploadComposeFail(error) {
|
export function uploadComposeFail(error) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_FAIL,
|
type: COMPOSE_UPLOAD_FAIL,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function undoUploadCompose(media_id) {
|
export function undoUploadCompose(media_id) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_UNDO,
|
type: COMPOSE_UPLOAD_UNDO,
|
||||||
media_id: media_id
|
media_id: media_id
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function changeFollow(text) {
|
||||||
type: FOLLOW_CHANGE,
|
type: FOLLOW_CHANGE,
|
||||||
text: text
|
text: text
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitFollow() {
|
export function submitFollow() {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
@ -25,24 +25,24 @@ export function submitFollow() {
|
||||||
dispatch(submitFollowFail(error));
|
dispatch(submitFollowFail(error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitFollowRequest() {
|
export function submitFollowRequest() {
|
||||||
return {
|
return {
|
||||||
type: FOLLOW_SUBMIT_REQUEST
|
type: FOLLOW_SUBMIT_REQUEST
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitFollowSuccess(account) {
|
export function submitFollowSuccess(account) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOW_SUBMIT_SUCCESS,
|
type: FOLLOW_SUBMIT_SUCCESS,
|
||||||
account: account
|
account: account
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitFollowFail(error) {
|
export function submitFollowFail(error) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOW_SUBMIT_FAIL,
|
type: FOLLOW_SUBMIT_FAIL,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
|
@ -22,14 +22,14 @@ export function reblog(status) {
|
||||||
dispatch(reblogFail(status, error));
|
dispatch(reblogFail(status, error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function reblogRequest(status) {
|
export function reblogRequest(status) {
|
||||||
return {
|
return {
|
||||||
type: REBLOG_REQUEST,
|
type: REBLOG_REQUEST,
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function reblogSuccess(status, response) {
|
export function reblogSuccess(status, response) {
|
||||||
return {
|
return {
|
||||||
|
@ -37,7 +37,7 @@ export function reblogSuccess(status, response) {
|
||||||
status: status,
|
status: status,
|
||||||
response: response
|
response: response
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function reblogFail(status, error) {
|
export function reblogFail(status, error) {
|
||||||
return {
|
return {
|
||||||
|
@ -45,7 +45,7 @@ export function reblogFail(status, error) {
|
||||||
status: status,
|
status: status,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function favourite(status) {
|
export function favourite(status) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
@ -57,14 +57,14 @@ export function favourite(status) {
|
||||||
dispatch(favouriteFail(status, error));
|
dispatch(favouriteFail(status, error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function favouriteRequest(status) {
|
export function favouriteRequest(status) {
|
||||||
return {
|
return {
|
||||||
type: FAVOURITE_REQUEST,
|
type: FAVOURITE_REQUEST,
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function favouriteSuccess(status, response) {
|
export function favouriteSuccess(status, response) {
|
||||||
return {
|
return {
|
||||||
|
@ -72,7 +72,7 @@ export function favouriteSuccess(status, response) {
|
||||||
status: status,
|
status: status,
|
||||||
response: response
|
response: response
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function favouriteFail(status, error) {
|
export function favouriteFail(status, error) {
|
||||||
return {
|
return {
|
||||||
|
@ -80,4 +80,4 @@ export function favouriteFail(status, error) {
|
||||||
status: status,
|
status: status,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,4 +5,4 @@ export function setAccessToken(token) {
|
||||||
type: ACCESS_TOKEN_SET,
|
type: ACCESS_TOKEN_SET,
|
||||||
token: token
|
token: token
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS';
|
||||||
|
|
||||||
|
export function dismissNotification(notification) {
|
||||||
|
return {
|
||||||
|
type: NOTIFICATION_DISMISS,
|
||||||
|
notification: notification
|
||||||
|
};
|
||||||
|
};
|
|
@ -14,7 +14,7 @@ export function setTimeline(timeline, statuses) {
|
||||||
timeline: timeline,
|
timeline: timeline,
|
||||||
statuses: statuses
|
statuses: statuses
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateTimeline(timeline, status) {
|
export function updateTimeline(timeline, status) {
|
||||||
return {
|
return {
|
||||||
|
@ -22,21 +22,21 @@ export function updateTimeline(timeline, status) {
|
||||||
timeline: timeline,
|
timeline: timeline,
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deleteFromTimelines(id) {
|
export function deleteFromTimelines(id) {
|
||||||
return {
|
return {
|
||||||
type: TIMELINE_DELETE,
|
type: TIMELINE_DELETE,
|
||||||
id: id
|
id: id
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function refreshTimelineRequest(timeline) {
|
export function refreshTimelineRequest(timeline) {
|
||||||
return {
|
return {
|
||||||
type: TIMELINE_REFRESH_REQUEST,
|
type: TIMELINE_REFRESH_REQUEST,
|
||||||
timeline: timeline
|
timeline: timeline
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function refreshTimeline(timeline) {
|
export function refreshTimeline(timeline) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
@ -48,13 +48,13 @@ export function refreshTimeline(timeline) {
|
||||||
dispatch(refreshTimelineFail(timeline, error));
|
dispatch(refreshTimelineFail(timeline, error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function refreshTimelineSuccess(timeline, statuses) {
|
export function refreshTimelineSuccess(timeline, statuses) {
|
||||||
return function (dispatch) {
|
return function (dispatch) {
|
||||||
dispatch(setTimeline(timeline, statuses));
|
dispatch(setTimeline(timeline, statuses));
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function refreshTimelineFail(timeline, error) {
|
export function refreshTimelineFail(timeline, error) {
|
||||||
return {
|
return {
|
||||||
|
@ -62,4 +62,4 @@ export function refreshTimelineFail(timeline, error) {
|
||||||
timeline: timeline,
|
timeline: timeline,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import ColumnsArea from './columns_area';
|
import ColumnsArea from './columns_area';
|
||||||
import Column from './column';
|
import Column from './column';
|
||||||
import Drawer from './drawer';
|
import Drawer from './drawer';
|
||||||
import ComposeFormContainer from '../containers/compose_form_container';
|
import ComposeFormContainer from '../containers/compose_form_container';
|
||||||
import FollowFormContainer from '../containers/follow_form_container';
|
import FollowFormContainer from '../containers/follow_form_container';
|
||||||
import UploadFormContainer from '../containers/upload_form_container';
|
import UploadFormContainer from '../containers/upload_form_container';
|
||||||
import StatusListContainer from '../containers/status_list_container';
|
import StatusListContainer from '../containers/status_list_container';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import NotificationsContainer from '../containers/notifications_container';
|
||||||
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
|
||||||
const Frontend = React.createClass({
|
const Frontend = React.createClass({
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ const Frontend = React.createClass({
|
||||||
<StatusListContainer type='mentions' />
|
<StatusListContainer type='mentions' />
|
||||||
</Column>
|
</Column>
|
||||||
</ColumnsArea>
|
</ColumnsArea>
|
||||||
|
|
||||||
|
<NotificationsContainer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { NotificationStack } from 'react-notification';
|
||||||
|
import { dismissNotification } from '../actions/notifications';
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
return {
|
||||||
|
notifications: state.get('notifications').map((item, i) => ({
|
||||||
|
message: item.get('message'),
|
||||||
|
title: item.get('title'),
|
||||||
|
key: i,
|
||||||
|
action: 'Dismiss',
|
||||||
|
dismissAfter: 5000
|
||||||
|
})).toJS()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
onDismiss: notifiction => {
|
||||||
|
dispatch(dismissNotification(notifiction));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(NotificationStack);
|
|
@ -58,4 +58,4 @@ export default function compose(state = initialState, action) {
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -21,4 +21,4 @@ export default function compose(state = initialState, action) {
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,10 +3,12 @@ import timelines from './timelines';
|
||||||
import meta from './meta';
|
import meta from './meta';
|
||||||
import compose from './compose';
|
import compose from './compose';
|
||||||
import follow from './follow';
|
import follow from './follow';
|
||||||
|
import notifications from './notifications';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
timelines,
|
timelines,
|
||||||
meta,
|
meta,
|
||||||
compose,
|
compose,
|
||||||
follow
|
follow,
|
||||||
|
notifications
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,4 +10,4 @@ export default function meta(state = initialState, action) {
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
27
app/assets/javascripts/components/reducers/notifications.jsx
Normal file
27
app/assets/javascripts/components/reducers/notifications.jsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { COMPOSE_SUBMIT_FAIL, COMPOSE_UPLOAD_FAIL } from '../actions/compose';
|
||||||
|
import { FOLLOW_SUBMIT_FAIL } from '../actions/follow';
|
||||||
|
import { REBLOG_FAIL, FAVOURITE_FAIL } from '../actions/interactions';
|
||||||
|
import { TIMELINE_REFRESH_FAIL } from '../actions/timelines';
|
||||||
|
import { NOTIFICATION_DISMISS } from '../actions/notifications';
|
||||||
|
import Immutable from 'immutable';
|
||||||
|
|
||||||
|
const initialState = Immutable.List();
|
||||||
|
|
||||||
|
export default function meta(state = initialState, action) {
|
||||||
|
switch(action.type) {
|
||||||
|
case COMPOSE_SUBMIT_FAIL:
|
||||||
|
case COMPOSE_UPLOAD_FAIL:
|
||||||
|
case FOLLOW_SUBMIT_FAIL:
|
||||||
|
case REBLOG_FAIL:
|
||||||
|
case FAVOURITE_FAIL:
|
||||||
|
case TIMELINE_REFRESH_FAIL:
|
||||||
|
return state.push(Immutable.fromJS({
|
||||||
|
message: action.error.response.statusText,
|
||||||
|
title: `${action.error.response.status}`
|
||||||
|
}));
|
||||||
|
case NOTIFICATION_DISMISS:
|
||||||
|
return state.clear();
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
|
@ -66,4 +66,4 @@ export default function timelines(state = initialState, action) {
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,6 +3,10 @@ class Api::FollowsController < ApiController
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
if params[:uri].blank?
|
||||||
|
raise ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
@follow = FollowService.new.(current_user.account, params[:uri])
|
@follow = FollowService.new.(current_user.account, params[:uri])
|
||||||
render action: :show
|
render action: :show
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ class RemoveStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_delete_salmon(account, status)
|
def send_delete_salmon(account, status)
|
||||||
SendInteractionService.new.(status.stream_entry, account)
|
NotificationWorker.perform_async(status.stream_entry_id, account.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_reblogs(status)
|
def remove_reblogs(status)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"moment": "^2.14.1",
|
"moment": "^2.14.1",
|
||||||
"react-addons-pure-render-mixin": "^15.3.1",
|
"react-addons-pure-render-mixin": "^15.3.1",
|
||||||
"react-immutable-proptypes": "^2.1.0",
|
"react-immutable-proptypes": "^2.1.0",
|
||||||
|
"react-notification": "^6.1.1",
|
||||||
"react-redux": "^4.4.5",
|
"react-redux": "^4.4.5",
|
||||||
"react-router": "^2.8.0",
|
"react-router": "^2.8.0",
|
||||||
"redux": "^3.5.2",
|
"redux": "^3.5.2",
|
||||||
|
|
Loading…
Reference in a new issue