mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merge branch 'AD-456-ikonotv-branded-page-for-registra' of bitbucket.org:ascribe/onion into AD-456-ikonotv-branded-page-for-registra
This commit is contained in:
commit
6555c02f23
@ -57,7 +57,7 @@ class PieceListActions {
|
||||
PieceListFetcher
|
||||
.fetchRequestActions()
|
||||
.then((res) => {
|
||||
this.actions.updatePieceListRequestActions(res.piece_ids);
|
||||
this.actions.updatePieceListRequestActions(res);
|
||||
})
|
||||
.catch((err) => console.logGlobal(err));
|
||||
}
|
||||
|
@ -61,12 +61,13 @@ let AccordionListItemWallet = React.createClass({
|
||||
},
|
||||
|
||||
getGlyphicon(){
|
||||
if (this.props.content.requestAction && this.props.content.requestAction.length > 0) {
|
||||
if ((this.props.content.request_action && this.props.content.request_action.length > 0) ||
|
||||
(this.props.content.request_action_editions)){
|
||||
return (
|
||||
<OverlayTrigger
|
||||
delay={500}
|
||||
placement="left"
|
||||
overlay={<Tooltip>{getLangText('You have actions pending in one of your editions')}</Tooltip>}>
|
||||
overlay={<Tooltip>{getLangText('You have actions pending')}</Tooltip>}>
|
||||
<Glyphicon glyph='bell' color="green"/>
|
||||
</OverlayTrigger>);
|
||||
}
|
||||
|
@ -36,6 +36,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
|
||||
|
@ -18,14 +18,20 @@ let CreateContractForm = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
digitalWorkKey: null,
|
||||
contractKey: null,
|
||||
isUploadReady: false
|
||||
};
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
blob: this.state.contractKey
|
||||
};
|
||||
},
|
||||
|
||||
submitKey(key) {
|
||||
this.setState({
|
||||
digitalWorkKey: key
|
||||
contractKey: key
|
||||
});
|
||||
},
|
||||
|
||||
@ -39,6 +45,7 @@ let CreateContractForm = React.createClass({
|
||||
return (
|
||||
<Form
|
||||
url={ApiUrls.ownership_contract}
|
||||
getFormData={this.getFormData}
|
||||
buttons={
|
||||
<button
|
||||
type="submit"
|
||||
|
@ -6,6 +6,8 @@ import AclButton from './../ascribe_buttons/acl_button';
|
||||
import ActionPanel from '../ascribe_panel/action_panel';
|
||||
import Form from './form';
|
||||
|
||||
import PieceListActions from '../../actions/piece_list_actions';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
@ -71,10 +73,16 @@ let RequestActionForm = React.createClass({
|
||||
let notification = new GlobalNotificationModel(message, 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
this.handleSuccess();
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
handleSuccess() {
|
||||
PieceListActions.fetchPieceRequestActions();
|
||||
if(this.props.handleSuccess) {
|
||||
this.props.handleSuccess();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
getContent() {
|
||||
@ -99,7 +107,7 @@ let RequestActionForm = React.createClass({
|
||||
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
|
||||
pieceOrEditions={this.props.pieceOrEditions}
|
||||
currentUser={this.props.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
handleSuccess={this.handleSuccess} />
|
||||
);
|
||||
} else if(this.props.requestAction === 'loan_request') {
|
||||
return (
|
||||
@ -110,7 +118,7 @@ let RequestActionForm = React.createClass({
|
||||
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
|
||||
pieceOrEditions={this.props.pieceOrEditions}
|
||||
currentUser={this.props.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
handleSuccess={this.handleSuccess} />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
|
43
js/components/global_action.js
Normal file
43
js/components/global_action.js
Normal 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;
|
@ -3,12 +3,6 @@
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import UserActions from '../actions/user_actions';
|
||||
import UserStore from '../stores/user_store';
|
||||
|
||||
import WhitelabelActions from '../actions/whitelabel_actions';
|
||||
import WhitelabelStore from '../stores/whitelabel_store';
|
||||
import EventActions from '../actions/event_actions';
|
||||
|
||||
import Nav from 'react-bootstrap/lib/Nav';
|
||||
import Navbar from 'react-bootstrap/lib/Navbar';
|
||||
@ -18,6 +12,15 @@ import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
|
||||
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
|
||||
|
||||
import UserActions from '../actions/user_actions';
|
||||
import UserStore from '../stores/user_store';
|
||||
|
||||
import WhitelabelActions from '../actions/whitelabel_actions';
|
||||
import WhitelabelStore from '../stores/whitelabel_store';
|
||||
import EventActions from '../actions/event_actions';
|
||||
|
||||
import HeaderNotifications from './header_notification';
|
||||
|
||||
import HeaderNotificationDebug from './header_notification_debug';
|
||||
|
||||
import NavRoutesLinks from './nav_routes_links';
|
||||
@ -41,7 +44,10 @@ let Header = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions(WhitelabelStore.getState(), UserStore.getState());
|
||||
return mergeOptions(
|
||||
WhitelabelStore.getState(),
|
||||
UserStore.getState()
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
@ -96,7 +102,9 @@ let Header = React.createClass({
|
||||
let navRoutesLinks;
|
||||
if (this.state.currentUser.username){
|
||||
account = (
|
||||
<DropdownButton eventKey="1" title={this.state.currentUser.username}>
|
||||
<DropdownButton
|
||||
eventKey="1"
|
||||
title={this.state.currentUser.username}>
|
||||
<MenuItemLink eventKey="2" to="settings">{getLangText('Account Settings')}</MenuItemLink>
|
||||
<MenuItem divider />
|
||||
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
|
||||
@ -126,6 +134,7 @@ let Header = React.createClass({
|
||||
{account}
|
||||
{signup}
|
||||
</Nav>
|
||||
<HeaderNotifications />
|
||||
{navRoutesLinks}
|
||||
</CollapsibleNav>
|
||||
</Navbar>
|
||||
|
144
js/components/header_notification.js
Normal file
144
js/components/header_notification.js
Normal file
@ -0,0 +1,144 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||
|
||||
import Nav from 'react-bootstrap/lib/Nav';
|
||||
|
||||
import PieceListStore from '../stores/piece_list_store';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
|
||||
|
||||
let HeaderNotifications = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions(
|
||||
PieceListStore.getState()
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PieceListStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
onSelected(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.
|
||||
*/
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this.state.requestActions && this.state.requestActions.length > 0) {
|
||||
return (
|
||||
<Nav navbar right>
|
||||
<DropdownButton
|
||||
eventKey="1"
|
||||
title={
|
||||
<span>
|
||||
<Glyphicon glyph='envelope' color="green"/>
|
||||
<span className="notification-amount">({this.state.requestActions.length})</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>);
|
||||
}
|
||||
)}
|
||||
</DropdownButton>
|
||||
</Nav>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
let NotificationListItem = React.createClass({
|
||||
propTypes: {
|
||||
pieceOrEdition: React.PropTypes.object
|
||||
},
|
||||
|
||||
getLinkData() {
|
||||
|
||||
if(this.props.pieceOrEdition && this.props.pieceOrEdition.parent) {
|
||||
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 HeaderNotifications;
|
@ -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,6 +149,10 @@ let PieceList = React.createClass({
|
||||
render() {
|
||||
let loadingElement = (<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />);
|
||||
let AccordionListItemType = this.props.accordionListItemType;
|
||||
|
||||
//<GlobalAction requestActions={this.state.requestActions} />
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PieceListToolbar
|
||||
|
@ -86,7 +86,6 @@ let PieceContainer = React.createClass({
|
||||
|
||||
loadPiece() {
|
||||
PieceActions.fetchOne(this.props.params.pieceId);
|
||||
this.setState(this.state);
|
||||
},
|
||||
|
||||
render() {
|
||||
|
@ -28,6 +28,7 @@ class PieceListStore {
|
||||
this.orderBy = 'artist_name';
|
||||
this.orderAsc = true;
|
||||
this.filterBy = {};
|
||||
this.requestActions = {};
|
||||
this.bindActions(PieceListActions);
|
||||
}
|
||||
|
||||
@ -71,10 +72,8 @@ class PieceListStore {
|
||||
this.pieceList = pieceList;
|
||||
}
|
||||
|
||||
onUpdatePieceListRequestActions(requestActions) {
|
||||
this.pieceList.forEach((piece) => {
|
||||
piece.requestAction = requestActions.indexOf(piece.id) > -1;
|
||||
});
|
||||
onUpdatePieceListRequestActions(res) {
|
||||
this.requestActions = res.actions;
|
||||
}
|
||||
|
||||
onUpdatePropertyForPiece({pieceId, key, value}) {
|
||||
|
@ -166,7 +166,7 @@ $ascribe-accordion-list-item-height: 8em;
|
||||
.request-action-badge {
|
||||
color: $ascribe-color-green;
|
||||
font-size: 1.2em;
|
||||
padding: .3em;
|
||||
padding: .8em;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
25
sass/ascribe_global_action.scss
Normal file
25
sass/ascribe_global_action.scss
Normal file
@ -0,0 +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 {
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
color: black;
|
||||
border: 1px solid #cccccc;
|
||||
background-color: white;
|
||||
margin-top: 1px;
|
||||
}
|
65
sass/ascribe_notification_list.scss
Normal file
65
sass/ascribe_notification_list.scss
Normal 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;
|
||||
}
|
@ -22,7 +22,9 @@ $BASE_URL: '<%= BASE_URL %>';
|
||||
@import 'ascribe_media_player';
|
||||
@import 'ascribe_uploader';
|
||||
@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';
|
||||
|
Loading…
Reference in New Issue
Block a user