fineuploader + register

This commit is contained in:
ddejongh 2015-06-23 13:55:05 +02:00
parent 3f3e9a273f
commit 6dd3e582df
9 changed files with 171 additions and 100 deletions

View File

@ -4,4 +4,5 @@ node_modules
js/**/__tests__ js/**/__tests__
server.js server.js
js/components/ascribe_uploader/vendor

View File

@ -81,8 +81,8 @@ var FileDragAndDrop = React.createClass({
handleOnClick() { handleOnClick() {
// Simulate click on hidden file input // Simulate click on hidden file input
var event = document.createEvent("HTMLEvents"); var event = document.createEvent('HTMLEvents');
event.initEvent("click", false, true); event.initEvent('click', false, true);
this.refs.fileinput.getDOMNode().dispatchEvent(event); this.refs.fileinput.getDOMNode().dispatchEvent(event);
}, },
@ -101,17 +101,17 @@ var FileDragAndDrop = React.createClass({
onDrop={this.handleDrop} onDrop={this.handleDrop}
onDragEnd={this.handleDragEnd}> onDragEnd={this.handleDragEnd}>
{hasFiles ? null : <span>Click or drag to add files</span>} {hasFiles ? null : <span>Click or drag to add files</span>}
<FileDragAndDropPreviewIterator <FileDragAndDropPreviewIterator
files={this.props.filesToUpload} files={this.props.filesToUpload}
handleDeleteFile={this.handleDeleteFile}/> handleDeleteFile={this.handleDeleteFile}/>
<input <input
multiple multiple
ref="fileinput" ref="fileinput"
type="file" type="file"
style={{ style={{
display: 'none', display: 'none',
height:0, height: 0,
width:0 width: 0
}} }}
onChange={this.handleDrop} /> onChange={this.handleDrop} />
</div> </div>

View File

@ -12,24 +12,15 @@ import FileDragAndDrop from './file_drag_and_drop';
var ReactS3FineUploader = React.createClass({ var ReactS3FineUploader = React.createClass({
getInitialState() {
return {
filesToUpload: [],
uploader: new fineUploader.s3.FineUploaderBasic(this.propsToConfig())
};
},
componentDidMount() {
//console.log(JSON.stringify(this.propsToConfig()));
//let file = this.state.uploader.getResumableFilesData()[0];
//this.state.uploader.retry('1RKieODp_EBoDPNhISXBDNuA1JKdVuXCWhyk44DTK81WUQvpu3M8TXsKPLkjm3ICSvbbyR2KaHhEysvRQ_s4qHNFCbBiYrZ0Q8clXGCYtzk-');
},
propTypes: { propTypes: {
keyRoutine: React.PropTypes.shape({ keyRoutine: React.PropTypes.shape({
url: React.PropTypes.string, url: React.PropTypes.string,
fileClass: React.PropTypes.string fileClass: React.PropTypes.string
}), }),
createBlobRoutine: React.PropTypes.shape({
url: React.PropTypes.string
}),
handleChange: React.PropTypes.func,
autoUpload: React.PropTypes.bool, autoUpload: React.PropTypes.bool,
debug: React.PropTypes.bool, debug: React.PropTypes.bool,
objectProperties: React.PropTypes.shape({ objectProperties: React.PropTypes.shape({
@ -84,9 +75,16 @@ var ReactS3FineUploader = React.createClass({
}) })
}, },
getInitialState() {
return {
filesToUpload: [],
uploader: new fineUploader.s3.FineUploaderBasic(this.propsToConfig())
};
},
propsToConfig() { propsToConfig() {
let objectProperties = this.props.objectProperties; let objectProperties = this.props.objectProperties;
objectProperties['key'] = this.requestKey; objectProperties.key = this.requestKey;
return { return {
autoUpload: this.props.autoUpload, autoUpload: this.props.autoUpload,
@ -109,7 +107,7 @@ var ReactS3FineUploader = React.createClass({
onSubmit: this.onSubmit, onSubmit: this.onSubmit,
onComplete: this.onComplete, onComplete: this.onComplete,
onDelete: this.onDelete, onDelete: this.onDelete,
onSessionRequestComplete: this.onSessionRequestComplete, onSessionRequestComplete: this.onSessionRequestComplete,
onProgress: this.onProgress, onProgress: this.onProgress,
onRetry: this.onRetry, onRetry: this.onRetry,
onAutoRetry: this.onAutoRetry, onAutoRetry: this.onAutoRetry,
@ -118,6 +116,7 @@ var ReactS3FineUploader = React.createClass({
} }
}; };
}, },
getCookie(name) { getCookie(name) {
console.log(document.cookie); console.log(document.cookie);
let value = '; ' + document.cookie; let value = '; ' + document.cookie;
@ -160,8 +159,45 @@ var ReactS3FineUploader = React.createClass({
console.log('submit'); console.log('submit');
}, },
onComplete() { onComplete(id) {
console.log('complete'); let files = this.state.filesToUpload;
files[id].status = 'upload successful';
files[id].key = this.state.uploader.getKey(id);
let newState = React.addons.update(this.state, {
filesToUpload: { $set: files }
});
this.setState(newState);
this.createBlob(files[id]);
this.props.handleChange();
console.log('completed ' + files[id].name);
},
createBlob(file) {
let defer = new fineUploader.Promise();
fetch(this.props.createBlobRoutine.url, {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': this.getCookie('csrftoken')
},
credentials: 'include',
body: JSON.stringify({
'filename': file.name,
'key': file.key
})
})
.then((res) => {
return res.json();
})
.then((res) =>{
defer.success(res.key);
})
.catch((err) => {
console.error(err);
});
return defer;
}, },
onRetry() { onRetry() {
@ -193,13 +229,14 @@ var ReactS3FineUploader = React.createClass({
// also, sync files from state with the ones from fineuploader // also, sync files from state with the ones from fineuploader
let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload)); let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload));
// splice because I can // splice because I can
filesToUpload.splice(fileId, 1); filesToUpload.splice(id, 1);
// set state // set state
this.setState({ this.setState({
filesToUpload: React.addons.update(this.state.filesToUpload, {$set: filesToUpload}) filesToUpload: React.addons.update(this.state.filesToUpload, {$set: filesToUpload})
}); });
} else { } else {
console.log(id);
// TODO: add global notification // TODO: add global notification
} }
}, },
@ -207,7 +244,7 @@ var ReactS3FineUploader = React.createClass({
onProgress(id, name, uploadedBytes, totalBytes) { onProgress(id, name, uploadedBytes, totalBytes) {
var newState = React.addons.update(this.state, { var newState = React.addons.update(this.state, {
filesToUpload: { [id]: { filesToUpload: { [id]: {
progress: { $set: (uploadedBytes/totalBytes)*100} } progress: { $set: (uploadedBytes / totalBytes) * 100} }
} }
}); });
this.setState(newState); this.setState(newState);
@ -216,7 +253,7 @@ var ReactS3FineUploader = React.createClass({
handleDeleteFile(fileId) { handleDeleteFile(fileId) {
// delete file from server // delete file from server
this.state.uploader.deleteFile(fileId); this.state.uploader.deleteFile(fileId);
// this is being continues in onDeleteFile, as // this is being continues in onDeleteFile, as
// fineuploaders deleteFile does not return a correct callback or // fineuploaders deleteFile does not return a correct callback or
// promise // promise
}, },
@ -241,7 +278,7 @@ var ReactS3FineUploader = React.createClass({
for(let i = 0; i < oldAndNewFiles.length; i++) { for(let i = 0; i < oldAndNewFiles.length; i++) {
for(let j = 0; j < oldFiles.length; j++) { for(let j = 0; j < oldFiles.length; j++) {
if(oldAndNewFiles[i].originalName === oldFiles[j].name) { if(oldAndNewFiles[i].originalName === oldFiles[j].name) {
oldAndNewFiles[i].progress = 0; oldAndNewFiles[i].progress = oldFiles[j].progress;
oldAndNewFiles[i].type = oldFiles[j].type; oldAndNewFiles[i].type = oldFiles[j].type;
oldAndNewFiles[i].url = oldFiles[j].url; oldAndNewFiles[i].url = oldFiles[j].url;
} }
@ -256,7 +293,7 @@ var ReactS3FineUploader = React.createClass({
render() { render() {
return ( return (
<FileDragAndDrop <FileDragAndDrop
onDrop={this.handleUploadFile} onDrop={this.handleUploadFile}
filesToUpload={this.state.filesToUpload} filesToUpload={this.state.filesToUpload}
handleDeleteFile={this.handleDeleteFile}/> handleDeleteFile={this.handleDeleteFile}/>

View File

@ -20,16 +20,94 @@ import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader';
import DatePicker from 'react-datepicker/dist/react-datepicker'; import DatePicker from 'react-datepicker/dist/react-datepicker';
let RegisterPiece = React.createClass( { let RegisterPiece = React.createClass( {
render() { mixins: [Router.Navigation],
getInitialState(){
return {digital_work_key: null};
},
handleSuccess(){
let notification = new GlobalNotificationModel('Login successsful', 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
this.transitionTo('pieces');
},
getFormData(){
let data = {};
for (let ref in this.refs.form.refs){
data[this.refs.form.refs[ref].props.name] = this.refs.form.refs[ref].state.value;
}
data.digital_work_key = this.state.digital_work_key;
return data;
},
handleChange(){
this.setState({digital_work_key: this.refs.uploader.refs.fineuploader.state.filesToUpload[0].key})
},
render() {
let buttons = null;
if (this.refs.uploader && this.refs.uploader.refs.fineuploader.state.filesToUpload[0].status === 'upload successful'){
buttons = (
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
Register your artwork
</button>);
}
return ( return (
<div className="row ascribe-row"> <div className="row ascribe-row">
<div className="col-md-6"> <div className="col-md-5">
<FileUploader /> <FileUploader
ref='uploader'
handleChange={this.handleChange}/>
<br /> <br />
</div> </div>
<div className="col-md-6"> <div className="col-md-7">
<RegisterPieceForm /> <h3 style={{'marginTop': 0}}>Lock down title</h3>
<Form
ref='form'
url={apiUrls.pieces_list}
getFormData={this.getFormData}
handleSuccess={this.handleSuccess}
buttons={buttons}
spinner={
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</button>
}>
<Property
name='artist_name'
label="Artist Name">
<input
type="text"
placeholder="The name of the creator"
required/>
</Property>
<Property
name='title'
label="Artwork title">
<input
type="text"
placeholder="The title of the artwork"
required/>
</Property>
<Property
name='date_created'
label="Year Created">
<input
type="number"
placeholder="Year Created (e.g. 2015)"
min={0}
required/>
</Property>
<Property
name='num_editions'
label="Number of editions">
<input
type="number"
placeholder="Specify the number of unique editions for this artwork"
min={1}
required/>
</Property>
<hr />
</Form>
</div> </div>
</div> </div>
); );
@ -39,13 +117,17 @@ let RegisterPiece = React.createClass( {
let FileUploader = React.createClass( { let FileUploader = React.createClass( {
render() { render() {
return ( return (
<ReactS3FineUploader <ReactS3FineUploader
ref='fineuploader'
keyRoutine={{ keyRoutine={{
url: AppConstants.serverUrl + 's3/key/', url: AppConstants.serverUrl + 's3/key/',
fileClass: 'digitalwork' fileClass: 'digitalwork'
}} }}
createBlobRoutine={{
url: apiUrls.blob_digitalworks
}}
handleChange={this.props.handleChange}
autoUpload={true} autoUpload={true}
debug={false} debug={false}
objectProperties={{ objectProperties={{
@ -97,71 +179,11 @@ let FileUploader = React.createClass( {
} }
return name; return name;
}} }}
multiple={true}/> multiple={false}/>
); );
} }
}); });
let RegisterPieceForm = React.createClass({
mixins: [Router.Navigation],
handleSuccess(){
let notification = new GlobalNotificationModel('Login successsful', 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
this.transitionTo('pieces');
},
render() {
return (
<Form
url={apiUrls.pieces_list}
handleSuccess={this.handleSuccess}
buttons={
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
Register your artwork
</button>}
spinner={
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</button>
}>
<Property
name='artist_name'
label="Artist Name">
<input
type="text"
placeholder="The name of the creator"
required/>
</Property>
<Property
name='title'
label="Artwork title">
<input
type="text"
placeholder="The title of the artwork"
required/>
</Property>
<Property
name='date_created'
label="Year Created">
<InputDate
placeholderText="Year Created (e.g. 2015)" />
</Property>
<Property
name='num_editions'
label="Number of editions">
<input
type="number"
placeholder="Specify the number of unique editions for this artwork"
min={1}
required/>
</Property>
<hr />
</Form>
);
}
});
let InputDate = React.createClass({ let InputDate = React.createClass({
propTypes: { propTypes: {
@ -179,6 +201,11 @@ let InputDate = React.createClass({
this.setState({ this.setState({
value: date, value: date,
value_formatted: date.format('YYYY')}); value_formatted: date.format('YYYY')});
let event = document.createEvent('HTMLEvents');
event.initEvent('click', false, true);
document.dispatchEvent(event);
event.target.value = date;
this.props.onChange(event);
}, },
render: function () { render: function () {

View File

@ -202,7 +202,7 @@ let APISettings = React.createClass({
}, },
render() { render() {
let content = <img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />; let content = <img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />;
if (this.state.applications.length > 0) { if (this.state.applications.length > -1) {
content = this.state.applications.map(function(app) { content = this.state.applications.map(function(app) {
return ( return (
<Property <Property

View File

@ -5,6 +5,7 @@ import AppConstants from './application_constants';
let apiUrls = { let apiUrls = {
'applications': AppConstants.apiEndpoint + 'applications/', 'applications': AppConstants.apiEndpoint + 'applications/',
'application_token_refresh': AppConstants.apiEndpoint + 'applications/refresh_token/', 'application_token_refresh': AppConstants.apiEndpoint + 'applications/refresh_token/',
'blob_digitalworks': AppConstants.apiEndpoint + 'blob/digitalworks/',
'edition': AppConstants.apiEndpoint + 'editions/${bitcoin_id}/', 'edition': AppConstants.apiEndpoint + 'editions/${bitcoin_id}/',
'edition_delete': AppConstants.apiEndpoint + 'editions/${edition_id}/', 'edition_delete': AppConstants.apiEndpoint + 'editions/${edition_id}/',
'edition_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/${edition_id}/', 'edition_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/${edition_id}/',

View File

@ -1,7 +1,13 @@
$break-small: 764px; $break-small: 764px;
$break-medium: 991px;
.ascribe-row { .ascribe-row {
max-width: 600px; @media screen and (max-width: $break-medium) {
max-width: 600px;
}
@media screen and (min-width: $break-medium) {
max-width: 1200px;
}
margin: 0 auto margin: 0 auto
} }

View File

@ -89,7 +89,6 @@
} }
input, pre, textarea { input, pre, textarea {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 400; font-weight: 400;
font-size: 1.1em; font-size: 1.1em;
width:100%; width:100%;
@ -97,6 +96,7 @@
border: 0; border: 0;
background-color: rgba(0,0,0,0); background-color: rgba(0,0,0,0);
color: #38BAAD; color: #38BAAD;
padding-left: 0;
&:focus { &:focus {
border:0; border:0;

View File

@ -22,7 +22,6 @@ $BASE_URL: '<%= BASE_URL %>';
@import 'ascribe_piece_register'; @import 'ascribe_piece_register';
@import 'offset_right'; @import 'offset_right';
@import 'ascribe_settings'; @import 'ascribe_settings';
@import '../node_modules/react-s3-fineuploader/scss/ascribe-theme';
body { body {
background-color: #FDFDFD; background-color: #FDFDFD;