diff --git a/js/actions/edition_list_actions.js b/js/actions/edition_list_actions.js index 2d9868c1..d13882cd 100644 --- a/js/actions/edition_list_actions.js +++ b/js/actions/edition_list_actions.js @@ -17,21 +17,21 @@ class EditionListActions { ); } - fetchEditionList(pieceId, page, pageSize, orderBy, orderAsc) { - if(!orderBy && typeof orderAsc === 'undefined') { + fetchEditionList(pieceId, page, pageSize, orderBy, orderAsc, filterBy) { + if((!orderBy && typeof orderAsc === 'undefined') || !orderAsc) { orderBy = 'edition_number'; orderAsc = true; } // Taken from: http://stackoverflow.com/a/519157/1263876 - if(typeof page === 'undefined' && typeof pageSize === 'undefined') { + if((typeof page === 'undefined' || !page) && (typeof pageSize === 'undefined' || !pageSize)) { page = 1; pageSize = 10; } return Q.Promise((resolve, reject) => { EditionListFetcher - .fetch(pieceId, page, pageSize, orderBy, orderAsc) + .fetch(pieceId, page, pageSize, orderBy, orderAsc, filterBy) .then((res) => { this.actions.updateEditionList({ pieceId, @@ -39,6 +39,7 @@ class EditionListActions { pageSize, orderBy, orderAsc, + filterBy, 'editionListOfPiece': res.editions, 'count': res.count }); diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index dfb9bd44..1ebe7f42 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -14,7 +14,7 @@ class PieceListActions { ); } - fetchPieceList(page, pageSize, search, orderBy, orderAsc) { + fetchPieceList(page, pageSize, search, orderBy, orderAsc, filterBy) { // To prevent flickering on a pagination request, // we overwrite the piecelist with an empty list before // pieceListCount === -1 defines the loading state @@ -24,6 +24,7 @@ class PieceListActions { search, orderBy, orderAsc, + filterBy, 'pieceList': [], 'pieceListCount': -1 }); @@ -32,7 +33,7 @@ class PieceListActions { return Q.Promise((resolve, reject) => { PieceListFetcher - .fetch(page, pageSize, search, orderBy, orderAsc) + .fetch(page, pageSize, search, orderBy, orderAsc, filterBy) .then((res) => { this.actions.updatePieceList({ page, @@ -40,6 +41,7 @@ class PieceListActions { search, orderBy, orderAsc, + filterBy, 'pieceList': res.pieces, 'pieceListCount': res.count }); diff --git a/js/actions/prize_list_actions.js b/js/actions/prize_list_actions.js new file mode 100644 index 00000000..fddf1a04 --- /dev/null +++ b/js/actions/prize_list_actions.js @@ -0,0 +1,34 @@ +'use strict'; + +import alt from '../alt'; +import Q from 'q'; + +import PrizeListFetcher from '../fetchers/prize_list_fetcher'; + +class PrizeListActions { + constructor() { + this.generateActions( + 'updatePrizeList' + ); + } + + fetchPrizeList() { + return Q.Promise((resolve, reject) => { + PrizeListFetcher + .fetch() + .then((res) => { + this.actions.updatePrizeList({ + prizeList: res.prizes, + prizeListCount: res.count + }); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } +} + +export default alt.createActions(PrizeListActions); \ No newline at end of file diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index 5c47d060..6c07a891 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -21,7 +21,7 @@ import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; import AclProxy from '../acl_proxy'; -import SubmitToPrizeButton from '../ascribe_buttons/submit_to_prize_button'; +import SubmitToPrizeButton from '../whitelabel/prize/components/ascribe_buttons/submit_to_prize_button'; import { getLangText } from '../../utils/lang_utils'; import { mergeOptions } from '../../utils/general_utils'; @@ -87,14 +87,16 @@ let AccordionListItem = React.createClass({ }, handleSubmitPrizeSuccess(response) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); let notification = new GlobalNotificationModel(response.notification, 'success', 10000); GlobalNotificationActions.appendGlobalNotification(notification); }, onPollingSuccess(pieceId) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); EditionListActions.toggleEditionList(pieceId); let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); @@ -178,21 +180,13 @@ let AccordionListItem = React.createClass({ onPollingSuccess={this.onPollingSuccess}/> + aclObject={this.props.content.acl} + aclName="acl_submit_to_prize"> - - - {this.getLicences()} diff --git a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js index 9fb72b06..e4ba0d2b 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js @@ -6,10 +6,14 @@ import classNames from 'classnames'; import EditionListActions from '../../actions/edition_list_actions'; import EditionListStore from '../../stores/edition_list_store'; +import PieceListActions from '../../actions/piece_list_actions'; +import PieceListStore from '../../stores/piece_list_store'; + import Button from 'react-bootstrap/lib/Button'; import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; +import { mergeOptions } from '../../utils/general_utils'; import { getLangText } from '../../utils/lang_utils'; let AccordionListItemEditionWidget = React.createClass({ @@ -21,15 +25,20 @@ let AccordionListItemEditionWidget = React.createClass({ }, getInitialState() { - return EditionListStore.getState(); + return mergeOptions( + EditionListStore.getState(), + PieceListStore.getState() + ); }, componentDidMount() { EditionListStore.listen(this.onChange); + PieceListStore.listen(this.onChange); }, componentWillUnmount() { EditionListStore.unlisten(this.onChange); + PieceListStore.unlisten(this.onChange); }, onChange(state) { @@ -47,7 +56,7 @@ let AccordionListItemEditionWidget = React.createClass({ EditionListActions.toggleEditionList(pieceId); } else { EditionListActions.toggleEditionList(pieceId); - EditionListActions.fetchEditionList(pieceId); + EditionListActions.fetchEditionList(pieceId, null, null, null, null, this.state.filterBy); } }, @@ -85,7 +94,7 @@ let AccordionListItemEditionWidget = React.createClass({ let numEditions = piece.num_editions; if(numEditions <= 0) { - if (piece.acl.acl_editions){ + if (piece.acl.acl_create_editions){ return ( { - EditionListActions.fetchEditionList(this.props.piece.id) + + // requests, will try to merge the filterBy parameter with other parameters (mergeOptions). + // Therefore it can't but null but instead has to be an empty object + EditionListActions.fetchEditionList(this.props.piece.id, null, null, null, null, {}) .then((res) => { clearInterval(this.state.pollingIntervalIndex); this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions); }) - .catch(() => { + .catch((err) => { /* Ignore and keep going */ }); }, 5000); @@ -64,7 +67,7 @@ let CreateEditionsButton = React.createClass({ render: function () { let piece = this.props.piece; - if (!piece.acl.acl_editions || piece.num_editions > 0){ + if (!piece.acl.acl_create_editions || piece.num_editions > 0){ return null; } diff --git a/js/components/ascribe_buttons/submit_to_prize_button.js b/js/components/ascribe_buttons/submit_to_prize_button.js deleted file mode 100644 index 3565a3ee..00000000 --- a/js/components/ascribe_buttons/submit_to_prize_button.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -import React from 'react'; -import classNames from 'classnames'; - -import ModalWrapper from '../ascribe_modal/modal_wrapper'; -import PieceSubmitToPrizeForm from '../ascribe_forms/form_submit_to_prize'; - -import { getLangText } from '../../utils/lang_utils'; - -let SubmitToPrizeButton = React.createClass({ - propTypes: { - className: React.PropTypes.string, - handleSuccess: React.PropTypes.func, - piece: React.PropTypes.object.isRequired - }, - - getSubmitButton() { - return ( - - ); - }, - - render() { - return ( - - - - - ); - } -}); - -export default SubmitToPrizeButton; \ No newline at end of file diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index b19f93b3..25e8a97c 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -86,7 +86,8 @@ let Edition = React.createClass({ }, handleDeleteSuccess(response) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); EditionListActions.refreshEditionList(this.props.edition.parent); EditionListActions.closeAllEditionLists(); diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index 7dff529f..3fabb055 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -79,12 +79,14 @@ let Piece = React.createClass({ handleEditionCreationSuccess() { PieceActions.updateProperty({key: 'num_editions', value: 0}); - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); this.toggleCreateEditionsDialog(); }, handleDeleteSuccess(response) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); // since we're deleting a piece, we just need to close // all editions dialogs and not reload them @@ -124,7 +126,8 @@ let Piece = React.createClass({ // btw.: It's not sufficient to just set num_editions to numEditions, since a single accordion // list item also uses the firstEdition property which we can only get from the server in that case. // Therefore we need to at least refetch the changed piece from the server or on our case simply all - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); GlobalNotificationActions.appendGlobalNotification(notification); diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 0f022a0d..89e51da2 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -15,6 +15,9 @@ import { mergeOptionsWithDuplicates } from '../../utils/general_utils'; let Form = React.createClass({ propTypes: { url: React.PropTypes.string, + buttons: React.PropTypes.object, + buttonSubmitText: React.PropTypes.string, + spinner: React.PropTypes.object, handleSuccess: React.PropTypes.func, getFormData: React.PropTypes.func, children: React.PropTypes.oneOfType([ @@ -24,6 +27,12 @@ let Form = React.createClass({ className: React.PropTypes.string }, + getDefaultProps() { + return { + buttonSubmitText: 'SAVE' + }; + }, + getInitialState() { return { edited: false, @@ -125,7 +134,7 @@ let Form = React.createClass({ buttons = (

- +

diff --git a/js/components/ascribe_forms/form_signup.js b/js/components/ascribe_forms/form_signup.js index 238cd74e..55aff4b8 100644 --- a/js/components/ascribe_forms/form_signup.js +++ b/js/components/ascribe_forms/form_signup.js @@ -27,7 +27,7 @@ let SignupForm = React.createClass({ children: React.PropTypes.element }, - mixins: [Router.Navigation], + mixins: [Router.Navigation, Router.State], getDefaultProps() { return { @@ -35,7 +35,6 @@ let SignupForm = React.createClass({ submitMessage: getLangText('Sign up') }; }, - getInitialState() { return UserStore.getState(); }, @@ -57,22 +56,32 @@ let SignupForm = React.createClass({ } }, - handleSuccess(response){ - let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000); - GlobalNotificationActions.appendGlobalNotification(notification); - this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.'); + getFormData() { + return this.getQuery(); + }, + handleSuccess(response){ + if (response.user) { + let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000); + GlobalNotificationActions.appendGlobalNotification(notification); + this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.'); + } + else if (response.redirect) { + this.transitionTo('pieces'); + } }, render() { let tooltipPassword = getLangText('Your password must be at least 10 characters') + '.\n ' + getLangText('This password is securing your digital property like a bank account') + '.\n ' + getLangText('Store it in a safe place') + '!'; + let email = this.getQuery().email ? this.getQuery().email : null; return (
@@ -93,6 +102,7 @@ let SignupForm = React.createClass({ type="email" placeholder={getLangText('(e.g. andy@warhol.co.uk)')} autoComplete="on" + defaultValue={email} required/> +
+ {this.props.title} +
+
+ + {this.props.content} + + + {this.props.buttons} + +
+ + ); + } +}); + +export default ActionPanel; \ No newline at end of file diff --git a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js index 36a4c53d..3642a667 100644 --- a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js @@ -76,7 +76,8 @@ let PieceListBulkModal = React.createClass({ }, handleSuccess() { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); this.fetchSelectedPieceEditionList() .forEach((pieceId) => { diff --git a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js index 17e72072..e169adaa 100644 --- a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js @@ -1,7 +1,7 @@ 'use strict'; import React from 'react'; -import { getLangText } from '../../utils/lang_utils.js' +import { getLangText } from '../../utils/lang_utils.js'; let PieceListBulkModalSelectedEditionsWidget = React.createClass({ propTypes: { diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index 3f9d04ab..22034f0d 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -2,6 +2,8 @@ import React from 'react'; +import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget'; + import Input from 'react-bootstrap/lib/Input'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import { getLangText } from '../../utils/lang_utils'; @@ -11,6 +13,8 @@ let PieceListToolbar = React.createClass({ propTypes: { className: React.PropTypes.string, searchFor: React.PropTypes.func, + filterBy: React.PropTypes.object, + applyFilterBy: React.PropTypes.func, children: React.PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.element @@ -41,6 +45,15 @@ let PieceListToolbar = React.createClass({ onChange={this.searchFor} addonAfter={searchIcon} /> + + + diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js index d624dc68..13bfd9a0 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js @@ -2,30 +2,114 @@ import React from 'react'; -import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import DropdownButton from 'react-bootstrap/lib/DropdownButton'; import MenuItem from 'react-bootstrap/lib/MenuItem'; -import { getLangText } from '../../utils/lang_utils.js' + +import { getLangText } from '../../utils/lang_utils.js'; let PieceListToolbarFilterWidgetFilter = React.createClass({ + propTypes: { + // An array of either strings (which represent acl enums) or objects of the form + // + // { + // key: , + // label: + // } + // + filterParams: React.PropTypes.arrayOf(React.PropTypes.any).isRequired, + filterBy: React.PropTypes.object, + applyFilterBy: React.PropTypes.func + }, + + generateFilterByStatement(param) { + let filterBy = this.props.filterBy; + + if(filterBy) { + // we need hasOwnProperty since the values are all booleans + if(filterBy.hasOwnProperty(param)) { + filterBy[param] = !filterBy[param]; + + // if the parameter is false, then we want to remove it again + // from the list of queryParameters as this component is only about + // which actions *CAN* be done and not what *CANNOT* + if(!filterBy[param]) { + delete filterBy[param]; + } + + } else { + filterBy[param] = true; + } + } + + return filterBy; + }, + + /** + * We need overloading here to find the correct parameter of the label + * the user is clicking on. + */ + filterBy(param) { + return () => { + let filterBy = this.generateFilterByStatement(param); + this.props.applyFilterBy(filterBy); + }; + }, + + isFilterActive() { + let trueValuesOnly = Object.keys(this.props.filterBy).filter((acl) => acl); + + // We're hiding the star in that complicated matter so that, + // the surrounding button is not resized up on appearance + if(trueValuesOnly.length > 0) { + return { visibility: 'visible'}; + } else { + return { visibility: 'hidden' }; + } + }, + render() { - let filterIcon = ; + let filterIcon = ( + + + * + + ); return ( - +
  • - {getLangText('Show Pieces that')}: + {getLangText('Show works that')}:
  • - -
    - {getLangText('I can transfer')} -
    -
    - -
    - {getLangText('I can consign')} -
    -
    + {this.props.filterParams.map((param, i) => { + let label; + + if(typeof param !== 'string') { + label = param.label; + param = param.key; + } else { + param = param; + label = param.split('_')[1]; + } + + return ( + +
    + + {getLangText('I can') + ' ' + getLangText(label)} + + +
    +
    + ); + })}
    ); } diff --git a/js/components/ascribe_prizes_dashboard/prizes_dashboard.js b/js/components/ascribe_prizes_dashboard/prizes_dashboard.js new file mode 100644 index 00000000..b4c695f4 --- /dev/null +++ b/js/components/ascribe_prizes_dashboard/prizes_dashboard.js @@ -0,0 +1,82 @@ +'use strict'; + +import React from 'react'; + +import PrizeListActions from '../../actions/prize_list_actions'; +import PrizeListStore from '../../stores/prize_list_store'; + +import Table from '../ascribe_table/table'; +import TableItem from '../ascribe_table/table_item'; +import TableItemText from '../ascribe_table/table_item_text'; + +import { ColumnModel} from '../ascribe_table/models/table_models'; +import { getLangText } from '../../utils/lang_utils'; + +let PrizesDashboard = React.createClass({ + + getInitialState() { + return PrizeListStore.getState(); + }, + + componentDidMount() { + PrizeListStore.listen(this.onChange); + PrizeListActions.fetchPrizeList(); + }, + + componentWillUnmount() { + PrizeListStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + getColumnList() { + return [ + new ColumnModel( + (item) => { + return { + 'content': item.name + }; }, + 'name', + getLangText('Name'), + TableItemText, + 6, + false, + null + ), + new ColumnModel( + (item) => { + return { + 'content': item.domain + }; }, + 'domain', + getLangText('Domain'), + TableItemText, + 1, + false, + null + ) + ]; + }, + + render() { + return ( + + {this.state.prizeList.map((item, i) => { + return ( + + ); + })} +
    + ); + } +}); + +export default PrizesDashboard; \ No newline at end of file diff --git a/js/components/ascribe_table/table_header.js b/js/components/ascribe_table/table_header.js index 8f138fb4..f807627b 100644 --- a/js/components/ascribe_table/table_header.js +++ b/js/components/ascribe_table/table_header.js @@ -2,7 +2,6 @@ import React from 'react'; -import TableColumnMixin from '../../mixins/table_column_mixin'; import TableHeaderItem from './table_header_item'; import { ColumnModel } from './models/table_models'; @@ -17,15 +16,12 @@ let TableHeader = React.createClass({ orderBy: React.PropTypes.string }, - mixins: [TableColumnMixin], - render() { return ( {this.props.columnList.map((column, i) => { - let columnClasses = this.calcColumnClasses(this.props.columnList, i, 12); let columnName = column.columnName; let canBeOrdered = column.canBeOrdered; @@ -33,7 +29,6 @@ let TableHeader = React.createClass({ { - - let columnList = [ - new ColumnModel('edition_number', 'Number', TableItemText, 2, false), - new ColumnModel('user_registered', 'User', TableItemText, 4, true), - new ColumnModel('acl', 'Actions', TableItemAcl, 4, true) - ]; - - if(this.state.open && this.state.editionList[this.props.columnContent.id] && this.state.editionList[this.props.columnContent.id].length) { - return ( -
    -
    - - {this.state.editionList[this.props.columnContent.id].map((edition, i) => { - return ( - - ); - })} -
    -
    -
    - ); - } - }; - - return ( -
    -
    - -
    - -
    -
    - {renderEditionListTable()} -
    - ); - } -}); - -export default TableItemSubtable; diff --git a/js/components/ascribe_table/table_item_subtable_button.js b/js/components/ascribe_table/table_item_subtable_button.js deleted file mode 100644 index 75aeba7f..00000000 --- a/js/components/ascribe_table/table_item_subtable_button.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import React from 'react'; - -let TableItemSubtableButton = React.createClass({ - - propTypes: { - content: React.PropTypes.string.isRequired, - onClick: React.PropTypes.func.isRequired - }, - - render() { - return ( - - - - ); - } -}); - -export default TableItemSubtableButton; \ No newline at end of file diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 711f53ea..1792b17a 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -34,7 +34,8 @@ let PieceList = React.createClass({ let page = this.getQuery().page || 1; PieceListStore.listen(this.onChange); if (this.state.pieceList.length === 0){ - PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc) + PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy) .then(PieceListActions.fetchPieceRequestActions()); } }, @@ -59,9 +60,9 @@ let PieceList = React.createClass({ // the site should go to the top document.body.scrollTop = document.documentElement.scrollTop = 0; - return () => PieceListActions.fetchPieceList(page, this.state.pageSize, - this.state.search, this.state.orderBy, - this.state.orderAsc); + return () => PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, + this.state.filterBy); }, getPagination() { @@ -79,13 +80,22 @@ let PieceList = React.createClass({ }, searchFor(searchTerm) { - PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy, this.state.orderAsc); + PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy, + this.state.orderAsc, this.state.filterBy); this.transitionTo(this.getPathname(), {page: 1}); }, + applyFilterBy(filterBy) { + PieceListActions.fetchPieceList(1, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, filterBy); + // we have to redirect the user always to page one as it could be that there is no page two + // for filtered pieces + this.transitionTo(this.getPathname(), {page: 1}); + }, + accordionChangeOrder(orderBy, orderAsc) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, - this.state.search, orderBy, orderAsc); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + orderBy, orderAsc, this.state.filterBy); }, render() { @@ -95,7 +105,9 @@ let PieceList = React.createClass({
    + searchFor={this.searchFor} + filterBy={this.state.filterBy} + applyFilterBy={this.applyFilterBy}> {this.props.customSubmitButton} diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 20826b7d..f46ab99c 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -101,7 +101,8 @@ let RegisterPiece = React.createClass( { this.state.pageSize, this.state.searchTerm, this.state.orderBy, - this.state.orderAsc + this.state.orderAsc, + this.state.filterBy ); this.transitionTo('piece', {pieceId: response.piece.id}); @@ -139,7 +140,7 @@ let RegisterPiece = React.createClass( { }, getSpecifyEditions() { - if(this.state.whitelabel && this.state.whitelabel.acl_editions || Object.keys(this.state.whitelabel).length === 0) { + if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) { return ( + {this.props.children} @@ -121,6 +128,7 @@ let AccountSettings = React.createClass({ +
    {/* */} -
    ); } diff --git a/js/components/whitelabel/prize/actions/prize_actions.js b/js/components/whitelabel/prize/actions/prize_actions.js new file mode 100644 index 00000000..5646e2d6 --- /dev/null +++ b/js/components/whitelabel/prize/actions/prize_actions.js @@ -0,0 +1,33 @@ +'use strict'; + +import alt from '../../../../alt'; +import Q from 'q'; + +import PrizeFetcher from '../fetchers/prize_fetcher'; + +class PrizeActions { + constructor() { + this.generateActions( + 'updatePrize' + ); + } + + fetchPrize() { + return Q.Promise((resolve, reject) => { + PrizeFetcher + .fetch() + .then((res) => { + this.actions.updatePrize({ + prize: res.prize + }); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } +} + +export default alt.createActions(PrizeActions); \ No newline at end of file diff --git a/js/components/whitelabel/prize/actions/prize_jury_actions.js b/js/components/whitelabel/prize/actions/prize_jury_actions.js new file mode 100644 index 00000000..e2fe1a96 --- /dev/null +++ b/js/components/whitelabel/prize/actions/prize_jury_actions.js @@ -0,0 +1,31 @@ +'use strict'; + +import alt from '../../../../alt'; +import Q from 'q'; + +import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher'; + +class PrizeJuryActions { + constructor() { + this.generateActions( + 'updatePrizeJury' + ); + } + + fetchJury() { + return Q.Promise((resolve, reject) => { + PrizeJuryFetcher + .fetch() + .then((res) => { + this.actions.updatePrizeJury(res.members); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } +} + +export default alt.createActions(PrizeJuryActions); \ No newline at end of file diff --git a/js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js b/js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js new file mode 100644 index 00000000..91594d44 --- /dev/null +++ b/js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js @@ -0,0 +1,54 @@ +'use strict'; + +import React from 'react'; +import classNames from 'classnames'; + +import ModalWrapper from '../../../../ascribe_modal/modal_wrapper'; +import PieceSubmitToPrizeForm from '../../../../ascribe_forms/form_submit_to_prize'; + +import { getLangText } from '../../../../../utils/lang_utils'; + +let SubmitToPrizeButton = React.createClass({ + propTypes: { + className: React.PropTypes.string, + handleSuccess: React.PropTypes.func, + piece: React.PropTypes.object.isRequired + }, + + getSubmitButton() { + if (this.props.piece.prize) { + return ( + + ); + } + else { + return ( + + ); + } + }, + + render() { + return ( + + + + + ); + } +}); + +export default SubmitToPrizeButton; \ No newline at end of file diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/settings_container.js new file mode 100644 index 00000000..fecc1fd0 --- /dev/null +++ b/js/components/whitelabel/prize/components/settings_container.js @@ -0,0 +1,250 @@ +'use strict'; + +import React from 'react'; + +import UserStore from '../../../../stores/user_store'; +import UserActions from '../../../../actions/user_actions'; +import PrizeActions from '../actions/prize_actions'; +import PrizeStore from '../stores/prize_store'; +import PrizeJuryActions from '../actions/prize_jury_actions'; +import PrizeJuryStore from '../stores/prize_jury_store'; + +import SettingsContainer from '../../../settings_container'; +import CollapsibleParagraph from '../../../ascribe_collapsible/collapsible_paragraph'; + +import Form from '../../../ascribe_forms/form'; +import Property from '../../../ascribe_forms/property'; +import FormPropertyHeader from '../../../ascribe_forms/form_property_header'; + +import ActionPanel from '../../../ascribe_panel/action_panel'; + +import Table from '../../../ascribe_table/table'; +import TableItem from '../../../ascribe_table/table_item'; +import TableItemText from '../../../ascribe_table/table_item_text'; + +import GlobalNotificationModel from '../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../actions/global_notification_actions'; + +import AppConstants from '../../../../constants/application_constants'; +import apiUrls from '../../../../constants/api_urls'; + +import { ColumnModel} from '../../../ascribe_table/models/table_models'; +import { getLangText } from '../../../../utils/lang_utils'; + + +let Settings = React.createClass({ + getInitialState() { + return UserStore.getState(); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + let prizeSettings = null; + if (this.state.currentUser.is_admin){ + prizeSettings = ; + } + return ( + + {prizeSettings} + + ); + } +}); + +let PrizeSettings = React.createClass({ + + getInitialState() { + return PrizeStore.getState(); + }, + + componentDidMount() { + PrizeStore.listen(this.onChange); + PrizeActions.fetchPrize(); + }, + + componentWillUnmount() { + PrizeStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + render() { + return ( + +
    + +
    {this.state.prize.name}
    +
    + +
    {this.state.prize.active_round}/{this.state.prize.rounds}
    +
    + +
    {this.state.prize.num_submissions}
    +
    +
    +
    + +
    + ); + } +}); + +let PrizeJurySettings = React.createClass({ + propTypes: { + prize: React.PropTypes.object + }, + + getInitialState() { + return PrizeJuryStore.getState(); + }, + + componentDidMount() { + PrizeJuryStore.listen(this.onChange); + PrizeJuryActions.fetchJury(); + }, + + componentWillUnmount() { + PrizeJuryStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleCreateSuccess(response) { + PrizeJuryActions.fetchJury(); + let notification = new GlobalNotificationModel(response.notification, 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + this.refs.form.refs.email.refs.input.getDOMNode().value = null; + }, + + render() { + let content = ( +
    + +
    ); + + if (this.state.members.length > -1) { + content = this.state.members.map(function(member, i) { + return ( + + {getLangText('RESEND INVITATION')} + } + />); + }, this); + content = ( +
    + {content} +
    ); + } + return ( +
    +
    + +

    Jury Members

    +
    + + + +
    +
    + {content} +
    + ); + } +}); + + +let PrizesDashboard = React.createClass({ + + getColumnList() { + return [ + new ColumnModel( + (item) => { + return { + 'content': item.name + }; }, + 'name', + getLangText('Name'), + TableItemText, + 6, + false, + null + ), + new ColumnModel( + (item) => { + return { + 'content': item.domain + }; }, + 'domain', + getLangText('Domain'), + TableItemText, + 1, + false, + null + ) + ]; + }, + + render() { + return ( + + {this.state.prizeList.map((item, i) => { + return ( + + ); + })} +
    + ); + } +}); + +export default Settings; \ No newline at end of file diff --git a/js/components/whitelabel/prize/constants/api_urls.js b/js/components/whitelabel/prize/constants/api_urls.js index e868d403..f9030794 100644 --- a/js/components/whitelabel/prize/constants/api_urls.js +++ b/js/components/whitelabel/prize/constants/api_urls.js @@ -1,15 +1,17 @@ 'use strict'; -import AppConstants from '../../../../constants/application_constants'; +import AppPrizeConstants from './application_prize_constants'; function getApiUrls(subdomain) { return { - 'pieces_list': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/', - 'users_login': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/login/', - 'users_signup': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/', - 'user': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/', - 'piece_submit_to_prize': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/submit/', - 'piece': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/' + 'pieces_list': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/', + 'users_login': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/login/', + 'users_signup': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/', + 'user': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/', + 'piece_submit_to_prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/submit/', + 'piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/', + 'prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/', + 'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/' }; } diff --git a/js/components/whitelabel/prize/constants/application_prize_constants.js b/js/components/whitelabel/prize/constants/application_prize_constants.js new file mode 100644 index 00000000..6026193b --- /dev/null +++ b/js/components/whitelabel/prize/constants/application_prize_constants.js @@ -0,0 +1,9 @@ +'use strict'; + +import AppConstants from '../../../../constants/application_constants'; + +let constants = { + prizeApiEndpoint: AppConstants.apiEndpoint + 'prizes/' +}; + +export default constants; \ No newline at end of file diff --git a/js/components/whitelabel/prize/fetchers/prize_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_fetcher.js new file mode 100644 index 00000000..0bf9fc55 --- /dev/null +++ b/js/components/whitelabel/prize/fetchers/prize_fetcher.js @@ -0,0 +1,12 @@ +'use strict'; + +import requests from '../../../../utils/requests'; + + +let PrizeFetcher = { + fetch() { + return requests.get('prize'); + } +}; + +export default PrizeFetcher; diff --git a/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js new file mode 100644 index 00000000..be00e930 --- /dev/null +++ b/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js @@ -0,0 +1,12 @@ +'use strict'; + +import requests from '../../../../utils/requests'; + + +let PrizeJuryFetcher = { + fetch() { + return requests.get('jury'); + } +}; + +export default PrizeJuryFetcher; diff --git a/js/components/whitelabel/prize/routes.js b/js/components/whitelabel/prize/routes.js index ac490c4e..16e57e50 100644 --- a/js/components/whitelabel/prize/routes.js +++ b/js/components/whitelabel/prize/routes.js @@ -12,7 +12,7 @@ import PrizeRegisterPiece from './components/register_piece'; import PrizePieceList from './components/piece_list'; import PrizePieceContainer from './components/ascribe_detail/piece_container'; import EditionContainer from '../../ascribe_detail/edition_container'; -import SettingsContainer from '../../../components/settings_container'; +import SettingsContainer from './components/settings_container'; import App from './app'; import AppConstants from '../../../constants/application_constants'; @@ -21,7 +21,7 @@ let Route = Router.Route; let baseUrl = AppConstants.baseUrl; -function getRoutes(commonRoutes) { +function getRoutes() { return ( diff --git a/js/components/whitelabel/prize/stores/prize_jury_store.js b/js/components/whitelabel/prize/stores/prize_jury_store.js new file mode 100644 index 00000000..59a54329 --- /dev/null +++ b/js/components/whitelabel/prize/stores/prize_jury_store.js @@ -0,0 +1,18 @@ +'use strict'; + +import alt from '../../../../alt'; + +import PrizeJuryActions from '../actions/prize_jury_actions'; + +class PrizeJuryStore { + constructor() { + this.members = []; + this.bindActions(PrizeJuryActions); + } + + onUpdatePrizeJury( members ) { + this.members = members; + } +} + +export default alt.createStore(PrizeJuryStore, 'PrizeJuryStore'); \ No newline at end of file diff --git a/js/components/whitelabel/prize/stores/prize_store.js b/js/components/whitelabel/prize/stores/prize_store.js new file mode 100644 index 00000000..f311e1fe --- /dev/null +++ b/js/components/whitelabel/prize/stores/prize_store.js @@ -0,0 +1,18 @@ +'use strict'; + +import alt from '../../../../alt'; + +import PrizeActions from '../actions/prize_actions'; + +class PrizeStore { + constructor() { + this.prize = []; + this.bindActions(PrizeActions); + } + + onUpdatePrize({ prize }) { + this.prize = prize; + } +} + +export default alt.createStore(PrizeStore, 'PrizeStore'); \ No newline at end of file diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index 5efe8ca2..b4f7d926 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -52,7 +52,8 @@ let apiUrls = { 'users_profile': AppConstants.apiEndpoint + 'users/profile/', 'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/', 'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/', - 'delete_s3_file': AppConstants.serverUrl + 's3/delete/' + 'delete_s3_file': AppConstants.serverUrl + 's3/delete/', + 'prize_list': AppConstants.apiEndpoint + 'prize/' }; diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 85699a87..04add909 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -10,9 +10,9 @@ let constants = { 'apiEndpoint': window.API_ENDPOINT, 'serverUrl': window.SERVER_URL, 'baseUrl': window.BASE_URL, - 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_editions', + 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions', 'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', - 'acl_withdraw_transfer'], + 'acl_withdraw_transfer', 'acl_submit_to_prize'], 'version': 0.1, 'csrftoken': 'csrftoken2', diff --git a/js/fetchers/edition_list_fetcher.js b/js/fetchers/edition_list_fetcher.js index 94a2116d..b416c595 100644 --- a/js/fetchers/edition_list_fetcher.js +++ b/js/fetchers/edition_list_fetcher.js @@ -3,20 +3,26 @@ import requests from '../utils/requests'; import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; - +import { mergeOptions } from '../utils/general_utils'; let EditionListFetcher = { /** * Fetches a list of editions from the API. */ - fetch(pieceId, page, pageSize, orderBy, orderAsc) { + fetch(pieceId, page, pageSize, orderBy, orderAsc, filterBy) { let ordering = generateOrderingQueryParams(orderBy, orderAsc); - return requests.get('editions_list', { - 'piece_id': pieceId, - page, - pageSize, - ordering - }); + + let queryParams = mergeOptions( + { + page, + pageSize, + ordering, + piece_id: pieceId + }, + filterBy + ); + + return requests.get('editions_list', queryParams); } }; diff --git a/js/fetchers/piece_list_fetcher.js b/js/fetchers/piece_list_fetcher.js index bdf0ea5e..8e58402a 100644 --- a/js/fetchers/piece_list_fetcher.js +++ b/js/fetchers/piece_list_fetcher.js @@ -1,17 +1,31 @@ 'use strict'; -import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import requests from '../utils/requests'; +import { mergeOptions } from '../utils/general_utils'; +import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; let PieceListFetcher = { /** * Fetches a list of pieces from the API. * Can be called with all supplied queryparams the API. */ - fetch(page, pageSize, search, orderBy, orderAsc) { + fetch(page, pageSize, search, orderBy, orderAsc, filterBy) { let ordering = generateOrderingQueryParams(orderBy, orderAsc); - return requests.get('pieces_list', { page, pageSize, search, ordering }); + + // filterBy is an object of acl key-value pairs. + // The values are booleans + let queryParams = mergeOptions( + { + page, + pageSize, + search, + ordering + }, + filterBy + ); + + return requests.get('pieces_list', queryParams); }, fetchRequestActions() { diff --git a/js/fetchers/prize_list_fetcher.js b/js/fetchers/prize_list_fetcher.js new file mode 100644 index 00000000..150f07a1 --- /dev/null +++ b/js/fetchers/prize_list_fetcher.js @@ -0,0 +1,12 @@ +'use strict'; + +import requests from '../utils/requests'; + + +let PrizeListFetcher = { + fetch() { + return requests.get('prize_list'); + } +}; + +export default PrizeListFetcher; diff --git a/js/mixins/table_column_mixin.js b/js/mixins/table_column_mixin.js deleted file mode 100644 index b8813433..00000000 --- a/js/mixins/table_column_mixin.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -import { sumNumList } from '../utils/general_utils'; - -let TableColumnMixin = { - /** - * Generates the bootstrap grid column declarations automatically using - * the columnMap. - */ - calcColumnClasses(list, i, numOfColumns) { - let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-']; - - let listOfRowValues = list.map((column) => column.rowWidth ); - let numOfUsedColumns = sumNumList(listOfRowValues); - - if(numOfUsedColumns > numOfColumns) { - throw new Error('This table has only ' + numOfColumns + ' columns to assign. You defined ' + numOfUsedColumns + '. Change this in the columnMap you\'re passing to the table.'); - } else { - return bootstrapClasses.join( listOfRowValues[i] + ' ') + listOfRowValues[i]; - } - } -}; - -export default TableColumnMixin; diff --git a/js/routes.js b/js/routes.js index 90248ef2..f7ea2ea6 100644 --- a/js/routes.js +++ b/js/routes.js @@ -20,6 +20,8 @@ import CoaVerifyContainer from './components/coa_verify_container'; import RegisterPiece from './components/register_piece'; +import PrizesDashboard from './components/ascribe_prizes_dashboard/prizes_dashboard'; + let Route = Router.Route; @@ -35,6 +37,7 @@ const COMMON_ROUTES = ( + ); diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js index 12835603..4e3a2fe8 100644 --- a/js/stores/edition_list_store.js +++ b/js/stores/edition_list_store.js @@ -12,7 +12,7 @@ class EditionListStore { this.bindActions(EditionsListActions); } - onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count}) { + onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count, filterBy}) { /* Basically there are two modes an edition list can be updated. @@ -54,6 +54,7 @@ class EditionListStore { this.editionList[pieceId].orderBy = orderBy; this.editionList[pieceId].orderAsc = orderAsc; this.editionList[pieceId].count = count; + this.editionList[pieceId].filterBy = filterBy; } /** @@ -80,7 +81,10 @@ class EditionListStore { this.editionList[pieceId].length = 0; // refetch editions with adjusted page size - EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength, this.editionList[pieceId].orderBy, this.editionList[pieceId].orderAsc) + EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength, + this.editionList[pieceId].orderBy, + this.editionList[pieceId].orderAsc, + this.editionList[pieceId].filterBy) .then(() => { // reset back to the normal pageSize and page this.editionList[pieceId].page = prevEditionListPage; diff --git a/js/stores/piece_list_store.js b/js/stores/piece_list_store.js index a8b73e44..c1622d99 100644 --- a/js/stores/piece_list_store.js +++ b/js/stores/piece_list_store.js @@ -26,16 +26,18 @@ class PieceListStore { this.search = ''; this.orderBy = 'artist_name'; this.orderAsc = true; + this.filterBy = {}; this.bindActions(PieceListActions); } - onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount }) { + onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount, filterBy }) { this.page = page; this.pageSize = pageSize; this.search = search; this.orderAsc = orderAsc; this.orderBy = orderBy; this.pieceListCount = pieceListCount; + this.filterBy = filterBy; /** * Pagination - Known Issue: diff --git a/js/stores/prize_list_store.js b/js/stores/prize_list_store.js new file mode 100644 index 00000000..99ee5d14 --- /dev/null +++ b/js/stores/prize_list_store.js @@ -0,0 +1,20 @@ +'use strict'; + +import alt from '../alt'; + +import PrizeListActions from '../actions/prize_list_actions'; + +class PrizeListStore { + constructor() { + this.prizeList = []; + this.prizeListCount = -1; + this.bindActions(PrizeListActions); + } + + onUpdatePrizeList({ prizeList, prizeListCount }) { + this.prizeList = prizeList; + this.prizeListCount = prizeListCount; + } +} + +export default alt.createStore(PrizeListStore, 'PrizeListStore'); \ No newline at end of file diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss new file mode 100644 index 00000000..43f8f15f --- /dev/null +++ b/sass/ascribe_panel.scss @@ -0,0 +1,13 @@ +.ascribe-panel-wrapper { + border: 1px solid #F5F5F5; +} + +.ascribe-panel-title { + padding: 1em 0 1em 1.5em; +} + +.ascribe-panel-content { + padding: .75em 0 .75em 1em; + font-size: 1em; + color: #616161; +} \ No newline at end of file diff --git a/sass/ascribe_piece_list_toolbar.scss b/sass/ascribe_piece_list_toolbar.scss index 2fa612aa..902d5be9 100644 --- a/sass/ascribe_piece_list_toolbar.scss +++ b/sass/ascribe_piece_list_toolbar.scss @@ -5,5 +5,41 @@ } .search-bar { - max-width: 160px; + max-width: 200px; + input { + height: 33px; + } +} + +.ascribe-piece-list-toolbar-filter-widget { + margin-right: 1em; + + .filter-widget-item { + + > a { + padding-left: 0; + padding-right: 0; + } + } + + .checkbox-line { + position: relative; + height: 25px; + + span { + position: absolute; + left: 9px; + top: 3px; + cursor: pointer; + + margin-right: 10px; + } + + input { + position: absolute; + top: 2px; + right: 9px; + margin-left: 10px; + } + } } \ No newline at end of file diff --git a/sass/ascribe_table.scss b/sass/ascribe_table.scss index ebb40672..225c27ca 100644 --- a/sass/ascribe_table.scss +++ b/sass/ascribe_table.scss @@ -22,10 +22,11 @@ } .ascribe-table-item-column { - display: table; font-family: 'Source Sans Pro'; font-size: .8em; height:3em; + vertical-align: middle; + display: table-cell; } .ascribe-table-item-column > * { @@ -37,7 +38,8 @@ } .ascribe-table-item-column > span > input { - margin-top:18px; + margin-top:10px; + margin-left:2px; } .ascribe-table-item-selected { diff --git a/sass/main.scss b/sass/main.scss index d8e5e7ff..5f00d2c9 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -27,6 +27,7 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'ascribe_settings'; @import 'ascribe_slides_container'; @import 'ascribe_form'; +@import 'ascribe_panel'; @import 'whitelabel/index';