import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './StorageItem.styl' import { hashHistory } from 'react-router' import modal from 'browser/main/lib/modal' import CreateFolderModal from 'browser/main/modals/CreateFolderModal' import RenameFolderModal from 'browser/main/modals/RenameFolderModal' import dataApi from 'browser/main/lib/dataApi' import StorageItemChild from 'browser/components/StorageItem' import eventEmitter from 'browser/main/lib/eventEmitter' import _ from 'lodash' import * as path from 'path' const { remote } = require('electron') const { Menu, MenuItem, dialog } = remote class StorageItem extends React.Component { constructor (props) { super(props) this.state = { isOpen: true } } handleHeaderContextMenu (e) { const menu = Menu.buildFromTemplate([ { label: 'Add Folder', click: (e) => this.handleAddFolderButtonClick(e) }, { type: 'separator' }, { label: 'Unlink Storage', click: (e) => this.handleUnlinkStorageClick(e) } ]) menu.popup() } handleUnlinkStorageClick (e) { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: 'Unlink Storage', detail: 'This work will just detatches a storage from Boostnote. (Any data won\'t be deleted.)', buttons: ['Confirm', 'Cancel'] }) if (index === 0) { const { storage, dispatch } = this.props dataApi.removeStorage(storage.key) .then(() => { dispatch({ type: 'REMOVE_STORAGE', storageKey: storage.key }) }) .catch((err) => { throw err }) } } handleToggleButtonClick (e) { this.setState({ isOpen: !this.state.isOpen }) } handleAddFolderButtonClick (e) { const { storage } = this.props modal.open(CreateFolderModal, { storage }) } handleHeaderInfoClick (e) { const { storage } = this.props hashHistory.push('/storages/' + storage.key) } handleFolderButtonClick (folderKey) { return (e) => { const { storage } = this.props hashHistory.push('/storages/' + storage.key + '/folders/' + folderKey) } } handleFolderButtonContextMenu (e, folder) { const menu = Menu.buildFromTemplate([ { label: 'Rename Folder', click: (e) => this.handleRenameFolderClick(e, folder) }, { type: 'separator' }, { label: 'Export Folder', submenu: [ { label: 'Export as txt', click: (e) => this.handleExportFolderClick(e, folder, 'txt') }, { label: 'Export as md', click: (e) => this.handleExportFolderClick(e, folder, 'md') } ] }, { type: 'separator' }, { label: 'Delete Folder', click: (e) => this.handleFolderDeleteClick(e, folder) } ]) menu.popup() } handleRenameFolderClick (e, folder) { const { storage } = this.props modal.open(RenameFolderModal, { storage, folder }) } handleExportFolderClick (e, folder, fileType) { const options = { properties: ['openDirectory', 'createDirectory'], buttonLabel: 'Select directory', title: 'Select a folder to export the files to', multiSelections: false } dialog.showOpenDialog(remote.getCurrentWindow(), options, (paths) => { if (paths && paths.length === 1) { const { storage, dispatch } = this.props dataApi .exportFolder(storage.key, folder.key, fileType, paths[0]) .then((data) => { dispatch({ type: 'EXPORT_FOLDER', storage: data.storage, folderKey: data.folderKey, fileType: data.fileType }) }) } }) } handleFolderDeleteClick (e, folder) { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: 'Delete Folder', detail: 'This will delete all notes in the folder and can not be undone.', buttons: ['Confirm', 'Cancel'] }) if (index === 0) { const { storage, dispatch } = this.props dataApi .deleteFolder(storage.key, folder.key) .then((data) => { dispatch({ type: 'DELETE_FOLDER', storage: data.storage, folderKey: data.folderKey }) }) } } handleDragEnter (e) { e.dataTransfer.setData('defaultColor', e.target.style.backgroundColor) e.target.style.backgroundColor = 'rgba(129, 130, 131, 0.08)' } handleDragLeave (e) { e.target.style.opacity = '1' e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') } dropNote (storage, folder, dispatch, location, noteData) { noteData = noteData.filter((note) => folder.key !== note.folder) if (noteData.length === 0) return const newNoteData = noteData.map((note) => Object.assign({}, note, {storage: storage, folder: folder.key})) Promise.all( newNoteData.map((note) => dataApi.createNote(storage.key, note)) ) .then((createdNoteData) => { createdNoteData.forEach((note) => { dispatch({ type: 'UPDATE_NOTE', note: note }) }) }) .catch((err) => { console.error(`error on create notes: ${err}`) }) .then(() => { return Promise.all( noteData.map((note) => dataApi.deleteNote(note.storage, note.key)) ) }) .then((deletedNoteData) => { deletedNoteData.forEach((note) => { dispatch({ type: 'DELETE_NOTE', storageKey: note.storageKey, noteKey: note.noteKey }) }) }) .catch((err) => { console.error(`error on delete notes: ${err}`) }) } handleDrop (e, storage, folder, dispatch, location) { e.target.style.opacity = '1' e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') const noteData = JSON.parse(e.dataTransfer.getData('note')) this.dropNote(storage, folder, dispatch, location, noteData) } render () { const { storage, location, isFolded, data, dispatch } = this.props const { folderNoteMap, trashedSet } = data const folderList = storage.folders.map((folder) => { const isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key))) const noteSet = folderNoteMap.get(storage.key + '-' + folder.key) let noteCount = 0 if (noteSet) { let trashedNoteCount = 0 const noteKeys = noteSet.map(noteKey => { return noteKey }) trashedSet.toJS().forEach(trashedKey => { if (noteKeys.some(noteKey => { return noteKey === trashedKey })) trashedNoteCount++ }) noteCount = noteSet.size - trashedNoteCount } return ( this.handleFolderButtonClick(folder.key)(e)} handleContextMenu={(e) => this.handleFolderButtonContextMenu(e, folder)} folderName={folder.name} folderColor={folder.color} isFolded={isFolded} noteCount={noteCount} handleDrop={(e) => this.handleDrop(e, storage, folder, dispatch, location)} handleDragEnter={this.handleDragEnter} handleDragLeave={this.handleDragLeave} /> ) }) const isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$')) return (
this.handleHeaderContextMenu(e)} > {!isFolded && }
{this.state.isOpen &&
{folderList}
}
) } } StorageItem.propTypes = { isFolded: PropTypes.bool } export default CSSModules(StorageItem, styles)