From ed589c79c480aeb071aa3cf7ff6ba71d3ef30480 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 4 Nov 2017 17:51:56 -0700 Subject: [PATCH] unfinished, not rebased, topic card uploads --- .../open-iconic-document.svg | 3 + .../open-iconic-file.svg | 3 + .../open-iconic-image.svg | 3 + .../open-iconic-musical-note.svg | 4 + .../open-iconic-question-mark.svg | 4 + app/assets/images/recording-button.png | Bin 0 -> 48083 bytes .../images/upload_icons/CameraIcons.png | Bin 0 -> 1141 bytes app/assets/images/upload_icons/CloudIcons.png | Bin 0 -> 1429 bytes app/assets/images/upload_icons/LinkIcons.png | Bin 0 -> 2664 bytes app/assets/images/upload_icons/MicIcons.png | Bin 0 -> 1793 bytes .../javascripts/Metamaps.ServerData.js.erb | 7 ++ app/assets/stylesheets/base.scss.erb | 106 +++++++++++++++++- app/models/attachment.rb | 2 +- frontend/src/Metamaps/GlobalUI/ReactApp.js | 9 +- frontend/src/Metamaps/Views/TopicCard.js | 52 +++++++++ .../src/components/TopicCard/Attachments.js | 98 ++++++++++++++-- .../src/components/TopicCard/AudioUploader.js | 81 +++++++++++++ .../{EmbedlyLink/Card.js => EmbedlyCard.js} | 16 ++- .../index.js => EmbedlyLinkChooser.js} | 39 ++----- .../components/TopicCard/FileAttachment.js | 57 ++++++++++ .../src/components/TopicCard/FileUploader.js | 34 ++++++ .../src/components/TopicCard/PhotoUploader.js | 34 ++++++ frontend/src/components/TopicCard/index.js | 17 ++- package.json | 1 + 24 files changed, 518 insertions(+), 52 deletions(-) create mode 100644 app/assets/images/attachmentFileTypeIcons/open-iconic-document.svg create mode 100644 app/assets/images/attachmentFileTypeIcons/open-iconic-file.svg create mode 100644 app/assets/images/attachmentFileTypeIcons/open-iconic-image.svg create mode 100644 app/assets/images/attachmentFileTypeIcons/open-iconic-musical-note.svg create mode 100644 app/assets/images/attachmentFileTypeIcons/open-iconic-question-mark.svg create mode 100644 app/assets/images/recording-button.png create mode 100644 app/assets/images/upload_icons/CameraIcons.png create mode 100644 app/assets/images/upload_icons/CloudIcons.png create mode 100644 app/assets/images/upload_icons/LinkIcons.png create mode 100644 app/assets/images/upload_icons/MicIcons.png create mode 100644 frontend/src/components/TopicCard/AudioUploader.js rename frontend/src/components/TopicCard/{EmbedlyLink/Card.js => EmbedlyCard.js} (82%) rename frontend/src/components/TopicCard/{EmbedlyLink/index.js => EmbedlyLinkChooser.js} (50%) create mode 100644 frontend/src/components/TopicCard/FileAttachment.js create mode 100644 frontend/src/components/TopicCard/FileUploader.js create mode 100644 frontend/src/components/TopicCard/PhotoUploader.js diff --git a/app/assets/images/attachmentFileTypeIcons/open-iconic-document.svg b/app/assets/images/attachmentFileTypeIcons/open-iconic-document.svg new file mode 100644 index 00000000..c3e2b061 --- /dev/null +++ b/app/assets/images/attachmentFileTypeIcons/open-iconic-document.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/attachmentFileTypeIcons/open-iconic-file.svg b/app/assets/images/attachmentFileTypeIcons/open-iconic-file.svg new file mode 100644 index 00000000..6a5932db --- /dev/null +++ b/app/assets/images/attachmentFileTypeIcons/open-iconic-file.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/attachmentFileTypeIcons/open-iconic-image.svg b/app/assets/images/attachmentFileTypeIcons/open-iconic-image.svg new file mode 100644 index 00000000..092665c1 --- /dev/null +++ b/app/assets/images/attachmentFileTypeIcons/open-iconic-image.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/assets/images/attachmentFileTypeIcons/open-iconic-musical-note.svg b/app/assets/images/attachmentFileTypeIcons/open-iconic-musical-note.svg new file mode 100644 index 00000000..bc66c5c9 --- /dev/null +++ b/app/assets/images/attachmentFileTypeIcons/open-iconic-musical-note.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/app/assets/images/attachmentFileTypeIcons/open-iconic-question-mark.svg b/app/assets/images/attachmentFileTypeIcons/open-iconic-question-mark.svg new file mode 100644 index 00000000..4eb6ff36 --- /dev/null +++ b/app/assets/images/attachmentFileTypeIcons/open-iconic-question-mark.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/app/assets/images/recording-button.png b/app/assets/images/recording-button.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea03b22516ae91c4daeb3098a3acb8469ed1172 GIT binary patch literal 48083 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�cYlDCd3$0EZtjBf1 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 Hu0mjf{5C9N literal 0 HcmV?d00001 diff --git a/app/assets/images/upload_icons/CloudIcons.png b/app/assets/images/upload_icons/CloudIcons.png new file mode 100644 index 0000000000000000000000000000000000000000..eb887a59bb47393f8260d9fca13616b82a11ec30 GIT binary patch literal 1429 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 literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/Metamaps.ServerData.js.erb b/app/assets/javascripts/Metamaps.ServerData.js.erb index bd412a93..0c96df3c 100644 --- a/app/assets/javascripts/Metamaps.ServerData.js.erb +++ b/app/assets/javascripts/Metamaps.ServerData.js.erb @@ -13,6 +13,13 @@ Metamaps.ServerData['sounds/MM_sounds.ogg'] = '<%= asset_path 'sounds/MM_sounds. Metamaps.ServerData['exploremaps_sprite.png'] = '<%= asset_path 'exploremaps_sprite.png' %>' Metamaps.ServerData['map_control_sprite.png'] = '<%= asset_path 'map_control_sprite.png' %>' Metamaps.ServerData['user_sprite.png'] = '<%= asset_path 'user_sprite.png' %>' +Metamaps.ServerData.attachmentFileTypeIcons = { + pdf: '<%= asset_path('attachmentFileTypeIcons//open-iconic-document.svg') %>', + text: '<%= asset_path('attachmentFileTypeIcons//open-iconic-file.svg') %>', + image: '<%= asset_path('attachmentFileTypeIcons//open-iconic-image.svg') %>', + audio: '<%= asset_path('attachmentFileTypeIcons//open-iconic-musical-note.svg') %>', + unknown: '<%= asset_path('attachmentFileTypeIcons//open-iconic-question-mark.svg') %>' +} Metamaps.ServerData.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %> Metamaps.ServerData.REALTIME_SERVER = '<%= ENV['REALTIME_SERVER'] %>' Metamaps.ServerData.RAILS_ENV = '<%= ENV['RAILS_ENV'] %>' diff --git a/app/assets/stylesheets/base.scss.erb b/app/assets/stylesheets/base.scss.erb index b4b7bb0c..f7e8f8ee 100644 --- a/app/assets/stylesheets/base.scss.erb +++ b/app/assets/stylesheets/base.scss.erb @@ -197,6 +197,7 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6); .CardOnGraph .links { position: relative; + background-color: #e0e0e0; z-index: 2; .linkItem { @@ -625,18 +626,117 @@ background-color: #E0E0E0; z-index:100; } +.attachments { + border-top: 1px solid #bdbdbd; + position: relative; + min-height: 3em; + + .file { + margin-top: 0.75em; + max-width: 85%; + + .filetype-icon { + width: 16px; + height: 16px; + padding: 0.5em; + padding-top: 0; + float: left; + } + } +} + +.upload-audio-start, +.upload-file-dropzone, +.upload-photo-dropzone, +.CardOnGraph .attachment-type-chooser > div { + text-align: center; + color: #cccccc; + font-size: 12px; + cursor: pointer; + + &:hover { + color: #999999; + } + + & > div { + width: 48px; + height: 48px; + margin: 0 auto; + box-sizing: border-box; + padding-top: 75%; + } + &.photo-upload > div { + background-image: url(<%= asset_path('upload_icons/CameraIcons.png') %>); + } + &.link-upload > div { + background-image: url(<%= asset_path('upload_icons/LinkIcons.png') %>); + } + &.audio-upload > div { + background-image: url(<%= asset_path('upload_icons/MicIcons.png') %>); + } + &.file-upload > div { + background-image: url(<%= asset_path('upload_icons/CloudIcons.png') %>); + } +} + +.photo-upload, +.link-upload, +.audio-upload, +.file-upload { + background-repeat: no-repeat; + background-size: 48px 48px; + background-position: 0 center; + width: 48px; + height: 48px; + + &:hover { + /*background-position: ;*/ + } +} + +.upload-audio-start, +.upload-file-dropzone, +.upload-photo-dropzone { + padding-top: 0.75em; +} + +.upload-audio-recording { + font-size: small; + color: #aaa; + text-align: center; +} + +$recording_button_size: 48px; +.upload-audio-stop { + background-image: url(<%= asset_path('recording-button.png') %>); + background-size: $recording_button_size; + width: $recording_button_size; + height: $recording_button_size; + margin: 0 auto; + cursor: pointer; +} + +.CardOnGraph .attachment-type-chooser { + padding-top: .75em; + + & > div { + display: inline-block; + width: 25%; + } +} + #embedlyLinkLoader { margin: 0 auto; width: 28px; } -.CardOnGraph .link-adder { +.CardOnGraph .link-chooser { width:100%; height:47px; position: relative; } -.link-adder a { +.link-chooser a { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -720,7 +820,7 @@ font-family: 'din-regular', helvetica, sans-serif; z-index: 1; } -#addLinkReset { +.attachment-cancel { position: absolute; top: 8px; right: 15px; diff --git a/app/models/attachment.rb b/app/models/attachment.rb index a18e0956..dd6a569c 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -17,7 +17,7 @@ class Attachment < ApplicationRecord validates :attachable, presence: true validates_attachment_content_type :file, content_type: Attachable.allowed_types - validates_attachment_size :file, in: 0.megabytes..5.megabytes + validates_attachment_size :file, :in => 0.megabytes..5.megabytes def image? Attachable.image_types.include?(file.instance.file_content_type) diff --git a/frontend/src/Metamaps/GlobalUI/ReactApp.js b/frontend/src/Metamaps/GlobalUI/ReactApp.js index 6237f08a..63820a53 100644 --- a/frontend/src/Metamaps/GlobalUI/ReactApp.js +++ b/frontend/src/Metamaps/GlobalUI/ReactApp.js @@ -37,12 +37,14 @@ const ReactApp = { mobileTitle: '', mobileTitleWidth: 0, metacodeSets: [], + attachmentFileTypeIcons: {}, init: function(serverData, openLightbox) { const self = ReactApp self.serverData = serverData self.mobileTitle = serverData.mobileTitle self.openLightbox = openLightbox self.metacodeSets = serverData.metacodeSets + self.attachmentFileTypeIcons = serverData.attachmentFileTypeIcons routes = makeRoutes(serverData.ActiveMapper) self.resize() window && window.addEventListener('resize', self.resize) @@ -154,10 +156,13 @@ const ReactApp = { getTopicCardProps: function() { const self = ReactApp return { - openTopic: TopicCard.openTopic, metacodeSets: self.metacodeSets, + onTopicFollow: Topic.onTopicFollow, + openTopic: TopicCard.openTopic, updateTopic: (topic, obj) => topic.save(obj), - onTopicFollow: Topic.onTopicFollow + uploadAttachment: TopicCard.uploadAttachment, + removeAttachment: TopicCard.removeAttachment, + fileTypeIcons: self.attachmentFileTypeIcons } }, getContextMenuProps: function() { diff --git a/frontend/src/Metamaps/Views/TopicCard.js b/frontend/src/Metamaps/Views/TopicCard.js index 943869e9..dadc81b5 100644 --- a/frontend/src/Metamaps/Views/TopicCard.js +++ b/frontend/src/Metamaps/Views/TopicCard.js @@ -1,3 +1,5 @@ +/* global $ */ + import { ReactApp } from '../GlobalUI' const TopicCard = { @@ -9,6 +11,56 @@ const TopicCard = { hideCard: function() { TopicCard.openTopic = null ReactApp.render() + }, + uploadAttachment: (topic, file) => { + const data = new window.FormData() + data.append('attachment[file]', file) + data.append('attachment[attachable_type]', 'Topic') + data.append('attachment[attachable_id]', topic.id) + return new Promise((resolve, reject) => { + $.ajax({ + url: '/attachments', + type: 'POST', + data, + processData: false, + contentType: false, + success: (data) => { + console.log('file upolad success', data) + topic.fetch({ success: () => { + ReactApp.render() + resolve(true) + }}) + }, + error: (error) => { + console.error(error) + window.alert('File upload failed') + topic.fetch({ success: () => { + ReactApp.render() + resolve(false) + }}) + } + }) + }) + }, + removeAttachment: (topic) => { + const attachments = topic.get('attachments') + if (!attachments || attachments.length < 1) { + return + } + + $.ajax({ + url: `/attachments/${attachments[0].id}`, + type: 'DELETE', + success: () => { + console.log('delete success, syncing topic') + topic.fetch({ success: () => ReactApp.render() }) + }, + error: error => { + console.error(error) + window.alert('Failed to remove attachment') + topic.fetch({ success: () => ReactApp.render() }) + } + }) } } diff --git a/frontend/src/components/TopicCard/Attachments.js b/frontend/src/components/TopicCard/Attachments.js index fcb5bea8..539d7271 100644 --- a/frontend/src/components/TopicCard/Attachments.js +++ b/frontend/src/components/TopicCard/Attachments.js @@ -1,20 +1,101 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import EmbedlyLink from './EmbedlyLink' +import EmbedlyLinkChooser from './EmbedlyLinkChooser' +import EmbedlyCard from './EmbedlyCard' +import FileUploader from './FileUploader' +import PhotoUploader from './PhotoUploader' +import AudioUploader from './AudioUploader' +import FileAttachment from './FileAttachment' class Attachments extends Component { + constructor(props) { + super(props) + + this.state = this.defaultState + } + + defaultState = { + addingPhoto: false, + addingLink: false, + addingAudio: false, + addingFile: false + } + + clearState = () => { + this.setState(this.defaultState) + } + + // onClick handler for the 4 buttons, which triggers showing the proper uploader + choose = key => () => { + this.setState(Object.assign({}, this.defaultState, { [key]: true })) + } + render = () => { const { topic, authorizedToEdit, updateTopic } = this.props const link = topic.get('link') + const attachments = topic.get('attachments') + const file = attachments && attachments.length ? attachments[0] : null + + let childComponent + if (link) { + childComponent = ( + + ) + } else if (file) { + childComponent = ( + + ) + } else if (!authorizedToEdit) { + childComponent = null + } else if (this.state.addingPhoto) { + childComponent = ( + + ) + } else if (this.state.addingLink) { + childComponent = ( + + ) + } else if (this.state.addingAudio) { + childComponent = ( + + ) + } else if (this.state.addingFile) { + childComponent = ( + + ) + } else { + childComponent = ( +
+
Photo
+
Link
+
Audio
+
Upload
+
+ ) + } return (
- + {childComponent}
) } @@ -23,7 +104,10 @@ class Attachments extends Component { Attachments.propTypes = { topic: PropTypes.object, // Backbone object authorizedToEdit: PropTypes.bool, - updateTopic: PropTypes.func + updateTopic: PropTypes.func, + uploadAttachment: PropTypes.func, + removeAttachment: PropTypes.func, + fileTypeIcons: PropTypes.objectOf(PropTypes.string) } export default Attachments diff --git a/frontend/src/components/TopicCard/AudioUploader.js b/frontend/src/components/TopicCard/AudioUploader.js new file mode 100644 index 00000000..a579e24b --- /dev/null +++ b/frontend/src/components/TopicCard/AudioUploader.js @@ -0,0 +1,81 @@ +import React, { Component, PropTypes } from 'react' + +import Recorder from 'react-recorder' + +class AudioUploader extends Component { + constructor(props) { + super(props) + + this.state = { + command: 'none' + } + } + + timeLimit30sTimeoutId = null + + enforce30sTimeLimit = cmd => { + window.clearTimeout(this.timeLimit30sTimeoutId) + if (cmd === 'start') { + this.timeLimit30sTimeoutId = window.setTimeout(() => { + this.command('stop')() + }, 30000) + } + } + + command = cmd => () => { + this.enforce30sTimeLimit(cmd) + this.setState({ command: cmd }) + } + + onStop = blob => { + const now = new Date() + const date = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}-${now.getHours()}:${now.getMinutes()}` + const filename = `metamaps-recorded-audio-${date}.wav` + const file = new window.File([blob], filename, { lastModifiedDate: now }) + + this.props.uploadAttachment(file).then(success => { + if (!success) { + this.command('none') + } + }) + } + + handleRecordingError = () => { + window.alert(`Audio recording failed. Some possible reasons include: + not using an HTTPS connection, + missing microphone, + you haven't allowed your browser access to your microphone, + or you need to reload the page.`) + } + + render() { + return ( +
+ + {this.state.command === 'start' && ( +
+
+
  Recording...
+
+ )} + {this.state.command === 'none' && ( +
+ Click to record
+ (max 30 seconds) +
+ )} +
+
+ ) + } +} + +AudioUploader.propTypes = { + uploadAttachment: PropTypes.func, + cancel: PropTypes.func +} + +export default AudioUploader diff --git a/frontend/src/components/TopicCard/EmbedlyLink/Card.js b/frontend/src/components/TopicCard/EmbedlyCard.js similarity index 82% rename from frontend/src/components/TopicCard/EmbedlyLink/Card.js rename to frontend/src/components/TopicCard/EmbedlyCard.js index da7474cb..e8b05e16 100644 --- a/frontend/src/components/TopicCard/EmbedlyLink/Card.js +++ b/frontend/src/components/TopicCard/EmbedlyCard.js @@ -1,4 +1,4 @@ -/* global $, embedly */ +/* global embedly */ import React, { Component } from 'react' import PropTypes from 'prop-types' @@ -38,29 +38,33 @@ class EmbedlyCard extends Component { } render = () => { - const { link } = this.props const { embedlyLinkLoaded, embedlyLinkStarted, embedlyLinkError } = this.state const notReady = embedlyLinkStarted && !embedlyLinkLoaded && !embedlyLinkError return ( -
+
- {link} + {this.props.link} {notReady &&
loading...
} + {this.props.authorizedToEdit && ( +
+ )}
) } } EmbedlyCard.propTypes = { - link: PropTypes.string + link: PropTypes.string, + authorizedToEdit: PropTypes.bool, + removeLink: PropTypes.func } export default EmbedlyCard diff --git a/frontend/src/components/TopicCard/EmbedlyLink/index.js b/frontend/src/components/TopicCard/EmbedlyLinkChooser.js similarity index 50% rename from frontend/src/components/TopicCard/EmbedlyLink/index.js rename to frontend/src/components/TopicCard/EmbedlyLinkChooser.js index 0f6df211..d35dc893 100644 --- a/frontend/src/components/TopicCard/EmbedlyLink/index.js +++ b/frontend/src/components/TopicCard/EmbedlyLinkChooser.js @@ -1,10 +1,7 @@ -/* global embedly */ import React, { Component } from 'react' import PropTypes from 'prop-types' -import Card from './Card' - -class EmbedlyLink extends Component { +class EmbedlyLinkChooser extends Component { constructor(props) { super(props) @@ -13,12 +10,9 @@ class EmbedlyLink extends Component { } } - removeLink = () => { - this.props.updateTopic({ link: null }) - } - resetLink = () => { this.setState({ linkEdit: '' }) + this.props.cancel() } onLinkChangeHandler = e => { @@ -35,17 +29,11 @@ class EmbedlyLink extends Component { } render = () => { - const { link, authorizedToEdit, topicId } = this.props const { linkEdit } = this.state - const hasAttachment = !!link - - if (!hasAttachment && !authorizedToEdit) return null return ( -
-
+
+
(this.linkInput = input)} @@ -53,26 +41,17 @@ class EmbedlyLink extends Component { value={linkEdit} onChange={this.onLinkChangeHandler} onKeyUp={this.onLinkKeyUpHandler}> - {linkEdit &&
} +
- {link && } - {authorizedToEdit && ( -
- )}
) } } -EmbedlyLink.propTypes = { - topicId: PropTypes.number, - link: PropTypes.string, - authorizedToEdit: PropTypes.bool, - updateTopic: PropTypes.func +EmbedlyLinkChooser.propTypes = { + updateTopic: PropTypes.func, + cancel: PropTypes.func } -export default EmbedlyLink +export default EmbedlyLinkChooser diff --git a/frontend/src/components/TopicCard/FileAttachment.js b/frontend/src/components/TopicCard/FileAttachment.js new file mode 100644 index 00000000..d7053a4b --- /dev/null +++ b/frontend/src/components/TopicCard/FileAttachment.js @@ -0,0 +1,57 @@ +import React, { Component, PropTypes } from 'react' + +class FileAttachment extends Component { + getFileType = contentType => { + if (contentType === 'text/plain') { + return 'text' + } else if (contentType === 'application/pdf') { + return 'pdf' + } else if (contentType.match(/^image\//)) { + return 'image' + } else if (contentType.match(/^audio\//) || + contentType === 'video/ogg' || + contentType === 'video/webm') { + return 'audio' + } else { + return 'unknown' + } + } + + getFileIcon = file => { + const type = this.getFileType(file.content_type) + + if (this.props.fileTypeIcons[type]) { + return this.props.fileTypeIcons[type] + } else { + return this.props.fileTypeIcons.unknown + } + } + + render() { + const { file } = this.props + return ( +
+ + + {file.file_name} + +
+
+ ) + } +} + +FileAttachment.propTypes = { + file: PropTypes.shape({ + content_type: PropTypes.string, + file_name: PropTypes.string, + url: PropTypes.string + }), + authorizedToEdit: PropTypes.bool, + removeAttachment: PropTypes.func, + fileTypeIcons: PropTypes.objectOf(PropTypes.string) +} + +export default FileAttachment diff --git a/frontend/src/components/TopicCard/FileUploader.js b/frontend/src/components/TopicCard/FileUploader.js new file mode 100644 index 00000000..80682291 --- /dev/null +++ b/frontend/src/components/TopicCard/FileUploader.js @@ -0,0 +1,34 @@ +import React, { Component, PropTypes } from 'react' +import Dropzone from 'react-dropzone' + +class FileUploader extends Component { + handleFileUpload = (acceptedFiles, rejectedFiles) => { + if (acceptedFiles.length >= 1) { + this.props.uploadAttachment(acceptedFiles[0]) + } else { + window.alert('File upload failed, please try again.') + } + } + + render() { + return ( +
+ + Drag file here
+ (maximum 5mb) +
+
+
+ ) + } +} + +FileUploader.propTypes = { + updateTopic: PropTypes.func, + uploadAttachment: PropTypes.func, + cancel: PropTypes.func +} + +export default FileUploader diff --git a/frontend/src/components/TopicCard/PhotoUploader.js b/frontend/src/components/TopicCard/PhotoUploader.js new file mode 100644 index 00000000..9cd66fe5 --- /dev/null +++ b/frontend/src/components/TopicCard/PhotoUploader.js @@ -0,0 +1,34 @@ +import React, { Component, PropTypes } from 'react' +import Dropzone from 'react-dropzone' + +class PhotoUploader extends Component { + handleFileUpload = (acceptedFiles, rejectedFiles) => { + if (acceptedFiles.length >= 1) { + this.props.uploadAttachment(acceptedFiles[0]) + } else { + window.alert('File upload failed, please try again.') + } + } + + render() { + return ( +
+ + Drag photo here
+ or click to upload +
+
+
+ ) + } +} + +PhotoUploader.propTypes = { + updateTopic: PropTypes.func, + uploadAttachment: PropTypes.func, + cancel: PropTypes.func +} + +export default PhotoUploader diff --git a/frontend/src/components/TopicCard/index.js b/frontend/src/components/TopicCard/index.js index 69ffa4e7..82751ca8 100644 --- a/frontend/src/components/TopicCard/index.js +++ b/frontend/src/components/TopicCard/index.js @@ -10,12 +10,17 @@ import Info from './Info' class ReactTopicCard extends Component { render = () => { - const { currentUser, onTopicFollow, updateTopic } = this.props + const { + currentUser, onTopicFollow, updateTopic, uploadAttachment, + removeAttachment + } = this.props const topic = this.props.openTopic if (!topic) return null const wrappedUpdateTopic = obj => updateTopic(topic, obj) + const wrappedUploadAttachment = file => uploadAttachment(topic, file) + const wrappedRemoveAttachment = () => removeAttachment(topic) const authorizedToEdit = topic.authorizeToEdit(currentUser) const hasAttachment = topic.get('link') && topic.get('link') !== '' @@ -48,9 +53,13 @@ class ReactTopicCard extends Component { authorizedToEdit={authorizedToEdit} onChange={wrappedUpdateTopic} /> -
@@ -75,7 +84,9 @@ ReactTopicCard.propTypes = { name: PropTypes.string })) })), - redrawCanvas: PropTypes.func + redrawCanvas: PropTypes.func, + uploadAttachment: PropTypes.func, + fileTypeIcons: PropTypes.objectOf(PropTypes.string) } export default ReactTopicCard diff --git a/package.json b/package.json index 5cece282..0830ef5d 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "react-draggable": "3.0.3", "react-dropzone": "4.1.2", "react-onclickoutside": "6.5.0", + "react-recorder": "1.0.0", "react-router": "3.0.5", "redux": "3.7.2", "riek": "1.1.0",