Adding a notification stack for error messages
This commit is contained in:
		
							parent
							
								
									05b0c985b4
								
							
						
					
					
						commit
						d6a64f45fd
					
				@ -19,20 +19,20 @@ export function changeCompose(text) {
 | 
			
		||||
    type: COMPOSE_CHANGE,
 | 
			
		||||
    text: text
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function replyCompose(status) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_REPLY,
 | 
			
		||||
    status: status
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function cancelReplyCompose() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_REPLY_CANCEL
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitCompose() {
 | 
			
		||||
  return function (dispatch, getState) {
 | 
			
		||||
@ -48,27 +48,27 @@ export function submitCompose() {
 | 
			
		||||
      dispatch(submitComposeFail(error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitComposeRequest() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_SUBMIT_REQUEST
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitComposeSuccess(status) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_SUBMIT_SUCCESS,
 | 
			
		||||
    status: status
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitComposeFail(error) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_SUBMIT_FAIL,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function uploadCompose(files) {
 | 
			
		||||
  return function (dispatch, getState) {
 | 
			
		||||
@ -87,13 +87,13 @@ export function uploadCompose(files) {
 | 
			
		||||
      dispatch(uploadComposeFail(error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function uploadComposeRequest() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_UPLOAD_REQUEST
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function uploadComposeProgress(loaded, total) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -101,25 +101,25 @@ export function uploadComposeProgress(loaded, total) {
 | 
			
		||||
    loaded: loaded,
 | 
			
		||||
    total: total
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function uploadComposeSuccess(media) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_UPLOAD_SUCCESS,
 | 
			
		||||
    media: media
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function uploadComposeFail(error) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_UPLOAD_FAIL,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function undoUploadCompose(media_id) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: COMPOSE_UPLOAD_UNDO,
 | 
			
		||||
    media_id: media_id
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ export function changeFollow(text) {
 | 
			
		||||
    type: FOLLOW_CHANGE,
 | 
			
		||||
    text: text
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitFollow() {
 | 
			
		||||
  return function (dispatch, getState) {
 | 
			
		||||
@ -25,24 +25,24 @@ export function submitFollow() {
 | 
			
		||||
      dispatch(submitFollowFail(error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitFollowRequest() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: FOLLOW_SUBMIT_REQUEST
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitFollowSuccess(account) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: FOLLOW_SUBMIT_SUCCESS,
 | 
			
		||||
    account: account
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function submitFollowFail(error) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: FOLLOW_SUBMIT_FAIL,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22,14 +22,14 @@ export function reblog(status) {
 | 
			
		||||
      dispatch(reblogFail(status, error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function reblogRequest(status) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: REBLOG_REQUEST,
 | 
			
		||||
    status: status
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function reblogSuccess(status, response) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -37,7 +37,7 @@ export function reblogSuccess(status, response) {
 | 
			
		||||
    status: status,
 | 
			
		||||
    response: response
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function reblogFail(status, error) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -45,7 +45,7 @@ export function reblogFail(status, error) {
 | 
			
		||||
    status: status,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function favourite(status) {
 | 
			
		||||
  return function (dispatch, getState) {
 | 
			
		||||
@ -57,14 +57,14 @@ export function favourite(status) {
 | 
			
		||||
      dispatch(favouriteFail(status, error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function favouriteRequest(status) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: FAVOURITE_REQUEST,
 | 
			
		||||
    status: status
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function favouriteSuccess(status, response) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -72,7 +72,7 @@ export function favouriteSuccess(status, response) {
 | 
			
		||||
    status: status,
 | 
			
		||||
    response: response
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function favouriteFail(status, error) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -80,4 +80,4 @@ export function favouriteFail(status, error) {
 | 
			
		||||
    status: status,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -5,4 +5,4 @@ export function setAccessToken(token) {
 | 
			
		||||
    type: ACCESS_TOKEN_SET,
 | 
			
		||||
    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,
 | 
			
		||||
    statuses: statuses
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function updateTimeline(timeline, status) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -22,21 +22,21 @@ export function updateTimeline(timeline, status) {
 | 
			
		||||
    timeline: timeline,
 | 
			
		||||
    status: status
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function deleteFromTimelines(id) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: TIMELINE_DELETE,
 | 
			
		||||
    id: id
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function refreshTimelineRequest(timeline) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: TIMELINE_REFRESH_REQUEST,
 | 
			
		||||
    timeline: timeline
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function refreshTimeline(timeline) {
 | 
			
		||||
  return function (dispatch, getState) {
 | 
			
		||||
@ -48,13 +48,13 @@ export function refreshTimeline(timeline) {
 | 
			
		||||
      dispatch(refreshTimelineFail(timeline, error));
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function refreshTimelineSuccess(timeline, statuses) {
 | 
			
		||||
  return function (dispatch) {
 | 
			
		||||
    dispatch(setTimeline(timeline, statuses));
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function refreshTimelineFail(timeline, error) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -62,4 +62,4 @@ export function refreshTimelineFail(timeline, error) {
 | 
			
		||||
    timeline: timeline,
 | 
			
		||||
    error: error
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,12 @@
 | 
			
		||||
import ColumnsArea          from './columns_area';
 | 
			
		||||
import Column               from './column';
 | 
			
		||||
import Drawer               from './drawer';
 | 
			
		||||
import ComposeFormContainer from '../containers/compose_form_container';
 | 
			
		||||
import FollowFormContainer  from '../containers/follow_form_container';
 | 
			
		||||
import UploadFormContainer  from '../containers/upload_form_container';
 | 
			
		||||
import StatusListContainer  from '../containers/status_list_container';
 | 
			
		||||
import PureRenderMixin      from 'react-addons-pure-render-mixin';
 | 
			
		||||
import ComposeFormContainer   from '../containers/compose_form_container';
 | 
			
		||||
import FollowFormContainer    from '../containers/follow_form_container';
 | 
			
		||||
import UploadFormContainer    from '../containers/upload_form_container';
 | 
			
		||||
import StatusListContainer    from '../containers/status_list_container';
 | 
			
		||||
import NotificationsContainer from '../containers/notifications_container';
 | 
			
		||||
import PureRenderMixin        from 'react-addons-pure-render-mixin';
 | 
			
		||||
 | 
			
		||||
const Frontend = React.createClass({
 | 
			
		||||
 | 
			
		||||
@ -32,6 +33,8 @@ const Frontend = React.createClass({
 | 
			
		||||
            <StatusListContainer type='mentions' />
 | 
			
		||||
          </Column>
 | 
			
		||||
        </ColumnsArea>
 | 
			
		||||
 | 
			
		||||
        <NotificationsContainer />
 | 
			
		||||
      </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:
 | 
			
		||||
      return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -21,4 +21,4 @@ export default function compose(state = initialState, action) {
 | 
			
		||||
    default:
 | 
			
		||||
      return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -3,10 +3,12 @@ import timelines           from './timelines';
 | 
			
		||||
import meta                from './meta';
 | 
			
		||||
import compose             from './compose';
 | 
			
		||||
import follow              from './follow';
 | 
			
		||||
import notifications       from './notifications';
 | 
			
		||||
 | 
			
		||||
export default combineReducers({
 | 
			
		||||
  timelines,
 | 
			
		||||
  meta,
 | 
			
		||||
  compose,
 | 
			
		||||
  follow
 | 
			
		||||
  follow,
 | 
			
		||||
  notifications
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -10,4 +10,4 @@ export default function meta(state = initialState, action) {
 | 
			
		||||
    default:
 | 
			
		||||
      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:
 | 
			
		||||
      return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,10 @@ class Api::FollowsController < ApiController
 | 
			
		||||
  respond_to    :json
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    if params[:uri].blank?
 | 
			
		||||
      raise ActiveRecord::RecordNotFound
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    @follow = FollowService.new.(current_user.account, params[:uri])
 | 
			
		||||
    render action: :show
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ class RemoveStatusService < BaseService
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def send_delete_salmon(account, status)
 | 
			
		||||
    SendInteractionService.new.(status.stream_entry, account)
 | 
			
		||||
    NotificationWorker.perform_async(status.stream_entry_id, account.id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_reblogs(status)
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@
 | 
			
		||||
    "moment": "^2.14.1",
 | 
			
		||||
    "react-addons-pure-render-mixin": "^15.3.1",
 | 
			
		||||
    "react-immutable-proptypes": "^2.1.0",
 | 
			
		||||
    "react-notification": "^6.1.1",
 | 
			
		||||
    "react-redux": "^4.4.5",
 | 
			
		||||
    "react-router": "^2.8.0",
 | 
			
		||||
    "redux": "^3.5.2",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user