2017-04-29 02:42:32 +08:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import { defineMessages, injectIntl, FormattedDate } from 'react-intl';
|
2017-05-04 00:36:16 +08:00
|
|
|
import update from 'immutability-helper';
|
|
|
|
import ModalFullscreen from '/imports/ui/components/modal/component';
|
2017-04-29 02:42:32 +08:00
|
|
|
import Icon from '/imports/ui/components/icon/component';
|
|
|
|
import ButtonBase from '/imports/ui/components/button/base/component';
|
2017-05-04 00:36:16 +08:00
|
|
|
import Checkbox from '/imports/ui/components/checkbox/component';
|
2017-04-29 02:42:32 +08:00
|
|
|
import Dropzone from 'react-dropzone';
|
|
|
|
import styles from './styles.scss';
|
|
|
|
import cx from 'classnames';
|
|
|
|
|
|
|
|
const intlMessages = defineMessages({
|
|
|
|
title: {
|
|
|
|
id: 'app.presentationUploder.title',
|
|
|
|
defaultMessage: 'Presentation',
|
|
|
|
},
|
|
|
|
message: {
|
|
|
|
id: 'app.presentationUploder.message',
|
|
|
|
defaultMessage: `As a presenter in BigBlueButton, you have the ability of
|
|
|
|
uploading any office document or PDF file. We recommend for the best results,
|
|
|
|
to please upload a PDF file.`,
|
|
|
|
},
|
|
|
|
confirmLabel: {
|
|
|
|
id: 'app.presentationUploder.confirmLabel',
|
|
|
|
defaultMessage: 'Start',
|
|
|
|
},
|
|
|
|
confirmDesc: {
|
|
|
|
id: 'app.presentationUploder.confirmDesc',
|
|
|
|
defaultMessage: 'Save your changes and start the presentation',
|
|
|
|
},
|
|
|
|
dismissLabel: {
|
|
|
|
id: 'app.presentationUploder.dismissLabel',
|
|
|
|
defaultMessage: 'Cancel',
|
|
|
|
},
|
|
|
|
dismissDesc: {
|
|
|
|
id: 'app.presentationUploder.dismissDesc',
|
|
|
|
defaultMessage: 'Closes and discarts your changes',
|
|
|
|
},
|
|
|
|
dropzoneLabel: {
|
|
|
|
id: 'app.presentationUploder.dropzoneLabel',
|
|
|
|
defaultMessage: 'Drag files here to upload',
|
|
|
|
},
|
|
|
|
browseFilesLabel: {
|
|
|
|
id: 'app.presentationUploder.browseFilesLabel',
|
|
|
|
defaultMessage: 'or browse for files',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
class PresentationUploder extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
presentations: props.presentations,
|
2017-05-04 00:36:16 +08:00
|
|
|
isProcessing: false,
|
2017-04-29 02:42:32 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
this.handleConfirm = this.handleConfirm.bind(this);
|
|
|
|
this.handleDismiss = this.handleDismiss.bind(this);
|
|
|
|
this.handleFiledrop = this.handleFiledrop.bind(this);
|
|
|
|
this.handleCurrentChange = this.handleCurrentChange.bind(this);
|
|
|
|
this.handleRemove = this.handleRemove.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
handleConfirm() {
|
|
|
|
const { presentations } = this.state;
|
2017-05-04 00:36:16 +08:00
|
|
|
|
|
|
|
this.setState({ isProcessing: true });
|
|
|
|
|
|
|
|
return this.props.handleSave(presentations)
|
|
|
|
.then(() => {
|
|
|
|
this.setState({ isProcessing: false });
|
|
|
|
});
|
2017-04-29 02:42:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
handleDismiss() {
|
|
|
|
// we dont actually need to do anything, yay :D
|
|
|
|
}
|
|
|
|
|
|
|
|
handleFiledrop(files) {
|
|
|
|
let presentationsToUpload = files.map(file => ({
|
2017-05-04 00:36:16 +08:00
|
|
|
id: file.name,
|
|
|
|
file: file,
|
2017-04-29 02:42:32 +08:00
|
|
|
filename: file.name,
|
|
|
|
uploadedAt: new Date(),
|
|
|
|
isCurrent: false,
|
|
|
|
isUploaded: false,
|
|
|
|
isProcessed: false,
|
|
|
|
}));
|
|
|
|
|
|
|
|
this.setState(({ presentations }) => ({
|
|
|
|
presentations: presentations.concat(presentationsToUpload),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
handleCurrentChange(item) {
|
|
|
|
const { presentations } = this.state;
|
|
|
|
const currentIndex = presentations.findIndex(p => p.isCurrent);
|
|
|
|
const newCurrentIndex = presentations.indexOf(item);
|
|
|
|
|
|
|
|
let commands = {};
|
|
|
|
commands[currentIndex] = {
|
|
|
|
$apply: p => {
|
|
|
|
p.isCurrent = false;
|
|
|
|
return p;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
commands[newCurrentIndex] = {
|
|
|
|
$apply: p => {
|
|
|
|
p.isCurrent = true;
|
|
|
|
return p;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
let presentationsUpdated = update(presentations, commands);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
presentations: presentationsUpdated,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
handleRemove(item) {
|
|
|
|
const { presentations } = this.state;
|
|
|
|
const toRemoveIndex = presentations.indexOf(item);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
presentations: update(presentations, {
|
|
|
|
$splice: [[toRemoveIndex, 1]],
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { intl } = this.props;
|
2017-05-04 00:36:16 +08:00
|
|
|
const { isProcessing } = this.state;
|
2017-04-29 02:42:32 +08:00
|
|
|
|
|
|
|
return (
|
2017-05-04 00:36:16 +08:00
|
|
|
<ModalFullscreen
|
2017-04-29 02:42:32 +08:00
|
|
|
title={intl.formatMessage(intlMessages.title)}
|
|
|
|
confirm={{
|
|
|
|
callback: this.handleConfirm,
|
|
|
|
label: intl.formatMessage(intlMessages.confirmLabel),
|
|
|
|
description: intl.formatMessage(intlMessages.confirmDesc),
|
2017-05-04 00:36:16 +08:00
|
|
|
disabled: isProcessing,
|
2017-04-29 02:42:32 +08:00
|
|
|
}}
|
|
|
|
dismiss={{
|
|
|
|
callback: this.handleDismiss,
|
|
|
|
label: intl.formatMessage(intlMessages.dismissLabel),
|
|
|
|
description: intl.formatMessage(intlMessages.dismissDesc),
|
2017-05-04 00:36:16 +08:00
|
|
|
disabled: isProcessing,
|
2017-04-29 02:42:32 +08:00
|
|
|
}}>
|
|
|
|
<p>{intl.formatMessage(intlMessages.message)}</p>
|
|
|
|
{this.renderPresentationList()}
|
|
|
|
{this.renderDropzone()}
|
2017-05-04 00:36:16 +08:00
|
|
|
</ModalFullscreen>
|
2017-04-29 02:42:32 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPresentationList() {
|
|
|
|
const { presentations } = this.state;
|
|
|
|
|
|
|
|
let presentationsSorted = presentations
|
|
|
|
.sort((a, b) => a.uploadedAt.getTime() - b.uploadedAt.getTime());
|
|
|
|
|
|
|
|
return (
|
2017-05-04 00:36:16 +08:00
|
|
|
<div className={styles.fileList}>
|
|
|
|
<table className={styles.table}>
|
|
|
|
<tbody>
|
|
|
|
{ presentationsSorted.map(item => this.renderPresentationItem(item))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
2017-04-29 02:42:32 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPresentationItem(item) {
|
2017-05-04 00:36:16 +08:00
|
|
|
const { isProcessing } = this.state;
|
|
|
|
|
2017-04-29 02:42:32 +08:00
|
|
|
let itemClassName = {};
|
|
|
|
|
|
|
|
itemClassName[styles.tableItemNew] = !item.isUploaded && !item.isProcessed;
|
|
|
|
itemClassName[styles.tableItemUploading] = item.isUploading;
|
|
|
|
itemClassName[styles.tableItemProcessing] = item.isProcessing;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<tr
|
2017-05-04 00:36:16 +08:00
|
|
|
key={item.id}
|
2017-04-29 02:42:32 +08:00
|
|
|
className={cx(itemClassName)}
|
|
|
|
>
|
|
|
|
<td className={styles.tableItemIcon}>
|
2017-05-04 00:36:16 +08:00
|
|
|
<Icon iconName={'file'}/>
|
2017-04-29 02:42:32 +08:00
|
|
|
</td>
|
|
|
|
<th className={styles.tableItemName}>
|
|
|
|
<span>{item.filename}</span>
|
|
|
|
</th>
|
|
|
|
<td className={styles.tableItemTime}>
|
|
|
|
{
|
|
|
|
!item.isUploaded ? 'To be uploaded...'
|
|
|
|
: (
|
|
|
|
<time dateTime={item.uploadedAt}>
|
|
|
|
<FormattedDate
|
|
|
|
value={item.uploadedAt}
|
|
|
|
day="2-digit"
|
|
|
|
month="2-digit"
|
|
|
|
year="numeric"
|
|
|
|
hour="2-digit"
|
|
|
|
minute="2-digit"
|
|
|
|
/>
|
|
|
|
</time>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
</td>
|
|
|
|
<td className={styles.tableItemActions}>
|
2017-05-04 00:36:16 +08:00
|
|
|
<Checkbox
|
|
|
|
disabled={isProcessing}
|
|
|
|
checked={item.isCurrent}
|
|
|
|
onChange={() => this.handleCurrentChange(item)}
|
|
|
|
/>
|
2017-04-29 02:42:32 +08:00
|
|
|
<ButtonBase
|
2017-05-04 00:36:16 +08:00
|
|
|
disabled={isProcessing || item.isCurrent || item.filename === 'default.pdf'}
|
2017-04-29 02:42:32 +08:00
|
|
|
onClick={() => this.handleRemove(item)}>
|
2017-05-04 00:36:16 +08:00
|
|
|
<Icon iconName={'close'}/>
|
2017-04-29 02:42:32 +08:00
|
|
|
</ButtonBase>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderDropzone() {
|
2017-05-04 00:36:16 +08:00
|
|
|
const {
|
|
|
|
intl,
|
|
|
|
fileSizeMin,
|
|
|
|
fileSizeMax,
|
|
|
|
fileValidMimeTypes,
|
|
|
|
} = this.props;
|
2017-04-29 02:42:32 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<Dropzone
|
|
|
|
className={styles.dropzone}
|
|
|
|
activeClassName={styles.dropzoneActive}
|
|
|
|
rejectClassName={styles.dropzoneReject}
|
2017-05-04 00:36:16 +08:00
|
|
|
accept={fileValidMimeTypes.join()}
|
|
|
|
minSize={fileSizeMin}
|
|
|
|
maxSize={fileSizeMax}
|
2017-04-29 02:42:32 +08:00
|
|
|
disablePreview={true}
|
|
|
|
onDrop={this.handleFiledrop}
|
2017-05-04 00:36:16 +08:00
|
|
|
onDragStart={this.handleDragStart}
|
2017-04-29 02:42:32 +08:00
|
|
|
>
|
|
|
|
<Icon className={styles.dropzoneIcon} iconName={'undecided'}/>
|
|
|
|
<p className={styles.dropzoneMessage}>
|
|
|
|
{intl.formatMessage(intlMessages.dropzoneLabel)}
|
|
|
|
<span className={styles.dropzoneLink}>
|
|
|
|
{intl.formatMessage(intlMessages.browseFilesLabel)}
|
|
|
|
</span>
|
|
|
|
</p>
|
|
|
|
</Dropzone>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export default injectIntl(PresentationUploder);
|