mirror of
https://github.com/ascribe/onion.git
synced 2025-01-03 10:25:08 +01:00
notification app
notification refactor in onion - split by piece/edition
This commit is contained in:
parent
7f39c62130
commit
edcd8e57a4
34
js/actions/notification_actions.js
Normal file
34
js/actions/notification_actions.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
import alt from '../alt';
|
||||
|
||||
import NotificationFetcher from '../fetchers/notification_fetcher';
|
||||
|
||||
class NotificationActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'updatePieceListNotifications',
|
||||
'updateEditionListNotifications'
|
||||
);
|
||||
}
|
||||
|
||||
fetchPieceListNotifications() {
|
||||
NotificationFetcher
|
||||
.fetchPieceListNotifications()
|
||||
.then((res) => {
|
||||
this.actions.updatePieceListNotifications(res);
|
||||
})
|
||||
.catch((err) => console.logGlobal(err));
|
||||
}
|
||||
|
||||
fetchEditionListNotifications() {
|
||||
NotificationFetcher
|
||||
.fetchEditionListNotifications()
|
||||
.then((res) => {
|
||||
this.actions.updateEditionListNotifications(res);
|
||||
})
|
||||
.catch((err) => console.logGlobal(err));
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createActions(NotificationActions);
|
@ -61,7 +61,6 @@ let EditionContainer = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
console.log(this.state);
|
||||
if('title' in this.state.edition) {
|
||||
return (
|
||||
<Edition
|
||||
|
@ -96,6 +96,31 @@ let Header = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
onMenuItemClick(event) {
|
||||
/*
|
||||
This is a hack to make the dropdown close after clicking on an item
|
||||
The function just need to be defined
|
||||
|
||||
from https://github.com/react-bootstrap/react-bootstrap/issues/368:
|
||||
|
||||
@jvillasante - Have you tried to use onSelect with the DropdownButton?
|
||||
I don't have a working example that is exactly like yours,
|
||||
but I just noticed that the Dropdown closes when I've attached an event handler to OnSelect:
|
||||
|
||||
<DropdownButton eventKey={3} title="Admin" onSelect={ this.OnSelected } >
|
||||
|
||||
onSelected: function(e) {
|
||||
// doesn't need to have functionality (necessarily) ... just wired up
|
||||
}
|
||||
Internally, a call to DropdownButton.setDropDownState(false) is made which will hide the dropdown menu.
|
||||
So, you should be able to call that directly on the DropdownButton instance as well if needed.
|
||||
|
||||
NOW, THAT DIDN'T WORK - the onSelect routine isnt triggered in all cases
|
||||
Hence, we do this manually
|
||||
*/
|
||||
this.refs.dropdownbutton.setDropdownState(false);
|
||||
},
|
||||
|
||||
render() {
|
||||
let account;
|
||||
let signup;
|
||||
@ -103,9 +128,15 @@ let Header = React.createClass({
|
||||
if (this.state.currentUser.username){
|
||||
account = (
|
||||
<DropdownButton
|
||||
ref='dropdownbutton'
|
||||
eventKey="1"
|
||||
title={this.state.currentUser.username}>
|
||||
<MenuItemLink eventKey="2" to="settings">{getLangText('Account Settings')}</MenuItemLink>
|
||||
<MenuItemLink
|
||||
eventKey="2"
|
||||
to="settings"
|
||||
onClick={this.onMenuItemClick}>
|
||||
{getLangText('Account Settings')}
|
||||
</MenuItemLink>
|
||||
<MenuItem divider />
|
||||
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
|
||||
</DropdownButton>
|
||||
|
@ -8,7 +8,8 @@ import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||
|
||||
import Nav from 'react-bootstrap/lib/Nav';
|
||||
|
||||
import PieceListStore from '../stores/piece_list_store';
|
||||
import NotificationActions from '../actions/notification_actions';
|
||||
import NotificationStore from '../stores/notification_store';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
@ -20,23 +21,25 @@ let HeaderNotifications = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions(
|
||||
PieceListStore.getState()
|
||||
NotificationStore.getState()
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PieceListStore.listen(this.onChange);
|
||||
NotificationStore.listen(this.onChange);
|
||||
NotificationActions.fetchPieceListNotifications();
|
||||
NotificationActions.fetchEditionListNotifications();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
NotificationStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
onSelected(event) {
|
||||
onMenuItemClick(event) {
|
||||
/*
|
||||
This is a hack to make the dropdown close after clicking on an item
|
||||
The function just need to be defined
|
||||
@ -54,32 +57,87 @@ let HeaderNotifications = React.createClass({
|
||||
}
|
||||
Internally, a call to DropdownButton.setDropDownState(false) is made which will hide the dropdown menu.
|
||||
So, you should be able to call that directly on the DropdownButton instance as well if needed.
|
||||
|
||||
NOW, THAT DIDN'T WORK - the onSelect routine isnt triggered in all cases
|
||||
Hence, we do this manually
|
||||
*/
|
||||
this.refs.dropdownbutton.setDropdownState(false);
|
||||
},
|
||||
|
||||
getPieceNotifications(){
|
||||
if (this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className="notification-header">
|
||||
Artworks ({this.state.pieceListNotifications.length})
|
||||
</div>
|
||||
{this.state.pieceListNotifications.map((pieceNotification, i) => {
|
||||
return (
|
||||
<MenuItem eventKey={i + 2}>
|
||||
<NotificationListItem
|
||||
ref={i}
|
||||
notification={pieceNotification.notification}
|
||||
pieceOrEdition={pieceNotification.piece}
|
||||
onClick={this.onMenuItemClick}/>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getEditionNotifications(){
|
||||
if (this.state.editionListNotifications && this.state.editionListNotifications.length > 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className="notification-header">
|
||||
Editions ({this.state.editionListNotifications.length})
|
||||
</div>
|
||||
{this.state.editionListNotifications.map((editionNotification, i) => {
|
||||
return (
|
||||
<MenuItem eventKey={i + 2}>
|
||||
<NotificationListItem
|
||||
ref={'edition' + i}
|
||||
notification={editionNotification.notification}
|
||||
pieceOrEdition={editionNotification.edition}
|
||||
onClick={this.onMenuItemClick}/>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this.state.requestActions && this.state.requestActions.length > 0) {
|
||||
if ((this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) ||
|
||||
(this.state.editionListNotifications && this.state.editionListNotifications.length > 0)){
|
||||
let numNotifications = 0;
|
||||
if (this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) {
|
||||
numNotifications += this.state.pieceListNotifications.length;
|
||||
}
|
||||
if (this.state.editionListNotifications && this.state.editionListNotifications.length > 0) {
|
||||
numNotifications += this.state.editionListNotifications.length;
|
||||
}
|
||||
return (
|
||||
<Nav navbar right>
|
||||
<DropdownButton
|
||||
ref='dropdownbutton'
|
||||
eventKey="1"
|
||||
title={
|
||||
<span>
|
||||
<Glyphicon glyph='envelope' color="green"/>
|
||||
<span className="notification-amount">({this.state.requestActions.length})</span>
|
||||
<span className="notification-amount">({numNotifications})</span>
|
||||
</span>
|
||||
}
|
||||
className="notification-menu"
|
||||
onSelect={this.onSelected}>
|
||||
{this.state.requestActions.map((pieceOrEdition, i) => {
|
||||
return (
|
||||
<MenuItem eventKey={i + 2}>
|
||||
<NotificationListItem
|
||||
ref={i}
|
||||
pieceOrEdition={pieceOrEdition}/>
|
||||
</MenuItem>);
|
||||
}
|
||||
)}
|
||||
className="notification-menu">
|
||||
{this.getPieceNotifications()}
|
||||
{this.getEditionNotifications()}
|
||||
</DropdownButton>
|
||||
</Nav>
|
||||
);
|
||||
@ -90,33 +148,42 @@ let HeaderNotifications = React.createClass({
|
||||
|
||||
let NotificationListItem = React.createClass({
|
||||
propTypes: {
|
||||
pieceOrEdition: React.PropTypes.object
|
||||
notification: React.PropTypes.array,
|
||||
pieceOrEdition: React.PropTypes.object,
|
||||
onClick: React.PropTypes.func
|
||||
},
|
||||
|
||||
isPiece() {
|
||||
return !(this.props.pieceOrEdition && this.props.pieceOrEdition.parent);
|
||||
},
|
||||
|
||||
getLinkData() {
|
||||
|
||||
if(this.props.pieceOrEdition && this.props.pieceOrEdition.parent) {
|
||||
return {
|
||||
to: 'edition',
|
||||
params: {
|
||||
editionId: this.props.pieceOrEdition.bitcoin_id
|
||||
}
|
||||
};
|
||||
} else {
|
||||
if (this.isPiece()) {
|
||||
return {
|
||||
to: 'piece',
|
||||
params: {
|
||||
pieceId: this.props.pieceOrEdition.id
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
to: 'edition',
|
||||
params: {
|
||||
editionId: this.props.pieceOrEdition.bitcoin_id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onClick(event){
|
||||
this.props.onClick(event);
|
||||
},
|
||||
render() {
|
||||
if (this.props.pieceOrEdition) {
|
||||
return (
|
||||
<Link {...this.getLinkData()}>
|
||||
<Link {...this.getLinkData()} onClick={this.onClick}>
|
||||
<div className="row notification-wrapper">
|
||||
<div className="col-xs-4 clear-paddings">
|
||||
<div className="thumbnail-wrapper">
|
||||
@ -127,11 +194,7 @@ let NotificationListItem = React.createClass({
|
||||
<h1>{this.props.pieceOrEdition.title}</h1>
|
||||
<div className="sub-header">by {this.props.pieceOrEdition.artist_name}</div>
|
||||
<div className="notification-action">
|
||||
{
|
||||
this.props.pieceOrEdition.request_action.map((requestAction) => {
|
||||
return 'Pending ' + requestAction.action + ' request';
|
||||
})
|
||||
}
|
||||
{'Pending ' + this.props.notification[0].action + ' request'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -65,8 +65,7 @@ let PieceList = React.createClass({
|
||||
let orderBy = this.props.orderBy ? this.props.orderBy : this.state.orderBy;
|
||||
if (this.state.pieceList.length === 0 || this.state.page !== page){
|
||||
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
|
||||
orderBy, this.state.orderAsc, this.state.filterBy)
|
||||
.then(() => PieceListActions.fetchPieceRequestActions());
|
||||
orderBy, this.state.orderAsc, this.state.filterBy);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -27,6 +27,8 @@ let ApiUrls = {
|
||||
'note_private_piece': AppConstants.apiEndpoint + 'note/private/pieces/',
|
||||
'note_public_edition': AppConstants.apiEndpoint + 'note/public/editions/',
|
||||
'note_public_piece': AppConstants.apiEndpoint + 'note/public/pieces/',
|
||||
'notification_piecelist': AppConstants.apiEndpoint + 'notifications/pieces/',
|
||||
'notification_editionlist': AppConstants.apiEndpoint + 'notifications/editions/',
|
||||
'ownership_contract_agreements': AppConstants.apiEndpoint + 'ownership/contract_agreements/',
|
||||
'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/',
|
||||
'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/',
|
||||
@ -52,7 +54,6 @@ let ApiUrls = {
|
||||
'piece_extradata': AppConstants.apiEndpoint + 'pieces/${piece_id}/extradata/',
|
||||
'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/',
|
||||
'pieces_list': AppConstants.apiEndpoint + 'pieces/',
|
||||
'pieces_list_request_actions': AppConstants.apiEndpoint + 'pieces/request_actions/',
|
||||
'piece_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/pieces/${piece_id}/',
|
||||
'user': AppConstants.apiEndpoint + 'users/',
|
||||
'users_login': AppConstants.apiEndpoint + 'users/login/',
|
||||
|
17
js/fetchers/notification_fetcher.js
Normal file
17
js/fetchers/notification_fetcher.js
Normal file
@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../utils/requests';
|
||||
|
||||
|
||||
let NotificationFetcher = {
|
||||
|
||||
fetchPieceListNotifications() {
|
||||
return requests.get('notification_piecelist');
|
||||
},
|
||||
|
||||
fetchEditionListNotifications() {
|
||||
return requests.get('notification_editionlist');
|
||||
}
|
||||
};
|
||||
|
||||
export default NotificationFetcher;
|
26
js/stores/notification_store.js
Normal file
26
js/stores/notification_store.js
Normal file
@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import alt from '../alt';
|
||||
|
||||
import NotificationActions from '../actions/notification_actions';
|
||||
|
||||
|
||||
class NotificationStore {
|
||||
constructor() {
|
||||
this.pieceListNotifications = {};
|
||||
this.editionListNotifications = {};
|
||||
this.bindActions(NotificationActions);
|
||||
}
|
||||
|
||||
onUpdatePieceListNotifications(res) {
|
||||
this.pieceListNotifications = res.notifications;
|
||||
}
|
||||
|
||||
onUpdateEditionListNotifications(res) {
|
||||
this.editionListNotifications = res.notifications;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default alt.createStore(NotificationStore, 'NotificationStore');
|
@ -2,13 +2,27 @@ $break-small: 764px;
|
||||
$break-medium: 991px;
|
||||
$break-medium: 1200px;
|
||||
|
||||
.notification-wrapper {
|
||||
.notification-header,.notification-wrapper {
|
||||
width: 350px;
|
||||
height:8em;
|
||||
padding: 0.3em;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
margin: -3px -20px;
|
||||
}
|
||||
|
||||
.notification-header {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
border-top: 1px solid #cccccc;
|
||||
padding: 0.3em 1em;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.notification-wrapper {
|
||||
height:8.4em;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
margin: -3px 0;
|
||||
padding: 0.5em;
|
||||
color: black;
|
||||
|
||||
&:hover{
|
||||
background-color: rgba(2, 182, 163, .05);
|
||||
}
|
||||
// ToDo: Include media queries for thumbnail
|
||||
.thumbnail-wrapper {
|
||||
width: 7.4em;
|
||||
@ -46,6 +60,10 @@ $break-medium: 1200px;
|
||||
li a {
|
||||
padding-top: 0;
|
||||
}
|
||||
border-top: 0;
|
||||
overflow-y:auto;
|
||||
overflow-x:hidden;
|
||||
max-height: 70vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user