From 9a32ca893e6885eab4ac64748800588cd37681f7 Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Thu, 5 Nov 2015 10:36:14 +0900 Subject: [PATCH 1/8] 0.4.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13a197d2..0801ca76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boost", - "version": "0.4.0-beta", + "version": "0.4.0-beta.1", "description": "Boost App", "main": "main.js", "scripts": { From 2736024cb768636537d741b2d1b1b603d66ebabb Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Thu, 5 Nov 2015 14:47:53 +0900 Subject: [PATCH 2/8] fix Title overflow behaviour --- .../main/HomeContainer/components/ArticleList.styl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/browser/styles/main/HomeContainer/components/ArticleList.styl b/browser/styles/main/HomeContainer/components/ArticleList.styl index 071fee3e..c5e32172 100644 --- a/browser/styles/main/HomeContainer/components/ArticleList.styl +++ b/browser/styles/main/HomeContainer/components/ArticleList.styl @@ -32,17 +32,20 @@ articleItemColor = #777 float right line-height 20px .middle - clearfix() padding 3px 0 7px font-size 16px + position relative + height 26px .mode - float left + position absolute + left 0 font-size 12px line-height 16px .title - float left + position absolute + left 19px + right 0 overflow ellipsis - padding 0 5px .bottom padding 5px 0 overflow-x auto From 83a8f4b911c5ed7e419878238634dd6df1d0373c Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Fri, 6 Nov 2015 21:46:29 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Cmd+S=E3=81=A7=E4=BF=9D=E5=AD=98=20debug=20?= =?UTF-8?q?craetedAt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/main/HomePage.js | 2 +- browser/main/HomePage/ArticleDetail.js | 1 + lib/reducer.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/browser/main/HomePage.js b/browser/main/HomePage.js index da1f6162..2f6f2983 100644 --- a/browser/main/HomePage.js +++ b/browser/main/HomePage.js @@ -47,7 +47,7 @@ class HomePage extends React.Component { if (e.keyCode === 27) { detail.handleCancelButtonClick() } - if (e.keyCode === 13 && e.metaKey) { + if ((e.keyCode === 13 && e.metaKey) || (e.keyCode === 83 && e.metaKey)) { detail.handleSaveButtonClick() } break diff --git a/browser/main/HomePage/ArticleDetail.js b/browser/main/HomePage/ArticleDetail.js index 5820ecd3..4601ae50 100644 --- a/browser/main/HomePage/ArticleDetail.js +++ b/browser/main/HomePage/ArticleDetail.js @@ -182,6 +182,7 @@ export default class ArticleDetail extends React.Component { delete newArticle.status newArticle.updatedAt = new Date() + if (newArticle.createdAt == null) newArticle.createdAt = new Date() dispatch(updateArticle(newArticle)) dispatch(switchMode(IDLE_MODE)) diff --git a/lib/reducer.js b/lib/reducer.js index 728f4384..c51df6de 100644 --- a/lib/reducer.js +++ b/lib/reducer.js @@ -23,7 +23,7 @@ function folders (state = initialFolders, action) { newFolder.name = newFolder.name.trim().replace(/\s/, '_') Object.assign(newFolder, { key: keygen(), - createAt: new Date(), + createdAt: new Date(), updatedAt: new Date(), // random number (0-7) color: Math.round(Math.random() * 7) From 8428588a4c92aec3e1e05dd6266844e644283c2e Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Fri, 6 Nov 2015 23:45:00 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Hotkey=20setting=08=E3=81=AE=E6=99=82Alert?= =?UTF-8?q?=E3=81=A7=E7=B5=90=E6=9E=9C=E3=82=92=E5=87=BA=E3=81=99=20Folder?= =?UTF-8?q?=20name=E3=81=8C=E9=95=B7=E3=81=99=E3=81=8E=E9=9B=A8=E6=99=82?= =?UTF-8?q?=E3=81=AElayout=E5=B4=A9=E3=82=8C=E8=A7=A3=E6=B1=BA=20ArticleNa?= =?UTF-8?q?vigator=E3=81=AE=E4=BD=99=E8=A8=88=E3=81=AA=E3=82=B9=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=82=92=E3=81=AA=E3=81=8F=E3=81=99=20Defaul?= =?UTF-8?q?t=20article=E3=81=AE=E8=AA=A4=E5=AD=97=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/main/HomePage/ArticleDetail.js | 2 +- browser/main/HomePage/ArticleList.js | 2 +- .../components/ArticleDetail.styl | 5 +++ .../HomeContainer/components/ArticleList.styl | 6 ++-- .../components/ArticleNavigator.styl | 7 ++-- .../main/HomeContainer/lib/Preferences.styl | 7 ++++ .../modal/Preference/AppSettingTab.js | 33 ++++++++++++++++++- lib/dataStore.js | 2 +- main.js | 6 +++- 9 files changed, 61 insertions(+), 9 deletions(-) diff --git a/browser/main/HomePage/ArticleDetail.js b/browser/main/HomePage/ArticleDetail.js index 4601ae50..fcecf5de 100644 --- a/browser/main/HomePage/ArticleDetail.js +++ b/browser/main/HomePage/ArticleDetail.js @@ -132,7 +132,7 @@ export default class ArticleDetail extends React.Component {
- {folder.name}  + {folder.name}  Created : {moment(activeArticle.createdAt).format('YYYY/MM/DD')}  Updated : {moment(activeArticle.updatedAt).format('YYYY/MM/DD')}
diff --git a/browser/main/HomePage/ArticleList.js b/browser/main/HomePage/ArticleList.js index 5232ca79..4f48f48a 100644 --- a/browser/main/HomePage/ArticleList.js +++ b/browser/main/HomePage/ArticleList.js @@ -85,7 +85,7 @@ export default class ArticleList extends React.Component {
this.handleArticleClick(article)(e)} className={'articleItem' + (activeArticle.key === article.key ? ' active' : '')}>
{folder != null - ? {folder.name} + ? {folder.name} : Unknown } {article.status != null ? article.status : moment(article.updatedAt).fromNow()} diff --git a/browser/styles/main/HomeContainer/components/ArticleDetail.styl b/browser/styles/main/HomeContainer/components/ArticleDetail.styl index c9536b16..f385a64b 100644 --- a/browser/styles/main/HomeContainer/components/ArticleDetail.styl +++ b/browser/styles/main/HomeContainer/components/ArticleDetail.styl @@ -44,6 +44,11 @@ iptFocusBorderColor = #369DCD .left absolute top left bottom right 120px + .folderName + display inline-block + max-width 100px + overflow ellipsis + height 10px .right absolute top right .detailBody diff --git a/browser/styles/main/HomeContainer/components/ArticleList.styl b/browser/styles/main/HomeContainer/components/ArticleList.styl index c5e32172..6617773a 100644 --- a/browser/styles/main/HomeContainer/components/ArticleList.styl +++ b/browser/styles/main/HomeContainer/components/ArticleList.styl @@ -26,8 +26,10 @@ articleItemColor = #777 line-height 20px padding 5px 0 color articleItemColor - .profileImage - vertical-align middle + .folderName + overflow ellipsis + display inline-block + width 120px .updatedAt float right line-height 20px diff --git a/browser/styles/main/HomeContainer/components/ArticleNavigator.styl b/browser/styles/main/HomeContainer/components/ArticleNavigator.styl index 05cb70a2..91b25fa7 100644 --- a/browser/styles/main/HomeContainer/components/ArticleNavigator.styl +++ b/browser/styles/main/HomeContainer/components/ArticleNavigator.styl @@ -100,9 +100,12 @@ articleNavBgColor = #353535 background-color brandColor border-color brandColor .folders - margin-bottom 15px + absolute bottom + top 200px + width 100% .folderList - height 340px + absolute bottom + top 38px overflow-y auto .folderList button height 33px diff --git a/browser/styles/main/HomeContainer/lib/Preferences.styl b/browser/styles/main/HomeContainer/lib/Preferences.styl index 3dbdbd14..004c3eaa 100644 --- a/browser/styles/main/HomeContainer/lib/Preferences.styl +++ b/browser/styles/main/HomeContainer/lib/Preferences.styl @@ -103,6 +103,11 @@ iptFocusBorderColor = #369DCD font-size 14px &:hover background-color lighten(brandColor, 10%) + .alert + float right + width 250px + padding 10px 15px + margin 0 10px 0 .alert color infoTextColor background-color infoBackgroundColor @@ -374,6 +379,7 @@ iptFocusBorderColor = #369DCD .folderName float left width 175px + overflow ellipsis padding-left 15px .folderPublic float left @@ -480,6 +486,7 @@ iptFocusBorderColor = #369DCD height 33px width 250px padding-left 15px + overflow ellipsis strong font-size 16px color brandColor diff --git a/lib/components/modal/Preference/AppSettingTab.js b/lib/components/modal/Preference/AppSettingTab.js index f96b01db..77bec059 100644 --- a/lib/components/modal/Preference/AppSettingTab.js +++ b/lib/components/modal/Preference/AppSettingTab.js @@ -9,10 +9,33 @@ export default class AppSettingTab extends React.Component { let keymap = remote.getGlobal('keymap') this.state = { - toggleFinder: keymap.toggleFinder + toggleFinder: keymap.toggleFinder, + alert: null } } + componentDidMount () { + this.handleSettingDone = () => { + this.setState({alert: { + type: 'success', + message: 'Successfully done!' + }}) + } + this.handleSettingError = err => { + this.setState({alert: { + type: 'error', + message: err.message + }}) + } + ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) + ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) + } + + componentWillUnmount () { + ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone) + ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError) + } + handleSaveButtonClick (e) { ipc.send('hotkeyUpdated', { toggleFinder: this.state.toggleFinder @@ -20,6 +43,13 @@ export default class AppSettingTab extends React.Component { } render () { + let alert = this.state.alert + let alertElement = alert != null ? ( +

+ {alert.message} +

+ ) : null + return (
@@ -30,6 +60,7 @@ export default class AppSettingTab extends React.Component {
+ {alertElement}
    diff --git a/lib/dataStore.js b/lib/dataStore.js index a142f6c2..96d51153 100644 --- a/lib/dataStore.js +++ b/lib/dataStore.js @@ -1,6 +1,6 @@ import keygen from 'boost/keygen' -let defaultContent = '**Boost**は全く新しいエンジニアライクのノートアプリです。\n\n# ◎特徴\nBoostはエンジニアの仕事を圧倒的に効率化するいくつかの機能を備えています。\nその一部をご紹介します。\n1. Folderで情報を分類\n2. 豊富なsyantaxに対応\n3. Finder機能\n4. チーム機能(リアルタイム搭載)\n\n* * * *\n\n# 1. Folderで情報を分類、欲しい情報にすぐアクセス。\n左側のバーに存在する「Folders」。\n今すぐプラスボタンを押しましょう。\n分類の仕方も自由自在です。\n- 言語やフレームワークごとにFolderを作成\n- 自分用のカジュアルなメモをまとめる場としてFolderを作成\n\n\n# 2. 豊富なsyantaxに対応、自分の脳の代わりに。\nプログラミングに関する情報を全て、手軽に保存しましょう。\n- mdで、apiの仕様をまとめる\n- よく使うモジュールやスニペット\n\nBoostに保存しておくことで、何度も同じコードを書いたり調べたりする必要がなくなります。\n\n# 3. Finder機能を搭載、もうコマンドを手打ちする必要はありません。\n**「shift+cmd+tab」** を同時に押してみてください。\nここでは、一瞬でBoostの中身を検索するウィンドウを表示させることができます。\n\n矢印キーで選択、Enterを押し、cmd+vでペーストすると…続きはご自身の目でお確かめください。\n- sqlやlinux等の、よく使うが手打ちが面倒なコマンド\n- (メールやカスタマーサポート等でよく使うフレーズ)\n\n私たちは、圧倒的な効率性を支援します。\n\* * * *\n\n\n## ◎詳しくは\nこちらのブログ( http://blog-jp.b00st.io )にて随時更新しています。\n\nそれでは素晴らしいエンジニアライフを!\n\n## Hack your memory**' +let defaultContent = '**Boost**は全く新しいエンジニアライクのノートアプリです。\n\n# ◎特徴\nBoostはエンジニアの仕事を圧倒的に効率化するいくつかの機能を備えています。\nその一部をご紹介します。\n1. Folderで情報を分類\n2. 豊富なsyantaxに対応\n3. Finder機能\n4. チーム機能(リアルタイム搭載)\n\n* * * *\n\n# 1. Folderで情報を分類、欲しい情報にすぐアクセス。\n左側のバーに存在する「Folders」。\n今すぐプラスボタンを押しましょう。\n分類の仕方も自由自在です。\n- 言語やフレームワークごとにFolderを作成\n- 自分用のカジュアルなメモをまとめる場としてFolderを作成\n\n\n# 2. 豊富なsyntaxに対応、自分の脳の代わりに。\nプログラミングに関する情報を全て、手軽に保存しましょう。\n- mdで、apiの仕様をまとめる\n- よく使うモジュールやスニペット\n\nBoostに保存しておくことで、何度も同じコードを書いたり調べたりする必要がなくなります。\n\n# 3. Finder機能を搭載、もうコマンドを手打ちする必要はありません。\n**「shift+cmd+tab」** を同時に押してみてください。\nここでは、一瞬でBoostの中身を検索するウィンドウを表示させることができます。\n\n矢印キーで選択、Enterを押し、cmd+vでペーストすると…続きはご自身の目でお確かめください。\n- sqlやlinux等の、よく使うが手打ちが面倒なコマンド\n- (メールやカスタマーサポート等でよく使うフレーズ)\n\n私たちは、圧倒的な効率性を支援します。\n\* * * *\n\n\n## ◎詳しくは\nこちらのブログ( http://blog-jp.b00st.io )にて随時更新しています。\n\nそれでは素晴らしいエンジニアライフを!\n\n## Hack your memory**' export function init () { console.log('initialize data store') diff --git a/main.js b/main.js index 0512751b..d3b9bd7d 100644 --- a/main.js +++ b/main.js @@ -138,8 +138,12 @@ app.on('ready', function () { } finderWindow.show() }) + mainWindow.webContents.send('APP_SETTING_DONE', {}) } catch (err) { - console.log(err.name) + console.error(err) + mainWindow.webContents.send('APP_SETTING_ERROR', { + message: 'Failed to apply hotkey: Invalid format' + }) } }) From 746df9277cab74f809d0e30cdff77b88ff8d6d02 Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Mon, 9 Nov 2015 15:07:17 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=E8=A1=8C=E5=8B=95=E3=83=87=E3=83=BC?= =?UTF-8?q?=E3=82=BF,=20contact=20form,=20default=20article=E3=81=AB?= =?UTF-8?q?=E8=8B=B1=E8=AA=9E=E6=96=87=E8=BF=BD=E5=8A=A0,=20Intro=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/finder/index.js | 3 + browser/main/HomePage/ArticleDetail.js | 9 +- browser/main/index.js | 3 + .../main/HomeContainer/lib/Preferences.styl | 64 +++++++++ .../main/HomeContainer/lib/Tutorial.styl | 3 +- lib/activityRecord.js | 122 +++++++++++++++++ lib/api.js | 10 +- lib/components/modal/Preference/ContactTab.js | 123 ++++++++++++++++++ lib/components/modal/Preferences.js | 10 +- lib/components/modal/Tutorial.js | 13 +- lib/dataStore.js | 2 +- lib/reducer.js | 5 +- 12 files changed, 356 insertions(+), 11 deletions(-) create mode 100644 lib/activityRecord.js create mode 100644 lib/components/modal/Preference/ContactTab.js diff --git a/browser/finder/index.js b/browser/finder/index.js index fb2a40a7..7fef8c7d 100644 --- a/browser/finder/index.js +++ b/browser/finder/index.js @@ -8,6 +8,7 @@ import FinderList from './FinderList' import FinderDetail from './FinderDetail' import { selectArticle, searchArticle, refreshData } from './actions' import _ from 'lodash' +import activityRecord from 'boost/activityRecord' import remote from 'remote' var hideFinder = remote.getGlobal('hideFinder') @@ -46,6 +47,7 @@ class FinderMain extends React.Component { if (e.keyCode === 13) { let { activeArticle } = this.props clipboard.writeText(activeArticle.content) + activityRecord.emit('FINDER_COPY') hideFinder() e.preventDefault() } @@ -174,6 +176,7 @@ var store = createStore(reducer) window.onfocus = e => { store.dispatch(refreshData()) + activityRecord.emit('FINDER_OPEN') } ReactDOM.render(( diff --git a/browser/main/HomePage/ArticleDetail.js b/browser/main/HomePage/ArticleDetail.js index fcecf5de..75d1f628 100644 --- a/browser/main/HomePage/ArticleDetail.js +++ b/browser/main/HomePage/ArticleDetail.js @@ -12,6 +12,7 @@ import linkState from 'boost/linkState' import FolderMark from 'boost/components/FolderMark' import TagLink from 'boost/components/TagLink' import TagSelect from 'boost/components/TagSelect' +import activityRecord from 'boost/activityRecord' var modeOptions = aceModes.map(function (mode) { return { @@ -93,6 +94,7 @@ export default class ArticleDetail extends React.Component { let { dispatch, activeArticle } = this.props dispatch(destroyArticle(activeArticle.key)) + activityRecord.emit('ARTICLE_DESTROY') this.setState({openDeleteConfirmMenu: false}) } @@ -182,7 +184,12 @@ export default class ArticleDetail extends React.Component { delete newArticle.status newArticle.updatedAt = new Date() - if (newArticle.createdAt == null) newArticle.createdAt = new Date() + if (newArticle.createdAt == null) { + newArticle.createdAt = new Date() + activityRecord.emit('ARTICLE_CREATE') + } else { + activityRecord.emit('ARTICLE_UPDATE') + } dispatch(updateArticle(newArticle)) dispatch(switchMode(IDLE_MODE)) diff --git a/browser/main/index.js b/browser/main/index.js index 29e05a9c..a749bdbe 100644 --- a/browser/main/index.js +++ b/browser/main/index.js @@ -10,6 +10,9 @@ import ReactDOM from 'react-dom' require('../styles/main/index.styl') import { openModal } from 'boost/modal' import Tutorial from 'boost/components/modal/Tutorial' +import activityRecord from 'boost/activityRecord' + +activityRecord.init() let routes = ( diff --git a/browser/styles/main/HomeContainer/lib/Preferences.styl b/browser/styles/main/HomeContainer/lib/Preferences.styl index 004c3eaa..79fe0e56 100644 --- a/browser/styles/main/HomeContainer/lib/Preferences.styl +++ b/browser/styles/main/HomeContainer/lib/Preferences.styl @@ -119,6 +119,70 @@ iptFocusBorderColor = #369DCD &.error color errorTextColor background-color errorBackgroundColor + &.ContactTab + &.done + .message + margin-top 75px + margin-bottom 15px + text-align center + font-size 22px + .checkIcon + margin-bottom 15px + font-size 144px + color brandColor + text-align center + .control + text-align center + button + border solid 1px borderColor + border-radius 5px + background-color white + padding 15px 15px + font-size 14px + &:hover + background-color darken(white, 10%) + &.form + padding 10px + .title + font-size 18px + color brandColor + margin-top 10px + margin-bottom 10px + .description + margin-bottom 15px + .iptGroup + margin-bottom 10px + input, textarea + border-radius 5px + border 1px solid borderColor + font-size 14px + outline none + padding 10px 15px + width 100% + &:focus + border-color iptFocusBorderColor + textarea + resize vertical + min-height 150px + .formControl + clearfix() + .alert + float right + padding 10px 15px + margin 0 5px 0 + font-size 14px + line-height normal + button + padding 10px 15px + background-color brandColor + color white + font-size 14px + border-radius 5px + border none + float right + &:hover + background-color lighten(brandColor, 10%) + &.AppSettingTab .description marked() diff --git a/browser/styles/main/HomeContainer/lib/Tutorial.styl b/browser/styles/main/HomeContainer/lib/Tutorial.styl index ced4547c..913bfbe5 100644 --- a/browser/styles/main/HomeContainer/lib/Tutorial.styl +++ b/browser/styles/main/HomeContainer/lib/Tutorial.styl @@ -109,8 +109,9 @@ slideBgColor4 = #00B493 .slide3 background-color slideBgColor3 .content + font-size 18px &>img - margin-top 45px + margin-top 25px .slide4 background-color slideBgColor4 .content diff --git a/lib/activityRecord.js b/lib/activityRecord.js new file mode 100644 index 00000000..71e61a82 --- /dev/null +++ b/lib/activityRecord.js @@ -0,0 +1,122 @@ +import _ from 'lodash' +import moment from 'moment' +import keygen from 'boost/keygen' +import dataStore from 'boost/dataStore' +import { request, WEB_URL } from 'boost/api' + +function isSameDate (a, b) { + a = moment(a).utcOffset(+540).format('YYYYMMDD') + b = moment(b).utcOffset(+540).format('YYYYMMDD') + + return a === b +} + +export function init () { + let records = getAllRecords() + if (records == null) { + saveAllRecords([]) + } + + postRecords() + if (window != null) { + window.addEventListener('online', postRecords) + window.setInterval(postRecords, 1000 * 60 * 60 * 24) + } +} + +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 () { + return JSON.parse(localStorage.getItem('activityRecords')) +} + +export function saveAllRecords (records) { + localStorage.setItem('activityRecords', JSON.stringify(records)) +} + +/* +Post all records(except today) +and remove all posted records +*/ +export function postRecords (data) { + let records = getAllRecords() + records = records.filter(record => { + return !isSameDate(new Date(), record.date) + }) + + if (records.length === 0) { + console.log('No records to post') + return + } + + console.log('posting...', records) + let input = { + clientKey: getClientKey(), + records + } + return request.post(WEB_URL + 'apis/activity') + .send(input) + .then(res => { + let records = getAllRecords() + let todayRecord = _.find(records, record => { + return isSameDate(new Date(), record.date) + }) + if (todayRecord != null) saveAllRecords([todayRecord]) + else saveAllRecords([]) + }) + .catch(err => { + console.error(err) + }) +} + +export function emit (type, data) { + let records = getAllRecords() + + let index = _.findIndex(records, record => { + return isSameDate(new Date(), record.date) + }) + + let todayRecord + if (index < 0) { + todayRecord = {date: new Date()} + records.push(todayRecord) + } + else todayRecord = records[index] + console.log(type) + switch (type) { + case 'ARTICLE_CREATE': + case 'ARTICLE_UPDATE': + case 'ARTICLE_DESTROY': + case 'FOLDER_CREATE': + case 'FOLDER_UPDATE': + case 'FOLDER_DESTROY': + case 'FINDER_OPEN': + case 'FINDER_COPY': + todayRecord[type] = todayRecord[type] == null + ? 1 + : todayRecord[type] + 1 + + break + } + + let storeData = dataStore.getData() + todayRecord.FOLDER_COUNT = _.isArray(storeData.folders) ? storeData.folders.length : 0 + todayRecord.ARTICLE_COUNT = _.isArray(storeData.articles) ? storeData.articles.length : 0 + + saveAllRecords(records) +} + +export default { + init, + emit, + getClientKey, + postRecords +} diff --git a/lib/api.js b/lib/api.js index 5a3ffa8f..e7156ce5 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,9 +1,12 @@ import superagent from 'superagent' import superagentPromise from 'superagent-promise' -import { API_URL } from '../config' import auth from 'boost/auth' -const request = superagentPromise(superagent, Promise) +export const API_URL = 'http://boost-api4.elasticbeanstalk.com/' +// export const WEB_URL = 'http://b00st.io/' +export const WEB_URL = 'http://localhost:3333/' + +export const request = superagentPromise(superagent, Promise) export function login (input) { return request @@ -163,6 +166,9 @@ export function sendEmail (input) { } export default { + API_URL, + WEB_URL, + request, login, signup, updateUserInfo, diff --git a/lib/components/modal/Preference/ContactTab.js b/lib/components/modal/Preference/ContactTab.js new file mode 100644 index 00000000..0de972a3 --- /dev/null +++ b/lib/components/modal/Preference/ContactTab.js @@ -0,0 +1,123 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import { getClientKey } from 'boost/activityRecord' +import linkState from 'boost/linkState' +import _ from 'lodash' +import { request, WEB_URL } from 'boost/api' + +const FORM_MODE = 'FORM_MODE' +const DONE_MODE = 'DONE_MODE' + +export default class ContactTab extends React.Component { + constructor (props) { + super(props) + + this.state = { + title: '', + content: '', + email: '', + mode: FORM_MODE, + alert: null + } + } + + componentDidMount () { + let titleInput = ReactDOM.findDOMNode(this.refs.title) + if (titleInput != null) titleInput.focus() + } + + handleBackButtonClick (e) { + this.setState({ + mode: FORM_MODE + }) + } + + handleSendButtonClick (e) { + let input = _.pick(this.state, ['title', 'content', 'email']) + input.clientKey = getClientKey() + + this.setState({ + alert: { + type: 'info', + message: 'Sending...' + } + }, () => { + request.post(WEB_URL + 'apis/inquiry') + .send(input) + .then(res => { + console.log('sent') + this.setState({ + title: '', + content: '', + mode: DONE_MODE, + alert: null + }) + }) + .catch(err => { + if (err.code === 'ECONNREFUSED') { + this.setState({ + alert: { + type: 'error', + message: 'Can\'t connect to API server.' + } + }) + } else { + console.error(err) + this.setState({ + alert: { + type: 'error', + message: err.message + } + }) + } + }) + }) + } + + render () { + switch (this.state.mode) { + case DONE_MODE: + return ( +
    +
    +
    + Your message has been sent successfully!! +
    +
    + +
    +
    + ) + case FORM_MODE: + default: + let alertElement = this.state.alert != null + ? ( +
    {this.state.alert.message}
    + ) + : null + return ( +
    +
    Contact form
    +
    + Your feedback is highly appreciated and will help us to improve our app. :D +
    +
    + +
    +
    +