1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 09:23:13 +01:00

Merge remote-tracking branch 'origin/master' into AD-538-users-and-even-devs-are-unsure-wh

Conflicts:
	js/components/ascribe_detail/edition.js
	js/utils/general_utils.js
	sass/main.scss
This commit is contained in:
Tim Daubenschütz 2015-10-15 10:06:39 +02:00
commit a1f159fc2d
84 changed files with 500 additions and 262 deletions

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import ApplicationFetcher from '../fetchers/application_fetcher';

View File

@ -1,8 +1,9 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import CoaFetcher from '../fetchers/coa_fetcher';
import Q from 'q';
class CoaActions {
constructor() {
@ -12,23 +13,38 @@ class CoaActions {
);
}
fetchOne(id) {
CoaFetcher.fetchOne(id)
.then((res) => {
this.actions.updateCoa(res.coa);
})
.catch((err) => {
console.logGlobal(err);
});
fetchOrCreate(id, bitcoinId) {
return Q.Promise((resolve, reject) => {
CoaFetcher.fetchOne(id)
.then((res) => {
if (res.coa) {
this.actions.updateCoa(res.coa);
resolve(res.coa);
}
else {
this.actions.create(bitcoinId);
}
})
.catch((err) => {
console.logGlobal(err);
this.actions.updateCoa(null);
reject(err);
});
});
}
create(edition) {
CoaFetcher.create(edition.bitcoin_id)
.then((res) => {
this.actions.updateCoa(res.coa);
})
.catch((err) => {
console.logGlobal(err);
});
create(bitcoinId) {
return Q.Promise((resolve, reject) => {
CoaFetcher.create(bitcoinId)
.then((res) => {
this.actions.updateCoa(res.coa);
})
.catch((err) => {
console.logGlobal(err);
this.actions.updateCoa(null);
reject(err);
});
});
}
}

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import Q from 'q';
import OwnershipFetcher from '../fetchers/ownership_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import OwnershipFetcher from '../fetchers/ownership_fetcher';
import Q from 'q';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import EditionFetcher from '../fetchers/edition_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import Q from 'q';
import EditionListFetcher from '../fetchers/edition_list_fetcher.js';
@ -33,6 +33,10 @@ class EditionListActions {
EditionListFetcher
.fetch(pieceId, page, pageSize, orderBy, orderAsc, filterBy)
.then((res) => {
if(res && !res.editions) {
throw new Error('Piece has no editions to fetch.');
}
this.actions.updateEditionList({
pieceId,
page,
@ -46,6 +50,7 @@ class EditionListActions {
resolve(res);
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
});

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
class EventActions {
@ -16,4 +16,4 @@ class EventActions {
}
}
export default alt.createActions(EventActions);
export default altThirdParty.createActions(EventActions);

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
class GlobalNotificationActions {

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import LicenseFetcher from '../fetchers/license_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import Q from 'q';
import NotificationFetcher from '../fetchers/notification_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import OwnershipFetcher from '../fetchers/ownership_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import PieceFetcher from '../fetchers/piece_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import Q from 'q';
import PieceListFetcher from '../fetchers/piece_list_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import Q from 'q';
import PrizeListFetcher from '../fetchers/prize_list_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altUser } from '../alt';
import UserFetcher from '../fetchers/user_fetcher';
@ -34,4 +34,4 @@ class UserActions {
}
}
export default alt.createActions(UserActions);
export default altUser.createActions(UserActions);

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import WalletSettingsFetcher from '../fetchers/wallet_settings_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altWhitelabel } from '../alt';
import WhitelabelFetcher from '../fetchers/whitelabel_fetcher';
@ -26,4 +26,4 @@ class WhitelabelActions {
}
}
export default alt.createActions(WhitelabelActions);
export default altWhitelabel.createActions(WhitelabelActions);

View File

@ -2,4 +2,7 @@
import Alt from 'alt';
export default new Alt();
export let alt = new Alt();
export let altThirdParty = new Alt();
export let altUser = new Alt();
export let altWhitelabel = new Alt();

View File

@ -10,13 +10,15 @@ import fetch from 'isomorphic-fetch';
/* eslint-enable */
import ApiUrls from './constants/api_urls';
import { updateApiUrls } from './constants/api_urls';
import appConstants from './constants/application_constants';
import AppConstants from './constants/application_constants';
import getRoutes from './routes';
import requests from './utils/requests';
import { updateApiUrls } from './constants/api_urls';
import { getSubdomainSettings } from './utils/constants_utils';
import { initLogging } from './utils/error_utils';
import { getSubdomain } from './utils/general_utils';
import EventActions from './actions/event_actions';
@ -48,11 +50,11 @@ requests.defaults({
class AppGateway {
start() {
let settings;
let subdomain = window.location.host.split('.')[0];
let subdomain = getSubdomain();
try {
settings = getSubdomainSettings(subdomain);
appConstants.whitelabel = settings;
AppConstants.whitelabel = settings;
updateApiUrls(settings.type, subdomain);
this.load(settings);
} catch(err) {

View File

@ -6,7 +6,7 @@ import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store';
import AclButton from '../ascribe_buttons/acl_button';
import {getLangText} from '../../utils/lang_utils';
let AclButtonList = React.createClass({
propTypes: {
@ -16,7 +16,6 @@ let AclButtonList = React.createClass({
React.PropTypes.array
]),
availableAcls: React.PropTypes.object,
actionsLabelStyle: React.PropTypes.object,
buttonsStyle: React.PropTypes.object,
handleSuccess: React.PropTypes.func,
children: React.PropTypes.oneOfType([

View File

@ -6,15 +6,11 @@ import Router from 'react-router';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import Button from 'react-bootstrap/lib/Button';
import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store';
import CoaActions from '../../actions/coa_actions';
import CoaStore from '../../stores/coa_store';
import PieceListActions from '../../actions/piece_list_actions';
import PieceListStore from '../../stores/piece_list_store';
import EditionListActions from '../../actions/edition_list_actions';
import HistoryIterator from './history_iterator';
@ -28,14 +24,7 @@ import EditionDetailProperty from './detail_property';
import LicenseDetail from './license_detail';
import EditionFurtherDetails from './further_details';
import ListRequestActions from './../ascribe_forms/list_form_request_actions';
import AclButtonList from './../ascribe_buttons/acl_button_list';
import UnConsignRequestButton from './../ascribe_buttons/unconsign_request_button';
import DeleteButton from './../ascribe_buttons/delete_button';
import AclInformationButton from './../ascribe_buttons/acl_information_button';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import EditionActionPanel from './edition_action_panel';
import Note from './note';
@ -43,7 +32,6 @@ import ApiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils';
import { mergeOptions } from '../../utils/general_utils';
let Link = Router.Link;
/**
@ -58,15 +46,11 @@ let Edition = React.createClass({
mixins: [Router.Navigation],
getInitialState() {
return mergeOptions(
UserStore.getState(),
PieceListStore.getState()
);
return UserStore.getState();
},
componentDidMount() {
UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
UserActions.fetchCurrentUser();
},
@ -81,31 +65,12 @@ let Edition = React.createClass({
CoaActions.flushCoa();
UserStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
handleDeleteSuccess(response) {
this.refreshCollection();
EditionListActions.closeAllEditionLists();
EditionListActions.clearAllEditionSelections();
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
this.transitionTo('pieces');
},
refreshCollection() {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
EditionListActions.refreshEditionList({pieceId: this.props.edition.parent});
},
render() {
return (
<Row>
@ -122,12 +87,9 @@ let Edition = React.createClass({
<hr/>
</div>
<EditionSummary
handleSuccess={this.props.loadEdition}
refreshCollection={this.refreshCollection}
currentUser={this.state.currentUser}
edition={this.props.edition}
handleDeleteSuccess={this.handleDeleteSuccess}/>
currentUser={this.state.currentUser}
handleSuccess={this.props.loadEdition}/>
<CollapsibleParagraph
title={getLangText('Certificate of Authenticity')}
show={this.props.edition.acl.acl_coa === true}>
@ -208,29 +170,14 @@ let Edition = React.createClass({
let EditionSummary = React.createClass({
propTypes: {
edition: React.PropTypes.object,
handleSuccess: React.PropTypes.func,
currentUser: React.PropTypes.object,
handleDeleteSuccess: React.PropTypes.func,
refreshCollection: React.PropTypes.func
},
getTransferWithdrawData(){
return {'bitcoin_id': this.props.edition.bitcoin_id};
handleSuccess: React.PropTypes.func
},
handleSuccess() {
this.props.refreshCollection();
this.props.handleSuccess();
},
showNotification(response){
this.props.handleSuccess();
if (response){
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
},
getStatus(){
let status = null;
if (this.props.edition.status.length > 0){
@ -244,92 +191,27 @@ let EditionSummary = React.createClass({
}
return status;
},
getVerbList(){
let verbsToCheck = ['acl_transfer', 'acl_consign', 'acl_loan', 'acl_share', 'acl_delete'];
let verbListIndices = [];
let acl = this.props.edition.acl;
Object.keys(acl).forEach((key) => {
let index = verbsToCheck.indexOf(key);
if (acl[key] === true && index !== -1) {
verbListIndices.push(verbsToCheck[index].slice(4));
}
});
return verbListIndices;
},
getActions(){
let actions = null;
if (this.props.edition &&
this.props.edition.notifications &&
this.props.edition.notifications.length > 0){
actions = (
<ListRequestActions
pieceOrEditions={[this.props.edition]}
currentUser={this.props.currentUser}
handleSuccess={this.showNotification}
notifications={this.props.edition.notifications}/>);
}
else {
let withdrawButton = null;
if (this.props.edition.status.length > 0 && this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer) {
withdrawButton = (
<Form
url={ApiUrls.ownership_transfers_withdraw}
getFormData={this.getTransferWithdrawData}
handleSuccess={this.showNotification}
className='inline'
isInline={true}>
<Button bsStyle="danger" className="btn-delete pull-center" bsSize="small" type="submit">
WITHDRAW TRANSFER
</Button>
</Form>
);
}
let unconsignRequestButton = null;
if (this.props.edition.acl.acl_request_unconsign) {
unconsignRequestButton = (
<UnConsignRequestButton
currentUser={this.props.currentUser}
edition={this.props.edition}
handleSuccess={this.props.handleSuccess} />
);
}
actions = (
<Row>
<Col md={11}>
<AclButtonList
className="ascribe-button-list ascribe-button-list-detail"
availableAcls={this.props.edition.acl}
editions={[this.props.edition]}
handleSuccess={this.handleSuccess}>
{withdrawButton}
<DeleteButton
handleSuccess={this.props.handleDeleteSuccess}
editions={[this.props.edition]}/>
{unconsignRequestButton}
<AclInformationButton verbs = {this.getVerbList()}/>
</AclButtonList>
</Col>
</Row>);
}
return actions;
},
render() {
let { edition, currentUser } = this.props;
return (
<div className="ascribe-detail-header">
<EditionDetailProperty
label={getLangText('EDITION')}
value={this.props.edition.edition_number + ' ' + getLangText('of') + ' ' + this.props.edition.num_editions} />
value={ edition.edition_number + ' ' + getLangText('of') + ' ' + edition.num_editions} />
<EditionDetailProperty
label={getLangText('ID')}
value={ this.props.edition.bitcoin_id }
value={ edition.bitcoin_id }
ellipsis={true} />
<EditionDetailProperty
label={getLangText('OWNER')}
value={ this.props.edition.owner } />
<LicenseDetail license={this.props.edition.license_type}/>
value={ edition.owner } />
<LicenseDetail license={edition.license_type}/>
{this.getStatus()}
<hr />
{this.getActions()}
<EditionActionPanel
edition={edition}
currentUser={currentUser}
handleSuccess={this.handleSuccess} />
<hr/>
</div>
);
@ -347,12 +229,13 @@ let CoaDetails = React.createClass({
},
componentDidMount() {
let { edition } = this.props;
CoaStore.listen(this.onChange);
if(this.props.edition.coa) {
CoaActions.fetchOne(this.props.edition.coa);
if(edition.coa) {
CoaActions.fetchOrCreate(edition.coa, edition.bitcoin_id);
}
else {
CoaActions.create(this.props.edition);
CoaActions.create(edition.bitcoin_id);
}
},

View File

@ -0,0 +1,185 @@
'use strict';
import React from 'react';
import Router from 'react-router';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Button from 'react-bootstrap/lib/Button';
import EditionListActions from '../../actions/edition_list_actions';
import PieceListActions from '../../actions/piece_list_actions';
import PieceListStore from '../../stores/piece_list_store';
import Form from './../ascribe_forms/form';
import Property from './../ascribe_forms/property';
import ListRequestActions from './../ascribe_forms/list_form_request_actions';
import AclButtonList from './../ascribe_buttons/acl_button_list';
import UnConsignRequestButton from './../ascribe_buttons/unconsign_request_button';
import DeleteButton from '../ascribe_buttons/delete_button';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import AclInformationButton from '../ascribe_buttons/acl_information_button';
import AclProxy from '../acl_proxy';
import ApiUrls from '../../constants/api_urls';
import { getLangText } from '../../utils/lang_utils';
/*
A component that handles all the actions inside of the edition detail
handleSuccess requires a loadEdition action (could be refactored)
*/
let EditionActionPanel = React.createClass({
propTypes: {
edition: React.PropTypes.object,
currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
mixins: [Router.Navigation],
getInitialState() {
return PieceListStore.getState();
},
componentDidMount() {
PieceListStore.listen(this.onChange);
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
handleDeleteSuccess(response) {
this.refreshCollection();
EditionListActions.closeAllEditionLists();
EditionListActions.clearAllEditionSelections();
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
this.transitionTo('pieces');
},
refreshCollection() {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
EditionListActions.refreshEditionList({pieceId: this.props.edition.parent});
},
handleSuccess(response){
this.refreshCollection();
this.props.handleSuccess();
if (response){
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
},
getVerbList(){
let verbsToCheck = ['acl_transfer', 'acl_consign', 'acl_loan', 'acl_share', 'acl_delete'];
let verbListIndices = [];
let acl = this.props.edition.acl;
Object.keys(acl).forEach((key) => {
let index = verbsToCheck.indexOf(key);
if (acl[key] && index !== -1) {
verbListIndices.push(verbsToCheck[index].slice(4));
}
});
return verbListIndices;
},
render(){
let {edition, currentUser} = this.props;
if (edition &&
edition.notifications &&
edition.notifications.length > 0){
return (
<ListRequestActions
pieceOrEditions={[edition]}
currentUser={currentUser}
handleSuccess={this.handleSuccess}
notifications={edition.notifications}/>);
}
else {
return (
<Row>
<Col md={12}>
<AclButtonList
className="text-center ascribe-button-list"
availableAcls={edition.acl}
editions={[edition]}
handleSuccess={this.handleSuccess}>
<AclProxy
aclObject={edition.acl}
aclName="acl_withdraw_transfer">
<Form
url={ApiUrls.ownership_transfers_withdraw}
handleSuccess={this.handleSuccess}
className='inline'
isInline={true}>
<Property
name="bitcoin_id"
hidden={true}>
<input
type="text"
value={edition.bitcoin_id} />
</Property>
<Button bsStyle="danger" className="btn-delete pull-center" bsSize="small" type="submit">
{getLangText('WITHDRAW TRANSFER')}
</Button>
</Form>
</AclProxy>
<AclProxy
aclObject={edition.acl}
aclName="acl_withdraw_consign">
<Form
url={ApiUrls.ownership_consigns_withdraw}
handleSuccess={this.handleSuccess}
className='inline'
isInline={true}>
<Property
name="bitcoin_id"
hidden={true}>
<input
type="text"
value={edition.bitcoin_id} />
</Property>
<Button bsStyle="danger" className="btn-delete pull-center" bsSize="small" type="submit">
{getLangText('WITHDRAW CONSIGN')}
</Button>
</Form>
</AclProxy>
<AclProxy
aclObject={edition.acl}
aclName="acl_request_unconsign">
<UnConsignRequestButton
currentUser={currentUser}
edition={edition}
handleSuccess={this.handleSuccess} />
</AclProxy>
<DeleteButton
handleSuccess={this.handleDeleteSuccess}
editions={[edition]}/>
<AclInformationButton aim="button" verbs = {this.getVerbList()}/>
</AclButtonList>
</Col>
</Row>
);
}
}
});
export default EditionActionPanel;

View File

@ -43,7 +43,7 @@ let FurtherDetailsFileuploader = React.createClass({
return (
<Property
label="Additional files (max. 50MB per file)">
label="Additional files">
<ReactS3FineUploader
uploadStarted={this.props.uploadStarted}
keyRoutine={{

View File

@ -44,6 +44,10 @@ let LoginForm = React.createClass({
componentDidMount() {
UserStore.listen(this.onChange);
let { redirect } = this.getQuery();
if (redirect && redirect !== 'login'){
this.transitionTo(redirect, null, this.getQuery());
}
},
componentWillUnmount() {
@ -56,6 +60,15 @@ let LoginForm = React.createClass({
// if user is already logged in, redirect him to piece list
if(this.state.currentUser && this.state.currentUser.email && this.props.redirectOnLoggedIn) {
// FIXME: hack to redirect out of the dispatch cycle
let { redirectAuthenticated } = this.getQuery();
if ( redirectAuthenticated) {
/*
* redirectAuthenticated contains an arbirary path
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
* hence transitionTo cannot be used directly
*/
window.location = AppConstants.baseUrl + redirectAuthenticated;
}
window.setTimeout(() => this.transitionTo('pieces'), 0);
}
},
@ -79,7 +92,13 @@ let LoginForm = React.createClass({
Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future.
Until then, we redirect the HARD way, but reloading the whole page using window.location
*/
window.location = AppConstants.baseUrl + 'collection';
let { redirectAuthenticated } = this.getQuery();
if ( redirectAuthenticated) {
window.location = AppConstants.baseUrl + redirectAuthenticated;
}
else {
window.location = AppConstants.baseUrl + 'collection';
}
} else if(this.props.onLogin) {
// In some instances we want to give a callback to an outer container,
// to show that the one login action the user triggered actually went through.

View File

@ -14,6 +14,7 @@ import Form from './form';
import Property from './property';
import InputCheckbox from './input_checkbox';
import AppConstants from '../../constants/application_constants';
import ApiUrls from '../../constants/api_urls';
@ -40,6 +41,10 @@ let SignupForm = React.createClass({
componentDidMount() {
UserStore.listen(this.onChange);
let { redirect } = this.getQuery();
if (redirect && redirect !== 'signup'){
this.transitionTo(redirect, null, this.getQuery());
}
},
componentWillUnmount() {
@ -51,7 +56,16 @@ let SignupForm = React.createClass({
// if user is already logged in, redirect him to piece list
if(this.state.currentUser && this.state.currentUser.email) {
this.transitionTo('pieces');
let { redirectAuthenticated } = this.getQuery();
if ( redirectAuthenticated) {
/*
* redirectAuthenticated contains an arbirary path
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
* hence transitionTo cannot be used directly
*/
window.location = AppConstants.baseUrl + redirectAuthenticated;
}
window.setTimeout(() => this.transitionTo('pieces'));
}
},
@ -62,6 +76,15 @@ let SignupForm = React.createClass({
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.');
}
else if (response.redirect) {
let { redirectAuthenticated } = this.getQuery();
if ( redirectAuthenticated) {
/*
* redirectAuthenticated contains an arbirary path
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
* hence transitionTo cannot be used directly
*/
window.location = AppConstants.baseUrl + redirectAuthenticated;
}
this.transitionTo('pieces');
}
},

View File

@ -22,6 +22,7 @@ let InputCheckbox = React.createClass({
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
]),
name: React.PropTypes.string,
// provided by Property
disabled: React.PropTypes.bool,
@ -50,7 +51,7 @@ let InputCheckbox = React.createClass({
// Developer's are used to define defaultValues for inputs via defaultValue, but since this is a
// input of type checkbox we warn the dev to not do that.
if(this.props.defaultValue) {
if(this.props.defaultValue) { //eslint-disable-line react/prop-types
console.warn('InputCheckbox is of type checkbox. Therefore its value is represented by checked and defaultChecked. defaultValue will do nothing!');
}
@ -102,8 +103,10 @@ let InputCheckbox = React.createClass({
return (
<span
style={this.props.style}
onClick={this.onChange}>
onClick={this.onChange}
name={this.props.name}>
<input
name={this.props.name}
type="checkbox"
ref="checkbox"
onChange={this.onChange}
@ -119,4 +122,4 @@ let InputCheckbox = React.createClass({
}
});
export default InputCheckbox;
export default InputCheckbox;

View File

@ -31,6 +31,7 @@ let Property = React.createClass({
footer: React.PropTypes.element,
handleChange: React.PropTypes.func,
ignoreFocus: React.PropTypes.bool,
name: React.PropTypes.string.isRequired,
className: React.PropTypes.string,
onClick: React.PropTypes.func,
@ -210,7 +211,8 @@ let Property = React.createClass({
onFocus: this.handleFocus,
onBlur: this.handleBlur,
disabled: !this.props.editable,
ref: 'input'
ref: 'input',
name: this.props.name
});
});
},
@ -260,4 +262,4 @@ let Property = React.createClass({
}
});
export default Property;
export default Property;

View File

@ -33,21 +33,28 @@ let PieceListBulkModal = React.createClass({
);
},
onChange(state) {
this.setState(state);
},
componentDidMount() {
EditionListStore.listen(this.onChange);
UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
UserActions.fetchCurrentUser();
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
},
componentWillUnmount() {
EditionListStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
fetchSelectedPieceEditionList() {
let filteredPieceIdList = Object.keys(this.state.editionList)
.filter((pieceId) => {

View File

@ -0,0 +1,25 @@
'use strict';
import React from 'react';
import { getLangText } from '../utils/lang_utils';
let ErrorNotFoundPage = React.createClass({
render() {
return (
<div className="row">
<div className="col-md-12">
<div className="error-wrapper">
<h1>404</h1>
<p>
{getLangText('Ups, the page you are looking for does not exist.')}
</p>
</div>
</div>
</div>
);
}
});
export default ErrorNotFoundPage;

View File

@ -4,7 +4,7 @@ import React from 'react';
import Router from 'react-router';
import UserActions from '../actions/user_actions';
import Alt from '../alt';
import { alt, altWhitelabel, altUser, altThirdParty } from '../alt';
import AppConstants from '../constants/application_constants';
let baseUrl = AppConstants.baseUrl;
@ -16,7 +16,10 @@ let LogoutContainer = React.createClass({
componentDidMount() {
UserActions.logoutCurrentUser()
.then(() => {
Alt.flush();
alt.flush();
altWhitelabel.flush();
altUser.flush();
altThirdParty.flush();
// kill intercom (with fire)
window.Intercom('shutdown');
this.replaceWith(baseUrl);

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import Q from 'q';
import PrizeFetcher from '../fetchers/prize_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import Q from 'q';
import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import Q from 'q';
import PrizeRatingFetcher from '../fetchers/prize_rating_fetcher';

View File

@ -9,6 +9,9 @@ import GlobalNotification from '../../global_notification';
import getRoutes from './prize_routes';
import { getSubdomain } from '../../../utils/general_utils';
let RouteHandler = Router.RouteHandler;
let PrizeApp = React.createClass({
@ -16,7 +19,7 @@ let PrizeApp = React.createClass({
render() {
let header = null;
let subdomain = window.location.host.split('.')[0];
let subdomain = getSubdomain();
let ROUTES = getRoutes(null, subdomain);

View File

@ -14,11 +14,13 @@ import PrizePieceContainer from './components/ascribe_detail/prize_piece_contain
import EditionContainer from '../../ascribe_detail/edition_container';
import SettingsContainer from './components/prize_settings_container';
import CoaVerifyContainer from '../../../components/coa_verify_container';
import ErrorNotFoundPage from '../../../components/error_not_found_page';
import App from './prize_app';
import AppConstants from '../../../constants/application_constants';
let Route = Router.Route;
let NotFoundRoute = Router.NotFoundRoute;
let baseUrl = AppConstants.baseUrl;
@ -36,6 +38,7 @@ function getRoutes() {
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
<Route name="settings" path="settings" handler={SettingsContainer} />
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
</Route>
);
}

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import PrizeJuryActions from '../actions/prize_jury_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import PrizeRatingActions from '../actions/prize_rating_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../../../../alt';
import { alt } from '../../../../alt';
import PrizeActions from '../actions/prize_actions';

View File

@ -49,7 +49,7 @@ let WalletActionPanel = React.createClass({
className="text-center ascribe-button-list"
availableAcls={availableAcls}
editions={this.props.piece}
handleSuccess={this.loadPiece}>
handleSuccess={this.props.loadPiece}>
<AclProxy
aclObject={this.props.currentUser.acl}
aclName="acl_wallet_submit">
@ -58,7 +58,6 @@ let WalletActionPanel = React.createClass({
aclName="acl_wallet_submit">
<SubmitButtonType
className="btn-sm"
handleSuccess={this.handleSubmitSuccess}
piece={this.props.piece}/>
</AclProxy>
</AclProxy>

View File

@ -12,7 +12,7 @@ import UserStore from '../../../../../../stores/user_store';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import CylandSubmitButton from '../ascribe_buttons/cyland_submit_button';
import CylandSubmitButton from '../cyland_buttons/cyland_submit_button';
import AclProxy from '../../../../../acl_proxy';
import { getLangText } from '../../../../../../utils/lang_utils';

View File

@ -10,6 +10,7 @@ import WhitelabelStore from '../../../../../../stores/whitelabel_store';
import { getLangText } from '../../../../../../utils/lang_utils';
let CylandSubmitButton = React.createClass({
propTypes: {
className: React.PropTypes.string,

View File

@ -7,11 +7,11 @@ import PieceStore from '../../../../../../stores/piece_store';
import UserStore from '../../../../../../stores/user_store';
import CylandSubmitButton from '../ascribe_buttons/cyland_submit_button';
import CylandSubmitButton from '../cyland_buttons/cyland_submit_button';
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
import CylandAdditionalDataForm from '../ascribe_forms/cyland_additional_data_form';
import CylandAdditionalDataForm from '../cyland_forms/cyland_additional_data_form';
import WalletPieceContainer from '../../ascribe_detail/wallet_piece_container';
@ -21,6 +21,10 @@ import { getLangText } from '../../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';
let CylandPieceContainer = React.createClass({
propTypes: {
params: React.PropTypes.object
},
getInitialState() {
return mergeOptions(
PieceStore.getState(),

View File

@ -35,17 +35,17 @@ let CylandAdditionalDataForm = React.createClass({
};
},
handleSuccess() {
let notification = new GlobalNotificationModel('Further details successfully updated', 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getInitialState() {
return {
isUploadReady: true
};
},
handleSuccess() {
let notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getFormData() {
let extradata = {};
let formRefs = this.refs.form.refs;

View File

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

View File

@ -3,7 +3,6 @@
import React from 'react';
import Router from 'react-router';
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../stores/whitelabel_store';

View File

@ -6,7 +6,7 @@ import PieceList from '../../../../piece_list';
import UserActions from '../../../../../actions/user_actions';
import UserStore from '../../../../../stores/user_store';
import CylandAccordionListItem from './ascribe_accordion_list/cyland_accordion_list_item';
import CylandAccordionListItem from './cyland_accordion_list/cyland_accordion_list_item';
import { getLangText } from '../../../../../utils/lang_utils';

View File

@ -25,7 +25,7 @@ import PieceActions from '../../../../../actions/piece_actions';
import GlobalNotificationModel from '../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../actions/global_notification_actions';
import CylandAdditionalDataForm from './ascribe_forms/cyland_additional_data_form';
import CylandAdditionalDataForm from './cyland_forms/cyland_additional_data_form';
import LoanForm from '../../../../ascribe_forms/form_loan';

View File

@ -12,7 +12,7 @@ import UserStore from '../../../../../../stores/user_store';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button';
import IkonotvSubmitButton from '../ikonotv_buttons/ikonotv_submit_button';
import AclProxy from '../../../../../acl_proxy';

View File

@ -9,7 +9,6 @@ import { getLangText } from '../../../../../../utils/lang_utils';
let IkonotvSubmitButton = React.createClass({
propTypes: {
className: React.PropTypes.string,
handleSuccess: React.PropTypes.func,
piece: React.PropTypes.object.isRequired
},

View File

@ -7,13 +7,12 @@ import PieceStore from '../../../../../../stores/piece_store';
import UserStore from '../../../../../../stores/user_store';
import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button';
import IkonotvSubmitButton from '../ikonotv_buttons/ikonotv_submit_button';
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
import IkonotvArtistDetailsForm from '../ascribe_forms/ikonotv_artist_details_form';
import IkonotvArtworkDetailsForm from '../ascribe_forms/ikonotv_artwork_details_form';
import IkonotvArtistDetailsForm from '../ikonotv_forms/ikonotv_artist_details_form';
import IkonotvArtworkDetailsForm from '../ikonotv_forms/ikonotv_artwork_details_form';
import WalletPieceContainer from '../../ascribe_detail/wallet_piece_container';
@ -22,7 +21,12 @@ import AppConstants from '../../../../../../constants/application_constants';
import { getLangText } from '../../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';
let IkonotvPieceContainer = React.createClass({
propTypes: {
params: React.PropTypes.object
},
getInitialState() {
return mergeOptions(
PieceStore.getState(),

View File

@ -6,7 +6,7 @@ import PieceList from '../../../../piece_list';
import UserActions from '../../../../../actions/user_actions';
import UserStore from '../../../../../stores/user_store';
import IkonotvAccordionListItem from './ascribe_accordion_list/ikonotv_accordion_list_item';
import IkonotvAccordionListItem from './ikonotv_accordion_list/ikonotv_accordion_list_item';
import { getLangText } from '../../../../../utils/lang_utils';

View File

@ -22,8 +22,8 @@ import GlobalNotificationActions from '../../../../../actions/global_notificatio
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import LoanForm from '../../../../ascribe_forms/form_loan';
import IkonotvArtistDetailsForm from './ascribe_forms/ikonotv_artist_details_form';
import IkonotvArtworkDetailsForm from './ascribe_forms/ikonotv_artwork_details_form';
import IkonotvArtistDetailsForm from './ikonotv_forms/ikonotv_artist_details_form';
import IkonotvArtworkDetailsForm from './ikonotv_forms/ikonotv_artwork_details_form';
import SlidesContainer from '../../../../ascribe_slides_container/slides_container';

View File

@ -10,6 +10,8 @@ import GlobalNotification from '../../global_notification';
import getRoutes from './wallet_routes';
import classNames from 'classnames';
import { getSubdomain } from '../../../utils/general_utils';
let RouteHandler = Router.RouteHandler;
@ -18,7 +20,7 @@ let WalletApp = React.createClass({
mixins: [Router.State],
render() {
let subdomain = window.location.host.split('.')[0];
let subdomain = getSubdomain();
let ROUTES = getRoutes(null, subdomain);
let activeRoutes = this.getRoutes().map(elem => 'route--' + elem.name);

View File

@ -14,9 +14,10 @@ import PieceContainer from '../../../components/ascribe_detail/piece_container';
import EditionContainer from '../../../components/ascribe_detail/edition_container';
import SettingsContainer from '../../../components/ascribe_settings/settings_container';
import ContractSettings from '../../../components/ascribe_settings/contract_settings';
import ErrorNotFoundPage from '../../../components/error_not_found_page';
import CylandLanding from './components/cyland/cyland_landing';
import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piece_container';
import CylandPieceContainer from './components/cyland/cyland_detail/cyland_piece_container';
import CylandRegisterPiece from './components/cyland/cyland_register_piece';
import CylandPieceList from './components/cyland/cyland_piece_list';
@ -24,7 +25,7 @@ import IkonotvLanding from './components/ikonotv/ikonotv_landing';
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan';
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import IkonotvPieceContainer from './components/ikonotv/ascribe_detail/ikonotv_piece_container';
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
import CCRegisterPiece from './components/cc/cc_register_piece';
@ -33,6 +34,7 @@ import WalletApp from './wallet_app';
import AppConstants from '../../../constants/application_constants';
let Route = Router.Route;
let NotFoundRoute = Router.NotFoundRoute;
let Redirect = Router.Redirect;
let baseUrl = AppConstants.baseUrl;
@ -52,6 +54,7 @@ let ROUTES = {
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
<Route name="settings" path="settings" handler={SettingsContainer} />
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
</Route>
),
'cc': (
@ -68,6 +71,7 @@ let ROUTES = {
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
<Route name="settings" path="settings" handler={SettingsContainer} />
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
</Route>
),
'ikonotv': (
@ -86,6 +90,7 @@ let ROUTES = {
<Route name="settings" path="settings" handler={SettingsContainer} />
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
<Route name="contract_notifications" path="contract_notifications" handler={IkonotvContractNotifications} />
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
</Route>
)
};

View File

@ -38,6 +38,7 @@ let ApiUrls = {
'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/',
'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/',
'ownership_consigns_deny': AppConstants.apiEndpoint + 'ownership/consigns/deny/',
'ownership_consigns_withdraw': AppConstants.apiEndpoint + 'ownership/consigns/withdraw/',
'ownership_loans_pieces': AppConstants.apiEndpoint + 'ownership/loans/pieces/',
'ownership_loans_pieces_confirm': AppConstants.apiEndpoint + 'ownership/loans/pieces/confirm/',
'ownership_loans_pieces_deny': AppConstants.apiEndpoint + 'ownership/loans/pieces/deny/',

View File

@ -61,7 +61,7 @@ let constants = {
'validation': {
'additionalData': {
'itemLimit': 100,
'sizeLimit': '50000000'
'sizeLimit': '25000000000'
},
'registerWork': {
'itemLimit': 1,

View File

@ -2,12 +2,15 @@
import requests from '../utils/requests';
import { getSubdomain } from '../utils/general_utils';
let LicenseFetcher = {
/**
* Fetch the available licenses from the API (might be bound to the subdomain e.g. cc.ascribe.io).
*/
fetch() {
return requests.get('licenses', {'subdomain': window.location.host.split('.')[0]});
return requests.get('licenses', {'subdomain': getSubdomain()});
}
};

View File

@ -2,12 +2,15 @@
import requests from '../utils/requests';
import { getSubdomain } from '../utils/general_utils';
let WhitelabelFetcher = {
/**
* Fetch the custom whitelabel data from the API.
*/
fetch() {
return requests.get('whitelabel_settings', {'subdomain': window.location.host.split('.')[0]});
return requests.get('whitelabel_settings', {'subdomain': getSubdomain()});
}
};

View File

@ -21,11 +21,14 @@ import ContractSettings from './components/ascribe_settings/contract_settings';
import SettingsContainer from './components/ascribe_settings/settings_container';
import CoaVerifyContainer from './components/coa_verify_container';
import ErrorNotFoundPage from './components/error_not_found_page';
import RegisterPiece from './components/register_piece';
import AppConstants from './constants/application_constants';
let Route = Router.Route;
let NotFoundRoute = Router.NotFoundRoute;
let Redirect = Router.Redirect;
let baseUrl = AppConstants.baseUrl;
@ -45,6 +48,7 @@ const COMMON_ROUTES = (
<Route name="settings" path="settings" handler={SettingsContainer} />
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
</Route>
);

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import ApplicationActions from '../actions/application_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import CoaActions from '../actions/coa_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import ContractAgreementListActions from '../actions/contract_agreement_list_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import ContractListActions from '../actions/contract_list_actions';

View File

@ -2,7 +2,7 @@
import React from 'react';
import alt from '../alt';
import { alt } from '../alt';
import EditionsListActions from '../actions/edition_list_actions';
class EditionListStore {
@ -13,7 +13,6 @@ class EditionListStore {
}
onUpdateEditionList({pieceId, editionListOfPiece, page, pageSize, orderBy, orderAsc, count, filterBy}) {
/*
Basically there are two modes an edition list can be updated.

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import EditionActions from '../actions/edition_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import GlobalNotificationActions from '../actions/global_notification_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import LicenseActions from '../actions/license_actions';

View File

@ -1,7 +1,7 @@
'use strict';
import React from 'react';
import alt from '../alt';
import { alt } from '../alt';
import NotificationActions from '../actions/notification_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import OwnershipActions from '../actions/ownership_actions';

View File

@ -1,7 +1,7 @@
'use strict';
import React from 'react';
import alt from '../alt';
import { alt } from '../alt';
import PieceListActions from '../actions/piece_list_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import PieceActions from '../actions/piece_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import PrizeListActions from '../actions/prize_list_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altUser } from '../alt';
import UserActions from '../actions/user_actions';
@ -18,4 +18,4 @@ class UserStore {
}
}
export default alt.createStore(UserStore, 'UserStore');
export default altUser.createStore(UserStore, 'UserStore');

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { alt } from '../alt';
import WalletSettingsActions from '../actions/wallet_settings_actions';

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altWhitelabel } from '../alt';
import WhitelabelActions from '../actions/whitelabel_actions';
@ -15,4 +15,4 @@ class WhitelabelStore {
}
}
export default alt.createStore(WhitelabelStore, 'WhitelabelStore');
export default altWhitelabel.createStore(WhitelabelStore, 'WhitelabelStore');

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
import EventActions from '../actions/event_actions';
@ -27,4 +27,4 @@ class DebugHandler {
}
}
export default alt.createStore(DebugHandler, 'DebugHandler');
export default altThirdParty.createStore(DebugHandler, 'DebugHandler');

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
import EventActions from '../actions/event_actions';
class GoogleAnalyticsHandler {
@ -23,4 +23,4 @@ class GoogleAnalyticsHandler {
}
export default alt.createStore(GoogleAnalyticsHandler, 'GoogleAnalyticsHandler');
export default altThirdParty.createStore(GoogleAnalyticsHandler, 'GoogleAnalyticsHandler');

View File

@ -1,8 +1,10 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
import EventActions from '../actions/event_actions';
import { getSubdomain } from '../utils/general_utils';
class IntercomHandler {
constructor() {
@ -20,7 +22,7 @@ class IntercomHandler {
/* eslint-enable */
app_id: 'oboxh5w1',
email: profile.email,
subdomain: window.location.host.split('.')[0],
subdomain: getSubdomain(),
widget: {
activator: '#IntercomDefaultWidget'
}
@ -31,4 +33,4 @@ class IntercomHandler {
}
export default alt.createStore(IntercomHandler, 'IntercomHandler');
export default altThirdParty.createStore(IntercomHandler, 'IntercomHandler');

View File

@ -1,10 +1,12 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
import EventActions from '../actions/event_actions';
import NotificationActions from '../actions/notification_actions';
import { getSubdomain } from '../utils/general_utils';
class NotificationsHandler {
@ -13,11 +15,11 @@ class NotificationsHandler {
this.loaded = false;
}
onProfileDidLoad(profile) {
onProfileDidLoad() {
if (this.loaded) {
return;
}
let subdomain = window.location.host.split('.')[0];
let subdomain = getSubdomain();
if (subdomain === 'ikonotv') {
NotificationActions.fetchContractAgreementListNotifications().then(
(res) => {
@ -33,4 +35,4 @@ class NotificationsHandler {
}
}
export default alt.createStore(NotificationsHandler, 'NotificationsHandler');
export default altThirdParty.createStore(NotificationsHandler, 'NotificationsHandler');

View File

@ -1,6 +1,6 @@
'use strict';
import alt from '../alt';
import { altThirdParty } from '../alt';
import EventActions from '../actions/event_actions';
import Raven from 'raven-js';
@ -25,4 +25,4 @@ class RavenHandler {
}
}
export default alt.createStore(RavenHandler, 'RavenHandler');
export default altThirdParty.createStore(RavenHandler, 'RavenHandler');

View File

@ -231,4 +231,15 @@ export function truncateTextAtCharIndex(text, charIndex, replacement = '...') {
export function replaceSubstringAtIndex(baseString, substrToReplace, stringToBePut) {
let index = baseString.indexOf(substrToReplace);
return baseString.substr(0, index) + stringToBePut + baseString.substr(index + substrToReplace.length);
}
/**
* Extracts the user's subdomain from the browser's window.
* If no subdomain is found (for example on a naked domain), the default "www" is just assumed.
* @return {string} subdomain as a string
*/
export function getSubdomain() {
let { host } = window.location;
let tokens = host.split('.');
return tokens.length > 2 ? tokens[0] : 'www';
}

View File

@ -7,6 +7,7 @@ $BASE_URL: '<%= BASE_URL %>';
@import 'ascribe_variables';
@import 'variables';
@import '../node_modules/bootstrap-sass/assets/stylesheets/bootstrap';
@import '../node_modules/react-star-rating/dist/css/react-star-rating.min';
@import '../node_modules/react-datepicker/dist/react-datepicker';
@import 'glyphicons-social';
@import 'ascribe_theme';
@ -487,4 +488,22 @@ hr {
.modal-header-ascribe {
padding: 15px;
border-bottom: none;
min-height: 16.42857px; }
min-height: 16.42857px;
}
.error-wrapper {
width: 100%;
text-align: center;
padding: 5% 20% 5% 20%;
> h1 {
font-size: 10em;
font-weight: 600;
margin-bottom: .25em;
}
> p {
font-size: 2em;
}
}