diff --git a/src/components/basicHeader/view/basicHeaderStyles.js b/src/components/basicHeader/view/basicHeaderStyles.js index 700b8bf9c..374afb299 100644 --- a/src/components/basicHeader/view/basicHeaderStyles.js +++ b/src/components/basicHeader/view/basicHeaderStyles.js @@ -49,6 +49,9 @@ export default EStyleSheet.create({ justifyContent: 'center', alignSelf: 'center', }, + scheduleIcon: { + color: '$iconColor', + }, textButton: { fontSize: 16, }, diff --git a/src/components/basicHeader/view/basicHeaderView.js b/src/components/basicHeader/view/basicHeaderView.js index a22d09ce6..ce82a28d7 100644 --- a/src/components/basicHeader/view/basicHeaderView.js +++ b/src/components/basicHeader/view/basicHeaderView.js @@ -4,16 +4,19 @@ import { } from 'react-native'; import { injectIntl } from 'react-intl'; import DatePicker from 'react-native-datepicker'; +import moment from 'moment'; // Components import { TextButton } from '../..'; import { IconButton } from '../../iconButton'; import { DropdownButton } from '../../dropdownButton'; import { TextInput } from '../../textInput'; +import { Icon } from '../../icon'; // Constants // Styles import styles from './basicHeaderStyles'; +import datePickerStyles from './datePickerStyles'; class BasicHeaderView extends Component { /* Props @@ -26,7 +29,7 @@ class BasicHeaderView extends Component { super(props); this.state = { isInputVisible: false, - date: '2016-05-15', + datePickerValue: '', }; } @@ -58,6 +61,16 @@ class BasicHeaderView extends Component { _handleOnInputChange = () => {}; + _handleDatePickerChange = (datePickerValue) => { + const { handleDatePickerChange } = this.props; + + this.setState({ datePickerValue }); + + if (handleDatePickerChange) { + handleDatePickerChange(datePickerValue); + } + } + render() { const { dropdownComponent, @@ -84,7 +97,7 @@ class BasicHeaderView extends Component { rightIconName, title, } = this.props; - const { isInputVisible } = this.state; + const { isInputVisible, datePickerValue } = this.state; return ( @@ -176,51 +189,35 @@ class BasicHeaderView extends Component { {isHasIcons && ( - {/* */} - - { this.setState({ date }); }} - hideText - customStyles={{ - dateIcon: { - position: 'absolute', - left: 0, - top: 4, - marginLeft: 0, - }, - dateInput: { - marginLeft: 36, - height: 10, - width: 10, - backgroundColor: '#cbcbcb', - }, - // ... You can check the source to find the other keys. - }} - iconComponent={( - - )} - /> + {!isReply + && ( + { this._handleDatePickerChange(_datePickerValue); }} + hideText + disabled={!isFormValid} + onPressDate + customStyles={{ + ...datePickerStyles, + }} + iconComponent={( + + )} + /> + ) + } { + await NetInfo.isConnected.fetch().then((_isConnected) => { isConnected = _isConnected; }); @@ -104,7 +106,9 @@ class ApplicationContainer extends Component { }; componentWillReceiveProps(nextProps) { - const { isDarkTheme: _isDarkTheme, selectedLanguage, isLogingOut, isConnected } = this.props; + const { + isDarkTheme: _isDarkTheme, selectedLanguage, isLogingOut, isConnected, + } = this.props; if (_isDarkTheme !== nextProps.isDarkTheme || selectedLanguage !== nextProps.selectedLanguage) { this.setState({ isRenderRequire: false }, () => this.setState({ isRenderRequire: true })); @@ -134,7 +138,7 @@ class ApplicationContainer extends Component { await this._getUserData(); }; - _handleConntectionChange = status => { + _handleConntectionChange = (status) => { const { dispatch, isConnected } = this.props; if (isConnected !== status) { @@ -168,19 +172,19 @@ class ApplicationContainer extends Component { let realmData = []; let currentUsername; - await getAuthStatus().then(res => { + await getAuthStatus().then((res) => { ({ currentUsername } = res); if (res) { - getUserData().then(async userData => { + getUserData().then(async (userData) => { if (userData.length > 0) { realmData = userData; userData.forEach((accountData, index) => { if ( - !accountData.accessToken && - !accountData.masterKey && - !accountData.postingKey && - !accountData.activeKey && - !accountData.memoKey + !accountData.accessToken + && !accountData.masterKey + && !accountData.postingKey + && !accountData.activeKey + && !accountData.memoKey ) { realmData.splice(index, 1); if (realmData.length === 0) { @@ -214,7 +218,7 @@ class ApplicationContainer extends Component { .then((accountData) => { dispatch(login(true)); - const isExistUser = await getExistUser(); + const isExistUser = getExistUser(); [accountData.local] = realmObject; @@ -225,7 +229,7 @@ class ApplicationContainer extends Component { } this._connectNotificationServer(accountData.name); }) - .catch(err => { + .catch((err) => { Alert.alert(err); }); } @@ -237,7 +241,7 @@ class ApplicationContainer extends Component { _getSettings = () => { const { dispatch } = this.props; - getSettings().then(response => { + getSettings().then((response) => { if (response) { if (response.isDarkTheme !== '') dispatch(isDarkTheme(response.isDarkTheme)); if (response.language !== '') dispatch(setLanguage(response.language)); @@ -263,7 +267,7 @@ class ApplicationContainer extends Component { }); }; - _connectNotificationServer = username => { + _connectNotificationServer = (username) => { const { dispatch, unreadActivityCount } = this.props; const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`); @@ -301,10 +305,10 @@ class ApplicationContainer extends Component { .catch(() => {}); }; - _switchAccount = async targetAccountUsername => { + _switchAccount = async (targetAccountUsername) => { const { dispatch } = this.props; - await switchAccount(targetAccountUsername).then(accountData => { + await switchAccount(targetAccountUsername).then((accountData) => { const realmData = getUserDataWithUsername(targetAccountUsername); const _currentAccount = accountData; _currentAccount.username = accountData.name; diff --git a/src/screens/drafts/container/draftsContainer.js b/src/screens/drafts/container/draftsContainer.js index 4ae75155f..75bae5a8b 100644 --- a/src/screens/drafts/container/draftsContainer.js +++ b/src/screens/drafts/container/draftsContainer.js @@ -5,8 +5,9 @@ import { injectIntl } from 'react-intl'; // Services and Actions import { - getDrafts, removeDraft, getSchedules, removeSchedule, + getDrafts, removeDraft, getSchedules, removeSchedule, moveSchedule } from '../../../providers/esteem/esteem'; +import { toastNotification } from '../../../redux/actions/uiAction'; // Middleware @@ -48,7 +49,7 @@ class DraftsContainer extends Component { getSchedules(currentAccount.name) .then((data) => { - this.setState({ schedules: this._sortData(data), isLoading: false }); + this.setState({ schedules: this._sortData(data, true), isLoading: false }); }) .catch(() => { Alert.alert(intl.formatMessage({ id: 'drafts.load_error' })); @@ -87,18 +88,47 @@ class DraftsContainer extends Component { _removeSchedule = (id) => { const { currentAccount, intl } = this.props; + console.log(id); removeSchedule({ username: currentAccount.name, draftId: id }) - .then(() => { + .then((res) => { const { schedules } = this.state; const newSchedules = [...schedules].filter(schedule => schedule._id !== id); + console.log(res); - this.setState({ schedules: this._sortData(newSchedules) }); + this.setState({ schedules: this._sortData(newSchedules, true) }); }) .catch(() => { Alert.alert(intl.formatMessage({ id: 'alert.fail' })); }); }; + + _moveScheduleToDraft = (id) => { + const { currentAccount, dispatch, intl } = this.props; + console.log(id); + + moveSchedule(id, currentAccount.name) + .then((res) => { + console.log(res); + dispatch( + toastNotification( + intl.formatMessage({ + id: 'alert.success_moved', + }), + ), + ); + + this._getDrafts(); + this._getSchedules(); + }) + .catch(() => { + dispatch( + toastNotification( + intl.formatMessage({ id: 'alert.fail' }) + ), + ); + }); + } _editDraft = (id) => { const { navigation } = this.props; @@ -114,9 +144,9 @@ class DraftsContainer extends Component { }); }; - _sortData = data => data.sort((a, b) => { - const dateA = new Date(a.created).getTime(); - const dateB = new Date(b.created).getTime(); + _sortData = (data, isSchedule) => data.sort((a, b) => { + const dateA = new Date(isSchedule ? a.schedule : a.created).getTime(); + const dateB = new Date(isSchedule ? a.schedule : b.created).getTime(); return dateB > dateA ? 1 : -1; }); @@ -133,6 +163,7 @@ class DraftsContainer extends Component { drafts={drafts} schedules={schedules} removeDraft={this._removeDraft} + moveScheduleToDraft={this._moveScheduleToDraft} removeSchedule={this._removeSchedule} /> ); diff --git a/src/screens/drafts/screen/draftsScreen.js b/src/screens/drafts/screen/draftsScreen.js index fc4c7e0b0..7b81adc85 100644 --- a/src/screens/drafts/screen/draftsScreen.js +++ b/src/screens/drafts/screen/draftsScreen.js @@ -6,13 +6,14 @@ import ScrollableTabView from '@esteemapp/react-native-scrollable-tab-view'; // Utils import { getPostSummary } from '../../../utils/formatter'; import { catchDraftImage } from '../../../utils/image'; -// Constants +import { getFormatedCreatedDate } from '../../../utils/time'; // Components import { BasicHeader } from '../../../components/basicHeader'; import { PostListItem } from '../../../components/postListItem'; import { PostCardPlaceHolder } from '../../../components/basicUIElements'; import { TabBar } from '../../../components/tabBar'; +import ActionSheet from 'react-native-actionsheet'; // Styles import globalStyles from '../../../globalStyles'; @@ -26,7 +27,9 @@ class DraftsScreen extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + selectedId: null, + } } // Component Life Cycles @@ -41,19 +44,22 @@ class DraftsScreen extends Component { const tag = tags[0] || ''; const image = catchDraftImage(item.body); const summary = getPostSummary(item.body, 100); + const isSchedules = type === 'schedules'; return ( isSchedules ? this.setState({selectedId: item._id}, () => this.ActionSheet.show()) : editDraft} + handleOnRemoveItem={isSchedules ? removeSchedule : removeDraft} id={item._id} + key={item._id} /> ); }; @@ -91,7 +97,8 @@ class DraftsScreen extends Component { }; render() { - const { drafts, schedules, intl } = this.props; + const { drafts, schedules, intl, moveScheduleToDraft } = this.props; + const { selectedId } = this.state; return ( @@ -129,6 +136,24 @@ class DraftsScreen extends Component { {this._getTabItem(schedules, 'schedules')} + (this.ActionSheet = o)} + title={intl.formatMessage({ + id: 'alert.move_question', + })} + options={[ + intl.formatMessage({ + id: 'alert.move', + }), + intl.formatMessage({ + id: 'alert.cancel', + }), + ]} + cancelButtonIndex={1} + onPress={(index) => { + index === 0 && moveScheduleToDraft(selectedId); + }} + /> ); } diff --git a/src/screens/editor/container/editorContainer.js b/src/screens/editor/container/editorContainer.js index 70cd36ebf..9bdb316b9 100644 --- a/src/screens/editor/container/editorContainer.js +++ b/src/screens/editor/container/editorContainer.js @@ -6,7 +6,13 @@ import ImagePicker from 'react-native-image-crop-picker'; // Services and Actions import { Buffer } from 'buffer'; -import { uploadImage, addDraft, updateDraft } from '../../../providers/esteem/esteem'; +import { + uploadImage, + addDraft, + updateDraft, + schedule, +} from '../../../providers/esteem/esteem'; +import { toastNotification } from '../../../redux/actions/uiAction'; import { postContent, getPurePost } from '../../../providers/steem/dsteem'; import { setDraftPost, getDraftPost } from '../../../realm/realm'; @@ -69,7 +75,11 @@ class EditorContainer extends Component { _draft = navigationParams.draft; this.setState({ - draftPost: { title: _draft.title, body: _draft.body, tags: _draft.tags.split(' ') }, + draftPost: { + title: _draft.title, + body: _draft.body, + tags: _draft.tags.includes(' ') ? _draft.tags.split(' ') : _draft.tags.split(','), + }, draftId: _draft._id, isDraft: true, }); @@ -87,16 +97,14 @@ class EditorContainer extends Component { if (navigationParams.isEdit) { ({ isEdit } = navigationParams); - this.setState( - { - isEdit, - draftPost: { - title: post.title, - body: post.markdownBody, - tags: post.json_metadata.tags, - }, + this.setState({ + isEdit, + draftPost: { + title: post.title, + body: post.markdownBody, + tags: post.json_metadata.tags, }, - ); + }); } if (navigationParams.action) { @@ -121,7 +129,11 @@ class EditorContainer extends Component { await getDraftPost(username) .then((result) => { this.setState({ - draftPost: { body: result.body, title: result.title, tags: result.tags.split(',') }, + draftPost: { + body: result.body, + title: result.title, + tags: result.tags.split(','), + }, }); }) .catch(() => { @@ -266,7 +278,8 @@ class EditorContainer extends Component { const draftField = { ...fields, - tags: fields.tags && fields.tags.length > 0 ? fields.tags.toString() : '', + tags: + fields.tags && fields.tags.length > 0 ? fields.tags.toString() : '', }; if (isReply && draftField.body) { @@ -277,9 +290,14 @@ class EditorContainer extends Component { } }; - _submitPost = async (fields) => { + _submitPost = async (fields, scheduleDate) => { const { - navigation, currentAccount, pinCode, intl, isDefaultFooter, + currentAccount, + dispatch, + intl, + navigation, + pinCode, + // isDefaultFooter, } = this.props; if (currentAccount) { @@ -305,43 +323,63 @@ class EditorContainer extends Component { const options = makeOptions(author, permlink); const parentPermlink = fields.tags[0]; - await postContent( - currentAccount, - pinCode, - '', - parentPermlink, - permlink, - fields.title, - fields.body, - jsonMeta, - options, - 0, - ) - .then(() => { - Alert.alert( - intl.formatMessage({ - id: 'alert.success', - }), - intl.formatMessage({ - id: 'alert.success_shared', - }), - ); - - navigation.navigate({ - routeName: ROUTES.SCREENS.POST, - params: { - author: currentAccount.name, - permlink, - isNewPost: true, - }, - key: permlink, - }); - - setDraftPost({ title: '', body: '', tags: '' }, currentAccount.name); - }) - .catch((error) => { - this._handleSubmitFailure(error); + if (scheduleDate) { + await this._setScheduledPost({ + author, + permlink, + fields, + scheduleDate, }); + } else { + await postContent( + currentAccount, + pinCode, + '', + parentPermlink, + permlink, + fields.title, + fields.body, + jsonMeta, + options, + 0, + ) + .then(() => { + // Alert.alert( + // intl.formatMessage({ + // id: 'alert.success', + // }), + // intl.formatMessage({ + // id: 'alert.success_shared', + // }), + // ); + + dispatch( + toastNotification( + intl.formatMessage({ + id: 'alert.success_shared', + }), + ), + ); + + navigation.navigate({ + routeName: ROUTES.SCREENS.POST, + params: { + author: currentAccount.name, + permlink, + isNewPost: true, + }, + key: permlink, + }); + + setDraftPost( + { title: '', body: '', tags: '' }, + currentAccount.name, + ); + }) + .catch((error) => { + this._handleSubmitFailure(error); + }); + } } }; @@ -353,7 +391,9 @@ class EditorContainer extends Component { const { post } = this.state; - const jsonMeta = makeJsonMetadataReply(post.json_metadata.tags || ['esteem']); + const jsonMeta = makeJsonMetadataReply( + post.json_metadata.tags || ['esteem'], + ); const permlink = generateReplyPermlink(post.author); const author = currentAccount.name; const options = makeOptions(author, permlink); @@ -479,6 +519,38 @@ class EditorContainer extends Component { } }; + _handleDatePickerChange = (datePickerValue, fields) => { + this._submitPost(fields, datePickerValue); + }; + + _setScheduledPost = (data) => { + const { dispatch } = this.props; + + schedule( + data.author, + data.fields.title, + data.permlink, + '', + data.fields.tags, + data.fields.body, + '', + '', + data.scheduleDate, + ).then(() => { + this.setState({ isPostSending: false }); + dispatch( + toastNotification( + // intl.formatMessage({ + // id: 'alert.copied', + // }), + 'Scheduled', + ), + ); + }).catch(() => { + this.setState({ isPostSending: false }); + }); + } + render() { const { isLoggedIn, isDarkTheme } = this.props; const { @@ -500,11 +572,11 @@ class EditorContainer extends Component { ); diff --git a/src/screens/editor/screen/editorScreen.js b/src/screens/editor/screen/editorScreen.js index 4af40c666..d34fdca80 100644 --- a/src/screens/editor/screen/editorScreen.js +++ b/src/screens/editor/screen/editorScreen.js @@ -174,6 +174,7 @@ class EditorScreen extends Component { post, uploadedImage, handleOnBackPress, + handleDatePickerChange, } = this.props; const rightButtonText = intl.formatMessage({ id: isEdit ? 'basic_header.update' : isReply ? 'basic_header.reply' : 'basic_header.publish', @@ -182,19 +183,20 @@ class EditorScreen extends Component { return ( handleDatePickerChange(date, fields)} + handleOnBackPress={handleOnBackPress} handleOnPressPreviewButton={this._handleOnPressPreviewButton} handleOnSaveButtonPress={this._handleOnSaveButtonPress} handleOnSubmit={this._handleOnSubmit} - handleOnBackPress={handleOnBackPress} isDraftSaved={isDraftSaved} isDraftSaving={isDraftSaving} + isEdit={isEdit} isFormValid={isFormValid} isHasIcons - isEdit={isEdit} - isLoggedIn={isLoggedIn} - isReply={isReply} isLoading={isPostSending || isUploading} + isLoggedIn={isLoggedIn} isPreviewActive={isPreviewActive} + isReply={isReply} quickTitle={wordsCount > 0 && `${wordsCount} words`} rightButtonText={rightButtonText} />