mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
refactored detail page for wallets
This commit is contained in:
parent
c837890895
commit
904793269b
@ -0,0 +1,70 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
import ListRequestActions from '../../../../ascribe_forms/list_form_request_actions';
|
||||||
|
import AclButtonList from '../../../../ascribe_buttons/acl_button_list';
|
||||||
|
import DeleteButton from '../../../../ascribe_buttons/delete_button';
|
||||||
|
|
||||||
|
import AclProxy from '../../../../acl_proxy';
|
||||||
|
|
||||||
|
|
||||||
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
|
let WalletActionPanel = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
piece: React.PropTypes.object.isRequired,
|
||||||
|
currentUser: React.PropTypes.object.isRequired,
|
||||||
|
loadPiece: React.PropTypes.func.isRequired,
|
||||||
|
submitButtonType: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
render(){
|
||||||
|
if (this.props.piece &&
|
||||||
|
this.props.piece.notifications &&
|
||||||
|
this.props.piece.notifications.length > 0) {
|
||||||
|
return (
|
||||||
|
<ListRequestActions
|
||||||
|
pieceOrEditions={this.props.piece}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
handleSuccess={this.props.loadPiece}
|
||||||
|
notifications={this.props.piece.notifications}/>);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
//We need to disable the normal acl_loan because we're inserting a custom acl_loan button
|
||||||
|
let availableAcls;
|
||||||
|
|
||||||
|
if (this.props.piece && this.props.piece.acl && typeof this.props.piece.acl.acl_loan !== 'undefined') {
|
||||||
|
// make a copy to not have side effects
|
||||||
|
availableAcls = mergeOptions({}, this.props.piece.acl);
|
||||||
|
availableAcls.acl_loan = false;
|
||||||
|
}
|
||||||
|
let SubmitButtonType = this.props.submitButtonType;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AclButtonList
|
||||||
|
className="text-center ascribe-button-list"
|
||||||
|
availableAcls={availableAcls}
|
||||||
|
editions={this.props.piece}
|
||||||
|
handleSuccess={this.loadPiece}>
|
||||||
|
<AclProxy
|
||||||
|
aclObject={availableAcls}
|
||||||
|
aclName="acl_submit">
|
||||||
|
<SubmitButtonType
|
||||||
|
className="btn-sm"
|
||||||
|
handleSuccess={this.handleSubmitSuccess}
|
||||||
|
piece={this.props.piece}/>
|
||||||
|
</AclProxy>
|
||||||
|
<DeleteButton
|
||||||
|
handleSuccess={this.handleDeleteSuccess}
|
||||||
|
piece={this.props.piece}/>
|
||||||
|
</AclButtonList>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default WalletActionPanel;
|
@ -0,0 +1,85 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
import Piece from '../../../../../components/ascribe_detail/piece';
|
||||||
|
|
||||||
|
import WalletActionPanel from './wallet_action_panel';
|
||||||
|
import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph';
|
||||||
|
|
||||||
|
import HistoryIterator from '../../../../ascribe_detail/history_iterator';
|
||||||
|
import Note from '../../../../ascribe_detail/note';
|
||||||
|
|
||||||
|
import DetailProperty from '../../../../ascribe_detail/detail_property';
|
||||||
|
|
||||||
|
import ApiUrls from '../../../../../constants/api_urls';
|
||||||
|
|
||||||
|
import { getLangText } from '../../../../../utils/lang_utils';
|
||||||
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
|
let WalletPieceContainer = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
piece: React.PropTypes.object.isRequired,
|
||||||
|
currentUser: React.PropTypes.object.isRequired,
|
||||||
|
loadPiece: React.PropTypes.func.isRequired,
|
||||||
|
submitButtonType: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Piece
|
||||||
|
piece={this.props.piece}
|
||||||
|
loadPiece={this.loadPiece}
|
||||||
|
header={
|
||||||
|
<div className="ascribe-detail-header">
|
||||||
|
<hr style={{marginTop: 0}}/>
|
||||||
|
<h1 className="ascribe-detail-title">{this.props.piece.title}</h1>
|
||||||
|
<DetailProperty label="BY" value={this.props.piece.artist_name} />
|
||||||
|
<DetailProperty label="DATE" value={ this.props.piece.date_created.slice(0, 4) } />
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
subheader={
|
||||||
|
<div className="ascribe-detail-header">
|
||||||
|
<DetailProperty label={getLangText('REGISTREE')} value={ this.props.piece.user_registered } />
|
||||||
|
<DetailProperty label={getLangText('ID')} value={ this.props.piece.bitcoin_id } ellipsis={true} />
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
}>
|
||||||
|
<WalletActionPanel
|
||||||
|
piece={this.props.piece}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
loadPiece={this.loadPiece}
|
||||||
|
submitButtonType={this.props.submitButtonType} />
|
||||||
|
<CollapsibleParagraph
|
||||||
|
title={getLangText('Loan History')}
|
||||||
|
show={this.props.piece.loan_history && this.props.piece.loan_history.length > 0}>
|
||||||
|
<HistoryIterator
|
||||||
|
history={this.props.piece.loan_history} />
|
||||||
|
</CollapsibleParagraph>
|
||||||
|
<CollapsibleParagraph
|
||||||
|
title={getLangText('Notes')}
|
||||||
|
show={!!(this.props.currentUser.username || this.props.piece.public_note)}>
|
||||||
|
<Note
|
||||||
|
id={() => {return {'id': this.props.piece.id}; }}
|
||||||
|
label={getLangText('Personal note (private)')}
|
||||||
|
defaultValue={this.props.piece.private_note || null}
|
||||||
|
placeholder={getLangText('Enter your comments ...')}
|
||||||
|
editable={true}
|
||||||
|
successMessage={getLangText('Private note saved')}
|
||||||
|
url={ApiUrls.note_private_piece}
|
||||||
|
currentUser={this.props.currentUser}/>
|
||||||
|
</CollapsibleParagraph>
|
||||||
|
|
||||||
|
{this.props.children}
|
||||||
|
</Piece>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default WalletPieceContainer;
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece';
|
import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece';
|
||||||
|
|
||||||
|
@ -7,29 +7,19 @@ import PieceStore from '../../../../../../stores/piece_store';
|
|||||||
|
|
||||||
import UserStore from '../../../../../../stores/user_store';
|
import UserStore from '../../../../../../stores/user_store';
|
||||||
|
|
||||||
import Piece from '../../../../../../components/ascribe_detail/piece';
|
import CylandSubmitButton from '../ascribe_buttons/cyland_submit_button';
|
||||||
|
|
||||||
|
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
|
||||||
|
|
||||||
|
import CylandAdditionalDataForm from '../ascribe_forms/cyland_additional_data_form';
|
||||||
|
|
||||||
|
import WalletPieceContainer from '../../ascribe_detail/wallet_piece_container';
|
||||||
|
|
||||||
import AppConstants from '../../../../../../constants/application_constants';
|
import AppConstants from '../../../../../../constants/application_constants';
|
||||||
|
|
||||||
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 HistoryIterator from '../../../../../ascribe_detail/history_iterator';
|
|
||||||
import Note from '../../../../../ascribe_detail/note';
|
|
||||||
|
|
||||||
import CylandAdditionalDataForm from '../../cyland/ascribe_forms/cyland_additional_data_form';
|
|
||||||
|
|
||||||
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
|
|
||||||
import DetailProperty from '../../../../../ascribe_detail/detail_property';
|
|
||||||
|
|
||||||
import ApiUrls from '../../../../../../constants/api_urls';
|
|
||||||
|
|
||||||
import { getLangText } from '../../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../../utils/lang_utils';
|
||||||
import { mergeOptions } from '../../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
let CylandPieceContainer = React.createClass({
|
let CylandPieceContainer = React.createClass({
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -40,16 +30,18 @@ let CylandPieceContainer = React.createClass({
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
PieceStore.listen(this.onChange);
|
PieceStore.listen(this.onChange);
|
||||||
PieceActions.fetchOne(this.props.params.pieceId);
|
|
||||||
UserStore.listen(this.onChange);
|
UserStore.listen(this.onChange);
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
// Every time we're leaving the piece detail page,
|
// Every time we're leaving the piece detail page,
|
||||||
// just reset the piece that is saved in the piece store
|
// just reset the piece that is saved in the piece store
|
||||||
// as it will otherwise display wrong/old data once the user loads
|
// as it will otherwise display wrong/old data once the user loads
|
||||||
// the piece detail a second time
|
// the piece detail a second time
|
||||||
PieceActions.updatePiece({});
|
PieceActions.updatePiece({});
|
||||||
|
|
||||||
|
this.loadPiece();
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
PieceStore.unlisten(this.onChange);
|
PieceStore.unlisten(this.onChange);
|
||||||
UserStore.unlisten(this.onChange);
|
UserStore.unlisten(this.onChange);
|
||||||
},
|
},
|
||||||
@ -65,45 +57,11 @@ let CylandPieceContainer = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
if(this.state.piece && this.state.piece.title) {
|
if(this.state.piece && this.state.piece.title) {
|
||||||
return (
|
return (
|
||||||
<Piece
|
<WalletPieceContainer
|
||||||
piece={this.state.piece}
|
piece={this.state.piece}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
loadPiece={this.loadPiece}
|
loadPiece={this.loadPiece}
|
||||||
header={
|
submitButtonType={CylandSubmitButton}>
|
||||||
<div className="ascribe-detail-header">
|
|
||||||
<hr style={{marginTop: 0}}/>
|
|
||||||
<h1 className="ascribe-detail-title">{this.state.piece.title}</h1>
|
|
||||||
<DetailProperty label="BY" value={this.state.piece.artist_name} />
|
|
||||||
<DetailProperty label="DATE" value={ this.state.piece.date_created.slice(0, 4) } />
|
|
||||||
<hr/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
subheader={
|
|
||||||
<div className="ascribe-detail-header">
|
|
||||||
<DetailProperty label={getLangText('REGISTREE')} value={ this.state.piece.user_registered } />
|
|
||||||
<DetailProperty label={getLangText('ID')} value={ this.state.piece.bitcoin_id } ellipsis={true} />
|
|
||||||
<hr/>
|
|
||||||
</div>
|
|
||||||
}>
|
|
||||||
|
|
||||||
<CollapsibleParagraph
|
|
||||||
title={getLangText('Loan History')}
|
|
||||||
show={this.state.piece.loan_history && this.state.piece.loan_history.length > 0}>
|
|
||||||
<HistoryIterator
|
|
||||||
history={this.state.piece.loan_history} />
|
|
||||||
</CollapsibleParagraph>
|
|
||||||
<CollapsibleParagraph
|
|
||||||
title={getLangText('Notes')}
|
|
||||||
show={!!(this.state.currentUser.username || this.state.piece.public_note)}>
|
|
||||||
<Note
|
|
||||||
id={() => {return {'id': this.state.piece.id}; }}
|
|
||||||
label={getLangText('Personal note (private)')}
|
|
||||||
defaultValue={this.state.piece.private_note || null}
|
|
||||||
placeholder={getLangText('Enter your comments ...')}
|
|
||||||
editable={true}
|
|
||||||
successMessage={getLangText('Private note saved')}
|
|
||||||
url={ApiUrls.note_private_piece}
|
|
||||||
currentUser={this.state.currentUser}/>
|
|
||||||
</CollapsibleParagraph>
|
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
title={getLangText('Further Details')}
|
title={getLangText('Further Details')}
|
||||||
show={true}
|
show={true}
|
||||||
@ -113,9 +71,10 @@ let CylandPieceContainer = React.createClass({
|
|||||||
disabled={!this.state.piece.acl.acl_edit}
|
disabled={!this.state.piece.acl.acl_edit}
|
||||||
isInline={true} />
|
isInline={true} />
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
</Piece>
|
</WalletPieceContainer>
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return (
|
return (
|
||||||
<div className="fullpage-spinner">
|
<div className="fullpage-spinner">
|
||||||
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
|
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
|
||||||
|
@ -7,13 +7,7 @@ import PieceStore from '../../../../../../stores/piece_store';
|
|||||||
|
|
||||||
import UserStore from '../../../../../../stores/user_store';
|
import UserStore from '../../../../../../stores/user_store';
|
||||||
|
|
||||||
import Piece from '../../../../../../components/ascribe_detail/piece';
|
|
||||||
|
|
||||||
import AppConstants from '../../../../../../constants/application_constants';
|
|
||||||
|
|
||||||
import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions';
|
|
||||||
import AclButtonList from '../../../../../ascribe_buttons/acl_button_list';
|
|
||||||
import DeleteButton from '../../../../../ascribe_buttons/delete_button';
|
|
||||||
import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button';
|
import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button';
|
||||||
|
|
||||||
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
|
import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph';
|
||||||
@ -21,19 +15,13 @@ import CollapsibleParagraph from '../../../../../../components/ascribe_collapsib
|
|||||||
import IkonotvArtistDetailsForm from '../ascribe_forms/ikonotv_artist_details_form';
|
import IkonotvArtistDetailsForm from '../ascribe_forms/ikonotv_artist_details_form';
|
||||||
import IkonotvArtworkDetailsForm from '../ascribe_forms/ikonotv_artwork_details_form';
|
import IkonotvArtworkDetailsForm from '../ascribe_forms/ikonotv_artwork_details_form';
|
||||||
|
|
||||||
import HistoryIterator from '../../../../../ascribe_detail/history_iterator';
|
import WalletPieceContainer from '../../ascribe_detail/wallet_piece_container';
|
||||||
import Note from '../../../../../ascribe_detail/note';
|
|
||||||
|
|
||||||
import DetailProperty from '../../../../../ascribe_detail/detail_property';
|
import AppConstants from '../../../../../../constants/application_constants';
|
||||||
|
|
||||||
import AclProxy from '../../../../../acl_proxy';
|
|
||||||
|
|
||||||
import ApiUrls from '../../../../../../constants/api_urls';
|
|
||||||
|
|
||||||
import { getLangText } from '../../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../../utils/lang_utils';
|
||||||
import { mergeOptions } from '../../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
let IkonotvPieceContainer = React.createClass({
|
let IkonotvPieceContainer = React.createClass({
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -68,93 +56,14 @@ let IkonotvPieceContainer = React.createClass({
|
|||||||
PieceActions.fetchOne(this.props.params.pieceId);
|
PieceActions.fetchOne(this.props.params.pieceId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getActions(){
|
|
||||||
if (this.state.piece &&
|
|
||||||
this.state.piece.notifications &&
|
|
||||||
this.state.piece.notifications.length > 0) {
|
|
||||||
return (
|
|
||||||
<ListRequestActions
|
|
||||||
pieceOrEditions={this.state.piece}
|
|
||||||
currentUser={this.state.currentUser}
|
|
||||||
handleSuccess={this.loadPiece}
|
|
||||||
notifications={this.state.piece.notifications}/>);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
//We need to disable the normal acl_loan because we're inserting a custom acl_loan button
|
|
||||||
let availableAcls;
|
|
||||||
|
|
||||||
if(this.state.piece && this.state.piece.acl && typeof this.state.piece.acl.acl_loan !== 'undefined') {
|
|
||||||
// make a copy to not have side effects
|
|
||||||
availableAcls = mergeOptions({}, this.state.piece.acl);
|
|
||||||
availableAcls.acl_loan = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AclButtonList
|
|
||||||
className="text-center ascribe-button-list"
|
|
||||||
availableAcls={availableAcls}
|
|
||||||
editions={this.state.piece}
|
|
||||||
handleSuccess={this.loadPiece}>
|
|
||||||
<AclProxy
|
|
||||||
aclObject={availableAcls}
|
|
||||||
aclName="acl_submit">
|
|
||||||
<IkonotvSubmitButton
|
|
||||||
className="btn-sm"
|
|
||||||
handleSuccess={this.handleSubmitSuccess}
|
|
||||||
piece={this.state.piece}/>
|
|
||||||
</AclProxy>
|
|
||||||
<DeleteButton
|
|
||||||
handleSuccess={this.handleDeleteSuccess}
|
|
||||||
piece={this.state.piece}/>
|
|
||||||
</AclButtonList>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if(this.state.piece && this.state.piece.title) {
|
if(this.state.piece && this.state.piece.title) {
|
||||||
return (
|
return (
|
||||||
<Piece
|
<WalletPieceContainer
|
||||||
piece={this.state.piece}
|
piece={this.state.piece}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
loadPiece={this.loadPiece}
|
loadPiece={this.loadPiece}
|
||||||
header={
|
submitButtonType={IkonotvSubmitButton}>
|
||||||
<div className="ascribe-detail-header">
|
|
||||||
<hr style={{marginTop: 0}}/>
|
|
||||||
<h1 className="ascribe-detail-title">{this.state.piece.title}</h1>
|
|
||||||
<DetailProperty label="BY" value={this.state.piece.artist_name} />
|
|
||||||
<DetailProperty label="DATE" value={ this.state.piece.date_created.slice(0, 4) } />
|
|
||||||
<hr/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
subheader={
|
|
||||||
<div className="ascribe-detail-header">
|
|
||||||
<DetailProperty label={getLangText('REGISTREE')} value={ this.state.piece.user_registered } />
|
|
||||||
<DetailProperty label={getLangText('ID')} value={ this.state.piece.bitcoin_id } ellipsis={true} />
|
|
||||||
<hr/>
|
|
||||||
</div>
|
|
||||||
}>
|
|
||||||
{this.getActions()}
|
|
||||||
<CollapsibleParagraph
|
|
||||||
title={getLangText('Loan History')}
|
|
||||||
show={this.state.piece.loan_history && this.state.piece.loan_history.length > 0}>
|
|
||||||
<HistoryIterator
|
|
||||||
history={this.state.piece.loan_history} />
|
|
||||||
</CollapsibleParagraph>
|
|
||||||
<CollapsibleParagraph
|
|
||||||
title={getLangText('Notes')}
|
|
||||||
show={!!(this.state.currentUser.username || this.state.piece.public_note)}>
|
|
||||||
<Note
|
|
||||||
id={() => {return {'id': this.state.piece.id}; }}
|
|
||||||
label={getLangText('Personal note (private)')}
|
|
||||||
defaultValue={this.state.piece.private_note || null}
|
|
||||||
placeholder={getLangText('Enter your comments ...')}
|
|
||||||
editable={true}
|
|
||||||
successMessage={getLangText('Private note saved')}
|
|
||||||
url={ApiUrls.note_private_piece}
|
|
||||||
currentUser={this.state.currentUser}/>
|
|
||||||
</CollapsibleParagraph>
|
|
||||||
|
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
title={getLangText('Further Details')}
|
title={getLangText('Further Details')}
|
||||||
show={true}
|
show={true}
|
||||||
@ -168,9 +77,10 @@ let IkonotvPieceContainer = React.createClass({
|
|||||||
isInline={true}
|
isInline={true}
|
||||||
disabled={!this.state.piece.acl.acl_edit} />
|
disabled={!this.state.piece.acl.acl_edit} />
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
</Piece>
|
</WalletPieceContainer>
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return (
|
return (
|
||||||
<div className="fullpage-spinner">
|
<div className="fullpage-spinner">
|
||||||
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
|
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />
|
||||||
|
Loading…
Reference in New Issue
Block a user