notifications unoptimized

This commit is contained in:
diminator 2015-09-01 14:45:14 +02:00
parent 9dddf0bf21
commit bfaf4886a4
8 changed files with 226 additions and 97 deletions

View File

@ -34,6 +34,15 @@ let EditionContainer = React.createClass({
EditionActions.fetchOne(this.props.params.editionId);
},
// This is done to update the container when the user clicks on the prev or next
// button to update the URL parameter (and therefore to switch pieces)
componentWillReceiveProps(nextProps) {
if(this.props.params.editionId !== nextProps.params.editionId) {
EditionActions.updateEdition({});
EditionActions.fetchOne(nextProps.params.editionId);
}
},
componentWillUnmount() {
// Every time we're leaving the edition detail page,
// just reset the edition that is saved in the edition store

View File

@ -0,0 +1,43 @@
'use strict';
import React from 'react';
let GlobalAction = React.createClass({
propTypes: {
requestActions: React.PropTypes.object
},
render() {
let pieceActions = null;
if (this.props.requestActions && this.props.requestActions.pieces){
pieceActions = this.props.requestActions.pieces.map((item) => {
return (
<div className="ascribe-global-action">
{item}
</div>);
});
}
let editionActions = null;
if (this.props.requestActions && this.props.requestActions.editions){
editionActions = Object.keys(this.props.requestActions.editions).map((pieceId) => {
return this.props.requestActions.editions[pieceId].map((item) => {
return (
<div className="ascribe-global-action">
{item}
</div>);
});
});
}
if (pieceActions || editionActions) {
return (
<div className="ascribe-global-action-wrapper">
{pieceActions}
{editionActions}
</div>);
}
return null;
}
});
export default GlobalAction;

View File

@ -3,6 +3,8 @@
import React from 'react';
import Router from 'react-router';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import UserActions from '../actions/user_actions';
import UserStore from '../stores/user_store';
@ -10,6 +12,8 @@ import WhitelabelActions from '../actions/whitelabel_actions';
import WhitelabelStore from '../stores/whitelabel_store';
import EventActions from '../actions/event_actions';
import PieceListStore from '../stores/piece_list_store';
import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav';
@ -25,6 +29,8 @@ import NavRoutesLinks from './nav_routes_links';
import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils';
let Link = Router.Link;
let Header = React.createClass({
propTypes: {
@ -41,7 +47,11 @@ let Header = React.createClass({
},
getInitialState() {
return mergeOptions(WhitelabelStore.getState(), UserStore.getState());
return mergeOptions(
WhitelabelStore.getState(),
UserStore.getState(),
PieceListStore.getState()
);
},
componentDidMount() {
@ -49,11 +59,13 @@ let Header = React.createClass({
UserStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
WhitelabelStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
},
componentWillUnmount() {
UserStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
},
getLogo(){
@ -90,6 +102,34 @@ let Header = React.createClass({
}
},
getNotifications() {
if (this.state.requestActions && this.state.requestActions.length > 0) {
return (
<DropdownButton
eventKey="1"
title={
<span>
<Glyphicon glyph='envelope' color="green"/>
<span className="notification-amount">({this.state.requestActions.length})</span>
</span>
}
className="notification-menu">
{this.state.requestActions.map((pieceOrEdition, i) => {
return (
<MenuItem eventKey={i + 2}>
<NotificationListItem
ref={i}
pieceOrEdition={pieceOrEdition}/>
</MenuItem>);
})
}
</DropdownButton>
);
}
return null;
},
render() {
let account;
let signup;
@ -100,7 +140,7 @@ let Header = React.createClass({
<MenuItemLink eventKey="2" to="settings">{getLangText('Account Settings')}</MenuItemLink>
<MenuItem divider />
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
</DropdownButton>
</DropdownButton>
);
navRoutesLinks = <NavRoutesLinks routes={this.props.routes} navbar right/>;
}
@ -122,6 +162,7 @@ let Header = React.createClass({
{this.getPoweredBy()}
</Nav>
<Nav navbar right>
{this.getNotifications()}
<HeaderNotificationDebug show={false}/>
{account}
{signup}
@ -134,4 +175,57 @@ let Header = React.createClass({
}
});
let NotificationListItem = React.createClass({
propTypes: {
pieceOrEdition: React.PropTypes.object
},
getLinkData() {
if(this.props.pieceOrEdition && this.props.pieceOrEdition.bitcoin_id) {
return {
to: 'edition',
params: {
editionId: this.props.pieceOrEdition.bitcoin_id
}
};
} else {
return {
to: 'piece',
params: {
pieceId: this.props.pieceOrEdition.id
}
};
}
},
render() {
if (this.props.pieceOrEdition) {
return (
<Link {...this.getLinkData()}>
<div className="row notification-wrapper">
<div className="col-xs-4 clear-paddings">
<div className="thumbnail-wrapper">
<img src={this.props.pieceOrEdition.thumbnail.url_safe}/>
</div>
</div>
<div className="col-xs-8 notification-list-item-header">
<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';
})
}
</div>
</div>
</div>
</Link>);
}
return null;
}
});
export default Header;

View File

@ -15,6 +15,7 @@ import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_l
import Pagination from './ascribe_pagination/pagination';
import GlobalAction from './global_action';
import PieceListBulkModal from './ascribe_piece_list_bulk_modal/piece_list_bulk_modal';
import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar';
@ -148,33 +149,11 @@ let PieceList = React.createClass({
let loadingElement = (<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />);
let AccordionListItemType = this.props.accordionListItemType;
let pieceActions = null;
if (this.state.requestActions && this.state.requestActions.pieces){
pieceActions = this.state.requestActions.pieces.map((item) => {
return (
<div className="ascribe-global-action">
test
</div>);
});
}
let editionActions = null;
if (this.state.requestActions && this.state.requestActions.editions){
for (let pieceId in this.state.requestActions.editions) {
editionActions = this.state.requestActions.editions[pieceId].map((item) => {
return (
<div className="ascribe-global-action">
test
</div>);
});
}
}
//<GlobalAction requestActions={this.state.requestActions} />
return (
<div>
<div className="ascribe-global-action-wrapper">
{pieceActions}
{editionActions}
</div>
<PieceListToolbar
className="ascribe-piece-list-toolbar"
searchFor={this.searchFor}

View File

@ -71,21 +71,7 @@ class PieceListStore {
}
onUpdatePieceListRequestActions(res) {
this.requestActions.pieces = res.piece_actions;
this.requestActions.editions = res.edition_actions;
for (let pieceId in res.edition_actions){
try {
this.onUpdatePropertyForPiece({
pieceId: parseInt(pieceId, 10),
key: 'request_action_editions',
value: res.edition_actions[pieceId]
});
}
catch(err) {
console.warn('couldnt match request action with piecelist, maybe on other page');
}
}
this.requestActions = res.actions;
}
onUpdatePropertyForPiece({pieceId, key, value}) {

View File

@ -1,73 +1,25 @@
$break-small: 764px;
$break-medium: 991px;
$break-medium: 1200px;
.ascribe-global-action-wrapper {
position: fixed;
width: 100%;
max-width: 500px;
height:3.5em;
left:0;
right: 0;
top:0;
z-index: 2000;
display:table;
margin: 1px auto;
}
.ascribe-global-action {
width: 40%;
margin: 1px auto;
text-align: center;
padding: 1em;
color: black;
border: 1px solid #cccccc;
background-color: white;
}
.ascribe-global-notification-off {
bottom: -3.5em;
}
.ascribe-global-notification-on {
bottom: 0;
}
.ascribe-global-notification > div, .ascribe-global-notification-bubble > div {
display:table-cell;
vertical-align: middle;
font-size: 1.25em;
font-family: 'Source Sans Pro';
text-align: right;
padding-right: 3em;
}
.ascribe-global-notification-bubble > div {
padding: .75em 1.5em .75em 1.5em;
}
.ascribe-global-notification-bubble {
position: fixed;
bottom: 3em;
right: -50em;
display:table;
height: 3.5em;
background-color: #212121;
border-radius: 2px;
color: white;
transition: 1s right ease;
}
.ascribe-global-notification-bubble-off {
right: -100em;
}
.ascribe-global-notification-bubble-on {
right: 3.5em;
}
.ascribe-global-notification-danger {
background-color: #d9534f;
}
.ascribe-global-notification-success {
background-color: rgba(2, 182, 163, 1);
margin-top: 1px;
}

View File

@ -0,0 +1,65 @@
$break-small: 764px;
$break-medium: 991px;
$break-medium: 1200px;
.notification-wrapper {
width: 350px;
height:8em;
padding: 0.3em;
border-bottom: 1px solid #cccccc;
margin: -3px -20px;
// ToDo: Include media queries for thumbnail
.thumbnail-wrapper {
width: 7.4em;
height: 7.4em;
padding:0;
cursor: pointer;
text-align: center;
img {
max-width: 100%;
max-height: 100%;
}
&::before {
content: ' ';
display: inline-block;
vertical-align: middle; /* vertical alignment of the inline element */
height: 100%;
}
}
h1 {
margin-top: 0.3em;
margin-bottom: 0.15em;
font-size: 1.8em;
}
.sub-header{
margin-bottom: 1em;
}
.notification-action{
color: $ascribe-color-green;
}
}
.notification-menu {
.dropdown-menu {
padding: 0 !important;
li a {
padding-top: 0;
}
}
}
.notification-amount {
padding: 0.3em;
font-size: 1.2em;
}
.ascribe-global-action {
text-align: center;
padding: 1em;
color: black;
border: 1px solid #cccccc;
background-color: white;
margin-top: 1px;
}

View File

@ -24,6 +24,7 @@ $BASE_URL: '<%= BASE_URL %>';
@import 'ascribe_footer';
@import 'ascribe_global_action';
@import 'ascribe_global_notification';
@import 'ascribe_notification_list';
@import 'ascribe_piece_register';
@import 'offset_right';
@import 'ascribe_settings';