mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
Url share done
This commit is contained in:
@@ -9,7 +9,7 @@ import _ from 'lodash'
|
|||||||
import { isModalOpen, closeModal } from 'boost/modal'
|
import { isModalOpen, closeModal } from 'boost/modal'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const BrowserWindow = electron.remote.BrowserWindow
|
const remote = electron.remote
|
||||||
|
|
||||||
const TEXT_FILTER = 'TEXT_FILTER'
|
const TEXT_FILTER = 'TEXT_FILTER'
|
||||||
const FOLDER_FILTER = 'FOLDER_FILTER'
|
const FOLDER_FILTER = 'FOLDER_FILTER'
|
||||||
@@ -29,10 +29,10 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown (e) {
|
handleKeyDown (e) {
|
||||||
if (process.env.BOOST_ENV === 'development' && e.keyCode === 73 && e.metaKey && e.altKey) {
|
if (e.keyCode === 73 && e.metaKey && e.altKey) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
BrowserWindow.getFocusedWindow().toggleDevTools()
|
remote.getCurrentWebContents().openDevTools()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ class HomePage extends React.Component {
|
|||||||
list.selectNextArticle()
|
list.selectNextArticle()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.keyCode === 65 || (e.keyCode === 13 && e.metaKey) || (e.keyCode === 78 && e.metaKey)) {
|
if ((e.keyCode === 65 && !e.metaKey && !e.ctrlKey) || (e.keyCode === 13 && e.metaKey) || (e.keyCode === 78 && e.metaKey)) {
|
||||||
nav.handleNewPostButtonClick()
|
nav.handleNewPostButtonClick()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
@@ -142,6 +142,7 @@ class HomePage extends React.Component {
|
|||||||
<ArticleDetail
|
<ArticleDetail
|
||||||
ref='detail'
|
ref='detail'
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
|
user={user}
|
||||||
activeArticle={activeArticle}
|
activeArticle={activeArticle}
|
||||||
folders={folders}
|
folders={folders}
|
||||||
status={status}
|
status={status}
|
||||||
|
|||||||
135
browser/main/HomePage/ArticleDetail/ShareButton.js
Normal file
135
browser/main/HomePage/ArticleDetail/ShareButton.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import api from 'boost/api'
|
||||||
|
import clientKey from 'boost/clientKey'
|
||||||
|
const clipboard = require('electron').clipboard
|
||||||
|
|
||||||
|
function getDefault () {
|
||||||
|
return {
|
||||||
|
openDropdown: false,
|
||||||
|
isSharing: false,
|
||||||
|
// Fetched url
|
||||||
|
url: null,
|
||||||
|
// for tooltip Copy -> Copied!
|
||||||
|
copied: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ShareButton extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.state = getDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
this.setState(getDefault())
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.dropdownInterceptor = e => {
|
||||||
|
this.dropdownClicked = true
|
||||||
|
}
|
||||||
|
ReactDOM.findDOMNode(this.refs.dropdown).addEventListener('click', this.dropdownInterceptor)
|
||||||
|
this.shareWithPublicURLHandler = e => {
|
||||||
|
this.handleShareWithPublicURLClick(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
document.removeEventListener('click', this.dropdownHandler)
|
||||||
|
ReactDOM.findDOMNode(this.refs.dropdown).removeEventListener('click', this.dropdownInterceptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpenButtonClick (e) {
|
||||||
|
this.openDropdown()
|
||||||
|
if (this.dropdownHandler == null) {
|
||||||
|
this.dropdownHandler = e => {
|
||||||
|
if (!this.dropdownClicked) {
|
||||||
|
this.closeDropdown()
|
||||||
|
} else {
|
||||||
|
this.dropdownClicked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.removeEventListener('click', this.dropdownHandler)
|
||||||
|
document.addEventListener('click', this.dropdownHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
openDropdown () {
|
||||||
|
this.setState({openDropdown: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDropdown () {
|
||||||
|
document.removeEventListener('click', this.dropdownHandler)
|
||||||
|
this.setState({openDropdown: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleShareWithPublicURLClick (e) {
|
||||||
|
let input = Object.assign({}, this.props.article, {clientKey: clientKey.get()})
|
||||||
|
api.shareWithPublicURL(input)
|
||||||
|
.then(res => {
|
||||||
|
let url = res.body.url
|
||||||
|
this.setState({url: url})
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCopyURLClick () {
|
||||||
|
clipboard.writeText(this.state.url)
|
||||||
|
this.setState({copied: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore copy url tooltip
|
||||||
|
handleCopyURLMouseLeave () {
|
||||||
|
this.setState({copied: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
let hasPublicURL = this.state.url != null
|
||||||
|
return (
|
||||||
|
<div className='ShareButton'>
|
||||||
|
<button ref='openButton' onClick={e => this.handleOpenButtonClick(e)} className='ShareButton-open-button'>
|
||||||
|
<i className='fa fa-fw fa-share-alt'/>
|
||||||
|
{
|
||||||
|
this.state.openDropdown ? null : (
|
||||||
|
<span className='tooltip'>Share</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
<div ref='dropdown' className={'share-dropdown' + (this.state.openDropdown ? '' : ' hide')}>
|
||||||
|
{
|
||||||
|
!hasPublicURL ? (
|
||||||
|
<button
|
||||||
|
onClick={e => this.shareWithPublicURLHandler(e)}
|
||||||
|
ref='sharePublicURL'
|
||||||
|
disabled={this.state.isSharing}>
|
||||||
|
<i className='fa fa-fw fa-external-link'/> {!this.state.isSharing ? 'Share with public URL' : 'Sharing...'}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<div className='ShareButton-url'>
|
||||||
|
<input className='ShareButton-url-input' value={this.state.url} readOnly/>
|
||||||
|
<button
|
||||||
|
onClick={e => this.handleCopyURLClick(e)}
|
||||||
|
className='ShareButton-url-button'
|
||||||
|
onMouseLeave={e => this.handleCopyURLMouseLeave(e)}
|
||||||
|
>
|
||||||
|
<i className='fa fa-fw fa-clipboard'/>
|
||||||
|
<div className='ShareButton-url-button-tooltip'>{this.state.copied ? 'Copied!' : 'Copy URL'}</div>
|
||||||
|
</button>
|
||||||
|
<div className='ShareButton-url-alert'>This url is valid for 7 days.</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShareButton.propTypes = {
|
||||||
|
article: PropTypes.shape({
|
||||||
|
publicURL: PropTypes.string
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -24,6 +24,8 @@ import TagLink from 'boost/components/TagLink'
|
|||||||
import TagSelect from 'boost/components/TagSelect'
|
import TagSelect from 'boost/components/TagSelect'
|
||||||
import ModeSelect from 'boost/components/ModeSelect'
|
import ModeSelect from 'boost/components/ModeSelect'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
import api from 'boost/api'
|
||||||
|
import ShareButton from './ShareButton'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const clipboard = electron.clipboard
|
const clipboard = electron.clipboard
|
||||||
@@ -106,12 +108,16 @@ export default class ArticleDetail extends React.Component {
|
|||||||
isTagChanged: false,
|
isTagChanged: false,
|
||||||
isTitleChanged: false,
|
isTitleChanged: false,
|
||||||
isContentChanged: false,
|
isContentChanged: false,
|
||||||
isModeChanged: false
|
isModeChanged: false,
|
||||||
|
openShareDropdown: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
||||||
|
this.shareDropdownInterceptor = e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
@@ -234,9 +240,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='right'>
|
<div className='right'>
|
||||||
|
<ShareButton article={activeArticle}/>
|
||||||
|
|
||||||
<button onClick={e => this.handleClipboardButtonClick(e)} className='editBtn'>
|
<button onClick={e => this.handleClipboardButtonClick(e)} className='editBtn'>
|
||||||
<i className='fa fa-fw fa-clipboard'/><span className='tooltip'>Copy to clipboard</span>
|
<i className='fa fa-fw fa-clipboard'/><span className='tooltip'>Copy to clipboard</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button onClick={e => this.handleEditButtonClick(e)} className='editBtn'>
|
<button onClick={e => this.handleEditButtonClick(e)} className='editBtn'>
|
||||||
<i className='fa fa-fw fa-edit'/><span className='tooltip'>Edit (e)</span>
|
<i className='fa fa-fw fa-edit'/><span className='tooltip'>Edit (e)</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -586,7 +595,8 @@ export default class ArticleDetail extends React.Component {
|
|||||||
ArticleDetail.propTypes = {
|
ArticleDetail.propTypes = {
|
||||||
status: PropTypes.shape(),
|
status: PropTypes.shape(),
|
||||||
activeArticle: PropTypes.shape(),
|
activeArticle: PropTypes.shape(),
|
||||||
activeUser: PropTypes.shape(),
|
user: PropTypes.shape(),
|
||||||
|
folders: PropTypes.array,
|
||||||
dispatch: PropTypes.func
|
dispatch: PropTypes.func
|
||||||
}
|
}
|
||||||
ArticleDetail.prototype.linkState = linkState
|
ArticleDetail.prototype.linkState = linkState
|
||||||
@@ -2,8 +2,6 @@ const electron = require('electron')
|
|||||||
const ipc = electron.ipcRenderer
|
const ipc = electron.ipcRenderer
|
||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
|
||||||
var ContactModal = require('boost/components/modal/ContactModal')
|
|
||||||
|
|
||||||
export default class MainContainer extends React.Component {
|
export default class MainContainer extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
@@ -20,20 +18,12 @@ export default class MainContainer extends React.Component {
|
|||||||
ipc.send('update-app', 'Deal with it.')
|
ipc.send('update-app', 'Deal with it.')
|
||||||
}
|
}
|
||||||
|
|
||||||
openContactModal () {
|
|
||||||
this.openModal(ContactModal)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className='Main'>
|
<div className='Main'>
|
||||||
{this.state.updateAvailable ? (
|
{this.state.updateAvailable ? (
|
||||||
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
|
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
|
||||||
) : null}
|
) : null}
|
||||||
{/* <button onClick={this.openContactModal} className='contactButton'>
|
|
||||||
<i className='fa fa-paper-plane-o'/>
|
|
||||||
<div className='tooltip'>Contact us</div>
|
|
||||||
</button> */}
|
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -284,7 +284,87 @@ iptFocusBorderColor = #369DCD
|
|||||||
color noTagsColor
|
color noTagsColor
|
||||||
.right
|
.right
|
||||||
z-index 30
|
z-index 30
|
||||||
button
|
div.share-dropdown
|
||||||
|
position absolute
|
||||||
|
right 5px
|
||||||
|
top 30px
|
||||||
|
background-color transparentify(invBackgroundColor, 80%)
|
||||||
|
padding 5px 0
|
||||||
|
width 200px
|
||||||
|
&.hide
|
||||||
|
display none
|
||||||
|
&>button
|
||||||
|
width 200px
|
||||||
|
text-align left
|
||||||
|
display block
|
||||||
|
height 33px
|
||||||
|
background-color transparent
|
||||||
|
color white
|
||||||
|
font-size 14px
|
||||||
|
padding 0 10px
|
||||||
|
border none
|
||||||
|
&:hover
|
||||||
|
background-color transparentify(lighten(invBackgroundColor, 30%), 80%)
|
||||||
|
&>.ShareButton-url
|
||||||
|
clearfix()
|
||||||
|
input.ShareButton-url-input
|
||||||
|
width 155px
|
||||||
|
margin 0 0 0 5px
|
||||||
|
height 25px
|
||||||
|
outline none
|
||||||
|
border none
|
||||||
|
border-top-left-radius 5px
|
||||||
|
border-bottom-left-radius 5px
|
||||||
|
float left
|
||||||
|
padding 5px
|
||||||
|
button.ShareButton-url-button
|
||||||
|
width 35px
|
||||||
|
height 25px
|
||||||
|
border none
|
||||||
|
margin 0 5px 0 0
|
||||||
|
outline none
|
||||||
|
border-top-right-radius 5px
|
||||||
|
border-bottom-right-radius 5px
|
||||||
|
background-color darken(white, 5%)
|
||||||
|
color inactiveTextColor
|
||||||
|
float right
|
||||||
|
div.ShareButton-url-button-tooltip
|
||||||
|
tooltip()
|
||||||
|
right 10px
|
||||||
|
&:hover
|
||||||
|
color textColor
|
||||||
|
div.ShareButton-url-button-tooltip
|
||||||
|
opacity 1
|
||||||
|
div.ShareButton-url-alert
|
||||||
|
float left
|
||||||
|
height 25px
|
||||||
|
line-height 25px
|
||||||
|
padding 0 15px
|
||||||
|
color white
|
||||||
|
|
||||||
|
.ShareButton
|
||||||
|
display inline-block
|
||||||
|
button.ShareButton-open-button
|
||||||
|
border-radius 16.5px
|
||||||
|
cursor pointer
|
||||||
|
height 33px
|
||||||
|
width 33px
|
||||||
|
border none
|
||||||
|
margin-right 5px
|
||||||
|
font-size 18px
|
||||||
|
color inactiveTextColor
|
||||||
|
background-color darken(white, 5%)
|
||||||
|
padding 0
|
||||||
|
.tooltip
|
||||||
|
tooltip()
|
||||||
|
margin-top 25px
|
||||||
|
margin-left -40px
|
||||||
|
&:hover
|
||||||
|
color textColor
|
||||||
|
.tooltip
|
||||||
|
opacity 1
|
||||||
|
|
||||||
|
&>button
|
||||||
border-radius 16.5px
|
border-radius 16.5px
|
||||||
cursor pointer
|
cursor pointer
|
||||||
height 33px
|
height 33px
|
||||||
|
|||||||
@@ -146,3 +146,23 @@ export function toggleTutorial () {
|
|||||||
type: TOGGLE_TUTORIAL
|
type: TOGGLE_TUTORIAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
updateUser,
|
||||||
|
clearNewArticle,
|
||||||
|
updateArticle,
|
||||||
|
destroyArticle,
|
||||||
|
createFolder,
|
||||||
|
updateFolder,
|
||||||
|
destroyFolder,
|
||||||
|
replaceFolder,
|
||||||
|
switchFolder,
|
||||||
|
switchMode,
|
||||||
|
switchArticle,
|
||||||
|
setSearchFilter,
|
||||||
|
setTagFilter,
|
||||||
|
clearSearch,
|
||||||
|
lockStatus,
|
||||||
|
unlockStatus,
|
||||||
|
toggleTutorial
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import keygen from 'boost/keygen'
|
|
||||||
import dataStore from 'boost/dataStore'
|
import dataStore from 'boost/dataStore'
|
||||||
import { request, WEB_URL } from 'boost/api'
|
import { request, WEB_URL } from 'boost/api'
|
||||||
|
import clientKey from 'boost/clientKey'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const version = electron.remote.app.getVersion()
|
const version = electron.remote.app.getVersion()
|
||||||
@@ -28,16 +28,6 @@ export function init () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getClientKey () {
|
|
||||||
let clientKey = localStorage.getItem('clientKey')
|
|
||||||
if (!_.isString(clientKey) || clientKey.length !== 40) {
|
|
||||||
clientKey = keygen()
|
|
||||||
localStorage.setItem('clientKey', clientKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientKey
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAllRecords () {
|
export function getAllRecords () {
|
||||||
return JSON.parse(localStorage.getItem('activityRecords'))
|
return JSON.parse(localStorage.getItem('activityRecords'))
|
||||||
}
|
}
|
||||||
@@ -67,7 +57,7 @@ export function postRecords (data) {
|
|||||||
|
|
||||||
console.log('posting...', records)
|
console.log('posting...', records)
|
||||||
let input = {
|
let input = {
|
||||||
clientKey: getClientKey(),
|
clientKey: clientKey.get(),
|
||||||
records
|
records
|
||||||
}
|
}
|
||||||
return request.post(WEB_URL + 'apis/activity')
|
return request.post(WEB_URL + 'apis/activity')
|
||||||
@@ -142,6 +132,5 @@ export function emit (type, data = {}) {
|
|||||||
export default {
|
export default {
|
||||||
init,
|
init,
|
||||||
emit,
|
emit,
|
||||||
getClientKey,
|
|
||||||
postRecords
|
postRecords
|
||||||
}
|
}
|
||||||
|
|||||||
189
lib/api.js
189
lib/api.js
@@ -1,191 +1,22 @@
|
|||||||
import superagent from 'superagent'
|
import superagent from 'superagent'
|
||||||
import superagentPromise from 'superagent-promise'
|
import superagentPromise from 'superagent-promise'
|
||||||
import auth from 'boost/auth'
|
// import auth from 'boost/auth'
|
||||||
|
|
||||||
export const API_URL = 'http://boost-api4.elasticbeanstalk.com/'
|
// export const SERVER_URL = 'https://b00st.io/'
|
||||||
export const WEB_URL = 'https://b00st.io/'
|
export const SERVER_URL = 'http://localhost:3333/'
|
||||||
// export const WEB_URL = 'http://localhost:3333/'
|
|
||||||
|
|
||||||
export const request = superagentPromise(superagent, Promise)
|
export const request = superagentPromise(superagent, Promise)
|
||||||
|
|
||||||
export function login (input) {
|
export function shareWithPublicURL (input) {
|
||||||
return request
|
return request
|
||||||
.post(API_URL + 'auth/login')
|
.post(SERVER_URL + 'apis/share')
|
||||||
.send(input)
|
// .set({
|
||||||
}
|
// Authorization: 'Bearer ' + auth.token()
|
||||||
|
// })
|
||||||
export function signup (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'auth/register')
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateUserInfo (input) {
|
|
||||||
return request
|
|
||||||
.put(API_URL + 'auth/user')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updatePassword (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'auth/password')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchCurrentUser () {
|
|
||||||
return request
|
|
||||||
.get(API_URL + 'auth/user')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchArticles (userId) {
|
|
||||||
return request
|
|
||||||
.get(API_URL + 'teams/' + userId + '/articles')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createArticle (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'articles/')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveArticle (input) {
|
|
||||||
return request
|
|
||||||
.put(API_URL + 'articles/' + input.id)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroyArticle (articleId) {
|
|
||||||
return request
|
|
||||||
.del(API_URL + 'articles/' + articleId)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTeam (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'teams')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateTeamInfo (teamId, input) {
|
|
||||||
return request
|
|
||||||
.put(API_URL + 'teams/' + teamId)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroyTeam (teamId) {
|
|
||||||
return request
|
|
||||||
.del(API_URL + 'teams/' + teamId)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function searchUser (key) {
|
|
||||||
return request
|
|
||||||
.get(API_URL + 'search/users')
|
|
||||||
.query({key: key})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMember (teamId, input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'teams/' + teamId + '/members')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteMember (teamId, input) {
|
|
||||||
return request
|
|
||||||
.del(API_URL + 'teams/' + teamId + '/members')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createFolder (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'folders/')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateFolder (id, input) {
|
|
||||||
return request
|
|
||||||
.put(API_URL + 'folders/' + id)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function destroyFolder (id) {
|
|
||||||
return request
|
|
||||||
.del(API_URL + 'folders/' + id)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sendEmail (input) {
|
|
||||||
return request
|
|
||||||
.post(API_URL + 'mail')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + auth.token()
|
|
||||||
})
|
|
||||||
.send(input)
|
.send(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
API_URL,
|
SERVER_URL,
|
||||||
WEB_URL,
|
shareWithPublicURL
|
||||||
request,
|
|
||||||
login,
|
|
||||||
signup,
|
|
||||||
updateUserInfo,
|
|
||||||
updatePassword,
|
|
||||||
fetchCurrentUser,
|
|
||||||
fetchArticles,
|
|
||||||
createArticle,
|
|
||||||
saveArticle,
|
|
||||||
destroyArticle,
|
|
||||||
createTeam,
|
|
||||||
updateTeamInfo,
|
|
||||||
destroyTeam,
|
|
||||||
searchUser,
|
|
||||||
setMember,
|
|
||||||
deleteMember,
|
|
||||||
createFolder,
|
|
||||||
updateFolder,
|
|
||||||
destroyFolder,
|
|
||||||
sendEmail
|
|
||||||
}
|
}
|
||||||
|
|||||||
23
lib/clientKey.js
Normal file
23
lib/clientKey.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
|
import keygen from 'boost/keygen'
|
||||||
|
|
||||||
|
function getClientKey () {
|
||||||
|
let clientKey = localStorage.getItem('clientKey')
|
||||||
|
if (!_.isString(clientKey) || clientKey.length !== 40) {
|
||||||
|
clientKey = keygen()
|
||||||
|
setClientKey(clientKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientKey
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClientKey (newKey) {
|
||||||
|
localStorage.setItem('clientKey', newKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
getClientKey()
|
||||||
|
|
||||||
|
export default {
|
||||||
|
get: getClientKey,
|
||||||
|
set: setClientKey
|
||||||
|
}
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import React, { PropTypes, findDOMNode } from 'react'
|
|
||||||
import linkState from 'boost/linkState'
|
|
||||||
import { sendEmail } from 'boost/api'
|
|
||||||
|
|
||||||
export default class ContactModal extends React.Component {
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.linkState = linkState
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isSent: false,
|
|
||||||
mail: {
|
|
||||||
title: '',
|
|
||||||
content: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyCast (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
case 'submitContactModal':
|
|
||||||
if (this.state.isSent) {
|
|
||||||
this.props.close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.sendEmail()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
findDOMNode(this.refs.title).focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
sendEmail () {
|
|
||||||
sendEmail(this.state.mail)
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({isSent: !this.state.isSent})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='ContactModal modal'>
|
|
||||||
<div className='modal-header'><h1>Contact form</h1></div>
|
|
||||||
|
|
||||||
{!this.state.isSent ? (
|
|
||||||
<div className='contactForm'>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<div className='formField'>
|
|
||||||
<input ref='title' valueLink={this.linkState('mail.title')} placeholder='Title'/>
|
|
||||||
</div>
|
|
||||||
<div className='formField'>
|
|
||||||
<textarea valueLink={this.linkState('mail.content')} placeholder='Content'/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='modal-footer'>
|
|
||||||
<div className='formControl'>
|
|
||||||
<button onClick={this.sendEmail} className='sendButton'>Send</button>
|
|
||||||
<button onClick={this.props.close}>Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className='confirmation'>
|
|
||||||
<div className='confirmationMessage'>Thanks for sharing your opinion!</div>
|
|
||||||
<button className='doneButton' onClick={this.props.close}>Done</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactModal.propTypes = {
|
|
||||||
close: PropTypes.func
|
|
||||||
}
|
|
||||||
@@ -180,7 +180,9 @@ function articles (state = initialArticles, action) {
|
|||||||
|
|
||||||
let targetIndex = _.findIndex(state, _article => article.key === _article.key)
|
let targetIndex = _.findIndex(state, _article => article.key === _article.key)
|
||||||
if (targetIndex < 0) state.unshift(article)
|
if (targetIndex < 0) state.unshift(article)
|
||||||
else state.splice(targetIndex, 1, article)
|
else {
|
||||||
|
Object.assign(state[targetIndex], article)
|
||||||
|
}
|
||||||
|
|
||||||
if (article.status !== 'NEW') dataStore.setArticles(state)
|
if (article.status !== 'NEW') dataStore.setArticles(state)
|
||||||
else isCreatingNew = true
|
else isCreatingNew = true
|
||||||
|
|||||||
Reference in New Issue
Block a user