created schedules part 2

This commit is contained in:
u-e 2019-04-13 17:19:55 +03:00
parent e5f10e189e
commit 738f24786c
10 changed files with 307 additions and 137 deletions

View File

@ -49,6 +49,9 @@ export default EStyleSheet.create({
justifyContent: 'center',
alignSelf: 'center',
},
scheduleIcon: {
color: '$iconColor',
},
textButton: {
fontSize: 16,
},

View File

@ -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 (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
@ -176,51 +189,35 @@ class BasicHeaderView extends Component {
{isHasIcons && (
<Fragment>
{/* <IconButton
style={styles.iconButton}
iconStyle={styles.rightIcon}
size={20}
iconType="MaterialIcons"
name="timer"
/> */}
<DatePicker
// style={{ width: 200 }}
date={this.state.date}
mode="date"
placeholder="select date"
format="YYYY-MM-DD"
minDate="2018-05-01"
maxDate="3000-06-01"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
onDateChange={(date) => { 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={(
<IconButton
style={styles.iconButton}
iconStyle={styles.rightIcon}
size={20}
iconType="MaterialIcons"
name="timer"
/>
)}
/>
{!isReply
&& (
<DatePicker
style={{ width: 50 }}
date={datePickerValue}
mode="date"
format="YYYY-MM-DD"
minDate={moment()}
maxDate="3000-06-01"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
onDateChange={(_datePickerValue) => { this._handleDatePickerChange(_datePickerValue); }}
hideText
disabled={!isFormValid}
onPressDate
customStyles={{
...datePickerStyles,
}}
iconComponent={(
<Icon
style={{ ...styles.iconButton, ...styles.scheduleIcon }}
size={20}
iconType="MaterialIcons"
name="timer"
/>
)}
/>
)
}
<IconButton
style={styles.iconButton}
size={25}

View File

@ -0,0 +1,31 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
btnConfirm: {
color: '$iconColor',
},
btnTextCancel: {
color: '$iconColor',
},
datePicker: {
marginTop: 42,
borderTopColor: '$borderColor',
borderTopWidth: 1,
backgroundColor: '$primaryBackgroundColor',
},
dateText: {
color: '$primaryDarkText',
},
btnText: {
position: 'absolute',
top: 0,
height: 42,
paddingHorizontal: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
datePickerCon: {
backgroundColor: '$primaryBackgroundColor',
},
});

View File

@ -45,6 +45,7 @@ class PostListItemView extends Component {
handleOnRemoveItem,
id,
intl,
isFormatedDate,
} = this.props;
return (
@ -53,7 +54,7 @@ class PostListItemView extends Component {
<View style={styles.header}>
<PostHeaderDescription
// date={intl.formatRelative(created)}
date={getTimeFromNow(created, true)}
date={isFormatedDate ? created : getTimeFromNow(created, true)}
name={username}
reputation={reputation}
size={32}

View File

@ -150,7 +150,10 @@
"allRead": "Marked all notifications as read",
"claim_reward_balance_ok": "Reward balance claimed",
"fail": "Fail!",
"move": "Move",
"move_question": "Are you sure to move to drafts?",
"success_shared": "Your post succesfully shared",
"success_moved": "Moved to draft",
"permission_denied": "Permission denied",
"permission_text": "Please, go to phone Settings and change eSteem app permissions.",
"success_rebloged": "Reblogged!",

View File

@ -1,5 +1,7 @@
import React, { Component } from 'react';
import { Platform, BackHandler, Alert, NetInfo } from 'react-native';
import {
Platform, BackHandler, Alert, NetInfo,
} from 'react-native';
import { connect } from 'react-redux';
import { addLocaleData } from 'react-intl';
import Config from 'react-native-config';
@ -87,7 +89,7 @@ class ApplicationContainer extends Component {
const { isIos } = this.state;
let isConnected;
await NetInfo.isConnected.fetch().then(_isConnected => {
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;

View File

@ -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,19 +88,48 @@ 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;
const { drafts } = this.state;
@ -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}
/>
);

View File

@ -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 (
<PostListItem
created={item.created}
created={isSchedules ? getFormatedCreatedDate(item.schedule) : item.created}
mainTag={tag}
title={item.title}
isFormatedDate={isSchedules}
summary={summary}
image={image ? { uri: catchDraftImage(item.body) } : null}
username={currentAccount.name}
reputation={currentAccount.reputation}
handleOnPressItem={editDraft}
handleOnRemoveItem={type === 'schedules' ? removeSchedule : removeDraft}
handleOnPressItem={() => 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 (
<View style={globalStyles.container}>
@ -129,6 +136,24 @@ class DraftsScreen extends Component {
{this._getTabItem(schedules, 'schedules')}
</View>
</ScrollableTabView>
<ActionSheet
ref={o => (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);
}}
/>
</View>
);
}

View File

@ -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 {
<EditorScreen
autoFocusText={autoFocusText}
draftPost={draftPost}
handleDatePickerChange={this._handleDatePickerChange}
handleFormChanged={this._handleFormChanged}
handleOnImagePicker={this._handleRoutingAction}
saveDraftToDB={this._saveDraftToDB}
handleOnSubmit={this._handleSubmit}
handleOnBackPress={this._handleOnBackPress}
handleOnImagePicker={this._handleRoutingAction}
handleOnSubmit={this._handleSubmit}
isCameraOrPickerOpen={isCameraOrPickerOpen}
isDarkTheme={isDarkTheme}
isDraftSaved={isDraftSaved}
@ -517,6 +589,7 @@ class EditorContainer extends Component {
isUploading={isUploading}
post={post}
saveCurrentDraft={this._saveCurrentDraft}
saveDraftToDB={this._saveDraftToDB}
uploadedImage={uploadedImage}
/>
);

View File

@ -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 (
<View style={globalStyles.defaultContainer}>
<BasicHeader
handleDatePickerChange={date => 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}
/>