import React, { Component } from 'react' import { Link } from 'react-router-dom' import { ReactSortable } from "react-sortablejs" import actions from 'app/actions' import { capitalize, simpleArraysEqual } from 'app/utils' import { preloadImage } from 'app/utils/image.utils' import { DISPLAY_SIZE, DISPLAY_QUALITY, THUMBNAIL_SIZE, THUMBNAIL_QUALITY } from 'app/constants' import { TextInput, LabelDescription, FileInputField, Select, TextArea, Checkbox, SubmitButton, Loader } from 'app/common' import { renderThumbnail } from 'app/common/upload.helpers' import GalleryImageForm from './media.formGalleryImage' export default class MediaGalleryForm extends Component { state = { loading: false, edit_image_id: null, } constructor(props) { super(props) this.handleSelect = this.handleSelect.bind(this) this.handleChange = this.handleChange.bind(this) this.handleSettingsChange = this.handleSettingsChange.bind(this) this.handleUpload = this.handleUpload.bind(this) this.uploadSize = this.uploadSize.bind(this) this.handleSaveItem = this.handleSaveItem.bind(this) this.handleUploadGalleryThumbnail = this.handleUploadGalleryThumbnail.bind(this) this.handleDestroyGalleryThumbnail = this.handleDestroyGalleryThumbnail.bind(this) } componentDidMount() { const { data } = this.props this.handleSettingsChange('multiple', { image_order: data.settings.image_order || [], image_lookup: data.settings.image_lookup || {}, caption_lookup: data.settings.caption_lookup || {}, thumbnail_lookup: data.settings.thumbnail_lookup || {}, }) } handleChange(e) { const { name, value } = e.target this.handleSelect(name, value) } handleSelect(name, value) { this.props.onSelect(name, value) } handleSettingsChange(name, value) { this.props.onSettingsChange(name, value) } handleUpload(files) { const { data } = this.props this.setState({ loading: true }) this.uploadFullsize(files) .then(() => { this.setState({ loading: false }) }) } handleUploadGalleryThumbnail(file) { this.setState({ loading: true }) if (this.props.data.thumbnail) { this.handleDestroyGalleryThumbnail() } this.uploadThumbnail(file, 'thumbnail', THUMBNAIL_SIZE, THUMBNAIL_QUALITY) .then(thumbnail => { this.uploadThumbnail(file, 'display', DISPLAY_SIZE, DISPLAY_QUALITY) .then(display => { console.log(thumbnail, display) this.handleSettingsChange('multiple', { thumbnail, display, }) this.setState({ loading: false }) }) }) } handleDestroyGalleryThumbnail(e) { if (e) { e.preventDefault() e.stopPropagation() } console.log(this.props.data) actions.upload.destroy({ id: this.props.data.settings.thumbnail.id }) } uploadFullsize(files) { const { data } = this.props // first, upload all the fullsize files let fullsizeUploadPromises = files.map(file => { return this.uploadSize(file, 'fullsize') }) // when these are done return Promise.all(fullsizeUploadPromises).then(results => { // get the added IDs in order const added_image_order = results.map(result => result.id) // append the new IDs to the image order const new_image_order = (data.settings.image_order || []).concat(added_image_order) // add the images to the lookup const image_lookup = results.reduce((a,b) => { a[b.id] = b return a }, (data.settings.image_lookup || {})) // add these images to the settings object this.handleSettingsChange('multiple', { image_order: new_image_order, image_lookup: image_lookup, caption_lookup: data.settings.caption_lookup || {}, thumbnail_lookup: data.settings.thumbnail_lookup || {}, }) return this.uploadResizedFiles(files, added_image_order) }) } uploadResizedFiles(files, added_image_order) { return ( this.uploadThumbnails(files, added_image_order, 'thumbnail', THUMBNAIL_SIZE, THUMBNAIL_QUALITY) .then(() => { return this.uploadThumbnails(files, added_image_order, 'display', DISPLAY_SIZE, DISPLAY_QUALITY) }) ) } uploadThumbnails(files, added_image_order, tag, maxSide, quality) { const { data } = this.props // construct thumbnails and upload these const thumbnailUploadPromises = files.map(file => { return this.uploadThumbnail(file, tag, maxSide, quality) }) // once the thumbnails are done uploading... return Promise.all(thumbnailUploadPromises).then(thumbnail_results => { // decide which lookup we're adding to const tag_lookup_name = tag + '_lookup' const tag_lookup = data.settings[tag_lookup_name] || {} // add them to the thumbnail lookup, keyed off the ID of the fullsize image const thumbnail_lookup = thumbnail_results.reduce((a, b, i) => { const id = added_image_order[i] a[id] = b return a }, tag_lookup) // update the settings object this.handleSettingsChange('multiple', { [tag_lookup_name]: thumbnail_lookup, }) }) } uploadThumbnail(file, tag, maxSide, quality) { return new Promise((resolve, reject) => { const type = (file.name.match('.png') !== -1) ? 'image/png' : 'image/jpg' const fr = new FileReader() fr.onload = fileReaderEvent => { fr.onload = null const image = new Image() image.onload = () => { image.onload = null const thumbnailCanvas = renderThumbnail(image, { maxSide }) thumbnailCanvas.toBlob(thumbnail => { this.uploadSize(thumbnail, tag, file.name) .then(res => { resolve(res) }) .catch(err => { reject(err) }) }, type, quality) } image.src = fileReaderEvent.target.result } fr.readAsDataURL(file) }) } uploadSize(image, tag, fn) { // console.log('uploading size', tag) const uploadData = { image, tag, username: 'animism', } if (fn) { uploadData['__image_filename'] = fn } // console.log(uploadData) return actions.upload.upload(uploadData).then(data => { // console.log(data) return data.res }) } handleOrderChanged(new_image_order) { // console.log(new_image_order) const image_order = new_image_order.map(el => el.id) if (!simpleArraysEqual(image_order, this.props.data.settings.image_order)) { this.handleSettingsChange('image_order', image_order) } } handleSaveItem(id, item, editNext) { if (!id) { this.setState({ edit_image_id: null }) } const caption_lookup = this.props.data.settings.caption_lookup || {} caption_lookup[id] = item this.handleSettingsChange('caption_lookup', caption_lookup) if (editNext) { const image_order = this.props.data.settings.image_order const index = image_order.indexOf(id) + 1 if (index < image_order.length) { this.setState({ edit_image_id: image_order[index] }) } else { this.setState({ edit_image_id: null }) } } else { this.setState({ edit_image_id: null }) } } handleDeleteItem(id) { let { image_order, image_lookup, thumbnail_lookup, display_lookup, caption_lookup } = this.props.data.settings const new_image_order = image_order.filter(n => n !== id) caption_lookup = caption_lookup || {} const image_lookup_upload_id = ((image_lookup && image_lookup[id]) || {}).id if (image_lookup_upload_id) { actions.upload.destroy({ id: image_lookup_upload_id }) } const thumbnail_lookup_upload_id = ((thumbnail_lookup && thumbnail_lookup[id]) || {}).id if (thumbnail_lookup_upload_id) { actions.upload.destroy({ id: thumbnail_lookup_upload_id }) } const display_lookup_upload_id = ((display_lookup && display_lookup[id]) || {}).id if (display_lookup_upload_id) { actions.upload.destroy({ id: display_lookup_upload_id }) } image_lookup && delete image_lookup[id] thumbnail_lookup && delete thumbnail_lookup[id] display_lookup && delete display_lookup[id] caption_lookup && delete caption_lookup[id] this.handleSettingsChange('multiple', { image_order: new_image_order, image_lookup: { ...image_lookup }, thumbnail_lookup: { ...thumbnail_lookup }, display_lookup: { ...display_lookup }, caption_lookup: { ...caption_lookup }, }) } render() { const { data } = this.props const { image_order, image_lookup, thumbnail_lookup, caption_lookup } = data.settings const { loading, edit_image_id } = this.state // console.log(data) return (