1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-23 01:36:28 +02:00

Merge pull request #199 from ascribe/nuke-prizes

Remove prize whitelabels
This commit is contained in:
Brett Sun 2016-06-02 17:10:53 +02:00
commit 669c2610cf
57 changed files with 17 additions and 3472 deletions

View File

@ -29,9 +29,7 @@ Additionally, to work on the white labeling functionality, you need to edit your
127.0.0.1 cc.localhost.com
127.0.0.1 cyland.localhost.com
127.0.0.1 ikonotv.localhost.com
127.0.0.1 sluice.localhost.com
127.0.0.1 lumenus.localhost.com
127.0.0.1 portfolioreview.localhost.com
127.0.0.1 23vivi.localhost.com
127.0.0.1 polline.localhost.com
127.0.0.1 artcity.localhost.com

View File

@ -13,8 +13,6 @@
<link rel="stylesheet" href="<%= BASE_URL %>static/css/main.css">
<% DEBUG && print('<link rel="stylesheet" href="' + BASE_URL + 'static/css/maps/main.css.map">') %>
<!-- This is for sluice -->
<link href='//fonts.googleapis.com/css?family=Nunito:400,700,300' rel='stylesheet' type='text/css'>
<script>
window.BASE_URL = '<%= BASE_URL %>';
window.SERVER_URL = '<%= SERVER_URL %>';

View File

@ -1,89 +0,0 @@
'use strict';
import React from 'react';
import Form from './form';
import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable';
import InputCheckbox from './input_checkbox';
import Alert from 'react-bootstrap/lib/Alert';
import AscribeSpinner from '../ascribe_spinner';
import ApiUrls from '../../constants/api_urls';
import { getLangText } from '../../utils/lang_utils.js';
import requests from '../../utils/requests';
let PieceSubmitToPrizeForm = React.createClass({
propTypes: {
piece: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
render() {
return (
<Form
ref='form'
url={requests.prepareUrl(ApiUrls.piece_submit_to_prize, {piece_id: this.props.piece.id})}
handleSuccess={this.props.handleSuccess}
buttons={
<div className="modal-footer">
<p className="pull-right">
<button
className="btn btn-default btn-sm ascribe-margin-1px"
type="submit">
{getLangText('SUBMIT TO PRIZE')}
</button>
</p>
</div>}
spinner={
<div className="modal-footer">
<p className="pull-right">
<AscribeSpinner color='dark-blue' size='md'/>
</p>
</div>}>
<Property
name='artist_statement'
label={getLangText('Artist statement')}
editable={true}
overrideForm={true}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter your statement')}
required />
</Property>
<Property
name='work_description'
label={getLangText('Work description')}
editable={true}
overrideForm={true}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter the description for your work')}
required />
</Property>
<Property
name="terms"
className="ascribe-property-collapsible-toggle">
<InputCheckbox>
<span>
{' ' + getLangText('I agree to the Terms of Service the art price') + ' '}
(<a href="https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/terms.pdf" target="_blank" style={{fontSize: '0.9em', color: 'rgba(0,0,0,0.7)'}}>
{getLangText('read')}
</a>)
</span>
</InputCheckbox>
</Property>
<Alert bsStyle='warning'>
<p>{getLangText('Are you sure you want to submit to the prize?')}</p>
<p>{getLangText('This is an irrevocable action%s', '.')}</p>
</Alert>
</Form>
);
}
});
export default PieceSubmitToPrizeForm;

View File

@ -1,28 +0,0 @@
'use strict';
import AppPrizeConstants from './prize_application_constants';
function getPrizeApiUrls(subdomain) {
return {
'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/',
'pieces_list': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/',
'piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/',
'prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/',
'jurys': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/',
'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/',
'jury_activate': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/activate/',
'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/',
'ratings': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/',
'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/',
'rating_average': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/average/',
'select_piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/select/',
'notes': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/',
'note': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/${piece_id}/'
};
}
export default getPrizeApiUrls;

View File

@ -1,9 +0,0 @@
'use strict';
import AppConstants from '../../../../constants/application_constants';
let prizeConstants = {
prizeApiEndpoint: AppConstants.apiEndpoint + 'prizes/'
};
export default prizeConstants;

View File

@ -1,417 +0,0 @@
'use strict';
import React from 'react';
import { History } from 'react-router';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import Form from '../../../../../ascribe_forms/form';
import Property from '../../../../../ascribe_forms/property';
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
import InputFineuploader from '../../../../../ascribe_forms/input_fineuploader';
import UploadButton from '../../../../../ascribe_uploader/ascribe_upload_button/upload_button';
import AscribeSpinner from '../../../../../ascribe_spinner';
import ApiUrls from '../../../../../../constants/api_urls';
import AppConstants from '../../../../../../constants/application_constants';
import { validationParts, validationTypes } from '../../../../../../constants/uploader_constants';
import requests from '../../../../../../utils/requests';
import { getErrorNotificationMessage } from '../../../../../../utils/error_utils';
import { setCookie } from '../../../../../../utils/fetch_api_utils';
import { validateForms } from '../../../../../../utils/form_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
const { object } = React.PropTypes;
const PRRegisterPieceForm = React.createClass({
propTypes: {
currentUser: object.isRequired,
location: object
},
mixins: [History],
getInitialState() {
return {
digitalWorkKeyReady: true,
thumbnailKeyReady: true,
// we set this to true, as it is not required
supportingMaterialsReady: true,
proofOfPaymentReady: true,
piece: null,
submitted: false
};
},
/**
* In this method, we're composing all fields on the page
* in two steps, first submitting the registration of the piece and
* second adding all the additional details
*/
submit() {
if (!this.validateForms()) {
return;
}
// disable the submission button right after the user
// clicks on it to avoid double submission
this.setState({
submitted: true
});
const { currentUser } = this.props;
const { registerPieceForm,
additionalDataForm,
uploadersForm } = this.refs;
const { digitalWorkKey,
thumbnailKey,
supportingMaterials,
proofOfPayment } = uploadersForm.refs;
const additionalDataFormData = additionalDataForm.getFormData();
// composing data for piece registration
const registerPieceFormData = registerPieceForm.getFormData();
registerPieceFormData.digital_work_key = digitalWorkKey.state.value;
registerPieceFormData.thumbnail_file = thumbnailKey.state.value;
registerPieceFormData.terms = true;
// submitting the piece
requests
.post(ApiUrls.pieces_list, { body: registerPieceFormData })
.then(({ piece, notification }) => {
this.setState({piece}, () => {
supportingMaterials.refs.input.createBlobRoutine();
proofOfPayment.refs.input.createBlobRoutine();
});
setCookie(currentUser.email, piece.id);
return requests
.post(ApiUrls.piece_extradata, {
body: {
extradata: additionalDataFormData,
piece_id: piece.id
},
piece_id: piece.id
})
.then(() => {
const notificationMessage = new GlobalNotificationModel(notification || getLangText('You have successfully submitted "%s" to Portfolio Review 2015', piece.title), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage);
});
})
.then(() => this.history.push(`/pieces/${this.state.piece.id}`))
.catch((err) => {
const errMessage = (getErrorNotificationMessage(err) || getLangText("Oops! We weren't able to send your submission.")) +
getLangText(' Please contact support@ascribe.io');
const notificationMessage = new GlobalNotificationModel(errMessage, 'danger', 10000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage);
console.logGlobal(new Error('Portfolio Review piece registration failed'), err);
// Reset the submit button
this.setState({
submitted: false
});
});
},
validateForms() {
const { registerPieceForm,
additionalDataForm,
uploadersForm } = this.refs;
return validateForms([registerPieceForm, additionalDataForm, uploadersForm], true);
},
getCreateBlobRoutine() {
const { piece } = this.state;
if(piece && piece.id) {
return {
url: ApiUrls.blob_otherdatas,
pieceId: piece.id
};
} else {
return null;
}
},
/**
* These two methods are overloaded so that we can track the ready-state
* of each uploader in the component
* @param {string} uploaderKey Name of the uploader's key to track
*/
setIsUploadReady(uploaderKey) {
return (isUploadReady) => {
this.setState({
[uploaderKey]: isUploadReady
});
};
},
handleOptionalFileValidationFailed(uploaderKey) {
return () => {
this.setState({
[uploaderKey]: true
});
};
},
getSubmitButton() {
const { digitalWorkKeyReady,
thumbnailKeyReady,
supportingMaterialsReady,
proofOfPaymentReady,
submitted } = this.state;
if(submitted) {
return (
<span disabled className="btn btn-default btn-wide btn-spinner">
<AscribeSpinner color="dark-blue" size="md" />
</span>
);
} else {
return (
<button
type="button"
className="btn btn-default btn-wide"
disabled={!(digitalWorkKeyReady && thumbnailKeyReady && proofOfPaymentReady && supportingMaterialsReady)}
onClick={this.submit}>
{getLangText('Submit to Portfolio Review')}
</button>
);
}
},
render() {
const { location } = this.props;
const maxThumbnailSize = validationTypes.workThumbnail.sizeLimit / 1000000;
return (
<div className="register-piece--form">
<Form
buttons={null}
className="ascribe-form-bordered"
ref="registerPieceForm">
<Property
name='artist_name'
label={getLangText('Full name')}>
<input
type="text"
placeholder={getLangText('(e.g. Andy Warhol)')}
required/>
</Property>
<Property
name='title'
label={getLangText('Title of the Work')}>
<input
type="text"
placeholder={getLangText("(e.g. 32 Campbell's Soup Cans)")}
required/>
</Property>
<Property
name='date_created'
label={getLangText('Year of creation')}>
<input
type="number"
placeholder={getLangText('(e.g. 1962)')}
min={1}
required/>
</Property>
<Property
name='artist_statement'
label={getLangText("Artist's statement")}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter your statement')}/>
</Property>
</Form>
<Form
buttons={null}
className="ascribe-form-bordered"
ref="additionalDataForm">
<Property
name='1-date_of_birth'
label={getLangText('Date of Birth')}>
<input
type="number"
placeholder={getLangText('(e.g. 1962)')}
min={1900}
required/>
</Property>
<Property
name='2-artist_bio'
label={getLangText('Biography')}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter your biography')}/>
</Property>
<Property
name='3-exhibition'
label={getLangText('Exhibition / Publication history (optional)')}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter exhibitions and publication history')}/>
</Property>
<Property
name='4-phone_number'
label={getLangText('Phone Number')}>
<input
type="tel"
placeholder={getLangText('Enter your phone number')}
required/>
</Property>
<Property
name='5-email'
label={getLangText('Email Address')}>
<input
type="email"
placeholder={getLangText('Enter your email')}
required/>
</Property>
<Property
name='6-website'
label={getLangText('Website')}>
<input
type="url"
placeholder={getLangText('Enter your website')}
required/>
</Property>
</Form>
<Form
buttons={null}
className="ascribe-form-bordered"
ref="uploadersForm">
<Property
name="digitalWorkKey"
label={getLangText('Select the PDF with your work')}>
<InputFineuploader
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
createBlobRoutine={{
url: ApiUrls.blob_digitalworks
}}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'digitalwork'
}}
validation={{
itemLimit: validationTypes.registerWork.itemLimit,
sizeLimit: validationTypes.additionalData.sizeLimit,
allowedExtensions: ['pdf']
}}
location={location}
fileClassToUpload={{
singular: getLangText('Select the Portfolio'),
plural: getLangText('Select the Portfolios')
}}
required/>
</Property>
<Property
name="thumbnailKey"
label={`${getLangText('Featured Cover photo')} (max ${maxThumbnailSize}MB)`}>
<InputFineuploader
fileInputElement={UploadButton()}
createBlobRoutine={{
url: ApiUrls.blob_thumbnails
}}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('thumbnailKeyReady')}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'thumbnail'
}}
validation={{
itemLimit: validationTypes.workThumbnail.itemLimit,
sizeLimit: validationTypes.workThumbnail.sizeLimit,
allowedExtensions: validationParts.allowedExtensions.images
}}
location={location}
fileClassToUpload={{
singular: getLangText('Select cover photo'),
plural: getLangText('Select cover photos')
}}
required/>
</Property>
<Property
name="supportingMaterials"
label={getLangText('Supporting Materials (Optional)')}>
<InputFineuploader
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('supportingMaterialsReady')}
onValidationFailed={this.handleOptionalFileValidationFailed('supportingMaterialsReady')}
createBlobRoutine={this.getCreateBlobRoutine()}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'otherdata'
}}
validation={{
itemLimit: validationParts.itemLimit.single,
sizeLimit: validationTypes.additionalData.sizeLimit
}}
location={location}
fileClassToUpload={{
singular: getLangText('Select supporting material'),
plural: getLangText('Select supporting materials')
}}/>
</Property>
<Property
name="proofOfPayment"
label={getLangText('Proof of payment')}>
<InputFineuploader
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('proofOfPaymentReady')}
createBlobRoutine={this.getCreateBlobRoutine()}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'otherdata'
}}
validation={{
itemLimit: validationParts.itemLimit.single,
sizeLimit: validationTypes.additionalData.sizeLimit,
allowedExtensions: validationParts.allowedExtensions.images
}}
location={location}
fileClassToUpload={{
singular: getLangText('Select Screenshot'),
plural: getLangText('Select Screenshots')
}}
required/>
</Property>
</Form>
<Form
buttons={null}
className="ascribe-form-bordered">
<Property
name="terms"
className="ascribe-property-collapsible-toggle">
<span>
{getLangText('By submitting this form, you agree to the') + ' '}
<a
href="https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/portfolioreview/tos-portfolioreview.pdf"
target="_blank">
{getLangText('Terms of Service')}
</a>
{' of Portfolio Review.'}
</span>
</Property>
</Form>
{this.getSubmitButton()}
</div>
);
}
});
export default PRRegisterPieceForm;

View File

@ -1,33 +0,0 @@
'use strict';
import React from 'react';
import { Link } from 'react-router';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import { getLangText } from '../../../../../utils/lang_utils';
const PRHero = React.createClass({
propTypes: {
currentUser: React.PropTypes.shape({
email: React.PropTypes.object
}).isRequired
},
render() {
const { currentUser } = this.props;
return (
<div className="piece--hero">
<h2><Glyphicon glyph="ok" />
&nbsp;{getLangText('Congratulations') + (currentUser.email ? ` ${currentUser.email}!` : '!')}
</h2>
<h1>{getLangText('You have successfully submitted to Portfolio Review 2016.')}</h1>
<p>Not you? <Link to="/logout">{getLangText('Change account.')}</Link></p>
</div>
);
}
});
export default PRHero;

View File

@ -1,124 +0,0 @@
'use strict';
import React from 'react';
import { History } from 'react-router';
import Button from 'react-bootstrap/lib/Button';
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import PrizeActions from '../../simple_prize/actions/prize_actions';
import PrizeStore from '../../simple_prize/stores/prize_store';
import { omitFromObject } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
const PRLanding = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
mixins: [History],
getInitialState() {
return PrizeStore.getState();
},
componentDidMount() {
const { location } = this.props;
PrizeStore.listen(this.onChange);
PrizeActions.fetchPrize();
if (location.query.redirect) {
window.setTimeout(() => this.history.replace({
pathname: `/${location.query.redirect}`,
query: omitFromObject(location.query, ['redirect'])
}));
}
},
componentWillUnmount() {
PrizeStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
getButtons() {
if (this.state.prize && this.state.prize.active) {
return (
<ButtonGroup className="enter" bsSize="large" vertical>
<LinkContainer to="/signup">
<Button>
{getLangText('Sign up to submit')}
</Button>
</LinkContainer>
<p>
{getLangText('or, already an ascribe user?')}
</p>
<LinkContainer to="/login">
<Button>
{getLangText('Log in to submit')}
</Button>
</LinkContainer>
</ButtonGroup>
);
} else {
return (
<ButtonGroup className="enter" bsSize="large" vertical>
<a className="btn btn-default" href="https://www.ascribe.io/app/signup">
{getLangText('Sign up to ascribe')}
</a>
<p>
{getLangText('or, already an ascribe user?')}
</p>
<LinkContainer to="/login">
<Button>
{getLangText('Log in')}
</Button>
</LinkContainer>
</ButtonGroup>
);
}
},
getTitle() {
const { prize } = this.state;
return (
<p>
{getLangText(prize && prize.active ? 'This is the submission page for Portfolio Review 2016.'
: 'Submissions for Portfolio Review 2016 are now closed.')}
</p>
);
},
render() {
return (
<div className="container">
<div className="row">
<div className="col-xs-12 wp-landing-wrapper">
<h1>
{getLangText('Welcome to Portfolio Review 2016')}
</h1>
{this.getTitle()}
{this.getButtons()}
</div>
</div>
</div>
);
}
});
export default PRLanding;

View File

@ -1,72 +0,0 @@
'use strict';
import React from 'react';
import { Link, History } from 'react-router';
import Col from 'react-bootstrap/lib/Col';
import Row from 'react-bootstrap/lib/Row';
import PRRegisterPieceForm from './pr_forms/pr_register_piece_form';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { getCookie } from '../../../../../utils/fetch_api_utils';
const { object } = React.PropTypes;
const PRRegisterPiece = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
location: object
},
mixins: [History],
componentDidUpdate() {
const { currentUser } = this.props;
if (currentUser.email) {
const submittedPieceId = getCookie(currentUser.email);
if (submittedPieceId) {
this.history.push(`/pieces/${submittedPieceId}`);
}
}
},
render() {
const { currentUser, location } = this.props;
setDocumentTitle(getLangText('Submit to Portfolio Review'));
return (
<Row>
<Col xs={6}>
<div className="register-piece--info">
<h1>Portfolio Review</h1>
<h2>{getLangText('Submission closing on %s', ' 27 Dec 2015')}</h2>
<p>For more information, visit:&nbsp;
<a href="http://www.portfolio-review.de/submission/" target="_blank">
portfolio-review.de
</a>
</p>
<p style={{marginTop: '1em'}}>
{getLangText("You're submitting as %s. ", currentUser.email)}
<Link to="/logout">{getLangText('Change account?')}</Link>
</p>
</div>
</Col>
<Col xs={6}>
<PRRegisterPieceForm
location={location}
currentUser={currentUser} />
</Col>
</Row>
);
}
});
export default PRRegisterPiece;

View File

@ -1,26 +0,0 @@
'use strict';
import history from '../../../../../../history';
export function AuthPrizeRoleRedirect({ to, when }) {
if (when.constructor !== Array || !when.length) {
throw new Error('`when` of AuthPrizeRoleRedirect must be an array containing values');
}
if (!to || to.indexOf('/') === -1) {
throw new Error('`to` of AuthPrizeRoleRedirect must be defined and contain a valid route');
}
return function(currentUser, query) {
const exprToValidate = when
.map(role => currentUser[role])
.reduce((a, b) => a || b);
if (exprToValidate) {
window.setTimeout(() => history.replace({ query, pathname: to }));
return true;
} else {
return false;
}
};
}

View File

@ -1,73 +0,0 @@
'use strict';
import React from 'react';
import classNames from 'classnames';
import EventActions from '../../../../actions/event_actions';
import UserStore from '../../../../stores/user_store';
import UserActions from '../../../../actions/user_actions';
import Hero from './components/pr_hero';
import AppBase from '../../../app_base';
import AppRouteWrapper from '../../../app_route_wrapper';
import Header from '../../../header';
import { getSubdomain } from '../../../../utils/general_utils';
import { getCookie } from '../../../../utils/fetch_api_utils';
let PRApp = React.createClass({
propTypes: {
activeRoute: React.PropTypes.object.isRequired,
children: React.PropTypes.element.isRequired,
history: React.PropTypes.object.isRequired,
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
// Provided from AppBase
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object
},
render() {
const { activeRoute, children, currentUser, history, routes, whitelabel } = this.props;
const subdomain = getSubdomain();
const path = activeRoute && activeRoute.path;
const Footer = activeRoute && activeRoute.footer;
let style = {};
let header;
if (currentUser && currentUser.email && history.isActive(`/pieces/${getCookie(currentUser.email)}`)) {
header = (<Hero currentUser={currentUser} />);
style = { paddingTop: '0 !important' };
} else if (currentUser && (currentUser.is_admin || currentUser.is_jury || currentUser.is_judge)) {
header = (
<Header
currentUser={currentUser}
routes={routes}
whitelabel={whitelabel}
/>
);
} else {
style = { paddingTop: '0 !important' };
}
return (
<div
style={style}
className={classNames('ascribe-app', 'ascribe-prize-app', `route--${(path ? path.split('/')[0] : 'landing')}`)}>
{header}
<AppRouteWrapper
currentUser={currentUser}
whitelabel={whitelabel}>
{/* Routes are injected here */}
{children}
</AppRouteWrapper>
{Footer ? <Footer /> : null}
</div>
);
}
});
export default AppBase(PRApp);

View File

@ -1,137 +0,0 @@
'use strict';
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import { ProxyHandler, AuthRedirect } from '../../../components/ascribe_routes/proxy_handler';
import { AuthPrizeRoleRedirect } from './portfolioreview/components/pr_routes/pr_proxy_handler';
// General components
import EditionContainer from '../../ascribe_detail/edition_container';
import LogoutContainer from '../../logout_container';
import PasswordResetContainer from '../../password_reset_container';
import CoaVerifyContainer from '../../coa_verify_container';
import ErrorNotFoundPage from '../../error_not_found_page';
import SPApp from './simple_prize/prize_app';
import SPLanding from './simple_prize/components/prize_landing';
import SPLoginContainer from './simple_prize/components/prize_login_container';
import SPSignupContainer from './simple_prize/components/prize_signup_container';
import SPRegisterPiece from './simple_prize/components/prize_register_piece';
import SPPieceList from './simple_prize/components/prize_piece_list';
import SPPieceContainer from './simple_prize/components/ascribe_detail/prize_piece_container';
import SPSettingsContainer from './simple_prize/components/prize_settings_container';
import SluicePieceContainer from './sluice/components/sluice_detail/sluice_piece_container';
import PRApp from './portfolioreview/pr_app';
import PRLanding from './portfolioreview/components/pr_landing';
import PRRegisterPiece from './portfolioreview/components/pr_register_piece';
import { getLangText } from '../../../utils/lang_utils';
const ROUTES = {
sluice: (
<Route path='/' component={SPApp}>
<IndexRoute
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SPLanding)} />
<Route
path='login'
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SPLoginContainer)} />
<Route
path='logout'
component={ProxyHandler(AuthRedirect({to: '/', when: 'loggedOut'}))(LogoutContainer)} />
<Route
path='signup'
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SPSignupContainer)} />
<Route
path='password_reset'
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(PasswordResetContainer)} />
<Route
path='settings'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPSettingsContainer)} />
<Route
path='register_piece'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPRegisterPiece)}
headerTitle={getLangText('+ NEW WORK')} />
<Route
path='collection'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
headerTitle={getLangText('COLLECTION')} />
<Route
path='pieces/:pieceId'
component={SluicePieceContainer} />
<Route
path='editions/:editionId'
component={EditionContainer} />
<Route
path='coa_verify'
component={CoaVerifyContainer} />
<Route
path='*'
component={ErrorNotFoundPage} />
</Route>
),
portfolioreview: (
<Route path='/' component={PRApp}>
<IndexRoute
component={ProxyHandler(AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }))(PRLanding)} />
<Route
path='register_piece'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PRRegisterPiece)} />
<Route
path='collection'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
headerTitle={getLangText('SUBMISSIONS')} />
<Route
path='login'
component={ProxyHandler(
AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
AuthRedirect({to: '/register_piece', when: 'loggedIn'})
)(SPLoginContainer)} />
<Route
path='logout'
component={ProxyHandler(AuthRedirect({to: '/', when: 'loggedOut'}))(LogoutContainer)} />
<Route
path='signup'
component={ProxyHandler(
AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
AuthRedirect({to: '/register_piece', when: 'loggedIn'})
)(SPSignupContainer)} />
<Route
path='password_reset'
component={ProxyHandler(
AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
AuthRedirect({to: '/register_piece', when: 'loggedIn'})
)(PasswordResetContainer)} />
<Route
path='settings'
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPSettingsContainer)} />
<Route
path='pieces/:pieceId'
component={SPPieceContainer} />
<Route
path='editions/:editionId'
component={EditionContainer} />
<Route
path='coa_verify'
component={CoaVerifyContainer} />
<Route
path='*'
component={ErrorNotFoundPage} />
</Route>
)
};
function getRoutes(commonRoutes, subdomain) {
if(subdomain in ROUTES) {
return ROUTES[subdomain];
} else {
throw new Error('Subdomain wasn\'t specified in the wallet app.');
}
}
export default getRoutes;

View File

@ -1,28 +0,0 @@
'use strict';
import { alt } from '../../../../../alt';
import PrizeFetcher from '../fetchers/prize_fetcher';
class PrizeActions {
constructor() {
this.generateActions(
'updatePrize'
);
}
fetchPrize() {
PrizeFetcher
.fetch()
.then((res) => {
this.actions.updatePrize({
prize: res
});
})
.catch((err) => {
console.logGlobal(err);
});
}
}
export default alt.createActions(PrizeActions);

View File

@ -1,76 +0,0 @@
'use strict';
import { alt } from '../../../../../alt';
import Q from 'q';
import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher';
class PrizeJuryActions {
constructor() {
this.generateActions(
'updatePrizeJury',
'removePrizeJury',
'activatePrizeJury'
);
}
fetchJury() {
return Q.Promise((resolve, reject) => {
PrizeJuryFetcher
.fetch()
.then((res) => {
this.actions.updatePrizeJury(res.members);
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});
}
activateJury(email) {
return Q.Promise((resolve, reject) => {
PrizeJuryFetcher
.activate(email)
.then((res) => {
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});
}
revokeJury(email) {
return Q.Promise((resolve, reject) => {
PrizeJuryFetcher
.delete(email)
.then((res) => {
this.actions.removePrizeJury(email);
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});
}
resendJuryInvitation(email) {
return Q.Promise((resolve, reject) => {
PrizeJuryFetcher
.resend(email)
.then((res) => {
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});
}
}
export default alt.createActions(PrizeJuryActions);

View File

@ -1,76 +0,0 @@
'use strict';
import { alt } from '../../../../../alt';
import Q from 'q';
import PrizeRatingFetcher from '../fetchers/prize_rating_fetcher';
class PrizeRatingActions {
constructor() {
this.generateActions(
'updatePrizeRatings',
'updatePrizeRatingAverage',
'updatePrizeRating',
'resetPrizeRatings'
);
}
fetchAverage(pieceId, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
.fetchAverage(pieceId, round)
.then((res) => {
this.actions.updatePrizeRatingAverage(res.data);
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});
}
fetchOne(pieceId, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
.fetchOne(pieceId, round)
.then((res) => {
this.actions.updatePrizeRating(res.rating.rating);
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
createRating(pieceId, rating, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
.rate(pieceId, rating, round)
.then((res) => {
this.actions.updatePrizeRating(res.rating.rating);
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
toggleShortlist(pieceId) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
.select(pieceId)
.then((res) => {
this.actions.updatePrizeRatings(res.data.ratings);
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
}
export default alt.createActions(PrizeRatingActions);

View File

@ -1,191 +0,0 @@
'use strict';
import React from 'react';
import { Link } from 'react-router';
import StarRating from 'react-star-rating';
import Moment from 'moment';
import PieceListActions from '../../../../../../actions/piece_list_actions';
import PieceListStore from '../../../../../../stores/piece_list_store';
import PrizeRatingActions from '../../actions/prize_rating_actions';
import InputCheckbox from '../../../../../ascribe_forms/input_checkbox';
import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece';
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 { getLangText } from '../../../../../../utils/lang_utils';
let AccordionListItemPrize = React.createClass({
propTypes: {
content: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
]),
className: React.PropTypes.string
},
getInitialState() {
return PieceListStore.getState();
},
componentDidMount() {
PieceListStore.listen(this.onChange);
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
handleSubmitPrizeSuccess(response) {
const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
const notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getPrizeButtons() {
const { currentUser, content: { id, ratings } } = this.props;
if (currentUser && (currentUser.is_jury || currentUser.is_judge)) {
if (ratings && (ratings.rating || ratings.average)) {
// jury and rating available
let rating = null;
let caption = null;
if (ratings.rating) {
rating = parseInt(ratings.rating, 10);
caption = getLangText('Your rating');
} else if (ratings.average) {
rating = ratings.average;
caption = getLangText('Average of ' + ratings.num_ratings + ' rating(s)');
}
return (
<div id="list-rating" className="pull-right">
<Link to={`/pieces/${id}`}>
<StarRating
ref='rating'
name="prize-rating"
caption={caption}
step={0.5}
size='sm'
rating={rating}
ratingAmount={5} />
</Link>
</div>
);
} else {
if (currentUser.is_judge) {
return (
<div className="react-rating-caption pull-right">
{getLangText('Not rated')}
</div>
);
} else {
// jury and no rating yet
return (
<div className="react-rating-caption pull-right">
<Link to={`/pieces/${id}`}>
{getLangText('Submit your rating')}
</Link>
</div>
);
}
}
} else {
return this.getPrizeButtonsParticipant();
}
},
getPrizeButtonsParticipant() {
return (
<AclProxy
aclObject={this.props.content.acl}
aclName="acl_wallet_submit">
<SubmitToPrizeButton
className="pull-right"
piece={this.props.content}
handleSuccess={this.handleSubmitPrizeSuccess} />
</AclProxy>
);
},
handleShortlistSuccess(message) {
const notification = new GlobalNotificationModel(message, 'success', 2000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
refreshPieceData() {
const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
onSelectChange() {
PrizeRatingActions.toggleShortlist(this.props.content.id)
.then((res) => {
this.refreshPieceData();
this.handleShortlistSuccess(res.notification);
});
},
getPrizeBadge() {
const { currentUser } = this.props;
if (currentUser && currentUser.is_judge) {
return (
<span className="pull-right ascribe-checkbox-wrapper ascribe-checkbox-badge">
<InputCheckbox
defaultChecked={this.props.content.selected}
onChange={this.onSelectChange} />
</span>
);
} else {
return null;
}
},
render() {
const { children, className, content, currentUser } = this.props;
// Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted
const artistName = ((currentUser.is_jury && !currentUser.is_judge) || (currentUser.is_judge && !content.selected )) ?
<span className="glyphicon glyphicon-eye-close" aria-hidden="true"/> : content.artist_name;
return (
<AccordionListItemPiece
className={className}
piece={content}
artistName={artistName}
subsubheading={
<div>
<span>{Moment(content.date_created, 'YYYY-MM-DD').year()}</span>
</div>
}
buttons={this.getPrizeButtons()}
badge={this.getPrizeBadge()}>
{children}
</AccordionListItemPiece>
);
}
});
export default AccordionListItemPrize;

View File

@ -1,55 +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() {
if (this.props.piece.prize) {
return (
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Submitted to prize') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
);
}
else {
return (
<button
className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
{getLangText('Submit to prize')}
</button>
);
}
},
render() {
return (
<ModalWrapper
trigger={this.getSubmitButton()}
handleSuccess={this.props.handleSuccess}
title={getLangText('Submit to prize')}>
<PieceSubmitToPrizeForm
piece={this.props.piece}
handleSuccess={this.props.handleSuccess}/>
</ModalWrapper>
);
}
});
export default SubmitToPrizeButton;

View File

@ -1,495 +0,0 @@
'use strict';
import React from 'react';
import { Link } from 'react-router';
import Moment from 'moment';
import StarRating from 'react-star-rating';
import ReactError from '../../../../../../mixins/react_error';
import { ResourceNotFoundError } from '../../../../../../models/errors';
import PrizeActions from '../../actions/prize_actions';
import PrizeStore from '../../stores/prize_store';
import PrizeRatingActions from '../../actions/prize_rating_actions';
import PrizeRatingStore from '../../stores/prize_rating_store';
import PieceListStore from '../../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../../actions/piece_list_actions';
import PieceActions from '../../../../../../actions/piece_actions';
import PieceStore from '../../../../../../stores/piece_store';
import Piece from '../../../../../../components/ascribe_detail/piece';
import Note from '../../../../../../components/ascribe_detail/note';
import AscribeSpinner from '../../../../../ascribe_spinner';
import Form from '../../../../../../components/ascribe_forms/form';
import Property from '../../../../../../components/ascribe_forms/property';
import InputTextAreaToggable from '../../../../../../components/ascribe_forms/input_textarea_toggable';
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
import InputCheckbox from '../../../../../ascribe_forms/input_checkbox';
import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import DetailProperty from '../../../../../ascribe_detail/detail_property';
import ApiUrls from '../../../../../../constants/api_urls';
import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../../utils/dom_utils';
/**
* This is the component that implements resource/data specific functionality
*/
let PrizePieceContainer = React.createClass({
propTypes: {
selectedPrizeActionButton: React.PropTypes.func,
// Provided from PrizeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object,
params: React.PropTypes.object
},
mixins: [ReactError],
getInitialState() {
return PieceStore.getInitialState();
},
componentDidMount() {
PieceStore.listen(this.onChange);
this.loadPiece();
},
// 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) or
// when the user clicks on a notification while being in another piece view
componentWillReceiveProps(nextProps) {
if (this.props.params.pieceId !== nextProps.params.pieceId) {
PieceActions.flushPiece();
this.loadPiece(nextProps.params.pieceId);
}
},
componentDidUpdate() {
const { pieceMeta: { err: pieceErr } } = this.state;
if (pieceErr && pieceErr.status === 404) {
this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist.")));
}
},
componentWillUnmount() {
PieceStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
getActions() {
const { currentUser } = this.props;
const { piece } = this.state;
if (piece.notifications && piece.notifications.length > 0) {
return (
<ListRequestActions
pieceOrEditions={piece}
currentUser={currentUser}
handleSuccess={this.loadPiece}
notifications={piece.notifications} />);
}
},
loadPiece(pieceId = this.props.params.pieceId) {
PieceActions.fetchPiece(pieceId);
},
render() {
const { currentUser, selectedPrizeActionButton } = this.props;
const { piece } = this.state;
if (piece.id) {
/*
This really needs a refactor!
- Tim
*/
// Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted
let artistName;
if ((currentUser.is_jury && !currentUser.is_judge) || (currentUser.is_judge && !piece.selected )) {
artistName = <span className="glyphicon glyphicon-eye-close" aria-hidden="true" />;
setDocumentTitle(piece.title);
} else {
artistName = piece.artist_name;
setDocumentTitle(`${artistName}, ${piece.title}`);
}
// Only show the artist email if you are a judge and the piece is shortlisted
const artistEmail = currentUser.is_judge && piece.selected ? (
<DetailProperty
label={getLangText('REGISTREE')}
value={piece.user_registered} />
) : null;
return (
<Piece
piece={piece}
currentUser={currentUser}
header={
<div className="ascribe-detail-header">
<NavigationHeader
piece={piece}
currentUser={currentUser} />
<h1 className="ascribe-detail-title">{piece.title}</h1>
<DetailProperty label={getLangText('BY')} value={artistName} />
<DetailProperty label={getLangText('DATE')} value={Moment(piece.date_created, 'YYYY-MM-DD').year()} />
{artistEmail}
{this.getActions()}
<hr />
</div>
}
subheader={
<PrizePieceRatings
loadPiece={this.loadPiece}
piece={piece}
currentUser={currentUser}
selectedPrizeActionButton={selectedPrizeActionButton} />
}>
<PrizePieceDetails piece={piece} />
</Piece>
);
} else {
return (
<div className="fullpage-spinner">
<AscribeSpinner color='dark-blue' size='lg' />
</div>
);
}
}
});
let NavigationHeader = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
piece: React.PropTypes.object.isRequired
},
render() {
const { currentUser, piece } = this.props;
if (currentUser.email && currentUser.is_judge && currentUser.is_jury && !currentUser.is_admin && piece.navigation) {
const nav = piece.navigation;
return (
<div style={{marginBottom: '1em'}}>
<div className="row no-margin">
<Link className="disable-select" to={`/pieces/${ nav.prev_index || piece.id }`}>
<span className="glyphicon glyphicon-chevron-left pull-left link-ascribe" aria-hidden="true">
{getLangText('Previous')}
</span>
</Link>
<Link className="disable-select" to={`/pieces/${ nav.next_index || piece.id }`}>
<span className="pull-right link-ascribe">
{getLangText('Next')}
<span className="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
</span>
</Link>
</div>
<hr/>
</div>
);
} else {
return null;
}
}
});
let PrizePieceRatings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
loadPiece: React.PropTypes.func.isRequired,
piece: React.PropTypes.object.isRequired,
selectedPrizeActionButton: React.PropTypes.func
},
getInitialState() {
return mergeOptions(
PieceListStore.getState(),
PrizeStore.getState(),
PrizeRatingStore.getInitialState()
);
},
componentDidMount() {
PrizeRatingStore.listen(this.onChange);
PrizeStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
PrizeActions.fetchPrize();
this.fetchRatingsIfAuthorized();
},
componentWillReceiveProps(nextProps) {
if (nextProps.currentUser.email !== this.props.currentUser.email) {
this.fetchRatingsIfAuthorized();
}
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
PrizeStore.unlisten(this.onChange);
PrizeRatingStore.unlisten(this.onChange);
},
// The StarRating component does not have a property that lets us set
// a default value at initialization. Since the ratingCache would otherwise on
// every mouseover be overridden, we need to set it ourselves initially to deal
// with the problem.
onChange(state) {
if (state.prize && state.prize.active_round != this.state.prize.active_round) {
this.fetchRatingsIfAuthorized(state);
}
this.setState(state);
if (this.refs.rating) {
this.refs.rating.state.ratingCache = {
pos: this.refs.rating.state.pos,
rating: this.state.currentRating,
caption: this.refs.rating.props.caption,
name: this.refs.rating.props.name
};
}
},
fetchRatingsIfAuthorized(state = this.state) {
const { currentUser: {
is_admin: isAdmin,
is_judge: isJudge,
is_jury: isJury
},
piece: { id: pieceId } } = this.props;
if (state.prize && 'active_round' in state.prize && (isAdmin || isJudge || isJury)) {
PrizeRatingActions.fetchOne(pieceId, state.prize.active_round);
PrizeRatingActions.fetchAverage(pieceId, state.prize.active_round);
}
},
onRatingClick(event, args) {
event.preventDefault();
PrizeRatingActions
.createRating(this.props.piece.id, args.rating, this.state.prize.active_round)
.then(this.refreshPieceData);
},
getSelectedActionButton() {
const { currentUser, piece, selectedPrizeActionButton: SelectedPrizeActionButton } = this.props;
if (piece.selected && SelectedPrizeActionButton) {
return (
<span className="pull-right">
<SelectedPrizeActionButton
piece={piece}
currentUser={currentUser} />
</span>
);
}
},
refreshPieceData() {
const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
this.props.loadPiece();
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
onSelectChange() {
PrizeRatingActions
.toggleShortlist(this.props.piece.id)
.then((res) => {
this.refreshPieceData();
if (res && res.notification) {
const notification = new GlobalNotificationModel(res.notification, 'success', 2000);
GlobalNotificationActions.appendGlobalNotification(notification);
}
});
},
render() {
if (this.props.piece.id && this.props.currentUser.is_judge && this.state.average) {
// Judge sees shortlisting, average and per-jury notes
return (
<div>
<CollapsibleParagraph
title={getLangText('Shortlisting')}
defaultExpanded={true}>
<div className="row no-margin">
<span className="ascribe-checkbox-wrapper" style={{marginLeft: '1.5em'}}>
<InputCheckbox
defaultChecked={this.props.piece.selected}
onChange={this.onSelectChange}>
<span>
{getLangText('Select for the prize')}
</span>
</InputCheckbox>
</span>
{this.getSelectedActionButton()}
</div>
<hr />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Average Rating')}
defaultExpanded={true}>
<div id="list-rating" style={{marginLeft: '1.5em', marginBottom: '1em'}}>
<StarRating
ref='average-rating'
name="average-rating"
caption=""
size='md'
step={0.5}
rating={this.state.average}
ratingAmount={5} />
</div>
<hr />
{this.state.ratings.map((item, i) => {
let note = item.note ? (
<div className="rating-note">
note: {item.note}
</div>
) : null;
return (
<div
key={item.user}
className="rating-list">
<div
id="list-rating"
className="row no-margin">
<span className="pull-right">
<StarRating
ref={'rating' + i}
name={'rating' + i}
caption=""
size='sm'
step={0.5}
rating={item.rating}
ratingAmount={5} />
</span>
<span> {item.user}</span>
{note}
</div>
</div>
);
})}
<hr />
</CollapsibleParagraph>
</div>);
} else if (this.props.currentUser.is_jury) {
// Jury can set rating and note
return (
<CollapsibleParagraph
title={getLangText('Rating')}
defaultExpanded={true}>
<div style={{marginLeft: '1.5em', marginBottom: '1em'}}>
<StarRating
ref='rating'
name="prize-rating"
caption=""
step={1}
size='md'
rating={this.state.currentRating}
onRatingClick={this.onRatingClick}
ratingAmount={5} />
</div>
<Note
id={() => ({ 'piece_id': this.props.piece.id })}
label={getLangText('Jury note')}
defaultValue={this.props.piece.note_from_user || null}
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Jury note saved')}
url={ApiUrls.notes}
currentUser={this.props.currentUser} />
</CollapsibleParagraph>);
} else {
return null;
}
}
});
let PrizePieceDetails = React.createClass({
propTypes: {
piece: React.PropTypes.object.isRequired
},
render() {
const { piece } = this.props;
if (piece.prize && piece.prize.name && Object.keys(piece.extra_data).length) {
return (
<CollapsibleParagraph
title={getLangText('Prize Details')}
defaultExpanded={true}>
<Form>
{Object
.keys(piece.extra_data)
.sort()
.map((data) => {
// Remove leading number (for sorting), if any, and underscores with spaces
const label = data.replace(/^\d-/, '').replace(/_/g, ' ');
const value = piece.extra_data[data] || 'N/A';
return (
<Property
key={label}
name={data}
label={label}
editable={false}
overrideForm={true}>
<InputTextAreaToggable
rows={1}
defaultValue={value} />
</Property>
);
})
}
<FurtherDetailsFileuploader
submitFile={() => {}}
setIsUploadReady={() => {}}
isReadyForFormSubmission={() => {}}
editable={false}
overrideForm={true}
pieceId={piece.id}
otherData={piece.other_data}
multiple={true} />
</Form>
</CollapsibleParagraph>
);
} else {
return null;
}
}
});
export default PrizePieceContainer;

View File

@ -1,20 +0,0 @@
'use strict';
import React from 'react';
import constants from '../../../../../constants/application_constants';
let Hero = React.createClass({
render() {
return (
<div className="hero">
<img
className="logo" src={constants.whitelabel.logo}
alt="Sluice Art Prize"
height="200px"/>
</div>
);
}
});
export default Hero;

View File

@ -1,111 +0,0 @@
'use strict';
import React from 'react';
import Button from 'react-bootstrap/lib/Button';
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import PrizeActions from '../actions/prize_actions';
import PrizeStore from '../stores/prize_store';
import { getLangText } from '../../../../../utils/lang_utils';
let Landing = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
getInitialState() {
return PrizeStore.getState();
},
componentDidMount() {
PrizeStore.listen(this.onChange);
PrizeActions.fetchPrize();
},
componentWillUnmount() {
PrizeStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
getButtons() {
if (this.state.prize && this.state.prize.active) {
return (
<ButtonGroup className="enter" bsSize="large" vertical>
<LinkContainer to="/signup">
<Button>
{getLangText('Sign up to submit')}
</Button>
</LinkContainer>
<p>
{getLangText('or, already an ascribe user?')}
</p>
<LinkContainer to="/login">
<Button>
{getLangText('Log in to submit')}
</Button>
</LinkContainer>
</ButtonGroup>
);
} else {
return (
<ButtonGroup className="enter" bsSize="large" vertical>
<a className="btn btn-default" href="https://www.ascribe.io/app/signup">
{getLangText('Sign up to ascribe')}
</a>
<p>
{getLangText('or, already an ascribe user?')}
</p>
<LinkContainer to="/login">
<Button>
{getLangText('Log in')}
</Button>
</LinkContainer>
</ButtonGroup>
);
}
},
getTitle() {
const { prize } = this.state;
return (
<p>
{getLangText(prize && prize.active ? 'This is the submission page for Sluice_screens ↄc Prize 2015.'
: 'Submissions for Sluice_screens ↄc Prize 2015 are now closed.')}
</p>
);
},
render() {
return (
<div className="container">
<div className="row">
<div className="col-xs-12 wp-landing-wrapper">
<h1>
{getLangText('Sluice_screens ↄc Prize 2015')}
</h1>
{this.getTitle()}
{this.getButtons()}
</div>
</div>
</div>
);
}
});
export default Landing;

View File

@ -1,45 +0,0 @@
'use strict';
import React from 'react';
import { Link } from 'react-router';
import LoginForm from '../../../../ascribe_forms/form_login';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
let LoginContainer = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
render() {
setDocumentTitle(getLangText('Log in'));
return (
<div className="ascribe-login-wrapper">
<LoginForm
headerMessage={getLangText('Log in with ascribe')}
location={this.props.location} />
<div className="ascribe-login-text">
{getLangText('I\'m not a user') + ' '}
<Link to="/signup">{getLangText('Sign up...')}</Link>
<br />
{getLangText('I forgot my password') + ' '}
<Link to="/password_reset">{getLangText('Rescue me...')}</Link>
</div>
</div>
);
}
});
export default LoginContainer;

View File

@ -1,94 +0,0 @@
'use strict';
import React from 'react';
import Button from 'react-bootstrap/lib/Button';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import PrizeActions from '../actions/prize_actions';
import PrizeStore from '../stores/prize_store';
import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize';
import PieceList from '../../../../piece_list';
import { mergeOptions } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
let PrizePieceList = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
getInitialState() {
return PrizeStore.getState();
},
componentDidMount() {
PrizeStore.listen(this.onChange);
PrizeActions.fetchPrize();
},
componentWillUnmount() {
PrizeStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
getButtonSubmit() {
const { currentUser } = this.props;
const { prize } = this.state;
if (prize && prize.active && !currentUser.is_jury && !currentUser.is_admin && !currentUser.is_judge) {
return (
<LinkContainer to="/register_piece">
<Button>
{getLangText('Submit to prize')}
</Button>
</LinkContainer>
);
} else {
return null;
}
},
shouldRedirect(pieceCount) {
const { currentUser } = this.props;
return !currentUser.is_admin && !currentUser.is_jury && !currentUser.is_judge && !pieceCount;
},
render() {
const { currentUser, location } = this.props;
setDocumentTitle(getLangText('Collection'));
let orderParams = ['artist_name', 'title'];
if (currentUser.is_jury) {
orderParams = ['rating', 'title'];
}
if (currentUser.is_judge) {
orderParams = ['rating', 'title', 'selected'];
}
return (
<PieceList
ref="list"
{...this.props}
accordionListItemType={AccordionListItemPrize}
customSubmitButton={this.getButtonSubmit()}
filterParams={[]}
orderParams={orderParams}
orderBy={currentUser.is_jury ? 'rating' : null}
shouldRedirect={this.shouldRedirect} />
);
}
});
export default PrizePieceList;

View File

@ -1,102 +0,0 @@
'use strict';
import React from 'react';
import PrizeActions from '../actions/prize_actions';
import PrizeStore from '../stores/prize_store';
import RegisterPiece from '../../../../register_piece';
import Property from '../../../../ascribe_forms/property';
import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable';
import InputCheckbox from '../../../../ascribe_forms/input_checkbox';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
let PrizeRegisterPiece = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
getInitialState() {
return PrizeStore.getState();
},
componentDidMount() {
PrizeStore.listen(this.onChange);
PrizeActions.fetchPrize();
},
componentWillUnmount() {
PrizeStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() {
const { prize } = this.state;
setDocumentTitle(getLangText('Submit to the prize'));
if (prize && prize.active) {
return (
<RegisterPiece
{...this.props}
enableLocalHashing={false}
headerMessage={''}
submitMessage={getLangText('Submit')}>
<Property
name='artist_statement'
label={getLangText('Artist statement')}
editable={true}
overrideForm={true}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter your statement')}
required />
</Property>
<Property
name='work_description'
label={getLangText('Work description')}
editable={true}
overrideForm={true}>
<InputTextAreaToggable
rows={1}
placeholder={getLangText('Enter the description for your work')}
required />
</Property>
<Property
name="terms"
className="ascribe-property-collapsible-toggle">
<InputCheckbox>
<span>
{' ' + getLangText('I agree to the Terms of Service the art price') + ' '}
(<a href="https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/terms.pdf" target="_blank" style={{fontSize: '0.9em', color: 'rgba(0,0,0,0.7)'}}>
{getLangText('read')}
</a>)
</span>
</InputCheckbox>
</Property>
</RegisterPiece>
);
} else {
return (
<div className='row'>
<div style={{textAlign: 'center'}}>
{getLangText('The prize is no longer active')}
</div>
</div>
);
}
}
});
export default PrizeRegisterPiece;

View File

@ -1,302 +0,0 @@
'use strict';
import React from 'react';
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 '../../../../ascribe_settings/settings_container';
import CollapsibleParagraph from '../../../../ascribe_collapsible/collapsible_paragraph';
import Form from '../../../../ascribe_forms/form';
import Property from '../../../../ascribe_forms/property';
import ActionPanel from '../../../../ascribe_panel/action_panel';
import GlobalNotificationModel from '../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../actions/global_notification_actions';
import AscribeSpinner from '../../../../ascribe_spinner';
import ApiUrls from '../../../../../constants/api_urls';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
let Settings = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
render() {
setDocumentTitle(getLangText('Account settings'));
return (
<SettingsContainer {...this.props}>
{this.props.currentUser.is_admin ? <PrizeSettings /> : null}
</SettingsContainer>
);
}
});
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 (
<CollapsibleParagraph
title={getLangText('Prize Settings for ') + this.state.prize.name}
defaultExpanded={true}>
<Form >
<Property
name='prize_name'
label={getLangText('Prize name')}
editable={false}>
<pre className="ascribe-pre">{this.state.prize.name}</pre>
</Property>
<Property
name='prize_rounds'
label={getLangText('Active round/Number of rounds')}
editable={false}>
<pre className="ascribe-pre">{this.state.prize.active_round}/{this.state.prize.rounds}</pre>
</Property>
<Property
name='num_submissions'
label={getLangText('Allowed number of submissions per user')}
editable={false}>
<pre className="ascribe-pre">{this.state.prize.num_submissions}</pre>
</Property>
<hr />
</Form>
<PrizeJurySettings
prize={this.state.prize}/>
</CollapsibleParagraph>
);
}
});
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();
this.displayNotification(response);
this.refs.form.refs.email.refs.input.getDOMNode().value = null;
},
handleActivate(event) {
let email = event.target.getAttribute('data-id');
PrizeJuryActions
.activateJury(email)
.then((response) => {
PrizeJuryActions.fetchJury();
this.displayNotification(response);
});
},
handleRevoke(event) {
let email = event.target.getAttribute('data-id');
PrizeJuryActions
.revokeJury(email)
.then(this.displayNotification);
},
handleResend(event) {
let email = event.target.getAttribute('data-id');
PrizeJuryActions
.resendJuryInvitation(email)
.then(this.displayNotification);
},
displayNotification(response) {
let notification = new GlobalNotificationModel(response.notification, 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getMembersPending() {
return this.state.membersPending.map(function(member, i) {
return (
<ActionPanel
name={member.email}
key={i}
content={
<div>
<div className='ascribe-panel-title'>
{member.email}
</div>
<div className="ascribe-panel-subtitle">
{member.status}
</div>
</div>
}
buttons={
<div className="pull-right">
<button
className="btn btn-default btn-sm margin-left-2px"
onClick={this.handleResend}
data-id={member.email}>
{getLangText('RESEND')}
</button>
<button
className="btn btn-warning btn-sm margin-left-2px"
onClick={this.handleRevoke}
data-id={member.email}>
{getLangText('REVOKE')}
</button>
</div>
}/>
);
}, this);
},
getMembersActive() {
return this.state.membersActive.map(function(member, i) {
return (
<ActionPanel
name={member.email}
key={i}
content={
<div>
<div className='ascribe-panel-title'>
{member.email}
</div>
<div className="ascribe-panel-subtitle">
{member.status}
</div>
</div>
}
buttons={
<button
className="btn btn-warning btn-sm"
onClick={this.handleRevoke}
data-id={member.email}>
{getLangText('REVOKE')}
</button>
}/>
);
}, this);
},
getMembersInactive() {
return this.state.membersInactive.map(function(member, i) {
return (
<ActionPanel
name={member.email}
key={i}
content={
<div>
<div className='ascribe-panel-title'>
{member.email}
</div>
<div className="ascribe-panel-subtitle">
{member.status}
</div>
</div>
}
buttons={
<button
className="btn btn-default btn-sm"
onClick={this.handleActivate}
data-id={member.email}>
{getLangText('ACTIVATE')}
</button>
}/>
);
}, this);
},
getMembers() {
let content = <AscribeSpinner color='dark-blue' size='md' />;
if (this.state.members.length > -1) {
content = (
<div>
<CollapsibleParagraph
title={getLangText('Active Jury Members')}
defaultExpanded={true}>
{this.getMembersActive()}
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Pending Jury Invitations')}
defaultExpanded={true}>
{this.getMembersPending()}
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Deactivated Jury Members')}
defaultExpanded={false}>
{this.getMembersInactive()}
</CollapsibleParagraph>
</div>);
}
return content;
},
render() {
return (
<div>
<Form
url={ApiUrls.jurys}
handleSuccess={this.handleCreateSuccess}
ref='form'
buttonSubmitText={getLangText('INVITE')}>
<div className="ascribe-form-header">
<h4 style={{margin: '30px 0px 10px 10px'}}>
{getLangText('Jury Members')}
</h4>
</div>
<Property
name='email'
label={getLangText('New jury member')}>
<input
type="email"
placeholder={getLangText('Enter an email to invite a jury member')}
required/>
</Property>
<hr />
</Form>
{this.getMembers()}
</div>
);
}
});
export default Settings;

View File

@ -1,61 +0,0 @@
'use strict';
import React from 'react';
import SignupForm from '../../../../ascribe_forms/form_signup';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
let SignupContainer = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object
},
getInitialState() {
return {
submitted: false,
message: null
};
},
handleSuccess(message) {
this.setState({
submitted: true,
message: message
});
},
render() {
const { location } = this.props;
const { message, submitted } = this.state;
setDocumentTitle(getLangText('Sign up'));
if (submitted) {
return (
<div className="ascribe-login-wrapper">
<div className="ascribe-login-text ascribe-login-header">
{message}
</div>
</div>
);
} else {
return (
<div className="ascribe-login-wrapper">
<SignupForm
headerMessage={getLangText('Create account for submission')}
submitMessage={getLangText('Sign up')}
handleSuccess={this.handleSuccess}
location={location} />
</div>
);
}
}
});
export default SignupContainer;

View File

@ -1,12 +0,0 @@
'use strict';
import requests from '../../../../../utils/requests';
let PrizeFetcher = {
fetch() {
return requests.get('prize');
}
};
export default PrizeFetcher;

View File

@ -1,24 +0,0 @@
'use strict';
import requests from '../../../../../utils/requests';
let PrizeJuryFetcher = {
fetch() {
return requests.get('jurys');
},
activate(email) {
return requests.post('jury_activate', {'email': email});
},
delete(email) {
return requests.delete('jury', {'email': email});
},
resend(email) {
return requests.post('jury_resend', {'email': email});
}
};
export default PrizeJuryFetcher;

View File

@ -1,49 +0,0 @@
'use strict';
import requests from '../../../../../utils/requests';
let PrizeRatingFetcher = {
fetchAverage(pieceId, round) {
const params = {
'piece_id': pieceId
};
if (typeof round === 'number') {
params['prize_round'] = round;
}
return requests.get('rating_average', params);
},
fetchOne(pieceId, round) {
const params = {
'piece_id': pieceId
};
if (typeof round === 'number') {
params['prize_round'] = round;
}
return requests.get('rating', params);
},
rate(pieceId, rating, round) {
const body = {
'piece_id': pieceId,
'note': rating
};
if (typeof round === 'number') {
body['prize_round'] = round;
}
return requests.post('ratings', { body });
},
select(pieceId) {
return requests.post('select_piece', {'piece_id': pieceId});
}
};
export default PrizeRatingFetcher;

View File

@ -1,61 +0,0 @@
'use strict';
import React from 'react';
import classNames from 'classnames';
import Hero from './components/prize_hero';
import AppBase from '../../../app_base';
import AppRouteWrapper from '../../../app_route_wrapper';
import Header from '../../../header';
import { getSubdomain } from '../../../../utils/general_utils';
let PrizeApp = React.createClass({
propTypes: {
activeRoute: React.PropTypes.object.isRequired,
children: React.PropTypes.element.isRequired,
history: React.PropTypes.object.isRequired,
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
// Provided from AppBase
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object
},
render() {
const { activeRoute, children, currentUser, history, routes, whitelabel } = this.props;
const subdomain = getSubdomain();
const path = activeRoute && activeRoute.path;
const Footer = activeRoute && activeRoute.footer;
let header = null;
// if the path of the current activeRoute is not defined, then this is the IndexRoute
if (!path || history.isActive('/login') || history.isActive('/signup')) {
header = (<Hero />);
} else {
header = (
<Header
currentUser={currentUser}
routes={routes}
whitelabel={whitelabel} />
);
}
return (
<div className={classNames('ascribe-app', 'ascribe-prize-app', `route--${(path ? path.split('/')[0] : 'landing')}`)}>
{header}
<AppRouteWrapper
currentUser={currentUser}
whitelabel={whitelabel}>
{/* Routes are injected here */}
{children}
</AppRouteWrapper>
{Footer ? <Footer /> : null}
</div>
);
}
});
export default AppBase(PrizeApp);

View File

@ -1,35 +0,0 @@
'use strict';
import { alt } from '../../../../../alt';
import PrizeJuryActions from '../actions/prize_jury_actions';
class PrizeJuryStore {
constructor() {
this.members = [];
this.membersActive = [];
this.membersPending = [];
this.membersInactive = [];
this.bindActions(PrizeJuryActions);
}
onUpdatePrizeJury( members ) {
this.members = members;
this.splitJuryMembers();
}
onRemovePrizeJury( email ) {
let memberInactive = this.members.filter((item)=> item.email === email );
this.membersActive = this.membersActive.filter((item)=> item.email !== email );
this.membersPending = this.membersPending.filter((item)=> item.email !== email );
this.membersInactive = this.membersInactive.concat(memberInactive);
}
splitJuryMembers(){
this.membersActive = this.members.filter((item)=> item.status === 'Invitation accepted' );
this.membersPending = this.members.filter((item)=> item.status === 'Invitation pending' );
this.membersInactive = this.members.filter((item)=> item.status === 'Deactivated' );
}
}
export default alt.createStore(PrizeJuryStore, 'PrizeJuryStore');

View File

@ -1,47 +0,0 @@
'use strict';
import { alt } from '../../../../../alt';
import PrizeRatingActions from '../actions/prize_rating_actions';
class PrizeRatingStore {
constructor() {
this.getInitialState();
this.bindActions(PrizeRatingActions);
this.exportPublicMethods({
getInitialState: this.getInitialState.bind(this)
});
}
getInitialState() {
this.ratings = [];
this.currentRating = null;
this.average = null;
return {
ratings: this.ratings,
currentRating: this.currentRating,
average: this.average
};
}
onUpdatePrizeRatings(ratings) {
this.ratings = ratings;
}
onUpdatePrizeRating(rating) {
this.currentRating = parseInt(rating, 10);
}
onUpdatePrizeRatingAverage(data) {
this.average = data.average;
this.ratings = data.ratings;
}
onResetPrizeRatings() {
this.getInitialState();
}
}
export default alt.createStore(PrizeRatingStore, 'PrizeRatingStore');

View File

@ -1,18 +0,0 @@
'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');

View File

@ -1,71 +0,0 @@
'use strict';
import React from 'react';
import Moment from 'moment';
import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import LoanForm from '../../../../../ascribe_forms/form_loan';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import ApiUrls from '../../../../../../constants/api_urls';
import { getLangText } from '../../../../../../utils/lang_utils';
const SluiceSelectedPrizeActionButton = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
piece: React.PropTypes.object.isRequired,
startLoanDate: React.PropTypes.object,
endLoanDate: React.PropTypes.object,
className: React.PropTypes.string,
handleSuccess: React.PropTypes.func
},
handleSuccess(res) {
const notification = new GlobalNotificationModel(res && res.notification || getLangText('You have successfully requested the loan, pending their confirmation.'), 'success', 4000);
GlobalNotificationActions.appendGlobalNotification(notification);
if (typeof this.props.handleSuccess === 'function') {
this.props.handleSuccess(res);
}
},
render() {
const { currentUser, piece } = this.props;
// Can't use default props since those are only created once
const startLoanDate = this.props.startLoanDate || new Moment();
const endLoanDate = this.props.endLoanDate || new Moment().add(6, 'months');
return (
<ModalWrapper
trigger={
<button className='btn btn-default btn-sm'>
{getLangText('SEND LOAN REQUEST')}
</button>
}
handleSuccess={this.handleSuccess}
title={getLangText('REQUEST LOAN')}>
<LoanForm
loanHeading={null}
message={getLangText('Congratulations,\nYou have been selected for the prize.\n' +
'Please accept the loan request to proceed.')}
id={{ piece_id: piece.id }}
url={ApiUrls.ownership_loans_pieces_request}
email={currentUser.email}
gallery={piece.prize.name}
startDate={startLoanDate}
endDate={endLoanDate}
showPersonalMessage={true}
showPassword={false} />
</ModalWrapper>
);
}
});
export default SluiceSelectedPrizeActionButton;

View File

@ -1,29 +0,0 @@
'use strict';
import React from 'react';
import SluiceSelectedPrizeActionButton from '../sluice_buttons/sluice_selected_prize_action_button';
import PrizePieceContainer from '../../../simple_prize/components/ascribe_detail/prize_piece_container';
const SluicePieceContainer = React.createClass({
propTypes: {
// Provided from PrizeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
location: React.PropTypes.object,
params: React.PropTypes.object
},
render() {
return (
<PrizePieceContainer
{...this.props}
selectedPrizeActionButton={SluiceSelectedPrizeActionButton} />
);
}
});
export default SluicePieceContainer;

View File

@ -8,7 +8,7 @@ import MarketPieceList from '../market/market_piece_list';
let Vivi23PieceList = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,

View File

@ -11,7 +11,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let ArtcityLanding = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired
},

View File

@ -31,7 +31,7 @@ import { mergeOptions } from '../../../../../../utils/general_utils';
let CylandPieceContainer = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,

View File

@ -14,7 +14,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let CylandLanding = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -10,7 +10,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let CylandPieceList = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -36,7 +36,7 @@ import { getAclFormMessage } from '../../../../../utils/form_utils';
let CylandRegisterPiece = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -25,7 +25,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let IkonotvContractNotifications = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -32,7 +32,7 @@ import { mergeOptions } from '../../../../../../utils/general_utils';
let IkonotvPieceContainer = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,

View File

@ -12,7 +12,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let IkonotvLanding = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,

View File

@ -14,7 +14,7 @@ import { getLangText } from '../../../../../utils/lang_utils';
let IkonotvPieceList = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -34,7 +34,7 @@ let IkonotvRegisterPiece = React.createClass({
propTypes: {
handleSuccess: React.PropTypes.func,
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -11,7 +11,7 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let LumenusLanding = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -14,7 +14,7 @@ let MarketPieceList = React.createClass({
propTypes: {
customThumbnailPlaceholder: React.PropTypes.func,
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -25,7 +25,7 @@ import { mergeOptions } from '../../../../../utils/general_utils';
let MarketRegisterPiece = React.createClass({
propTypes: {
// Provided from PrizeApp
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,

View File

@ -2,7 +2,6 @@
import AppConstants from './application_constants';
import getPrizeApiUrls from '../components/whitelabel/prize/constants/prize_api_urls';
import getWalletApiUrls from '../components/whitelabel/wallet/constants/wallet_api_urls';
import { update } from '../utils/general_utils';
@ -81,14 +80,9 @@ let ApiUrls = {
export function updateApiUrls(type, subdomain) {
let newUrls = {};
if (type === 'prize') {
newUrls = getPrizeApiUrls(subdomain);
} else if(type === 'wallet') {
newUrls = getWalletApiUrls(subdomain);
if (type === 'wallet') {
update(getWalletApiUrls(subdomain));
}
update(ApiUrls, newUrls);
}
export default ApiUrls;

View File

@ -27,12 +27,6 @@ const constants = {
'type': 'wallet',
'ga': 'UA-60614729-4'
},
{
'subdomain': 'sluice',
'name': 'Sluice Art Fair',
'type': 'prize',
'ga': 'UA-60614729-5'
},
{
'subdomain': 'cyland',
'name': 'Cyland media art lab',
@ -72,11 +66,6 @@ const constants = {
'subdomain': 'liquidgallery',
'name': 'Liquid Gallery',
'type': 'wallet'
},
{
'subdomain': 'portfolioreview',
'name': 'Portfolio Review',
'type': 'prize'
}
],
'defaultDomain': {

View File

@ -3,7 +3,6 @@
import React from 'react';
import { Route } from 'react-router';
import getPrizeRoutes from './components/whitelabel/prize/prize_routes';
import getWalletRoutes from './components/whitelabel/wallet/wallet_routes';
import AscribeApp from './components/ascribe_app';
@ -82,9 +81,7 @@ const COMMON_ROUTES = (
function getRoutes(type, subdomain) {
if (type === 'prize') {
return getPrizeRoutes(COMMON_ROUTES, subdomain);
} else if(type === 'wallet') {
if (type === 'wallet') {
return getWalletRoutes(COMMON_ROUTES, subdomain);
} else {
return COMMON_ROUTES;

View File

@ -1,3 +1,2 @@
@import 'prize/index';
@import 'wallet/index';

View File

@ -1,16 +0,0 @@
@import 'simple_prize/simple_prize_variables';
@import 'simple_prize/simple_prize_custom_style';
@import 'sluice/sluice_custom_style';
@import 'portfolioreview/portfolioreview_custom_style';
.ascribe-prize-app {
border-radius: 0;
padding-top: 70px;
padding-bottom: 10px;
}
@media print {
.ascribe-prize-app {
padding: 0 !important;
}
}

View File

@ -1,153 +0,0 @@
$pr--nav-fg-prim-color: black;
$pr--button-color: $pr--nav-fg-prim-color;
.client--portfolioreview {
.btn-wide,
.btn-default {
background-color: $pr--button-color;
border-color: $pr--button-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: lighten($pr--button-color, 20%);
border-color: lighten($pr--button-color, 20%);
}
}
.navbar-default {
.navbar-nav > .ascribe-powered-by, li > a {
color: $pr--button-color !important;
}
.active a {
border-bottom-color: $pr--button-color !important;
color: $pr--button-color !important;
}
}
.search-bar > .form-group > .input-group input {
&::-webkit-input-placeholder {
color: rgba($pr--button-color, 0.5);
}
&::-moz-placeholder {
color: rgba($pr--button-color, 0.5);
}
&:-ms-input-placeholder {
color: rgba($pr--button-color, 0.5);
}
&:-moz-placeholder {
color: rgba($pr--button-color, 0.5);
}
}
.icon-ascribe-search {
color: $pr--button-color;
}
// filter widget
.ascribe-piece-list-toolbar-widget button {
background-color: transparent !important;
border-color: transparent !important;
color: $pr--button-color !important;
&:hover,
&:active {
background-color: $pr--button-color !important;
border-color: $pr--button-color !important;
color: white !important;
}
}
.ascribe-property {
> div,
> input,
> pre,
> select,
> span:not(.glyphicon),
> p,
> p > span,
> textarea {
color: $pr--nav-fg-prim-color;
}
}
.ascribe-property-wrapper:hover {
border-left-color: lighten($pr--nav-fg-prim-color, 60%);
}
.is-focused {
border-left-color: $pr--nav-fg-prim-color !important;
background-color: lighten($pr--nav-fg-prim-color, 95%);
}
.register-piece--info {
text-align: center;
h1, h2 {
font-variant: small-caps;
}
h1 {
font-size: 5em;
color: #757575;
}
h2 {
font-size: 1.25em;
}
p {
margin-bottom: 0;
}
p + p {
margin-top: 0;
}
p:last-child {
margin-bottom: 1.5em;
}
}
.register-piece--form {
margin-top: 2em;
margin-bottom: 3em;
form {
border-top: none;
border-bottom: none;
}
}
.piece--hero {
text-align: center;
padding: 1em 0 1em 0;
margin-bottom: 3em;
border-bottom: 1px solid rgba(0, 0, 0, .1);
background-color: white;
h2 {
margin-top: 0;
}
}
.ascribe-property {
> p > span:not(> .span) {
text-transform: capitalize;
}
}
// intercom
#intercom-container .intercom-launcher-button {
background-color: $pr--button-color !important;
border-color: $pr--button-color !important;
}
}

View File

@ -1,70 +0,0 @@
.wp {
height: 100%;
max-width: 90%;
margin: auto;
/* We need this, otherwise piece list will have a scrollbar */
}
.hero {
font-family: 'Nunito', sans-serif;
font-weight: 300;
overflow: hidden;
text-align: center;
> img {
margin-top: 5em;
margin-bottom: 5em;
}
}
.wp-landing-wrapper {
text-align: center;
font-family: 'Nunito', sans-serif;
font-weight: 300;
> .enter {
margin-top: 2em;
> p {
margin-top: 2em;
}
}
}
.rating-container {
color: lighten($simple-prize--nav-fg-prim-color, 80%) !important;
.rating-stars {
width: 25px;
color: $simple-prize--nav-fg-prim-color !important;
}
}
#list-rating {
> a > span > span > .rating-container .rating-stars {
color: #000;
}
> span > span > span > .rating-container .rating-stars {
color: #000;
}
> span > span > .rating-container .rating-stars {
color: #000;
}
}
.react-rating-caption {
font-size: 1em;
}
.rating-list {
margin-left: 1.5em;
font-size: 0.9em;
margin-bottom: 0.3em;
color: #333;
}
.rating-note {
color: #666;
font-style: italic;
padding: 0.7em;
}

View File

@ -1,3 +0,0 @@
$simple-prize--nav-bg-color: #fcfcfc;
$simple-prize--nav-fg-prim-color: #1E1E1E;
$simple-prize--button-color: $simple-prize--nav-fg-prim-color;

View File

@ -1,178 +0,0 @@
.client--sluice {
.navbar-default {
background-color: $simple-prize--nav-bg-color;
box-shadow: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.navbar-nav > li > a,
.navbar-nav > li > .active a {
color: $simple-prize--nav-fg-prim-color;
background-color: $simple-prize--nav-bg-color;
}
.navbar-nav > li > a:hover {
color: lighten($simple-prize--nav-fg-prim-color, 40%);
}
.navbar-nav > .active a,
.navbar-nav > .active a:hover,
.navbar-nav > .active a:focus {
color: $simple-prize--nav-fg-prim-color;
border-bottom-color: $simple-prize--nav-fg-prim-color;
background-color: $simple-prize--nav-bg-color;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
color: lighten($simple-prize--nav-fg-prim-color, 40%);
background-color: $simple-prize--nav-bg-color;
}
.navbar-nav > .open > a,
.navbar-nav > .open > a:hover,
.navbar-nav > .open > a:focus,
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
color: lighten($simple-prize--nav-fg-prim-color, 40%);
background-color: $simple-prize--nav-bg-color;
}
.dropdown-menu {
background-color: $simple-prize--nav-bg-color;
}
.dropdown-menu > li > a {
color: $simple-prize--nav-fg-prim-color;
}
.navbar-toggle .icon-bar {
background-color: $simple-prize--nav-fg-prim-color;
}
.navbar-toggle:hover,
.navbar-toggle:focus {
background-color: $simple-prize--nav-bg-color;
}
}
.client--sluice .ascribe-footer {
display: none;
}
.client--sluice .icon-ascribe-search{
color: $simple-prize--button-color;
}
// disabled buttons
.client--sluice {
.btn-default.disabled,
.btn-default.disabled:hover,
.btn-default.disabled:focus,
.btn-default.disabled.focus,
.btn-default.disabled:active,
.btn-default.disabled.active,
.btn-default[disabled],
.btn-default[disabled]:hover,
.btn-default[disabled]:focus,
.btn-default[disabled].focus,
.btn-default[disabled]:active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-default:hover,
fieldset[disabled] .btn-default:focus,
fieldset[disabled] .btn-default.focus,
fieldset[disabled] .btn-default:active,
fieldset[disabled] .btn-default.active {
background-color: darken($simple-prize--button-color, 20%);
border-color: darken($simple-prize--button-color, 20%);
}
}
// buttons!
// thought of the day:
// "every great atrocity is the result of people just following orders"
.client--sluice {
.ascribe-piece-list-toolbar-widget button {
color: $simple-prize--button-color !important;
background-color: transparent !important;
border-color: transparent !important;
&:hover,
&:active {
background-color: $simple-prize--button-color !important;
border-color: $simple-prize--button-color !important;
color: white !important;
}
}
.btn-wide,
.btn-default {
background-color: $simple-prize--button-color;
border-color: $simple-prize--button-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: lighten($simple-prize--button-color, 20%);
border-color: lighten($simple-prize--button-color, 20%);
}
}
.open > .btn-default.dropdown-toggle:hover,
.open > .btn-default.dropdown-toggle:focus,
.open > .btn-default.dropdown-toggle.focus,
.open > .btn-default.dropdown-toggle.dropdown-toggle {
background-color: darken($simple-prize--button-color, 20%);
border-color: darken($simple-prize--button-color, 20%);
}
.pager li > a, .pager li > span {
background-color: $simple-prize--button-color;
border-color: $simple-prize--button-color;
}
.pager li.disabled > a,
.pager li.disabled > span {
background-color: $simple-prize--button-color !important;
border-color: $simple-prize--button-color;
}
}
// spinner!
.client--sluice {
.btn-spinner {
color: $simple-prize--button-color;
}
.spinner-circle {
border-color: $simple-prize--button-color;
}
.spinner-inner {
color: $simple-prize--button-color;
display: none;
}
}
// intercom stuff
.client--sluice {
#intercom-container .intercom-launcher-button {
background-color: $simple-prize--button-color !important;;
border-color: $simple-prize--button-color !important;;
}
}
// notifications
.client--sluice .ascribe-global-notification-success {
background-color: lighten($simple-prize--button-color, 50%);
}
// progress bar
.client--sluice .ascribe-progress-bar > .progress-bar {
background-color: $simple-prize--button-color;
}
.client--sluice .acl-information-dropdown-list .title {
color: $simple-prize--button-color;
}