bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx

262 lines
7.2 KiB
React
Raw Normal View History

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)}&nbsp;
<span className={styles.dropzoneLink}>
{intl.formatMessage(intlMessages.browseFilesLabel)}
</span>
</p>
</Dropzone>
);
}
};
export default injectIntl(PresentationUploder);