mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-17 10:21:33 +03:00
Merge branch 'development' of https://github.com/ecency/ecency-mobile into sa/fix-usenativedriver-warnings
This commit is contained in:
commit
752de13223
@ -144,7 +144,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch
|
||||
versionName "3.0.34"
|
||||
versionName "3.0.35"
|
||||
resValue "string", "build_config_package", "app.esteem.mobile.android"
|
||||
multiDexEnabled true
|
||||
// react-native-image-crop-picker
|
||||
|
@ -15,11 +15,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.34</string>
|
||||
<string>3.0.35</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2813</string>
|
||||
<string>2814</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true />
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.34</string>
|
||||
<string>3.0.35</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2813</string>
|
||||
<string>2814</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1132,7 +1132,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2813;
|
||||
CURRENT_PROJECT_VERSION = 2814;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
||||
EXCLUDED_ARCHS = "";
|
||||
@ -1211,7 +1211,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ecency/Ecency.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2813;
|
||||
CURRENT_PROJECT_VERSION = 2814;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = 75B6RXTKGT;
|
||||
EXCLUDED_ARCHS = "";
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.34</string>
|
||||
<string>3.0.35</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.34</string>
|
||||
<string>3.0.35</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2813</string>
|
||||
<string>2814</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.34</string>
|
||||
<string>3.0.35</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2813</string>
|
||||
<string>2814</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ecency",
|
||||
"version": "3.0.34",
|
||||
"version": "3.0.35",
|
||||
"displayName": "Ecency",
|
||||
"private": true,
|
||||
"rnpm": {
|
||||
@ -54,6 +54,9 @@
|
||||
"@react-navigation/native": "^6.0.11",
|
||||
"@react-navigation/native-stack": "^6.7.0",
|
||||
"@react-navigation/stack": "^6.2.2",
|
||||
"@tanstack/query-async-storage-persister": "^4.3.9",
|
||||
"@tanstack/react-query": "^4.3.9",
|
||||
"@tanstack/react-query-persist-client": "^4.3.9",
|
||||
"@tradle/react-native-http": "^2.0.0",
|
||||
"appcenter": "^4.1.0",
|
||||
"appcenter-analytics": "^4.1.0",
|
||||
@ -104,7 +107,6 @@
|
||||
"react-native-highlight-words": "^1.0.1",
|
||||
"react-native-iap": "^7.5.6",
|
||||
"react-native-image-crop-picker": "^0.35.2",
|
||||
"react-native-image-size": "^1.1.3",
|
||||
"react-native-image-zoom-viewer": "^2.2.27",
|
||||
"react-native-iphone-x-helper": "^1.3.1",
|
||||
"react-native-keyboard-aware-scroll-view": "^0.9.1",
|
||||
@ -201,7 +203,7 @@
|
||||
"rn-nodeify": "^10.3.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"yarn run lint:fix",
|
||||
"git add"
|
||||
]
|
||||
|
@ -25,16 +25,8 @@ class ContainerHeaderView extends PureComponent {
|
||||
// Component Functions
|
||||
|
||||
render() {
|
||||
const {
|
||||
color,
|
||||
defaultTitle,
|
||||
fontSize,
|
||||
hasSeperator,
|
||||
iconName,
|
||||
isBoldTitle,
|
||||
title,
|
||||
isCenter,
|
||||
} = this.props;
|
||||
const { color, defaultTitle, fontSize, hasSeperator, iconName, isBoldTitle, title, isCenter } =
|
||||
this.props;
|
||||
|
||||
return (
|
||||
<View style={[styles.wrapper, hasSeperator && styles.hasTopBorder]}>
|
||||
|
@ -14,16 +14,9 @@ export default EStyleSheet.create({
|
||||
body: {
|
||||
marginHorizontal: 9,
|
||||
},
|
||||
image: {
|
||||
margin: 0,
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
//height: 200,
|
||||
//width: '$deviceWidth - 16',
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
// paddingVertical: 10,
|
||||
marginVertical: 5,
|
||||
thumbnail: {
|
||||
width: '$deviceWidth - 16',
|
||||
height: 300
|
||||
},
|
||||
postDescripton: {
|
||||
flexDirection: 'column',
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useRef, useState, useEffect, Fragment } from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import ImageSize from 'react-native-image-size';
|
||||
|
||||
// Utils
|
||||
import { getTimeFromNow } from '../../../utils/time';
|
||||
@ -9,20 +8,14 @@ import { getTimeFromNow } from '../../../utils/time';
|
||||
// Components
|
||||
import { PostHeaderDescription } from '../../postElements';
|
||||
import { IconButton } from '../../iconButton';
|
||||
import ProgressiveImage from '../../progressiveImage';
|
||||
import { OptionsModal } from '../../atoms';
|
||||
|
||||
// Styles
|
||||
import styles from './draftListItemStyles';
|
||||
import { ScheduledPostStatus } from '../../../providers/ecency/ecency.types';
|
||||
import { PopoverWrapper } from '../../popoverWrapper/popoverWrapperView';
|
||||
import getWindowDimensions from '../../../utils/getWindowDimensions';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
// Defaults
|
||||
const DEFAULT_IMAGE =
|
||||
'https://images.ecency.com/DQmT8R33geccEjJfzZEdsRHpP3VE8pu3peRCnQa1qukU4KR/no_image_3x.png';
|
||||
|
||||
const dim = getWindowDimensions();
|
||||
|
||||
const DraftListItemView = ({
|
||||
title,
|
||||
@ -35,52 +28,55 @@ const DraftListItemView = ({
|
||||
thumbnail,
|
||||
handleOnPressItem,
|
||||
handleOnRemoveItem,
|
||||
handleOnMovePress,
|
||||
id,
|
||||
intl,
|
||||
isFormatedDate,
|
||||
status,
|
||||
isSchedules,
|
||||
isDeleting,
|
||||
}) => {
|
||||
const actionSheet = useRef(null);
|
||||
const [calcImgHeight, setCalcImgHeight] = useState(300);
|
||||
// Component Life Cycles
|
||||
const moveActionSheet = useRef(null);
|
||||
const [deleteRequested, setIsDeleteRequested] = useState(false);
|
||||
useEffect(() => {
|
||||
let _isMounted = false;
|
||||
if (image) {
|
||||
if (!_isMounted) {
|
||||
ImageSize.getSize(thumbnail.uri).then((size) => {
|
||||
setCalcImgHeight(Math.floor((size.height / size.width) * dim.width));
|
||||
});
|
||||
}
|
||||
if (deleteRequested && !isDeleting) {
|
||||
setIsDeleteRequested(false);
|
||||
}
|
||||
return () => {
|
||||
_isMounted = true;
|
||||
};
|
||||
}, []);
|
||||
}, [isDeleting]);
|
||||
|
||||
const _onItemPress = () => {
|
||||
if (isSchedules) {
|
||||
moveActionSheet.current.show();
|
||||
return;
|
||||
}
|
||||
|
||||
handleOnPressItem(id);
|
||||
};
|
||||
|
||||
// consts
|
||||
const scheduleStatus =
|
||||
status === ScheduledPostStatus.PENDING
|
||||
? intl.formatMessage({ id: 'schedules.pending' })
|
||||
: status === ScheduledPostStatus.POSTPONED
|
||||
? intl.formatMessage({ id: 'schedules.postponed' })
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? intl.formatMessage({ id: 'schedules.published' })
|
||||
: intl.formatMessage({ id: 'schedules.error' });
|
||||
? intl.formatMessage({ id: 'schedules.postponed' })
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? intl.formatMessage({ id: 'schedules.published' })
|
||||
: intl.formatMessage({ id: 'schedules.error' });
|
||||
const statusIcon =
|
||||
status === ScheduledPostStatus.PENDING
|
||||
? 'timer'
|
||||
: status === ScheduledPostStatus.POSTPONED
|
||||
? 'schedule'
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? 'check-circle'
|
||||
: 'error';
|
||||
? 'schedule'
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? 'check-circle'
|
||||
: 'error';
|
||||
const statusIconColor =
|
||||
status === ScheduledPostStatus.PUBLISHED
|
||||
? '#4FD688'
|
||||
: status === ScheduledPostStatus.ERROR
|
||||
? '#e63535'
|
||||
: '#c1c5c7';
|
||||
? '#e63535'
|
||||
: '#c1c5c7';
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@ -116,19 +112,17 @@ const DraftListItemView = ({
|
||||
onPress={() => actionSheet.current.show()}
|
||||
style={[styles.rightItem]}
|
||||
color="#c1c5c7"
|
||||
isLoading={isDeleting && deleteRequested}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.body}>
|
||||
<TouchableOpacity onPress={() => handleOnPressItem(id)}>
|
||||
<TouchableOpacity onPress={_onItemPress}>
|
||||
{image !== null && (
|
||||
<ProgressiveImage
|
||||
<FastImage
|
||||
source={image}
|
||||
thumbnailSource={thumbnail}
|
||||
style={[
|
||||
styles.thumbnail,
|
||||
{ width: dim.width - 16, height: Math.min(calcImgHeight, dim.height) },
|
||||
]}
|
||||
style={styles.thumbnail}
|
||||
resizeMode={FastImage.resizeMode.cover}
|
||||
/>
|
||||
)}
|
||||
<View style={[styles.postDescripton]}>
|
||||
@ -151,6 +145,29 @@ const DraftListItemView = ({
|
||||
onPress={(index) => {
|
||||
if (index === 0) {
|
||||
handleOnRemoveItem(id);
|
||||
setIsDeleteRequested(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<OptionsModal
|
||||
ref={moveActionSheet}
|
||||
title={intl.formatMessage({
|
||||
id: 'alert.move_question',
|
||||
})}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'alert.move',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={1}
|
||||
onPress={(index) => {
|
||||
if (index === 0) {
|
||||
handleOnMovePress(id);
|
||||
setIsDeleteRequested(true);
|
||||
}
|
||||
}}
|
||||
/>
|
@ -2,9 +2,7 @@ import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import isAndroidOreo from '../../../../utils/isAndroidOreo';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
// height: isAndroidOreo() ? 28 : 40,
|
||||
},
|
||||
container: {},
|
||||
textInput: {
|
||||
color: '$primaryBlack',
|
||||
fontSize: 15,
|
||||
@ -14,8 +12,7 @@ export default EStyleSheet.create({
|
||||
borderTopColor: '$primaryLightGray',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '$primaryLightGray',
|
||||
flex: 1,
|
||||
height: isAndroidOreo() ? 28 : 40,
|
||||
height: isAndroidOreo() ? 36 : 40,
|
||||
},
|
||||
warning: {
|
||||
color: '$primaryRed',
|
||||
|
@ -37,16 +37,8 @@ class MainButton extends Component {
|
||||
};
|
||||
|
||||
_getBody = () => {
|
||||
const {
|
||||
isLoading,
|
||||
text,
|
||||
secondText,
|
||||
iconColor,
|
||||
iconName,
|
||||
source,
|
||||
iconType,
|
||||
textStyle,
|
||||
} = this.props;
|
||||
const { isLoading, text, secondText, iconColor, iconName, source, iconType, textStyle } =
|
||||
this.props;
|
||||
|
||||
if (isLoading) {
|
||||
this._getIndicator();
|
||||
|
@ -17,6 +17,7 @@ export default EStyleSheet.create({
|
||||
color: '$primaryBlack',
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
textAlignVertical: 'top',
|
||||
maxHeight: isAndroidOreo() ? '$deviceHeight' : undefined,
|
||||
},
|
||||
previewContainer: {
|
||||
flex: 1,
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
Platform,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
TextStyle,
|
||||
} from 'react-native';
|
||||
import { renderPostBody, postBodySummary } from '@ecency/render-helper';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
@ -22,9 +23,7 @@ import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction';
|
||||
|
||||
// Components
|
||||
import {
|
||||
IconButton,
|
||||
PostBody,
|
||||
StickyBar,
|
||||
TextInput,
|
||||
UserAvatar,
|
||||
TitleArea,
|
||||
@ -33,13 +32,10 @@ import {
|
||||
SummaryArea,
|
||||
Modal,
|
||||
SnippetsModal,
|
||||
UploadsGalleryModal,
|
||||
Tooltip,
|
||||
InsertLinkModal,
|
||||
} from '../../index';
|
||||
|
||||
import { ThemeContainer } from '../../../containers';
|
||||
|
||||
// Styles
|
||||
import styles from '../styles/markdownEditorStyles';
|
||||
import applySnippet from '../children/formats/applySnippet';
|
||||
@ -52,6 +48,7 @@ import { walkthrough } from '../../../redux/constants/walkthroughConstants';
|
||||
import { MediaInsertData } from '../../uploadsGalleryModal/container/uploadsGalleryModal';
|
||||
import { EditorToolbar } from '../children/editorToolbar';
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
const MIN_BODY_INPUT_HEIGHT = 300;
|
||||
|
||||
@ -63,15 +60,12 @@ var bodySelection = { start: 0, end: 0 };
|
||||
const MarkdownEditorView = ({
|
||||
paramFiles,
|
||||
draftBody,
|
||||
handleOpenImagePicker,
|
||||
intl,
|
||||
isPreviewActive,
|
||||
isReply,
|
||||
isLoading,
|
||||
isUploading,
|
||||
initialFields,
|
||||
onChange,
|
||||
uploadedImage,
|
||||
isEdit,
|
||||
post,
|
||||
fields,
|
||||
@ -86,6 +80,8 @@ const MarkdownEditorView = ({
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const isDarkTheme = useAppSelector(state => state.application.isDarkTheme);
|
||||
|
||||
const [editable, setEditable] = useState(true);
|
||||
const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT);
|
||||
const [isSnippetsOpen, setIsSnippetsOpen] = useState(false);
|
||||
@ -93,6 +89,7 @@ const MarkdownEditorView = ({
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [insertedMediaUrls, setInsertedMediaUrls] = useState([]);
|
||||
|
||||
|
||||
const inputRef = useRef(null);
|
||||
const clearRef = useRef(null);
|
||||
const insertLinkModalRef = useRef(null);
|
||||
@ -199,20 +196,20 @@ const MarkdownEditorView = ({
|
||||
};
|
||||
|
||||
|
||||
const _debouncedOnTextChange = useCallback(debounce(()=>{
|
||||
const _debouncedOnTextChange = useCallback(debounce(() => {
|
||||
console.log("setting is editing to", false)
|
||||
setIsEditing(false)
|
||||
const urls = extractImageUrls({body:bodyText})
|
||||
if(urls.length !== insertedMediaUrls.length){
|
||||
const urls = extractImageUrls({ body: bodyText })
|
||||
if (urls.length !== insertedMediaUrls.length) {
|
||||
setInsertedMediaUrls(urls);
|
||||
}
|
||||
}, 500),[])
|
||||
}, 500), [])
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const _changeText = useCallback((input) => {
|
||||
bodyText = input;
|
||||
|
||||
if(!isEditing){
|
||||
if (!isEditing) {
|
||||
console.log('force setting is editing to true', true)
|
||||
setIsEditing(true)
|
||||
}
|
||||
@ -364,7 +361,7 @@ const MarkdownEditorView = ({
|
||||
_setTextAndSelection({ text: '', selection: { start: 0, end: 0 } });
|
||||
}
|
||||
};
|
||||
const _renderEditor = () => (
|
||||
const _renderEditor = (bodyInputStyle:TextStyle, editorScrollEnabled:boolean) => (
|
||||
<>
|
||||
{isReply && !isEdit && <SummaryArea summary={headerText} />}
|
||||
{!isReply && (
|
||||
@ -407,8 +404,6 @@ const MarkdownEditorView = ({
|
||||
</View>
|
||||
)}
|
||||
{!isPreviewActive ? (
|
||||
<ThemeContainer>
|
||||
{({ isDarkTheme }) => (
|
||||
<TextInput
|
||||
multiline
|
||||
autoCorrect={true}
|
||||
@ -420,55 +415,49 @@ const MarkdownEditorView = ({
|
||||
})}
|
||||
placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'}
|
||||
selectionColor="#357ce6"
|
||||
style={{ ...styles.textWrapper, height: bodyInputHeight }}
|
||||
style={{...styles.textWrapper, ...bodyInputStyle}}
|
||||
underlineColorAndroid="transparent"
|
||||
innerRef={inputRef}
|
||||
editable={editable}
|
||||
contextMenuHidden={false}
|
||||
autoGrow={false}
|
||||
scrollEnabled={false}
|
||||
scrollEnabled={editorScrollEnabled}
|
||||
onContentSizeChange={_handleOnContentSizeChange}
|
||||
/>
|
||||
)}
|
||||
</ThemeContainer>
|
||||
) : (
|
||||
_renderPreview()
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const _renderEditorWithScroll = () => (
|
||||
<ScrollView style={styles.container}>{_renderEditor()}</ScrollView>
|
||||
);
|
||||
|
||||
const _renderEditorWithoutScroll = () => <View style={styles.container}>{_renderEditor()}</View>;
|
||||
const _editorWithScroll = <ScrollView style={styles.container}>{_renderEditor({height:bodyInputHeight}, false)}</ScrollView>;
|
||||
const _editorWithoutScroll = <View style={styles.container}>{_renderEditor({flex:1}, true)}</View>;
|
||||
|
||||
const _renderContent = () => {
|
||||
const _innerContent = (
|
||||
<>
|
||||
{isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()}
|
||||
{isAndroidOreo() ? _editorWithoutScroll : _editorWithScroll}
|
||||
<UsernameAutofillBar text={bodyText} selection={bodySelection} onApplyUsername={_onApplyUsername} />
|
||||
{_renderFloatingDraftButton()}
|
||||
|
||||
<EditorToolbar
|
||||
insertedMediaUrls={insertedMediaUrls}
|
||||
isPreviewActive={isPreviewActive}
|
||||
paramFiles={paramFiles}
|
||||
setIsUploading={setIsUploading}
|
||||
handleMediaInsert={_handleMediaInsert}
|
||||
handleOnAddLinkPress={_handleOnAddLinkPress}
|
||||
handleShowSnippets={() => setIsSnippetsOpen(true)}
|
||||
handleOnClearPress={() => clearRef.current.show()}
|
||||
handleOnMarkupButtonPress={(item) => {
|
||||
item.onPress({
|
||||
text: bodyText,
|
||||
selection: bodySelection,
|
||||
setTextAndSelection: _setTextAndSelection,
|
||||
item
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<EditorToolbar
|
||||
insertedMediaUrls={insertedMediaUrls}
|
||||
isPreviewActive={isPreviewActive}
|
||||
paramFiles={paramFiles}
|
||||
setIsUploading={setIsUploading}
|
||||
handleMediaInsert={_handleMediaInsert}
|
||||
handleOnAddLinkPress={_handleOnAddLinkPress}
|
||||
handleShowSnippets={() => setIsSnippetsOpen(true)}
|
||||
handleOnClearPress={() => clearRef.current.show()}
|
||||
handleOnMarkupButtonPress={(item) => {
|
||||
item.onPress({
|
||||
text: bodyText,
|
||||
selection: bodySelection,
|
||||
setTextAndSelection: _setTextAndSelection,
|
||||
item
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
</>
|
||||
);
|
||||
|
||||
|
@ -56,6 +56,7 @@ const NotificationLineView = ({
|
||||
if (
|
||||
notification.type === 'vote' ||
|
||||
notification.type === 'reblog' ||
|
||||
notification.type === 'favorites' ||
|
||||
(notification.type === 'mention' && notification.post)
|
||||
) {
|
||||
_moreinfo = notification.title || notification.permlink;
|
||||
|
@ -61,7 +61,6 @@ const PostsContainer = ({
|
||||
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
|
||||
const username = useSelector((state) => state.account.currentAccount.name);
|
||||
const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
|
||||
const isAnalytics = useSelector((state) => state.application.isAnalytics);
|
||||
const currentAccount = useSelector((state) => state.account.currentAccount);
|
||||
const pinCode = useSelector((state) => state.application.pin);
|
||||
const leaderboard = useSelector((state) => state.user.leaderboard);
|
||||
@ -813,7 +812,6 @@ const PostsContainer = ({
|
||||
handleOnScroll={_handleOnScroll}
|
||||
isHideImage={isHideImages}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isAnalytics={isAnalytics}
|
||||
selectedOptionIndex={selectedOptionIndex}
|
||||
tag={tag}
|
||||
filterOptionsValue={filterOptionsValue}
|
||||
|
@ -20,7 +20,6 @@ const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUse
|
||||
const intl = useIntl();
|
||||
|
||||
const isHideImage = useAppSelector(state => state.application.hidePostsThumbnails);
|
||||
const isAnalytics = useAppSelector(state => state.application.isAnalytics);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [lastAuthor, setLastAuthor] = useState('');
|
||||
|
@ -56,13 +56,8 @@ class TabBar extends PureComponent {
|
||||
};
|
||||
|
||||
_renderUnderline = () => {
|
||||
const {
|
||||
tabs,
|
||||
tabUnderlineDefaultWidth,
|
||||
tabUnderlineScaleX,
|
||||
scrollValue,
|
||||
underlineStyle,
|
||||
} = this.props;
|
||||
const { tabs, tabUnderlineDefaultWidth, tabUnderlineScaleX, scrollValue, underlineStyle } =
|
||||
this.props;
|
||||
const { activeColor } = this.state;
|
||||
|
||||
const containerWidth = getWindowDimensions().nativeWidth;
|
||||
|
@ -20,7 +20,6 @@ export const loadPosts = async ({
|
||||
pageType,
|
||||
tag,
|
||||
nsfw,
|
||||
isAnalytics
|
||||
|
||||
}:LoadPostsOptions) => {
|
||||
let filter = filterKey;
|
||||
|
@ -41,7 +41,6 @@ export interface TabMeta {
|
||||
pageType:string,
|
||||
tag:string,
|
||||
nsfw:string,
|
||||
isAnalytics:boolean,
|
||||
isLatestPostsCheck?:boolean,
|
||||
refreshing?:boolean,
|
||||
|
||||
|
@ -43,7 +43,6 @@ const TabContent = ({
|
||||
//redux properties
|
||||
const dispatch = useDispatch();
|
||||
const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
|
||||
const isAnalytics = useSelector((state) => state.application.isAnalytics);
|
||||
const nsfw = useSelector((state) => state.application.nsfw);
|
||||
const isConnected = useSelector((state) => state.application.isConnected);
|
||||
const currentAccount = useSelector((state) => state.account.currentAccount);
|
||||
@ -195,7 +194,6 @@ const TabContent = ({
|
||||
prevPosts:_posts,
|
||||
tabMeta:_tabMeta,
|
||||
isLoggedIn,
|
||||
isAnalytics,
|
||||
nsfw,
|
||||
isConnected,
|
||||
isFeedScreen,
|
||||
|
@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TextInput, NativeModules } from 'react-native';
|
||||
|
||||
import { ThemeContainer } from '../../../containers';
|
||||
|
||||
// Styles
|
||||
import styles from './textInputStyles';
|
||||
|
||||
const TextInputView = ({ innerRef, height, style, ...props }) => (
|
||||
<ThemeContainer>
|
||||
{({ isDarkTheme }) => (
|
||||
<TextInput
|
||||
ref={innerRef}
|
||||
keyboardAppearance={isDarkTheme ? 'dark' : 'light'}
|
||||
textAlign={NativeModules.I18nManager.isRTL ? 'right' : 'left'}
|
||||
{...props}
|
||||
style={[styles.input, { minHeight: height }, style]}
|
||||
/>
|
||||
)}
|
||||
</ThemeContainer>
|
||||
);
|
||||
|
||||
export default TextInputView;
|
28
src/components/textInput/view/textInputView.tsx
Normal file
28
src/components/textInput/view/textInputView.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React, { Ref } from 'react';
|
||||
import { TextInput, NativeModules, TextInputProps, TextStyle } from 'react-native';
|
||||
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
// Styles
|
||||
import styles from './textInputStyles';
|
||||
|
||||
interface Props extends TextInputProps {
|
||||
innerRef: Ref<TextInput>,
|
||||
height: number,
|
||||
style: TextStyle
|
||||
}
|
||||
|
||||
const TextInputView = ({ innerRef, height, style, ...props }: Props) => {
|
||||
const isDarkTheme = useAppSelector(state => state.application.isDarkTheme);
|
||||
return (
|
||||
<TextInput
|
||||
ref={innerRef}
|
||||
keyboardAppearance={isDarkTheme ? 'dark' : 'light'}
|
||||
textAlign={NativeModules.I18nManager.isRTL ? 'right' : 'left'}
|
||||
{...props}
|
||||
style={[styles.input, { minHeight: height }, style]}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export default TextInputView;
|
@ -141,6 +141,7 @@
|
||||
"unvote": "downvoted",
|
||||
"reply": "replied to",
|
||||
"mention": "mentioned in",
|
||||
"favorites": "made new post",
|
||||
"follow": "followed you",
|
||||
"unfollow": "unfollowed you",
|
||||
"ignore": "ignored you",
|
||||
@ -227,6 +228,7 @@
|
||||
"vote": "Vote",
|
||||
"comment": "Comment",
|
||||
"mention": "Mention",
|
||||
"favorite": "Favorites",
|
||||
"reblog": "Reblog",
|
||||
"transfers": "Transfers",
|
||||
"delegations": "Delegations"
|
||||
|
@ -65,7 +65,6 @@ class ProfileContainer extends Component {
|
||||
navigation,
|
||||
isConnected,
|
||||
isLoggedIn,
|
||||
isAnalytics,
|
||||
currentAccount: { name: currentAccountUsername },
|
||||
} = this.props;
|
||||
const username = get(navigation, 'state.params.username');
|
||||
@ -93,7 +92,6 @@ class ProfileContainer extends Component {
|
||||
const { isOwnProfile, comments, user } = this.state;
|
||||
const {
|
||||
currentAccount: { name: currentAccountUsername },
|
||||
isAnalytics,
|
||||
} = this.props;
|
||||
this.setState({ isProfileLoading: true });
|
||||
let repliesAction;
|
||||
@ -585,7 +583,6 @@ const mapStateToProps = (state) => ({
|
||||
isDarkTheme: state.application.isDarkTheme,
|
||||
isLoggedIn: state.application.isLoggedIn,
|
||||
pinCode: state.application.pin,
|
||||
isAnalytics: state.application.isAnalytics,
|
||||
activeBottomTab: state.ui.activeBottomTab,
|
||||
currentAccount: state.account.currentAccount,
|
||||
isHideImage: state.application.hidePostsThumbnails,
|
||||
|
24
src/index.js
24
src/index.js
@ -5,22 +5,28 @@ import { PersistGate } from 'redux-persist/integration/react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { Host } from 'react-native-portalize';
|
||||
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
||||
import { flattenMessages } from './utils/flattenMessages';
|
||||
import messages from './config/locales';
|
||||
|
||||
import Application from './screens/application';
|
||||
import { store, persistor } from './redux/store/store';
|
||||
import { initQueryClient } from './providers/queries';
|
||||
|
||||
const queryClientProviderProps = initQueryClient();
|
||||
|
||||
const _renderApp = ({ locale }) => (
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<IntlProvider locale={locale} messages={flattenMessages(messages[locale])}>
|
||||
<SafeAreaProvider>
|
||||
<Host>
|
||||
<Application />
|
||||
</Host>
|
||||
</SafeAreaProvider>
|
||||
</IntlProvider>
|
||||
</PersistGate>
|
||||
<PersistQueryClientProvider {...queryClientProviderProps}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<IntlProvider locale={locale} messages={flattenMessages(messages[locale])}>
|
||||
<SafeAreaProvider>
|
||||
<Host>
|
||||
<Application />
|
||||
</Host>
|
||||
</SafeAreaProvider>
|
||||
</IntlProvider>
|
||||
</PersistGate>
|
||||
</PersistQueryClientProvider>
|
||||
);
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
|
File diff suppressed because it is too large
Load Diff
106
src/providers/queries/draftQueries.ts
Normal file
106
src/providers/queries/draftQueries.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useAppDispatch } from '../../hooks';
|
||||
import { toastNotification } from '../../redux/actions/uiAction';
|
||||
import {
|
||||
deleteDraft,
|
||||
deleteScheduledPost,
|
||||
getDrafts,
|
||||
getSchedules,
|
||||
moveScheduledToDraft,
|
||||
} from '../ecency/ecency';
|
||||
import QUERIES from './queryKeys';
|
||||
|
||||
/** hook used to return user drafts */
|
||||
export const useGetDraftsQuery = () => {
|
||||
return useQuery([QUERIES.DRAFTS.GET], _getDrafts);
|
||||
};
|
||||
|
||||
/** used to return user schedules */
|
||||
export const useGetSchedulesQuery = () => {
|
||||
return useQuery([QUERIES.SCHEDULES.GET], _getSchedules);
|
||||
};
|
||||
|
||||
export const useDraftDeleteMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
return useMutation(deleteDraft, {
|
||||
retry: 3,
|
||||
onSuccess: (data) => {
|
||||
console.log('Success draft delete', data);
|
||||
queryClient.setQueryData([QUERIES.DRAFTS.GET], _sortData(data));
|
||||
},
|
||||
onError: () => {
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useScheduleDeleteMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
return useMutation(deleteScheduledPost, {
|
||||
retry: 3,
|
||||
onSuccess: (data) => {
|
||||
console.log('Success scheduled post delete', data);
|
||||
queryClient.setQueryData([QUERIES.SCHEDULES.GET], _sortData(data));
|
||||
},
|
||||
onError: () => {
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useMoveScheduleToDraftsMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
return useMutation(moveScheduledToDraft, {
|
||||
retry: 3,
|
||||
onSuccess: (data) => {
|
||||
console.log('Moved to drafts data', data);
|
||||
queryClient.setQueryData([QUERIES.SCHEDULES.GET], _sortData(data));
|
||||
queryClient.invalidateQueries([QUERIES.DRAFTS.GET]);
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.success_moved' })));
|
||||
},
|
||||
onError: () => {
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _getDrafts = async () => {
|
||||
try {
|
||||
const data = await getDrafts();
|
||||
return _sortData(data || []);
|
||||
} catch (err) {
|
||||
throw new Error('draft.load_error');
|
||||
}
|
||||
};
|
||||
|
||||
const _getSchedules = async () => {
|
||||
try {
|
||||
const data = await getSchedules();
|
||||
return _sortDataS(data);
|
||||
} catch (err) {
|
||||
throw new Error('drafts.load_error');
|
||||
}
|
||||
};
|
||||
|
||||
const _sortDataS = (data) =>
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.schedule).getTime();
|
||||
const dateB = new Date(b.schedule).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
|
||||
const _sortData = (data) =>
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.created).getTime();
|
||||
const dateB = new Date(b.created).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
24
src/providers/queries/index.ts
Normal file
24
src/providers/queries/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { PersistQueryClientProviderProps } from '@tanstack/react-query-persist-client';
|
||||
|
||||
export const initQueryClient = () => {
|
||||
const asyncStoragePersister = createAsyncStoragePersister({
|
||||
storage: AsyncStorage,
|
||||
});
|
||||
|
||||
const client = new QueryClient({
|
||||
//Query client configurations go here...
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
cacheTime: 1000 * 60 * 60 * 24, // 24 hours
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
client,
|
||||
persistOptions: { persister: asyncStoragePersister },
|
||||
} as PersistQueryClientProviderProps;
|
||||
};
|
10
src/providers/queries/queryKeys.ts
Normal file
10
src/providers/queries/queryKeys.ts
Normal file
@ -0,0 +1,10 @@
|
||||
const QUERIES = {
|
||||
DRAFTS: {
|
||||
GET: 'QUERY_GET_DRAFTS',
|
||||
},
|
||||
SCHEDULES: {
|
||||
GET: 'QUERY_GET_SCHEDULES',
|
||||
},
|
||||
};
|
||||
|
||||
export default QUERIES;
|
@ -416,6 +416,9 @@ export const setNotificationSettings = async ({ type, action }) => {
|
||||
case 'notification.mention':
|
||||
setting.mentionNotification = action;
|
||||
break;
|
||||
case 'notification.favorite':
|
||||
setting.favoriteNotification = action;
|
||||
break;
|
||||
case 'notification.reblog':
|
||||
setting.reblogNotification = action;
|
||||
break;
|
||||
@ -524,6 +527,7 @@ export const getSettings = async () => {
|
||||
voteNotification: true,
|
||||
commentNotification: true,
|
||||
mentionNotification: true,
|
||||
favoriteNotification: true,
|
||||
reblogNotification: true,
|
||||
transfersNotification: true,
|
||||
isPinCodeOpen: false,
|
||||
|
@ -4,12 +4,12 @@ import {
|
||||
CHANGE_COMMENT_NOTIFICATION,
|
||||
CHANGE_FOLLOW_NOTIFICATION,
|
||||
CHANGE_MENTION_NOTIFICATION,
|
||||
CHANGE_FAVORITE_NOTIFICATION,
|
||||
CHANGE_REBLOG_NOTIFICATION,
|
||||
CHANGE_TRANSFERS_NOTIFICATION,
|
||||
CHANGE_ALL_NOTIFICATION_SETTINGS,
|
||||
CHANGE_VOTE_NOTIFICATION,
|
||||
IS_CONNECTED,
|
||||
IS_ANALYTICS,
|
||||
IS_DARK_THEME,
|
||||
IS_DEFAULT_FOOTER,
|
||||
IS_LOGIN_DONE,
|
||||
@ -32,7 +32,7 @@ import {
|
||||
SET_IS_BIOMETRIC_ENABLED,
|
||||
SET_ENC_UNLOCK_PIN,
|
||||
SET_POST_UPVOTE_PERCENT,
|
||||
SET_COMMENT_UPVOTE_PERCENT
|
||||
SET_COMMENT_UPVOTE_PERCENT,
|
||||
} from '../constants/constants';
|
||||
|
||||
export const login = (payload) => ({
|
||||
@ -52,9 +52,6 @@ export const isLoginDone = () => ({
|
||||
type: IS_LOGIN_DONE,
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// Settings actions
|
||||
export const setLanguage = (payload) => ({
|
||||
payload,
|
||||
@ -66,7 +63,6 @@ export const setApi = (payload) => ({
|
||||
type: SET_API,
|
||||
});
|
||||
|
||||
|
||||
export const setPostUpvotePercent = (payload) => ({
|
||||
payload,
|
||||
type: SET_POST_UPVOTE_PERCENT,
|
||||
@ -108,6 +104,12 @@ export const changeNotificationSettings = (payload) => {
|
||||
type: CHANGE_MENTION_NOTIFICATION,
|
||||
};
|
||||
|
||||
case 'notification.favorite':
|
||||
return {
|
||||
payload: payload.action,
|
||||
type: CHANGE_FAVORITE_NOTIFICATION,
|
||||
};
|
||||
|
||||
case 'notification.reblog':
|
||||
return {
|
||||
payload: payload.action,
|
||||
@ -136,10 +138,10 @@ export const isDarkTheme = (payload) => ({
|
||||
type: IS_DARK_THEME,
|
||||
});
|
||||
|
||||
export const setColorTheme = (payload:number) => ({
|
||||
export const setColorTheme = (payload: number) => ({
|
||||
payload,
|
||||
type: SET_COLOR_THEME
|
||||
})
|
||||
type: SET_COLOR_THEME,
|
||||
});
|
||||
|
||||
export const isPinCodeOpen = (payload) => ({
|
||||
payload,
|
||||
@ -151,11 +153,6 @@ export const setConnectivityStatus = (payload) => ({
|
||||
type: IS_CONNECTED,
|
||||
});
|
||||
|
||||
export const setAnalyticsStatus = (payload) => ({
|
||||
payload,
|
||||
type: IS_ANALYTICS,
|
||||
});
|
||||
|
||||
export const setNsfw = (payload) => ({
|
||||
payload,
|
||||
type: SET_NSFW,
|
||||
@ -172,11 +169,11 @@ export const isDefaultFooter = (payload) => ({
|
||||
export const setCurrency = (currency) => async (dispatch) => {
|
||||
const currencySymbol = getSymbolFromCurrency(currency);
|
||||
|
||||
const currencyRate = await getCurrencyRate(currency)
|
||||
const currencyRate = await getCurrencyRate(currency);
|
||||
dispatch({
|
||||
type: SET_CURRENCY,
|
||||
payload: { currency, currencyRate, currencySymbol },
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const setPinCode = (data) => ({
|
||||
@ -189,34 +186,32 @@ export const isRenderRequired = (payload) => ({
|
||||
type: IS_RENDER_REQUIRED,
|
||||
});
|
||||
|
||||
export const setLastAppVersion = (versionNumber:string) => ({
|
||||
payload:versionNumber,
|
||||
type: SET_LAST_APP_VERSION
|
||||
})
|
||||
export const setLastAppVersion = (versionNumber: string) => ({
|
||||
payload: versionNumber,
|
||||
type: SET_LAST_APP_VERSION,
|
||||
});
|
||||
|
||||
export const setSettingsMigrated = (isMigrated:boolean) => ({
|
||||
payload:isMigrated,
|
||||
type: SET_SETTINGS_MIGRATED
|
||||
})
|
||||
export const setSettingsMigrated = (isMigrated: boolean) => ({
|
||||
payload: isMigrated,
|
||||
type: SET_SETTINGS_MIGRATED,
|
||||
});
|
||||
|
||||
export const setHidePostsThumbnails = (shouldHide:boolean) => ({
|
||||
payload:shouldHide,
|
||||
export const setHidePostsThumbnails = (shouldHide: boolean) => ({
|
||||
payload: shouldHide,
|
||||
type: HIDE_POSTS_THUMBNAILS,
|
||||
});
|
||||
|
||||
export const setIsTermsAccepted = (isTermsAccepted:boolean) => ({
|
||||
payload:isTermsAccepted,
|
||||
type: SET_TERMS_ACCEPTED
|
||||
})
|
||||
|
||||
export const setIsBiometricEnabled = (enabled:boolean) => ({
|
||||
payload:enabled,
|
||||
type: SET_IS_BIOMETRIC_ENABLED
|
||||
})
|
||||
|
||||
export const setEncryptedUnlockPin = (encryptedUnlockPin:string) => ({
|
||||
payload:encryptedUnlockPin,
|
||||
type: SET_ENC_UNLOCK_PIN
|
||||
})
|
||||
export const setIsTermsAccepted = (isTermsAccepted: boolean) => ({
|
||||
payload: isTermsAccepted,
|
||||
type: SET_TERMS_ACCEPTED,
|
||||
});
|
||||
|
||||
export const setIsBiometricEnabled = (enabled: boolean) => ({
|
||||
payload: enabled,
|
||||
type: SET_IS_BIOMETRIC_ENABLED,
|
||||
});
|
||||
|
||||
export const setEncryptedUnlockPin = (encryptedUnlockPin: string) => ({
|
||||
payload: encryptedUnlockPin,
|
||||
type: SET_ENC_UNLOCK_PIN,
|
||||
});
|
||||
|
@ -5,7 +5,6 @@ export const SET_USER_DATA = 'SET_USER_DATA';
|
||||
|
||||
// Applicaiton
|
||||
export const IS_CONNECTED = 'IS_CONNECTED';
|
||||
export const IS_ANALYTICS = 'IS_ANALYTICS';
|
||||
export const IS_DARK_THEME = 'IS_DARK_THEME';
|
||||
export const IS_PIN_CODE_OPEN = 'IS_PIN_CODE_OPEN';
|
||||
export const IS_LOGGED_IN = 'IS_LOGGED_IN';
|
||||
@ -28,6 +27,7 @@ export const CHANGE_FOLLOW_NOTIFICATION = 'CHANGE_FOLLOW_NOTIFICATION';
|
||||
export const CHANGE_VOTE_NOTIFICATION = 'CHANGE_VOTE_NOTIFICATION';
|
||||
export const CHANGE_COMMENT_NOTIFICATION = 'CHANGE_COMMENT_NOTIFICATION';
|
||||
export const CHANGE_MENTION_NOTIFICATION = 'CHANGE_MENTION_NOTIFICATION';
|
||||
export const CHANGE_FAVORITE_NOTIFICATION = 'CHANGE_FAVORITE_NOTIFICATION';
|
||||
export const CHANGE_REBLOG_NOTIFICATION = 'CHANGE_REBLOG_NOTIFICATION';
|
||||
export const CHANGE_TRANSFERS_NOTIFICATION = 'CHANGE_TRANSFERS_NOTIFICATION';
|
||||
export const CHANGE_ALL_NOTIFICATION_SETTINGS = 'CHANGE_ALL_NOTIFICATION_SETTINGS';
|
||||
|
@ -2,12 +2,12 @@ import {
|
||||
CHANGE_COMMENT_NOTIFICATION,
|
||||
CHANGE_FOLLOW_NOTIFICATION,
|
||||
CHANGE_MENTION_NOTIFICATION,
|
||||
CHANGE_FAVORITE_NOTIFICATION,
|
||||
CHANGE_REBLOG_NOTIFICATION,
|
||||
CHANGE_TRANSFERS_NOTIFICATION,
|
||||
CHANGE_VOTE_NOTIFICATION,
|
||||
CHANGE_ALL_NOTIFICATION_SETTINGS,
|
||||
IS_CONNECTED,
|
||||
IS_ANALYTICS,
|
||||
IS_DARK_THEME,
|
||||
IS_DEFAULT_FOOTER,
|
||||
IS_LOGIN_DONE,
|
||||
@ -30,50 +30,50 @@ import {
|
||||
HIDE_POSTS_THUMBNAILS,
|
||||
SET_TERMS_ACCEPTED,
|
||||
SET_IS_BIOMETRIC_ENABLED,
|
||||
SET_ENC_UNLOCK_PIN
|
||||
SET_ENC_UNLOCK_PIN,
|
||||
} from '../constants/constants';
|
||||
|
||||
interface State {
|
||||
api: string;
|
||||
currency: {
|
||||
currency: string,
|
||||
currencyRate: number,
|
||||
currencySymbol: string,
|
||||
},
|
||||
isConnected: boolean|null, // internet connectivity
|
||||
currency: string;
|
||||
currencyRate: number;
|
||||
currencySymbol: string;
|
||||
};
|
||||
isConnected: boolean | null; // internet connectivity
|
||||
isDarkTheme: boolean;
|
||||
colorTheme: number;
|
||||
isDefaultFooter: boolean; //TODO: remove present of isDefaultFooter as it's no longer in use
|
||||
isLoggedIn: boolean; // Has any logged in user.
|
||||
isAnalytics: boolean;
|
||||
isLoginDone: boolean;
|
||||
isLogingOut: boolean;
|
||||
isNotificationOpen: boolean;
|
||||
language: string,
|
||||
language: string;
|
||||
loading: boolean; // It is lock to all screen and shows loading animation.
|
||||
notificationDetails: {
|
||||
commentNotification: boolean,
|
||||
followNotification: boolean,
|
||||
mentionNotification: boolean,
|
||||
reblogNotification: boolean,
|
||||
transfersNotification: boolean,
|
||||
voteNotification: boolean,
|
||||
},
|
||||
commentNotification: boolean;
|
||||
followNotification: boolean;
|
||||
mentionNotification: boolean;
|
||||
favoriteNotification: boolean;
|
||||
reblogNotification: boolean;
|
||||
transfersNotification: boolean;
|
||||
voteNotification: boolean;
|
||||
};
|
||||
postUpvotePercent: number;
|
||||
commentUpvotePercent: number;
|
||||
nsfw: string;
|
||||
pin: string|null; //encrypted pin used for encrypting sensitive user data
|
||||
pin: string | null; //encrypted pin used for encrypting sensitive user data
|
||||
isPinCodeOpen: boolean;
|
||||
isRenderRequired: boolean;
|
||||
encUnlockPin: string; //ecryped pin used for user defined lock screen pass code
|
||||
lastAppVersion:string;
|
||||
lastAppVersion: string;
|
||||
settingsMigratedV2: boolean;
|
||||
hidePostsThumbnails: boolean;
|
||||
isTermsAccepted: boolean;
|
||||
isBiometricEnabled: boolean;
|
||||
}
|
||||
|
||||
const initialState:State = {
|
||||
const initialState: State = {
|
||||
api: 'rpc.ecency.com',
|
||||
currency: {
|
||||
currency: 'usd',
|
||||
@ -85,7 +85,6 @@ const initialState:State = {
|
||||
colorTheme: 0, //values mapped from => src/constants/options/theme.ts
|
||||
isDefaultFooter: true, //TODO: remove present of isDefaultFooter as it's no longer in use
|
||||
isLoggedIn: false, // Has any logged in user.
|
||||
isAnalytics: false,
|
||||
isLoginDone: false,
|
||||
isLogingOut: false,
|
||||
isNotificationOpen: true,
|
||||
@ -95,6 +94,7 @@ const initialState:State = {
|
||||
commentNotification: true,
|
||||
followNotification: true,
|
||||
mentionNotification: true,
|
||||
favoriteNotification: true,
|
||||
reblogNotification: true,
|
||||
transfersNotification: true,
|
||||
voteNotification: true,
|
||||
@ -106,14 +106,14 @@ const initialState:State = {
|
||||
isPinCodeOpen: false,
|
||||
isRenderRequired: false,
|
||||
encUnlockPin: '',
|
||||
lastAppVersion:'',
|
||||
lastAppVersion: '',
|
||||
settingsMigratedV2: false,
|
||||
hidePostsThumbnails: false,
|
||||
isTermsAccepted: false,
|
||||
isBiometricEnabled: false
|
||||
isBiometricEnabled: false,
|
||||
};
|
||||
|
||||
export default function (state = initialState, action):State {
|
||||
export default function (state = initialState, action): State {
|
||||
switch (action.type) {
|
||||
case LOGIN:
|
||||
return {
|
||||
@ -130,11 +130,7 @@ export default function (state = initialState, action):State {
|
||||
...state,
|
||||
isConnected: action.payload,
|
||||
};
|
||||
case IS_ANALYTICS:
|
||||
return {
|
||||
...state,
|
||||
isAnalytics: action.payload,
|
||||
};
|
||||
|
||||
case LOGOUT:
|
||||
return {
|
||||
...state,
|
||||
@ -183,6 +179,13 @@ export default function (state = initialState, action):State {
|
||||
mentionNotification: action.payload,
|
||||
},
|
||||
});
|
||||
case CHANGE_FAVORITE_NOTIFICATION:
|
||||
return Object.assign({}, state, {
|
||||
notificationDetails: {
|
||||
...state.notificationDetails,
|
||||
favoriteNotification: action.payload,
|
||||
},
|
||||
});
|
||||
case CHANGE_REBLOG_NOTIFICATION:
|
||||
return Object.assign({}, state, {
|
||||
notificationDetails: {
|
||||
@ -210,6 +213,7 @@ export default function (state = initialState, action):State {
|
||||
notificationDetails: {
|
||||
...state.notificationDetails,
|
||||
mentionNotification: action.payload.mentionNotification,
|
||||
favoriteNotification: action.payload.favoriteNotification,
|
||||
reblogNotification: action.payload.reblogNotification,
|
||||
transfersNotification: action.payload.transfersNotification,
|
||||
voteNotification: action.payload.voteNotification,
|
||||
@ -224,7 +228,7 @@ export default function (state = initialState, action):State {
|
||||
case SET_COLOR_THEME:
|
||||
return {
|
||||
...state,
|
||||
colorTheme:action.payload
|
||||
colorTheme: action.payload,
|
||||
};
|
||||
case IS_PIN_CODE_OPEN:
|
||||
return Object.assign({}, state, {
|
||||
@ -256,42 +260,42 @@ export default function (state = initialState, action):State {
|
||||
return Object.assign({}, state, {
|
||||
isRenderRequired: action.payload,
|
||||
});
|
||||
|
||||
|
||||
case SET_LAST_APP_VERSION:
|
||||
return {
|
||||
...state,
|
||||
lastAppVersion:action.payload
|
||||
}
|
||||
lastAppVersion: action.payload,
|
||||
};
|
||||
|
||||
case SET_SETTINGS_MIGRATED:
|
||||
return {
|
||||
...state,
|
||||
settingsMigratedV2:action.payload
|
||||
}
|
||||
settingsMigratedV2: action.payload,
|
||||
};
|
||||
|
||||
case HIDE_POSTS_THUMBNAILS:
|
||||
return {
|
||||
...state,
|
||||
hidePostsThumbnails:action.payload
|
||||
}
|
||||
|
||||
hidePostsThumbnails: action.payload,
|
||||
};
|
||||
|
||||
case SET_TERMS_ACCEPTED:
|
||||
return {
|
||||
...state,
|
||||
isTermsAccepted:action.payload
|
||||
}
|
||||
|
||||
isTermsAccepted: action.payload,
|
||||
};
|
||||
|
||||
case SET_IS_BIOMETRIC_ENABLED:
|
||||
return {
|
||||
...state,
|
||||
isBiometricEnabled:action.payload
|
||||
}
|
||||
isBiometricEnabled: action.payload,
|
||||
};
|
||||
|
||||
case SET_ENC_UNLOCK_PIN:
|
||||
return {
|
||||
...state,
|
||||
encUnlockPin:action.payload
|
||||
}
|
||||
encUnlockPin: action.payload,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
|
@ -40,7 +40,7 @@ const persistConfig = {
|
||||
key: 'root',
|
||||
// Storage Method (React Native)
|
||||
storage: AsyncStorage,
|
||||
version: 0, // New version 0, default or previous version -1, versions are useful migrations
|
||||
version: 1, // New version 0, default or previous version -1, versions are useful migrations
|
||||
// Blacklist (Don't Save Specific Reducers)
|
||||
blacklist: ['communities', 'user', 'ui'],
|
||||
timeout: 0,
|
||||
|
@ -13,7 +13,7 @@ import messaging from '@react-native-firebase/messaging';
|
||||
import PushNotification from 'react-native-push-notification';
|
||||
import VersionNumber from 'react-native-version-number';
|
||||
import ReceiveSharingIntent from 'react-native-receive-sharing-intent';
|
||||
import SplashScreen from 'react-native-splash-screen'
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
|
||||
// Constants
|
||||
import AUTH_TYPE from '../../../constants/authType';
|
||||
@ -89,14 +89,12 @@ import MigrationHelpers from '../../../utils/migrationHelpers';
|
||||
import { deepLinkParser } from '../../../utils/deepLinkParser';
|
||||
import bugsnapInstance from '../../../config/bugsnag';
|
||||
|
||||
|
||||
let firebaseOnNotificationOpenedAppListener = null;
|
||||
let firebaseOnMessageListener = null;
|
||||
let removeAppearanceListener = null;
|
||||
|
||||
class ApplicationContainer extends Component {
|
||||
|
||||
_pinCodeTimer:any = null
|
||||
_pinCodeTimer: any = null;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -109,8 +107,7 @@ class ApplicationContainer extends Component {
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
|
||||
const { dispatch, isAnalytics } = this.props;
|
||||
const { dispatch } = this.props;
|
||||
|
||||
this._setNetworkListener();
|
||||
|
||||
@ -133,20 +130,19 @@ class ApplicationContainer extends Component {
|
||||
this._fetchApp();
|
||||
|
||||
ReceiveSharingIntent.getReceivedFiles(
|
||||
files => {
|
||||
(files) => {
|
||||
navigate({
|
||||
routeName: ROUTES.SCREENS.EDITOR,
|
||||
params: { hasSharedIntent: true, files },
|
||||
});
|
||||
// files returns as JSON Array example
|
||||
//[{ filePath: null, text: null, weblink: null, mimeType: null, contentUri: null, fileName: null, extension: null }]
|
||||
ReceiveSharingIntent.clearReceivedFiles(); // clear Intents
|
||||
ReceiveSharingIntent.clearReceivedFiles(); // clear Intents
|
||||
},
|
||||
(error) => {
|
||||
console.log('error :>> ', error);
|
||||
},
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
@ -167,7 +163,6 @@ class ApplicationContainer extends Component {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
const { isPinCodeOpen: _isPinCodeOpen } = this.props;
|
||||
|
||||
//TOOD: listen for back press and cancel all pending api requests;
|
||||
@ -225,15 +220,14 @@ class ApplicationContainer extends Component {
|
||||
_handleDeepLink = async (url = '') => {
|
||||
const { currentAccount, intl } = this.props;
|
||||
|
||||
if(!url){
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try{
|
||||
try {
|
||||
const deepLinkData = await deepLinkParser(url, currentAccount);
|
||||
const { routeName, params, key } = deepLinkData || {};
|
||||
|
||||
|
||||
if (routeName && key) {
|
||||
navigate({
|
||||
routeName,
|
||||
@ -241,10 +235,9 @@ class ApplicationContainer extends Component {
|
||||
key: key,
|
||||
});
|
||||
}
|
||||
} catch(err){
|
||||
this._handleAlert(err.message)
|
||||
} catch (err) {
|
||||
this._handleAlert(err.message);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
_compareAndPromptForUpdate = async () => {
|
||||
@ -309,16 +302,15 @@ class ApplicationContainer extends Component {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
_handleAppStateChange = (nextAppState) => {
|
||||
const { isPinCodeOpen:_isPinCodeOpen } = this.props;
|
||||
const { isPinCodeOpen: _isPinCodeOpen } = this.props;
|
||||
const { appState } = this.state;
|
||||
|
||||
if (appState.match(/inactive|background/) && nextAppState === 'active') {
|
||||
this._refreshGlobalProps();
|
||||
if (_isPinCodeOpen && this._pinCodeTimer) {
|
||||
clearTimeout(this._pinCodeTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (appState.match(/active|forground/) && nextAppState === 'inactive') {
|
||||
@ -330,12 +322,10 @@ class ApplicationContainer extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
_fetchApp = async () => {
|
||||
const {dispatch, settingsMigratedV2} = this.props;
|
||||
const { dispatch, settingsMigratedV2 } = this.props;
|
||||
|
||||
await MigrationHelpers.migrateSettings(dispatch, settingsMigratedV2)
|
||||
await MigrationHelpers.migrateSettings(dispatch, settingsMigratedV2);
|
||||
|
||||
this._refreshGlobalProps();
|
||||
await this._getUserDataFromRealm();
|
||||
@ -345,15 +335,15 @@ class ApplicationContainer extends Component {
|
||||
};
|
||||
|
||||
_startPinCodeTimer = () => {
|
||||
const {isPinCodeOpen:_isPinCodeOpen} = this.props;
|
||||
const { isPinCodeOpen: _isPinCodeOpen } = this.props;
|
||||
if (_isPinCodeOpen) {
|
||||
this._pinCodeTimer = setTimeout(() => {
|
||||
navigate({
|
||||
routeName:ROUTES.SCREENS.PINCODE
|
||||
})
|
||||
}, 1 * 60 * 1000);
|
||||
this._pinCodeTimer = setTimeout(() => {
|
||||
navigate({
|
||||
routeName: ROUTES.SCREENS.PINCODE,
|
||||
});
|
||||
}, 1 * 60 * 1000);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
_pushNavigate = (notification) => {
|
||||
const { dispatch } = this.props;
|
||||
@ -361,7 +351,7 @@ class ApplicationContainer extends Component {
|
||||
let key = null;
|
||||
let routeName = null;
|
||||
|
||||
if (!!notification) {
|
||||
if (notification) {
|
||||
const push = get(notification, 'data');
|
||||
const type = get(push, 'type', '');
|
||||
const fullPermlink =
|
||||
@ -467,7 +457,6 @@ class ApplicationContainer extends Component {
|
||||
this.setState({
|
||||
foregroundNotificationData: remoteMessage,
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
firebaseOnNotificationOpenedAppListener = messaging().onNotificationOpenedApp(
|
||||
@ -492,7 +481,6 @@ class ApplicationContainer extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_refreshGlobalProps = () => {
|
||||
const { actions } = this.props;
|
||||
actions.fetchGlobalProperties();
|
||||
@ -556,11 +544,10 @@ class ApplicationContainer extends Component {
|
||||
await switchAccount(realmObject[0].username);
|
||||
}
|
||||
|
||||
|
||||
realmObject[0].name = currentUsername;
|
||||
// If in dev mode pin code does not show
|
||||
if (_isPinCodeOpen) {
|
||||
navigate({routeName:ROUTES.SCREENS.PINCODE})
|
||||
navigate({ routeName: ROUTES.SCREENS.PINCODE });
|
||||
} else if (!_isPinCodeOpen) {
|
||||
const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
|
||||
dispatch(savePinCode(encryptedPin));
|
||||
@ -568,7 +555,6 @@ class ApplicationContainer extends Component {
|
||||
|
||||
if (isConnected) {
|
||||
this._fetchUserDataFromDsteem(realmObject[0]);
|
||||
|
||||
}
|
||||
|
||||
return realmObject[0];
|
||||
@ -655,11 +641,10 @@ class ApplicationContainer extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//update notification settings and update push token for each signed accoutn useing access tokens
|
||||
_registerDeviceForNotifications = (settings?: any) => {
|
||||
const { currentAccount, otherAccounts, notificationDetails, isNotificationsEnabled } = this.props;
|
||||
const { currentAccount, otherAccounts, notificationDetails, isNotificationsEnabled } =
|
||||
this.props;
|
||||
|
||||
const isEnabled = settings ? !!settings.notification : isNotificationsEnabled;
|
||||
settings = settings || notificationDetails;
|
||||
@ -675,28 +660,31 @@ class ApplicationContainer extends Component {
|
||||
}
|
||||
|
||||
this._enableNotification(account.name, isEnabled, settings, accessToken);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//updateing fcm token with settings;
|
||||
otherAccounts.forEach((account) => {
|
||||
//since there can be more than one accounts, process access tokens separate
|
||||
if (account?.local?.accessToken) {
|
||||
_enabledNotificationForAccount(account)
|
||||
_enabledNotificationForAccount(account);
|
||||
} else {
|
||||
console.warn("access token not present, reporting to bugsnag")
|
||||
bugsnapInstance.notify(new Error(`Reporting missing access token in other accounts section: account:${account.name} with local data ${JSON.stringify(account?.local)}`))
|
||||
console.warn('access token not present, reporting to bugsnag');
|
||||
bugsnapInstance.notify(
|
||||
new Error(
|
||||
`Reporting missing access token in other accounts section: account:${
|
||||
account.name
|
||||
} with local data ${JSON.stringify(account?.local)}`,
|
||||
),
|
||||
);
|
||||
|
||||
//fallback to current account access token to register atleast logged in account
|
||||
if (currentAccount.name === account.name) {
|
||||
_enabledNotificationForAccount(currentAccount)
|
||||
_enabledNotificationForAccount(currentAccount);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
_connectNotificationServer = (username) => {
|
||||
/* eslint no-undef: "warn" */
|
||||
const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`);
|
||||
@ -720,7 +708,6 @@ class ApplicationContainer extends Component {
|
||||
currentAccount: { name, local },
|
||||
dispatch,
|
||||
intl,
|
||||
|
||||
} = this.props;
|
||||
|
||||
removeUserData(name)
|
||||
@ -742,7 +729,7 @@ class ApplicationContainer extends Component {
|
||||
});
|
||||
setExistUser(false);
|
||||
dispatch(isPinCodeOpen(false));
|
||||
dispatch(setEncryptedUnlockPin(encryptKey(Config.DEFAULT_KEU, Config.PIN_KEY)))
|
||||
dispatch(setEncryptedUnlockPin(encryptKey(Config.DEFAULT_KEU, Config.PIN_KEY)));
|
||||
if (local.authType === AUTH_TYPE.STEEM_CONNECT) {
|
||||
removeSCAccount(name);
|
||||
}
|
||||
@ -771,6 +758,7 @@ class ApplicationContainer extends Component {
|
||||
commentNotification: 4,
|
||||
reblogNotification: 5,
|
||||
transfersNotification: 6,
|
||||
favoriteNotification: 13,
|
||||
};
|
||||
|
||||
Object.keys(settings).map((item) => {
|
||||
@ -836,7 +824,6 @@ class ApplicationContainer extends Component {
|
||||
dispatch(fetchSubscribedCommunities(_currentAccount.username));
|
||||
};
|
||||
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const {
|
||||
isDarkTheme: _isDarkTheme,
|
||||
@ -919,7 +906,6 @@ export default connect(
|
||||
isConnected: state.application.isConnected,
|
||||
api: state.application.api,
|
||||
isGlobalRenderRequired: state.application.isRenderRequired,
|
||||
isAnalytics: state.application.isAnalytics,
|
||||
lastUpdateCheck: state.application.lastUpdateCheck,
|
||||
settingsMigratedV2: state.application.settingsMigratedV2,
|
||||
isNotificationsEnabled: state.application.isNotificationOpen,
|
||||
|
@ -1,159 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Alert } from 'react-native';
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
// Services and Actions
|
||||
import {
|
||||
getDrafts,
|
||||
deleteDraft,
|
||||
getSchedules,
|
||||
moveScheduledToDraft,
|
||||
deleteScheduledPost,
|
||||
} from '../../../providers/ecency/ecency';
|
||||
import { toastNotification } from '../../../redux/actions/uiAction';
|
||||
|
||||
// Middleware
|
||||
|
||||
// Constants
|
||||
import { default as ROUTES } from '../../../constants/routeNames';
|
||||
|
||||
// Utilities
|
||||
|
||||
// Component
|
||||
import DraftsScreen from '../screen/draftsScreen';
|
||||
|
||||
const DraftsContainer = ({ currentAccount, intl, navigation, dispatch, route }) => {
|
||||
const [drafts, setDrafts] = useState([]);
|
||||
const [schedules, setSchedules] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [initialTabIndex] = useState(route.params?.showSchedules ? 1 : 0);
|
||||
|
||||
useEffect(() => {
|
||||
_getDrafts();
|
||||
_getSchedules();
|
||||
}, []);
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _getSchedules = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
getSchedules()
|
||||
.then((data) => {
|
||||
setSchedules(_sortDataS(data));
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
Alert.alert(intl.formatMessage({ id: 'drafts.load_error' }));
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const _getDrafts = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
getDrafts()
|
||||
.then((data) => {
|
||||
setDrafts(_sortData(data));
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
Alert.alert(intl.formatMessage({ id: 'drafts.load_error' }));
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const _removeDraft = (id) => {
|
||||
deleteDraft(id)
|
||||
.then(() => {
|
||||
const newDrafts = [...drafts].filter((draft) => draft._id !== id);
|
||||
setDrafts(_sortData(newDrafts));
|
||||
})
|
||||
.catch(() => {
|
||||
Alert.alert(intl.formatMessage({ id: 'alert.fail' }));
|
||||
});
|
||||
};
|
||||
|
||||
const _removeSchedule = (id) => {
|
||||
deleteScheduledPost(id)
|
||||
.then((res) => {
|
||||
const newSchedules = [...schedules].filter((schedule) => schedule._id !== id);
|
||||
|
||||
setSchedules(_sortDataS(newSchedules));
|
||||
})
|
||||
.catch(() => {
|
||||
Alert.alert(intl.formatMessage({ id: 'alert.fail' }));
|
||||
});
|
||||
};
|
||||
|
||||
const _moveScheduleToDraft = (id) => {
|
||||
moveScheduledToDraft(id)
|
||||
.then((res) => {
|
||||
dispatch(
|
||||
toastNotification(
|
||||
intl.formatMessage({
|
||||
id: 'alert.success_moved',
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
_getDrafts();
|
||||
_getSchedules();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('Failed to move scheduled post to drafts');
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
|
||||
});
|
||||
};
|
||||
|
||||
const _editDraft = (id) => {
|
||||
const selectedDraft = drafts.find((draft) => draft._id === id);
|
||||
|
||||
navigation.navigate({
|
||||
name: ROUTES.SCREENS.EDITOR,
|
||||
key: `editor_draft_${id}`,
|
||||
params: {
|
||||
draft: selectedDraft,
|
||||
fetchPost: _getDrafts,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _sortData = (data) =>
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.created).getTime();
|
||||
const dateB = new Date(b.created).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
|
||||
const _sortDataS = (data) =>
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.schedule).getTime();
|
||||
const dateB = new Date(b.schedule).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
|
||||
return (
|
||||
<DraftsScreen
|
||||
isLoading={isLoading}
|
||||
editDraft={_editDraft}
|
||||
currentAccount={currentAccount}
|
||||
drafts={drafts}
|
||||
schedules={schedules}
|
||||
removeDraft={_removeDraft}
|
||||
moveScheduleToDraft={_moveScheduleToDraft}
|
||||
removeSchedule={_removeSchedule}
|
||||
initialTabIndex={initialTabIndex}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccount: state.account.currentAccount,
|
||||
});
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(DraftsContainer));
|
93
src/screens/drafts/container/draftsContainer.tsx
Normal file
93
src/screens/drafts/container/draftsContainer.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
import React, { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
// Services and Actions
|
||||
import {
|
||||
useDraftDeleteMutation,
|
||||
useGetDraftsQuery,
|
||||
useGetSchedulesQuery,
|
||||
useMoveScheduleToDraftsMutation,
|
||||
useScheduleDeleteMutation,
|
||||
} from '../../../providers/queries/draftQueries';
|
||||
|
||||
// Middleware
|
||||
|
||||
// Constants
|
||||
import { default as ROUTES } from '../../../constants/routeNames';
|
||||
|
||||
// Utilities
|
||||
|
||||
// Component
|
||||
import DraftsScreen from '../screen/draftsScreen';
|
||||
|
||||
const DraftsContainer = ({ currentAccount, navigation, route }) => {
|
||||
const { mutate: deleteDraft, isLoading: isDeletingDraft } = useDraftDeleteMutation();
|
||||
const { mutate: deleteSchedule, isLoading: isDeletingSchedule } = useScheduleDeleteMutation();
|
||||
const {
|
||||
mutate: moveScheduleToDrafts,
|
||||
isLoading: isMovingToDrafts,
|
||||
} = useMoveScheduleToDraftsMutation();
|
||||
|
||||
const {
|
||||
isLoading: isLoadingDrafts,
|
||||
data: drafts = [],
|
||||
isFetching: isFetchingDrafts,
|
||||
refetch: refetchDrafts,
|
||||
} = useGetDraftsQuery();
|
||||
|
||||
const {
|
||||
isLoading: isLoadingSchedules,
|
||||
data: schedules = [],
|
||||
isFetching: isFetchingSchedules,
|
||||
refetch: refetchSchedules,
|
||||
} = useGetSchedulesQuery();
|
||||
|
||||
const [initialTabIndex] = useState(route.params?.showSchedules ? 1 : 0);
|
||||
|
||||
// Component Functions
|
||||
const _onRefresh = () => {
|
||||
refetchDrafts();
|
||||
refetchSchedules();
|
||||
};
|
||||
|
||||
const _editDraft = (id: string) => {
|
||||
const selectedDraft = drafts.find((draft) => draft._id === id);
|
||||
|
||||
navigation.navigate({
|
||||
name: ROUTES.SCREENS.EDITOR,
|
||||
key: `editor_draft_${id}`,
|
||||
params: {
|
||||
draft: selectedDraft,
|
||||
fetchPost: refetchDrafts,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _isLoading =
|
||||
isLoadingDrafts || isLoadingSchedules || isFetchingDrafts || isFetchingSchedules;
|
||||
|
||||
const _isDeleting = isDeletingDraft || isDeletingSchedule || isMovingToDrafts;
|
||||
|
||||
return (
|
||||
<DraftsScreen
|
||||
isLoading={_isLoading}
|
||||
isDeleting={_isDeleting}
|
||||
editDraft={_editDraft}
|
||||
currentAccount={currentAccount}
|
||||
drafts={drafts}
|
||||
schedules={schedules}
|
||||
removeDraft={deleteDraft}
|
||||
moveScheduleToDraft={moveScheduleToDrafts}
|
||||
removeSchedule={deleteSchedule}
|
||||
onRefresh={_onRefresh}
|
||||
initialTabIndex={initialTabIndex}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccount: state.account.currentAccount,
|
||||
});
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(DraftsContainer));
|
@ -1,6 +1,6 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { View, FlatList, Text, Platform } from 'react-native';
|
||||
import { View, FlatList, Text, Platform, RefreshControl } from 'react-native';
|
||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||
|
||||
// Utils
|
||||
@ -14,7 +14,7 @@ import { BasicHeader, TabBar, DraftListItem, PostCardPlaceHolder } from '../../.
|
||||
// Styles
|
||||
import globalStyles from '../../../globalStyles';
|
||||
import styles from './draftStyles';
|
||||
import { OptionsModal } from '../../../components/atoms';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
const DraftsScreen = ({
|
||||
currentAccount,
|
||||
@ -22,20 +22,15 @@ const DraftsScreen = ({
|
||||
editDraft,
|
||||
removeSchedule,
|
||||
isLoading,
|
||||
isDeleting,
|
||||
onRefresh,
|
||||
intl,
|
||||
drafts,
|
||||
schedules,
|
||||
moveScheduleToDraft,
|
||||
initialTabIndex,
|
||||
}) => {
|
||||
const [selectedId, setSelectedId] = useState(null);
|
||||
const ActionSheetRef = useRef(null);
|
||||
|
||||
const _onActionPress = (index) => {
|
||||
if (index === 0) {
|
||||
moveScheduleToDraft(selectedId);
|
||||
}
|
||||
};
|
||||
const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme);
|
||||
|
||||
// Component Functions
|
||||
const _renderItem = (item, type) => {
|
||||
@ -53,12 +48,7 @@ const DraftsScreen = ({
|
||||
const isSchedules = type === 'schedules';
|
||||
|
||||
const _onItemPress = () => {
|
||||
if (isSchedules) {
|
||||
setSelectedId(item._id);
|
||||
if (ActionSheetRef.current) {
|
||||
ActionSheetRef.current.show();
|
||||
}
|
||||
} else {
|
||||
if (!isSchedules) {
|
||||
editDraft(item._id);
|
||||
}
|
||||
};
|
||||
@ -75,11 +65,13 @@ const DraftsScreen = ({
|
||||
username={currentAccount.name}
|
||||
reputation={currentAccount.reputation}
|
||||
handleOnPressItem={_onItemPress}
|
||||
handleOnMovePress={moveScheduleToDraft}
|
||||
handleOnRemoveItem={isSchedules ? removeSchedule : removeDraft}
|
||||
id={item._id}
|
||||
key={item._id}
|
||||
status={item.status}
|
||||
isSchedules={isSchedules}
|
||||
isDeleting={isDeleting}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -111,6 +103,16 @@ const DraftsScreen = ({
|
||||
removeClippedSubviews={false}
|
||||
renderItem={({ item }) => _renderItem(item, type)}
|
||||
ListEmptyComponent={_renderEmptyContent()}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isLoading}
|
||||
onRefresh={onRefresh}
|
||||
progressBackgroundColor="#357CE6"
|
||||
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
|
||||
titleColor="#fff"
|
||||
colors={['#fff']}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@ -152,22 +154,6 @@ const DraftsScreen = ({
|
||||
{_getTabItem(schedules, 'schedules')}
|
||||
</View>
|
||||
</ScrollableTabView>
|
||||
<OptionsModal
|
||||
ref={ActionSheetRef}
|
||||
title={intl.formatMessage({
|
||||
id: 'alert.move_question',
|
||||
})}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'alert.move',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={1}
|
||||
onPress={_onActionPress}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
@ -2,63 +2,70 @@ import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'rea
|
||||
import { useIntl } from 'react-intl';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { BeneficiarySelectionContent, DateTimePicker, MainButton, Modal, SettingsItem } from '../../../components';
|
||||
import { View as AnimatedView } from 'react-native-animatable';
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||
import {
|
||||
BeneficiarySelectionContent,
|
||||
DateTimePicker,
|
||||
MainButton,
|
||||
Modal,
|
||||
SettingsItem,
|
||||
} from '../../../components';
|
||||
import styles from './postOptionsModalStyles';
|
||||
import ThumbSelectionContent from './thumbSelectionContent';
|
||||
import {View as AnimatedView} from 'react-native-animatable';
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||
|
||||
const REWARD_TYPES = [
|
||||
{
|
||||
key:'default',
|
||||
intlId:'editor.reward_default'
|
||||
key: 'default',
|
||||
intlId: 'editor.reward_default',
|
||||
},
|
||||
{
|
||||
key:'sp',
|
||||
intlId:'editor.reward_power_up'
|
||||
key: 'sp',
|
||||
intlId: 'editor.reward_power_up',
|
||||
},
|
||||
{
|
||||
key:'dp',
|
||||
intlId:'editor.reward_decline'
|
||||
key: 'dp',
|
||||
intlId: 'editor.reward_decline',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
];
|
||||
|
||||
export interface PostOptionsModalRef {
|
||||
showModal:()=>void;
|
||||
showModal: () => void;
|
||||
}
|
||||
|
||||
|
||||
interface PostOptionsModalProps {
|
||||
body:string;
|
||||
draftId:string;
|
||||
thumbIndex:number,
|
||||
isEdit:boolean;
|
||||
isCommunityPost:boolean;
|
||||
body: string;
|
||||
draftId: string;
|
||||
thumbUrl: string;
|
||||
isEdit: boolean;
|
||||
isCommunityPost: boolean;
|
||||
rewardType: string;
|
||||
isUploading: boolean;
|
||||
handleRewardChange:(rewardType:string)=>void;
|
||||
handleThumbSelection:(index:number)=>void;
|
||||
handleScheduleChange:(datetime:string|null)=>void;
|
||||
handleShouldReblogChange:(shouldReblog:boolean)=>void;
|
||||
handleFormUpdate:()=>void;
|
||||
handleRewardChange: (rewardType: string) => void;
|
||||
handleThumbSelection: (url: string) => void;
|
||||
handleScheduleChange: (datetime: string | null) => void;
|
||||
handleShouldReblogChange: (shouldReblog: boolean) => void;
|
||||
handleFormUpdate: () => void;
|
||||
}
|
||||
|
||||
const PostOptionsModal = forwardRef(({
|
||||
body,
|
||||
draftId,
|
||||
thumbIndex,
|
||||
isEdit,
|
||||
isCommunityPost,
|
||||
rewardType,
|
||||
isUploading,
|
||||
handleRewardChange,
|
||||
handleThumbSelection,
|
||||
handleScheduleChange,
|
||||
handleShouldReblogChange,
|
||||
handleFormUpdate
|
||||
}: PostOptionsModalProps, ref) => {
|
||||
const PostOptionsModal = forwardRef(
|
||||
(
|
||||
{
|
||||
body,
|
||||
draftId,
|
||||
thumbUrl,
|
||||
isEdit,
|
||||
isCommunityPost,
|
||||
rewardType,
|
||||
isUploading,
|
||||
handleRewardChange,
|
||||
handleThumbSelection,
|
||||
handleScheduleChange,
|
||||
handleShouldReblogChange,
|
||||
handleFormUpdate,
|
||||
}: PostOptionsModalProps,
|
||||
ref,
|
||||
) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@ -70,84 +77,83 @@ const PostOptionsModal = forwardRef(({
|
||||
|
||||
// removed the useeffect causing index reset bug
|
||||
|
||||
useEffect(()=>{
|
||||
if(!scheduleLater){
|
||||
handleScheduleChange(null)
|
||||
}else if(scheduledFor) {
|
||||
handleScheduleChange(scheduledFor)
|
||||
}
|
||||
}, [scheduleLater, scheduledFor])
|
||||
|
||||
useEffect(() => {
|
||||
handleShouldReblogChange(shouldReblog)
|
||||
}, [shouldReblog])
|
||||
if (!scheduleLater) {
|
||||
handleScheduleChange(null);
|
||||
} else if (scheduledFor) {
|
||||
handleScheduleChange(scheduledFor);
|
||||
}
|
||||
}, [scheduleLater, scheduledFor]);
|
||||
|
||||
useEffect(() => {
|
||||
if(!isCommunityPost && shouldReblog){
|
||||
handleShouldReblogChange(shouldReblog);
|
||||
}, [shouldReblog]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCommunityPost && shouldReblog) {
|
||||
setShouldReblog(false);
|
||||
}
|
||||
}, [isCommunityPost])
|
||||
}, [isCommunityPost]);
|
||||
|
||||
// load rewardtype from props if it is already saved in drafts
|
||||
useEffect(() => {
|
||||
if(rewardType){
|
||||
let rewardTypeKey = REWARD_TYPES.findIndex((item) => item.key === rewardType)
|
||||
if (rewardType) {
|
||||
let rewardTypeKey = REWARD_TYPES.findIndex((item) => item.key === rewardType);
|
||||
setRewardTypeIndex(rewardTypeKey);
|
||||
}
|
||||
},[rewardType])
|
||||
}, [rewardType]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: () => {
|
||||
setShowModal(true);
|
||||
},
|
||||
}));
|
||||
show: () => {
|
||||
setShowModal(true);
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const _handleRewardChange = (index:number) => {
|
||||
setRewardTypeIndex(index)
|
||||
const rewardTypeKey = REWARD_TYPES[index].key
|
||||
const _handleRewardChange = (index: number) => {
|
||||
setRewardTypeIndex(index);
|
||||
const rewardTypeKey = REWARD_TYPES[index].key;
|
||||
if (handleRewardChange) {
|
||||
handleRewardChange(rewardTypeKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _handleDatePickerChange = (date:string) => {
|
||||
const _handleDatePickerChange = (date: string) => {
|
||||
setScheduledFor(date);
|
||||
}
|
||||
};
|
||||
|
||||
const _onDonePress = () => {
|
||||
setShowModal(false);
|
||||
handleFormUpdate();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// handle index change here instead of useeffetc
|
||||
const _handleThumbIndexSelection = (index:number) => {
|
||||
handleThumbSelection(index)
|
||||
}
|
||||
const _handleThumbIndexSelection = (url: string) => {
|
||||
handleThumbSelection(url);
|
||||
};
|
||||
|
||||
const _renderContent = () => (
|
||||
<View style={styles.fillSpace}>
|
||||
<KeyboardAwareScrollView style={styles.fillSpace} >
|
||||
<KeyboardAwareScrollView style={styles.fillSpace}>
|
||||
<View style={styles.container}>
|
||||
{!isEdit && (
|
||||
<>
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({id:'editor.scheduled_for'}) }
|
||||
title={intl.formatMessage({ id: 'editor.scheduled_for' })}
|
||||
type="dropdown"
|
||||
actionType="reward"
|
||||
options={[
|
||||
intl.formatMessage({id:"editor.scheduled_immediate"}),
|
||||
intl.formatMessage({id:"editor.scheduled_later"}),
|
||||
intl.formatMessage({ id: 'editor.scheduled_immediate' }),
|
||||
intl.formatMessage({ id: 'editor.scheduled_later' }),
|
||||
]}
|
||||
selectedOptionIndex={scheduleLater ? 1 : 0}
|
||||
handleOnChange={(index)=> {
|
||||
handleOnChange={(index) => {
|
||||
setScheduleLater(index === 1);
|
||||
if (index !== 1) {
|
||||
handleScheduleChange(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
{scheduleLater && (
|
||||
<AnimatedView animation="flipInX" duration={700}>
|
||||
<DateTimePicker
|
||||
@ -156,23 +162,19 @@ const PostOptionsModal = forwardRef(({
|
||||
disabled={true}
|
||||
/>
|
||||
</AnimatedView>
|
||||
|
||||
)}
|
||||
|
||||
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
id: 'editor.setting_reward',
|
||||
})}
|
||||
type="dropdown"
|
||||
actionType="reward"
|
||||
options={
|
||||
REWARD_TYPES.map((type)=>intl.formatMessage({ id: type.intlId}))
|
||||
}
|
||||
options={REWARD_TYPES.map((type) => intl.formatMessage({ id: type.intlId }))}
|
||||
selectedOptionIndex={rewardTypeIndex}
|
||||
handleOnChange={_handleRewardChange}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{isCommunityPost && (
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
@ -184,42 +186,33 @@ const PostOptionsModal = forwardRef(({
|
||||
handleOnChange={setShouldReblog}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
<ThumbSelectionContent
|
||||
|
||||
<ThumbSelectionContent
|
||||
body={body}
|
||||
thumbIndex={thumbIndex}
|
||||
thumbUrl={thumbUrl}
|
||||
isUploading={isUploading}
|
||||
onThumbSelection={_handleThumbIndexSelection}
|
||||
/>
|
||||
|
||||
|
||||
{!isEdit && (
|
||||
<BeneficiarySelectionContent
|
||||
draftId={draftId}
|
||||
setDisableDone={setDisableDone}
|
||||
/>
|
||||
<BeneficiarySelectionContent draftId={draftId} setDisableDone={setDisableDone} />
|
||||
)}
|
||||
|
||||
|
||||
</View>
|
||||
</KeyboardAwareScrollView>
|
||||
|
||||
<MainButton
|
||||
style={{...styles.saveButton }}
|
||||
style={{ ...styles.saveButton }}
|
||||
isDisable={disableDone}
|
||||
onPress={_onDonePress}
|
||||
text={intl.formatMessage({id:"editor.done"})}
|
||||
/>
|
||||
text={intl.formatMessage({ id: 'editor.done' })}
|
||||
/>
|
||||
</View>
|
||||
|
||||
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
return (
|
||||
<Modal
|
||||
isOpen={showModal}
|
||||
handleOnModalClose={() => {
|
||||
setShowModal(false);
|
||||
@ -228,14 +221,14 @@ const PostOptionsModal = forwardRef(({
|
||||
isFullScreen
|
||||
isCloseButton
|
||||
presentationStyle="formSheet"
|
||||
title={intl.formatMessage({id:"editor.settings_title"})}
|
||||
title={intl.formatMessage({ id: 'editor.settings_title' })}
|
||||
animationType="slide"
|
||||
style={styles.modalStyle}
|
||||
>
|
||||
{_renderContent()}
|
||||
</Modal>
|
||||
|
||||
);
|
||||
});
|
||||
{_renderContent()}
|
||||
</Modal>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default PostOptionsModal
|
||||
export default PostOptionsModal;
|
||||
|
@ -1,59 +1,60 @@
|
||||
import { ViewStyle } from 'react-native';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position:'absolute',
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
zIndex:999
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 999,
|
||||
},
|
||||
thumbStyle: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
marginVertical: 8,
|
||||
marginRight: 8,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
checkContainer: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 6,
|
||||
backgroundColor: '$pureWhite',
|
||||
borderRadius: 12,
|
||||
},
|
||||
settingLabel: {
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign: 'left',
|
||||
},
|
||||
listContainer: {
|
||||
paddingBottom: getBottomSpace() + 16,
|
||||
},
|
||||
container: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom: 20 },
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
||||
contentLabel: { color: '$iconColor', marginTop: 4, textAlign: 'left' },
|
||||
weightInput: { width: 80 },
|
||||
weightFormInput: { flex: 1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex: 1, color: '$primaryBlack', marginLeft: 16 },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop: 16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton: { borderRadius: 16, backgroundColor: '$primaryBlue' },
|
||||
thumbSelectContainer: {
|
||||
marginTop: 12,
|
||||
},
|
||||
thumbStyle:{
|
||||
width:72,
|
||||
height:72,
|
||||
marginVertical:8,
|
||||
marginRight:8,
|
||||
borderRadius:12,
|
||||
backgroundColor:'$primaryLightGray'
|
||||
},
|
||||
selectedStyle:{
|
||||
borderWidth:4,
|
||||
borderColor:'$primaryBlack'
|
||||
},
|
||||
settingLabel:{
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign:'left',
|
||||
},
|
||||
listContainer:{
|
||||
paddingBottom:getBottomSpace() + 16,
|
||||
},
|
||||
container:{
|
||||
paddingVertical:16
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom:20},
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center'},
|
||||
contentLabel: { color: '$iconColor', marginTop:4, textAlign:'left' },
|
||||
weightInput: {width:80},
|
||||
weightFormInput: { flex:1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex:1, color: '$primaryBlack', marginLeft: 16 },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop:16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton:{borderRadius:16, backgroundColor:'$primaryBlue'},
|
||||
thumbSelectContainer:{
|
||||
marginTop:12,
|
||||
}
|
||||
});
|
||||
|
@ -1,87 +1,109 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { ActivityIndicator, Alert, Text, TouchableOpacity, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import ESStyleSheet from 'react-native-extended-stylesheet';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { View as AnimatedView } from 'react-native-animatable';
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import styles from './styles';
|
||||
import ESStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { Icon } from '../../../components';
|
||||
|
||||
interface ThumbSelectionContentProps {
|
||||
body: string;
|
||||
thumbIndex: number;
|
||||
isUploading: boolean;
|
||||
onThumbSelection: (index: number) => void;
|
||||
body: string;
|
||||
thumbUrl: string;
|
||||
isUploading: boolean;
|
||||
onThumbSelection: (url: string) => void;
|
||||
}
|
||||
|
||||
const ThumbSelectionContent = ({ body, thumbIndex, onThumbSelection, isUploading }: ThumbSelectionContentProps) => {
|
||||
const intl = useIntl();
|
||||
const ThumbSelectionContent = ({
|
||||
body,
|
||||
thumbUrl,
|
||||
onThumbSelection,
|
||||
isUploading,
|
||||
}: ThumbSelectionContentProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
const [needMore, setNeedMore] = useState(true);
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
const [needMore, setNeedMore] = useState(true);
|
||||
const [thumbIndex, setThumbIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const urls = extractImageUrls({ body });
|
||||
useEffect(() => {
|
||||
const urls = extractImageUrls({ body });
|
||||
|
||||
if (urls.length < 2) {
|
||||
setNeedMore(true);
|
||||
onThumbSelection(0);
|
||||
setImageUrls([])
|
||||
} else {
|
||||
setNeedMore(false);
|
||||
setImageUrls(urls)
|
||||
}
|
||||
}, [body])
|
||||
|
||||
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({ item, index }: { item: string, index: number }) => {
|
||||
const _onPress = () => {
|
||||
onThumbSelection(index);
|
||||
}
|
||||
|
||||
const selectedStyle = index === thumbIndex ? styles.selectedStyle : null
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => _onPress()} >
|
||||
<FastImage
|
||||
source={{ uri: item }}
|
||||
style={{ ...styles.thumbStyle, ...selectedStyle }}
|
||||
resizeMode='cover'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
if (urls.length < 2) {
|
||||
setNeedMore(true);
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
setImageUrls([]);
|
||||
} else {
|
||||
setNeedMore(false);
|
||||
setImageUrls(urls);
|
||||
}
|
||||
|
||||
const _renderHeader = () => (
|
||||
isUploading &&
|
||||
<View style={{flex:1, justifyContent:'center', marginRight: 16}}>
|
||||
<ActivityIndicator color={ESStyleSheet.value('$primaryBlack')} />
|
||||
</View>
|
||||
const _urlIndex = urls.indexOf(thumbUrl);
|
||||
if (_urlIndex < 0) {
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
} else {
|
||||
setThumbIndex(_urlIndex);
|
||||
}
|
||||
}, [body]);
|
||||
|
||||
)
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({ item, index }: { item: string; index: number }) => {
|
||||
const _onPress = () => {
|
||||
onThumbSelection(item);
|
||||
setThumbIndex(index);
|
||||
};
|
||||
|
||||
const isSelected = item === thumbUrl && index === thumbIndex;
|
||||
|
||||
return (
|
||||
<View style={styles.thumbSelectContainer}>
|
||||
<Text style={styles.settingLabel}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
{
|
||||
needMore ? (
|
||||
<Text style={styles.contentLabel}>{intl.formatMessage({ id: 'editor.add_more_imgs' })}</Text>
|
||||
) : (
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
ListHeaderComponent={_renderHeader}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false} />
|
||||
)
|
||||
}
|
||||
|
||||
</View>
|
||||
<TouchableOpacity onPress={() => _onPress()}>
|
||||
<FastImage source={{ uri: item }} style={styles.thumbStyle} resizeMode="cover" />
|
||||
{isSelected && (
|
||||
<AnimatedView duration={300} animation="zoomIn" style={styles.checkContainer}>
|
||||
<Icon
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
iconType="MaterialCommunityIcons"
|
||||
name="checkbox-marked-circle"
|
||||
size={20}
|
||||
/>
|
||||
</AnimatedView>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderHeader = () =>
|
||||
isUploading && (
|
||||
<View style={{ flex: 1, justifyContent: 'center', marginRight: 16 }}>
|
||||
<ActivityIndicator color={ESStyleSheet.value('$primaryBlack')} />
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.thumbSelectContainer}>
|
||||
<Text style={styles.settingLabel}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
{needMore ? (
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({ id: 'editor.add_more_imgs' })}
|
||||
</Text>
|
||||
) : (
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
ListHeaderComponent={_renderHeader}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThumbSelectionContent;
|
||||
|
@ -1,22 +1,20 @@
|
||||
import React, { useImperativeHandle, useRef, useState } from 'react';
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef } from 'react';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import ActionSheet from 'react-native-actions-sheet';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import styles from './styles';
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
import { View, Text, Alert, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import styles from './styles';
|
||||
|
||||
export interface ThumbSelectionModalProps {
|
||||
thumbIndex:number;
|
||||
onThumbSelection:(index:number)=>void;
|
||||
thumbUrl: string;
|
||||
onThumbSelection: (index: number) => void;
|
||||
}
|
||||
|
||||
|
||||
const ThumbSelectionModal = ({ onThumbSelection, thumbIndex }:ThumbSelectionModalProps, ref) => {
|
||||
const ThumbSelectionModal = ({ onThumbSelection, thumbUrl }: ThumbSelectionModalProps, ref) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
@ -24,82 +22,74 @@ const ThumbSelectionModal = ({ onThumbSelection, thumbIndex }:ThumbSelectionModa
|
||||
|
||||
//CALLBACK_METHODS
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: (postBody:string) => {
|
||||
console.log("Showing action modal")
|
||||
show: (postBody: string) => {
|
||||
console.log('Showing action modal');
|
||||
|
||||
const urls = extractImageUrls({body:postBody});
|
||||
const urls = extractImageUrls({ body: postBody });
|
||||
|
||||
if(urls.length < 2){
|
||||
console.log("Skipping modal show as post images are less than 2");
|
||||
Alert.alert(
|
||||
intl.formatMessage({id:'editor.two_thumbs_required'})
|
||||
)
|
||||
onThumbSelection(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setImageUrls(urls);
|
||||
sheetModalRef.current?.setModalVisible(true);
|
||||
if (urls.length < 2) {
|
||||
console.log('Skipping modal show as post images are less than 2');
|
||||
Alert.alert(intl.formatMessage({ id: 'editor.two_thumbs_required' }));
|
||||
onThumbSelection(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setImageUrls(urls);
|
||||
sheetModalRef.current?.setModalVisible(true);
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const _onSelection = (index:number) => {
|
||||
const _onSelection = (index: number) => {
|
||||
onThumbSelection(index);
|
||||
sheetModalRef.current?.setModalVisible(false);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({item, index}:{item:string, index:number}) => {
|
||||
const _onPress = () => {
|
||||
_onSelection(index);
|
||||
}
|
||||
const _renderImageItem = ({ item, index }: { item: string; index: number }) => {
|
||||
const _onPress = () => {
|
||||
_onSelection(index);
|
||||
};
|
||||
|
||||
const selectedStyle = index === thumbIndex ? styles.selectedStyle : null
|
||||
const selectedStyle = item === thumbUrl ? styles.selectedStyle : null;
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => _onPress()} >
|
||||
<FastImage
|
||||
source={{uri:item}}
|
||||
style={{...styles.thumbStyle, ...selectedStyle}}
|
||||
resizeMode='cover'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
<TouchableOpacity onPress={() => _onPress()}>
|
||||
<FastImage
|
||||
source={{ uri: item }}
|
||||
style={{ ...styles.thumbStyle, ...selectedStyle }}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderContent = () => {
|
||||
return (
|
||||
<View style={{alignItems:'center'}} >
|
||||
<Text style={styles.title}>{intl.formatMessage({id:'editor.select_thumb'})}</Text>
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
keyExtractor={(item, index)=>`${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Text style={styles.title}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={false}
|
||||
hideUnderlay
|
||||
containerStyle={styles.sheetContent}
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
|
||||
>
|
||||
{_renderContent()}
|
||||
</ActionSheet>
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={false}
|
||||
hideUnderlay
|
||||
containerStyle={styles.sheetContent}
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
|
||||
>
|
||||
{_renderContent()}
|
||||
</ActionSheet>
|
||||
);
|
||||
};
|
||||
|
||||
export default forwardRef(ThumbSelectionModal);
|
||||
export default forwardRef(ThumbSelectionModal);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { Alert } from 'react-native';
|
||||
import { Alert, AppState, AppStateStatus } from 'react-native';
|
||||
import get from 'lodash/get';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { isArray } from 'lodash';
|
||||
@ -9,13 +9,8 @@ import { isArray } from 'lodash';
|
||||
// Services and Actions
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import {
|
||||
|
||||
addDraft,
|
||||
updateDraft,
|
||||
getDrafts,
|
||||
addSchedule,
|
||||
} from '../../../providers/ecency/ecency';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { addDraft, updateDraft, getDrafts, addSchedule } from '../../../providers/ecency/ecency';
|
||||
import { toastNotification, setRcOffer } from '../../../redux/actions/uiAction';
|
||||
import {
|
||||
postContent,
|
||||
@ -43,7 +38,13 @@ import {
|
||||
import EditorScreen from '../screen/editorScreen';
|
||||
import { removeBeneficiaries, setBeneficiaries } from '../../../redux/actions/editorActions';
|
||||
import { DEFAULT_USER_DRAFT_ID, TEMP_BENEFICIARIES_ID } from '../../../redux/constants/constants';
|
||||
import { deleteDraftCacheEntry, updateCommentCache, updateDraftCache } from '../../../redux/actions/cacheActions';
|
||||
import {
|
||||
deleteDraftCacheEntry,
|
||||
updateCommentCache,
|
||||
updateDraftCache,
|
||||
} from '../../../redux/actions/cacheActions';
|
||||
import QUERIES from '../../../providers/queries/queryKeys';
|
||||
import bugsnapInstance from '../../../config/bugsnag';
|
||||
|
||||
/*
|
||||
* Props Name Description Value
|
||||
@ -54,6 +55,7 @@ import { deleteDraftCacheEntry, updateCommentCache, updateDraftCache } from '../
|
||||
class EditorContainer extends Component<any, any> {
|
||||
_isMounted = false;
|
||||
_updatedDraftFields = null;
|
||||
_appState = AppState.currentState;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -71,14 +73,12 @@ class EditorContainer extends Component<any, any> {
|
||||
uploadProgress: 0,
|
||||
post: null,
|
||||
uploadedImage: null,
|
||||
isDraft: false,
|
||||
community: [],
|
||||
rewardType: 'default',
|
||||
sharedSnippetText: null,
|
||||
onLoadDraftPress: false,
|
||||
thumbIndex: 0,
|
||||
thumbUrl: '',
|
||||
shouldReblog: false,
|
||||
failedImageUploads: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@ -105,7 +105,6 @@ class EditorContainer extends Component<any, any> {
|
||||
|
||||
this.setState({
|
||||
draftId: _draft._id,
|
||||
isDraft: true,
|
||||
});
|
||||
this._getStorageDraft(username, isReply, _draft);
|
||||
}
|
||||
@ -124,8 +123,8 @@ class EditorContainer extends Component<any, any> {
|
||||
|
||||
if (navigationParams.isReply) {
|
||||
({ isReply } = navigationParams);
|
||||
if(post){
|
||||
draftId = `${currentAccount.name}/${post.author}/${post.permlink}`
|
||||
if (post) {
|
||||
draftId = `${currentAccount.name}/${post.author}/${post.permlink}`;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
@ -135,7 +134,7 @@ class EditorContainer extends Component<any, any> {
|
||||
});
|
||||
if (draftId) {
|
||||
this._getStorageDraft(username, isReply, { _id: draftId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (navigationParams.isEdit) {
|
||||
@ -155,12 +154,12 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
|
||||
// handle file/text shared from ReceiveSharingIntent
|
||||
if(hasSharedIntent){
|
||||
if (hasSharedIntent) {
|
||||
const files = navigationParams.files;
|
||||
console.log('files : ', files);
|
||||
|
||||
|
||||
files.forEach((el) => {
|
||||
if (el.text) {
|
||||
if (el.text) {
|
||||
this.setState({
|
||||
sharedSnippetText: el.text,
|
||||
});
|
||||
@ -173,20 +172,34 @@ class EditorContainer extends Component<any, any> {
|
||||
this._fetchDraftsForComparison(isReply);
|
||||
}
|
||||
this._requestKeyboardFocus();
|
||||
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<any>, snapshot?: any): void {
|
||||
if(prevState.rewardType !== this.state.rewardType || prevProps.beneficiariesMap !== this.props.beneficiariesMap){
|
||||
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<any>): void {
|
||||
if (
|
||||
prevState.rewardType !== this.state.rewardType ||
|
||||
prevProps.beneficiariesMap !== this.props.beneficiariesMap
|
||||
) {
|
||||
// update isDraftSaved when reward type or beneficiaries are changed in post options
|
||||
this._handleFormChanged();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
_handleAppStateChange = (nextAppState: AppStateStatus) => {
|
||||
if (this._appState.match(/active|forground/) && nextAppState === 'inactive') {
|
||||
this._saveCurrentDraft(this._updatedDraftFields);
|
||||
}
|
||||
this._appState = nextAppState;
|
||||
};
|
||||
|
||||
_getStorageDraft = async (username, isReply, paramDraft) => {
|
||||
const { drafts, dispatch } = this.props;
|
||||
const { drafts } = this.props;
|
||||
if (isReply) {
|
||||
const _draft = drafts.get(paramDraft._id);
|
||||
if (_draft && _draft.body) {
|
||||
@ -204,15 +217,16 @@ class EditorContainer extends Component<any, any> {
|
||||
//if _draft is returned and param draft is available, compare timestamp, use latest
|
||||
//if no draft, use result anayways
|
||||
|
||||
if (_localDraft && (!paramDraft || paramDraft.timestamp < _localDraft.updated)) {
|
||||
const _remoteDraftModifiedAt = paramDraft ? new Date(paramDraft.modified).getTime() : 0;
|
||||
const _useLocalDraft = _localDraft && _remoteDraftModifiedAt < _localDraft.updated;
|
||||
if (_useLocalDraft) {
|
||||
this.setState({
|
||||
draftPost: {
|
||||
body: get(_localDraft, 'body', ''),
|
||||
title: get(_localDraft, 'title', ''),
|
||||
tags: get(_localDraft, 'tags', '').split(','),
|
||||
isDraft: paramDraft ? true : false,
|
||||
draftId: paramDraft ? paramDraft._id : null,
|
||||
meta: _localDraft.meta ? _localDraft.meta : null
|
||||
meta: _localDraft.meta ? _localDraft.meta : null,
|
||||
},
|
||||
});
|
||||
this._loadMeta(_localDraft); //load meta from local draft
|
||||
@ -229,15 +243,13 @@ class EditorContainer extends Component<any, any> {
|
||||
title: paramDraft.title,
|
||||
body: paramDraft.body,
|
||||
tags: _tags,
|
||||
meta: paramDraft.meta ? paramDraft.meta : null
|
||||
meta: paramDraft.meta ? paramDraft.meta : null,
|
||||
},
|
||||
isDraft: true,
|
||||
draftId: paramDraft._id,
|
||||
});
|
||||
|
||||
this._loadMeta(paramDraft); //load meta from param draft
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -248,9 +260,8 @@ class EditorContainer extends Component<any, any> {
|
||||
const body = draft.body;
|
||||
if (draft.meta && draft.meta.image) {
|
||||
const urls = extractImageUrls({ body });
|
||||
const draftThumbIndex = urls.indexOf(draft.meta.image[0]);
|
||||
this.setState({
|
||||
thumbIndex: draftThumbIndex,
|
||||
thumbUrl: draft.meta.image[0],
|
||||
});
|
||||
}
|
||||
|
||||
@ -262,12 +273,14 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
|
||||
if (draft._id && draft.meta && draft.meta.beneficiaries) {
|
||||
if(isArray(draft.meta.beneficiaries)){
|
||||
const filteredBeneficiaries = draft.meta.beneficiaries.filter((item) => item.account !== currentAccount.username); //remove default beneficiary from array while saving
|
||||
if (isArray(draft.meta.beneficiaries)) {
|
||||
const filteredBeneficiaries = draft.meta.beneficiaries.filter(
|
||||
(item) => item.account !== currentAccount.username,
|
||||
); //remove default beneficiary from array while saving
|
||||
dispatch(setBeneficiaries(draft._id || TEMP_BENEFICIARIES_ID, filteredBeneficiaries));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_requestKeyboardFocus = () => {
|
||||
//50 ms timeout is added to avoid keyboard not showing up on android
|
||||
setTimeout(() => {
|
||||
@ -286,7 +299,7 @@ class EditorContainer extends Component<any, any> {
|
||||
* @param isReply
|
||||
**/
|
||||
_fetchDraftsForComparison = async (isReply) => {
|
||||
const { currentAccount, isLoggedIn, intl, dispatch, drafts } = this.props;
|
||||
const { currentAccount, isLoggedIn, drafts } = this.props;
|
||||
const username = get(currentAccount, 'name', '');
|
||||
|
||||
//initilizes editor with reply or non remote id less draft
|
||||
@ -311,8 +324,8 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
|
||||
const remoteDrafts = await getDrafts(username);
|
||||
|
||||
const idLessDraft = drafts.get(DEFAULT_USER_DRAFT_ID + username)
|
||||
|
||||
const idLessDraft = drafts.get(DEFAULT_USER_DRAFT_ID + username);
|
||||
|
||||
const loadRecentDraft = () => {
|
||||
//if no draft available means local draft is recent
|
||||
@ -341,7 +354,6 @@ class EditorContainer extends Component<any, any> {
|
||||
//initilize editor as draft
|
||||
this.setState({
|
||||
draftId: _draft._id,
|
||||
isDraft: true,
|
||||
});
|
||||
this._getStorageDraft(username, isReply, _draft);
|
||||
};
|
||||
@ -361,21 +373,28 @@ class EditorContainer extends Component<any, any> {
|
||||
const { draftId } = this.state;
|
||||
const { beneficiariesMap, currentAccount } = this.props;
|
||||
|
||||
return beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID]
|
||||
|| [{ account: currentAccount.name, weight: 10000 }];
|
||||
}
|
||||
|
||||
return (
|
||||
beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID] || [
|
||||
{ account: currentAccount.name, weight: 10000 },
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
_saveDraftToDB = async (fields, saveAsNew = false) => {
|
||||
const { isDraftSaved, draftId, thumbIndex, isReply, rewardType } = this.state;
|
||||
const { currentAccount, dispatch, intl } = this.props;
|
||||
const { isDraftSaved, draftId, thumbUrl, isReply, rewardType } = this.state;
|
||||
const { currentAccount, dispatch, intl, queryClient } = this.props;
|
||||
|
||||
|
||||
if (isReply) {
|
||||
this._saveCurrentDraft(this._updatedDraftFields)
|
||||
return;
|
||||
try {
|
||||
//saves draft locallly
|
||||
this._saveCurrentDraft(this._updatedDraftFields);
|
||||
} catch (err) {
|
||||
console.warn('local draft safe failed, skipping for remote only', err);
|
||||
bugsnapInstance.notify(err);
|
||||
}
|
||||
|
||||
if (isReply) {
|
||||
return;
|
||||
}
|
||||
|
||||
const beneficiaries = this._extractBeneficiaries();
|
||||
|
||||
@ -395,14 +414,14 @@ class EditorContainer extends Component<any, any> {
|
||||
tags: fields.tags.join(' '),
|
||||
};
|
||||
}
|
||||
|
||||
const meta = Object.assign({}, extractMetadata(draftField.body, thumbIndex), {
|
||||
|
||||
const meta = Object.assign({}, extractMetadata(draftField.body, thumbUrl), {
|
||||
tags: draftField.tags,
|
||||
beneficiaries,
|
||||
rewardType
|
||||
rewardType,
|
||||
});
|
||||
const jsonMeta = makeJsonMetadata(meta, draftField.tags);
|
||||
|
||||
|
||||
//update draft is draftId is present
|
||||
if (draftId && draftField && !saveAsNew) {
|
||||
await updateDraft(draftId, draftField.title, draftField.body, draftField.tags, jsonMeta);
|
||||
@ -417,7 +436,12 @@ class EditorContainer extends Component<any, any> {
|
||||
|
||||
//create new darft otherwise
|
||||
else if (draftField) {
|
||||
const response = await addDraft(draftField.title, draftField.body, draftField.tags, jsonMeta);
|
||||
const response = await addDraft(
|
||||
draftField.title,
|
||||
draftField.body,
|
||||
draftField.tags,
|
||||
jsonMeta,
|
||||
);
|
||||
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
@ -426,17 +450,18 @@ class EditorContainer extends Component<any, any> {
|
||||
draftId: response._id,
|
||||
});
|
||||
}
|
||||
const filteredBeneficiaries = beneficiaries.filter((item) => item.account !== currentAccount.username); //remove default beneficiary from array while saving
|
||||
const filteredBeneficiaries = beneficiaries.filter(
|
||||
(item) => item.account !== currentAccount.username,
|
||||
); //remove default beneficiary from array while saving
|
||||
dispatch(setBeneficiaries(response._id, filteredBeneficiaries));
|
||||
dispatch(removeBeneficiaries(TEMP_BENEFICIARIES_ID));
|
||||
|
||||
//clear local copy if darft save is successful
|
||||
const username = get(currentAccount, 'name', '');
|
||||
|
||||
dispatch(deleteDraftCacheEntry(draftId || (DEFAULT_USER_DRAFT_ID + username)))
|
||||
dispatch(deleteDraftCacheEntry(draftId || DEFAULT_USER_DRAFT_ID + username));
|
||||
}
|
||||
|
||||
|
||||
dispatch(
|
||||
toastNotification(
|
||||
intl.formatMessage({
|
||||
@ -445,9 +470,10 @@ class EditorContainer extends Component<any, any> {
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
//call fetch post to drafts screen
|
||||
this._navigationBackFetchDrafts();
|
||||
if (queryClient) {
|
||||
queryClient.invalidateQueries([QUERIES.DRAFTS.GET]);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to save draft to DB: ', err);
|
||||
@ -456,9 +482,6 @@ class EditorContainer extends Component<any, any> {
|
||||
isDraftSaving: false,
|
||||
isDraftSaved: false,
|
||||
});
|
||||
|
||||
//saves draft locally if remote draft save fails
|
||||
this._saveCurrentDraft(this._updatedDraftFields)
|
||||
}
|
||||
|
||||
dispatch(
|
||||
@ -471,11 +494,9 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_updateDraftFields = (fields) => {
|
||||
this._updatedDraftFields = fields;
|
||||
}
|
||||
|
||||
this._updatedDraftFields = fields;
|
||||
};
|
||||
|
||||
_saveCurrentDraft = async (fields) => {
|
||||
const { draftId, isReply, isEdit, isPostSending } = this.state;
|
||||
@ -494,15 +515,15 @@ class EditorContainer extends Component<any, any> {
|
||||
tags: fields.tags && fields.tags.length > 0 ? fields.tags.toString() : '',
|
||||
author: username,
|
||||
meta: fields.meta && fields.meta,
|
||||
}
|
||||
};
|
||||
|
||||
//save reply data
|
||||
if (isReply && draftField.body !== null) {
|
||||
dispatch(updateDraftCache(draftId, draftField))
|
||||
dispatch(updateDraftCache(draftId, draftField));
|
||||
|
||||
//save existing draft data locally
|
||||
} else if (draftId) {
|
||||
dispatch(updateDraftCache(draftId, draftField))
|
||||
dispatch(updateDraftCache(draftId, draftField));
|
||||
}
|
||||
|
||||
//update editor data locally
|
||||
@ -511,12 +532,7 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_submitPost = async ({ fields, scheduleDate }: { fields: any, scheduleDate?: string }) => {
|
||||
|
||||
_submitPost = async ({ fields, scheduleDate }: { fields: any; scheduleDate?: string }) => {
|
||||
const {
|
||||
currentAccount,
|
||||
dispatch,
|
||||
@ -525,11 +541,10 @@ class EditorContainer extends Component<any, any> {
|
||||
pinCode,
|
||||
// isDefaultFooter,
|
||||
} = this.props;
|
||||
const { rewardType, isPostSending, thumbIndex, draftId, shouldReblog } = this.state;
|
||||
const { rewardType, isPostSending, thumbUrl, draftId, shouldReblog } = this.state;
|
||||
|
||||
const beneficiaries = this._extractBeneficiaries();
|
||||
|
||||
|
||||
if (isPostSending) {
|
||||
return;
|
||||
}
|
||||
@ -539,7 +554,7 @@ class EditorContainer extends Component<any, any> {
|
||||
isPostSending: true,
|
||||
});
|
||||
|
||||
const meta = extractMetadata(fields.body, thumbIndex);
|
||||
const meta = extractMetadata(fields.body, thumbUrl);
|
||||
const _tags = fields.tags.filter((tag) => tag && tag !== ' ');
|
||||
|
||||
const jsonMeta = makeJsonMetadata(meta, _tags);
|
||||
@ -553,7 +568,7 @@ class EditorContainer extends Component<any, any> {
|
||||
dublicatePost = null;
|
||||
}
|
||||
|
||||
if (dublicatePost && (dublicatePost.permlink === permlink)) {
|
||||
if (dublicatePost && dublicatePost.permlink === permlink) {
|
||||
permlink = generatePermlink(fields.title, true);
|
||||
}
|
||||
|
||||
@ -592,29 +607,25 @@ class EditorContainer extends Component<any, any> {
|
||||
voteWeight,
|
||||
)
|
||||
.then((response) => {
|
||||
|
||||
console.log(response);
|
||||
|
||||
//reblog if flag is active
|
||||
if (shouldReblog) {
|
||||
reblog(
|
||||
currentAccount,
|
||||
pinCode,
|
||||
author,
|
||||
permlink
|
||||
).then((resp) => {
|
||||
console.log("Successfully reblogged post", resp)
|
||||
}).catch((err) => {
|
||||
console.warn("Failed to reblog post", err)
|
||||
})
|
||||
reblog(currentAccount, pinCode, author, permlink)
|
||||
.then((resp) => {
|
||||
console.log('Successfully reblogged post', resp);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('Failed to reblog post', err);
|
||||
});
|
||||
}
|
||||
|
||||
//post publish updates
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name))
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name));
|
||||
|
||||
dispatch(removeBeneficiaries(TEMP_BENEFICIARIES_ID))
|
||||
dispatch(removeBeneficiaries(TEMP_BENEFICIARIES_ID));
|
||||
if (draftId) {
|
||||
dispatch(removeBeneficiaries(draftId))
|
||||
dispatch(removeBeneficiaries(draftId));
|
||||
}
|
||||
|
||||
dispatch(
|
||||
@ -632,9 +643,10 @@ class EditorContainer extends Component<any, any> {
|
||||
ROUTES.SCREENS.PROFILE,
|
||||
{
|
||||
username: get(currentAccount, 'name'),
|
||||
}, {
|
||||
key: get(currentAccount, 'name')
|
||||
}
|
||||
},
|
||||
{
|
||||
key: get(currentAccount, 'name'),
|
||||
},
|
||||
);
|
||||
}, 3000);
|
||||
})
|
||||
@ -665,7 +677,6 @@ class EditorContainer extends Component<any, any> {
|
||||
const parentPermlink = post.permlink;
|
||||
const parentTags = post.json_metadata.tags;
|
||||
|
||||
|
||||
await postComment(
|
||||
currentAccount,
|
||||
pinCode,
|
||||
@ -691,11 +702,10 @@ class EditorContainer extends Component<any, any> {
|
||||
markdownBody: fields.body,
|
||||
},
|
||||
{
|
||||
parentTags: parentTags || ['ecency']
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
parentTags: parentTags || ['ecency'],
|
||||
},
|
||||
),
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
this._handleSubmitFailure(error);
|
||||
@ -705,7 +715,7 @@ class EditorContainer extends Component<any, any> {
|
||||
|
||||
_submitEdit = async (fields) => {
|
||||
const { currentAccount, pinCode, dispatch } = this.props;
|
||||
const { post, isEdit, isPostSending, thumbIndex, isReply } = this.state;
|
||||
const { post, isEdit, isPostSending, thumbUrl, isReply } = this.state;
|
||||
|
||||
if (isPostSending) {
|
||||
return;
|
||||
@ -731,7 +741,7 @@ class EditorContainer extends Component<any, any> {
|
||||
newBody = patch;
|
||||
}
|
||||
|
||||
const meta = extractMetadata(fields.body, thumbIndex);
|
||||
const meta = extractMetadata(fields.body, thumbUrl);
|
||||
|
||||
let jsonMeta = {};
|
||||
|
||||
@ -773,13 +783,13 @@ class EditorContainer extends Component<any, any> {
|
||||
author_reputation: post.author_reputation,
|
||||
total_payout: post.total_payout,
|
||||
created: post.created,
|
||||
json_metadata: jsonMeta
|
||||
json_metadata: jsonMeta,
|
||||
},
|
||||
{
|
||||
isUpdate: true
|
||||
}
|
||||
)
|
||||
)
|
||||
isUpdate: true,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -799,10 +809,7 @@ class EditorContainer extends Component<any, any> {
|
||||
) {
|
||||
//when RC is not enough, offer boosting account
|
||||
dispatch(setRcOffer(true));
|
||||
} else if (
|
||||
error &&
|
||||
error.jse_shortmsg &&
|
||||
error.jse_shortmsg.includes('wait to transact')) {
|
||||
} else if (error && error.jse_shortmsg && error.jse_shortmsg.includes('wait to transact')) {
|
||||
//when RC is not enough, offer boosting account
|
||||
dispatch(setRcOffer(true));
|
||||
} else {
|
||||
@ -840,20 +847,10 @@ class EditorContainer extends Component<any, any> {
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
_navigationBackFetchDrafts = () => {
|
||||
const { route } = this.props;
|
||||
const { isDraft } = this.state;
|
||||
|
||||
if (isDraft && route.params?.fetchPost) {
|
||||
route.params.fetchPost
|
||||
}
|
||||
};
|
||||
|
||||
_handleSubmit = (form: any) => {
|
||||
const { isReply, isEdit } = this.state;
|
||||
const { intl } = this.props;
|
||||
|
||||
|
||||
if (isReply && !isEdit) {
|
||||
this._submitReply(form.fields);
|
||||
} else if (isEdit) {
|
||||
@ -909,8 +906,6 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
_handleFormChanged = () => {
|
||||
const { isDraftSaved } = this.state;
|
||||
|
||||
@ -921,7 +916,6 @@ class EditorContainer extends Component<any, any> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_handleSchedulePress = async (datePickerValue, fields) => {
|
||||
const { currentAccount, pinCode, intl } = this.props;
|
||||
|
||||
@ -998,13 +992,12 @@ class EditorContainer extends Component<any, any> {
|
||||
),
|
||||
);
|
||||
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name))
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name));
|
||||
|
||||
setTimeout(() => {
|
||||
navigation.replace(ROUTES.SCREENS.DRAFTS,
|
||||
{
|
||||
showSchedules: true
|
||||
})
|
||||
navigation.replace(ROUTES.SCREENS.DRAFTS, {
|
||||
showSchedules: true,
|
||||
});
|
||||
}, 3000);
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -1018,10 +1011,10 @@ class EditorContainer extends Component<any, any> {
|
||||
_initialEditor = () => {
|
||||
const {
|
||||
currentAccount: { name },
|
||||
dispatch
|
||||
dispatch,
|
||||
} = this.props;
|
||||
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + name))
|
||||
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + name));
|
||||
|
||||
this.setState({
|
||||
uploadedImage: null,
|
||||
@ -1032,26 +1025,23 @@ class EditorContainer extends Component<any, any> {
|
||||
this.setState({ rewardType: value });
|
||||
};
|
||||
|
||||
|
||||
_handleShouldReblogChange = (value: boolean) => {
|
||||
this.setState({
|
||||
shouldReblog: value
|
||||
})
|
||||
}
|
||||
shouldReblog: value,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
_handleSetThumbIndex = (index: number) => {
|
||||
_handleSetThumbUrl = (url: string) => {
|
||||
this.setState({
|
||||
thumbIndex: index
|
||||
})
|
||||
}
|
||||
thumbUrl: url,
|
||||
});
|
||||
};
|
||||
|
||||
_setIsUploading = (status:boolean) => {
|
||||
_setIsUploading = (status: boolean) => {
|
||||
this.setState({
|
||||
isUploading:status
|
||||
})
|
||||
}
|
||||
|
||||
isUploading: status,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isLoggedIn, isDarkTheme, currentAccount, route } = this.props;
|
||||
@ -1072,13 +1062,13 @@ class EditorContainer extends Component<any, any> {
|
||||
community,
|
||||
sharedSnippetText,
|
||||
onLoadDraftPress,
|
||||
thumbIndex,
|
||||
thumbUrl,
|
||||
uploadProgress,
|
||||
rewardType,
|
||||
} = this.state;
|
||||
|
||||
const tags = route.params?.tags;
|
||||
const paramFiles = route.params?.files;
|
||||
const paramFiles = route.params?.files;
|
||||
return (
|
||||
<EditorScreen
|
||||
paramFiles={paramFiles}
|
||||
@ -1088,7 +1078,7 @@ class EditorContainer extends Component<any, any> {
|
||||
handleShouldReblogChange={this._handleShouldReblogChange}
|
||||
handleSchedulePress={this._handleSchedulePress}
|
||||
handleFormChanged={this._handleFormChanged}
|
||||
handleOnBackPress={() => { }}
|
||||
handleOnBackPress={() => {}}
|
||||
handleOnSubmit={this._handleSubmit}
|
||||
initialEditor={this._initialEditor}
|
||||
isDarkTheme={isDarkTheme}
|
||||
@ -1102,7 +1092,7 @@ class EditorContainer extends Component<any, any> {
|
||||
quickReplyText={quickReplyText}
|
||||
isUploading={isUploading}
|
||||
post={post}
|
||||
updateDraftFields = {this._updateDraftFields}
|
||||
updateDraftFields={this._updateDraftFields}
|
||||
saveCurrentDraft={this._saveCurrentDraft}
|
||||
saveDraftToDB={this._saveDraftToDB}
|
||||
uploadedImage={uploadedImage}
|
||||
@ -1112,8 +1102,8 @@ class EditorContainer extends Component<any, any> {
|
||||
draftId={draftId}
|
||||
sharedSnippetText={sharedSnippetText}
|
||||
onLoadDraftPress={onLoadDraftPress}
|
||||
thumbIndex={thumbIndex}
|
||||
setThumbIndex={this._handleSetThumbIndex}
|
||||
thumbUrl={thumbUrl}
|
||||
setThumbUrl={this._handleSetThumbUrl}
|
||||
uploadProgress={uploadProgress}
|
||||
rewardType={rewardType}
|
||||
getBeneficiaries={this._extractBeneficiaries}
|
||||
@ -1132,4 +1122,10 @@ const mapStateToProps = (state) => ({
|
||||
drafts: state.cache.drafts,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(EditorContainer));
|
||||
export default connect(mapStateToProps)(
|
||||
injectIntl(
|
||||
//NOTE: remove extra integration step once compoent converted to functional component
|
||||
//TOOD: inject add and update draft mutation hooks as well
|
||||
(props) => <EditorContainer {...props} queryClient={useQueryClient()} />,
|
||||
),
|
||||
);
|
||||
|
@ -143,23 +143,23 @@ class EditorScreen extends Component {
|
||||
};
|
||||
|
||||
_handleOnSaveButtonPress = () => {
|
||||
const {draftId, intl} = this.props;
|
||||
if(draftId){
|
||||
Alert.alert(
|
||||
intl.formatMessage({id:'editor.draft_save_title'}),
|
||||
"",
|
||||
[{
|
||||
text:intl.formatMessage({id:'editor.draft_update'}),
|
||||
onPress:()=>this._saveDraftToDB(),
|
||||
},{
|
||||
text:intl.formatMessage({id:'editor.draft_save_new'}),
|
||||
onPress:()=>this._saveDraftToDB(true)
|
||||
},{
|
||||
text:intl.formatMessage({id:'alert.cancel'}),
|
||||
onPress:()=>{},
|
||||
style:'cancel'
|
||||
}]
|
||||
)
|
||||
const { draftId, intl } = this.props;
|
||||
if (draftId) {
|
||||
Alert.alert(intl.formatMessage({ id: 'editor.draft_save_title' }), '', [
|
||||
{
|
||||
text: intl.formatMessage({ id: 'editor.draft_update' }),
|
||||
onPress: () => this._saveDraftToDB(),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'editor.draft_save_new' }),
|
||||
onPress: () => this._saveDraftToDB(true),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'alert.cancel' }),
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
this._saveDraftToDB();
|
||||
@ -174,7 +174,7 @@ class EditorScreen extends Component {
|
||||
|
||||
this.changeTimer = setTimeout(() => {
|
||||
// saveCurrentDraft(fields);
|
||||
updateDraftFields(fields)
|
||||
updateDraftFields(fields);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
@ -182,7 +182,7 @@ class EditorScreen extends Component {
|
||||
const { handleOnSubmit, handleSchedulePress } = this.props;
|
||||
const { fields, scheduledFor } = this.state;
|
||||
|
||||
if(scheduledFor && handleSchedulePress){
|
||||
if (scheduledFor && handleSchedulePress) {
|
||||
handleSchedulePress(scheduledFor, fields);
|
||||
return;
|
||||
}
|
||||
@ -192,29 +192,28 @@ class EditorScreen extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleOnThumbSelection = (index) => {
|
||||
const { setThumbIndex } = this.props;
|
||||
if (setThumbIndex) {
|
||||
setThumbIndex(index);
|
||||
_handleOnThumbSelection = (url: string) => {
|
||||
const { setThumbUrl } = this.props;
|
||||
if (setThumbUrl) {
|
||||
setThumbUrl(url);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_handleScheduleChange = (datetime:string|null) => {
|
||||
_handleScheduleChange = (datetime: string | null) => {
|
||||
this.setState({
|
||||
scheduledFor:datetime,
|
||||
})
|
||||
}
|
||||
scheduledFor: datetime,
|
||||
});
|
||||
};
|
||||
|
||||
_handleRewardChange = (value) => {
|
||||
const { handleRewardChange } = this.props;
|
||||
handleRewardChange(value);
|
||||
}
|
||||
};
|
||||
_handleSettingsPress = () => {
|
||||
if(this.postOptionsModalRef){
|
||||
if (this.postOptionsModalRef) {
|
||||
this.postOptionsModalRef.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_handleIsFormValid = (bodyText) => {
|
||||
const { fields } = this.state;
|
||||
@ -236,7 +235,7 @@ class EditorScreen extends Component {
|
||||
};
|
||||
|
||||
_handleFormUpdate = (componentID, content) => {
|
||||
const { handleFormChanged, thumbIndex, rewardType, getBeneficiaries } = this.props;
|
||||
const { handleFormChanged, thumbUrl, rewardType, getBeneficiaries } = this.props;
|
||||
const { fields: _fields } = this.state;
|
||||
const fields = { ..._fields };
|
||||
|
||||
@ -248,14 +247,14 @@ class EditorScreen extends Component {
|
||||
fields.tags = content;
|
||||
}
|
||||
|
||||
const meta = Object.assign({}, extractMetadata(fields.body, thumbIndex), {
|
||||
const meta = Object.assign({}, extractMetadata(fields.body, thumbUrl), {
|
||||
tags: fields.tags,
|
||||
beneficiaries: getBeneficiaries(),
|
||||
rewardType,
|
||||
});
|
||||
const jsonMeta = makeJsonMetadata(meta, fields.tags);
|
||||
fields.meta = jsonMeta;
|
||||
|
||||
|
||||
if (
|
||||
get(fields, 'body', '').trim() !== get(_fields, 'body', '').trim() ||
|
||||
get(fields, 'title', '').trim() !== get(_fields, 'title', '').trim() ||
|
||||
@ -264,7 +263,7 @@ class EditorScreen extends Component {
|
||||
) {
|
||||
console.log('jsonMeta : ', jsonMeta);
|
||||
handleFormChanged();
|
||||
|
||||
|
||||
this._saveCurrentDraft(fields);
|
||||
}
|
||||
|
||||
@ -338,7 +337,7 @@ class EditorScreen extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
_saveDraftToDB(saveAsNew?:boolean) {
|
||||
_saveDraftToDB(saveAsNew?: boolean) {
|
||||
const { saveDraftToDB } = this.props;
|
||||
const { fields } = this.state;
|
||||
|
||||
@ -381,17 +380,22 @@ class EditorScreen extends Component {
|
||||
autoFocusText,
|
||||
sharedSnippetText,
|
||||
onLoadDraftPress,
|
||||
thumbIndex,
|
||||
thumbUrl,
|
||||
uploadProgress,
|
||||
rewardType,
|
||||
setIsUploading,
|
||||
} = this.props;
|
||||
|
||||
const rightButtonText = intl.formatMessage({
|
||||
id: isEdit ? 'basic_header.update' : isReply ? 'basic_header.reply' : scheduledFor ? 'basic_header.schedule' : 'basic_header.publish',
|
||||
id: isEdit
|
||||
? 'basic_header.update'
|
||||
: isReply
|
||||
? 'basic_header.reply'
|
||||
: scheduledFor
|
||||
? 'basic_header.schedule'
|
||||
: 'basic_header.publish',
|
||||
});
|
||||
|
||||
|
||||
const _renderCommunityModal = () => {
|
||||
return (
|
||||
<Modal
|
||||
@ -484,7 +488,7 @@ class EditorScreen extends Component {
|
||||
ref={(componentRef) => (this.postOptionsModalRef = componentRef)}
|
||||
body={fields.body}
|
||||
draftId={draftId}
|
||||
thumbIndex={thumbIndex}
|
||||
thumbUrl={thumbUrl}
|
||||
isEdit={isEdit}
|
||||
isCommunityPost={selectedCommunity !== null}
|
||||
rewardType={rewardType}
|
||||
|
@ -13,7 +13,7 @@ import PostScreen from '../screen/postScreen';
|
||||
*@props --> content which is include all post data Object
|
||||
*
|
||||
*/
|
||||
const PostContainer = ({ currentAccount, isLoggedIn, isAnalytics, route }) => {
|
||||
const PostContainer = ({ currentAccount, isLoggedIn, route }) => {
|
||||
const [post, setPost] = useState(null);
|
||||
const [error, setError] = useState(null);
|
||||
const [isNewPost, setIsNewPost] = useState(false);
|
||||
@ -119,7 +119,6 @@ const PostContainer = ({ currentAccount, isLoggedIn, isAnalytics, route }) => {
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccount: state.account.currentAccount,
|
||||
isLoggedIn: state.application.isLoggedIn,
|
||||
isAnalytics: state.application.isAnalytics,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(PostContainer);
|
||||
|
@ -50,7 +50,8 @@ const RegisterScreen = ({ navigation, route }) => {
|
||||
}, []);
|
||||
|
||||
const _handleEmailChange = (value) => {
|
||||
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
const re =
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
setIsEmailValid(re.test(value));
|
||||
setEmail(value);
|
||||
};
|
||||
|
@ -39,9 +39,8 @@ const CommunitiesResultsContainer = ({ children, searchValue }) => {
|
||||
// handle cache when searchResultsScreen data updates in communities reducer
|
||||
useEffect(() => {
|
||||
if (subscribingCommunitiesInSearchResultsScreen && selectedCommunityItem) {
|
||||
const { status } = subscribingCommunitiesInSearchResultsScreen[
|
||||
selectedCommunityItem.communityId
|
||||
];
|
||||
const { status } =
|
||||
subscribingCommunitiesInSearchResultsScreen[selectedCommunityItem.communityId];
|
||||
if (status === statusMessage.SUCCESS) {
|
||||
dispatch(updateSubscribedCommunitiesCache(selectedCommunityItem));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import VersionNumber from 'react-native-version-number';
|
||||
import Config from 'react-native-config';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import messaging from '@react-native-firebase/messaging';
|
||||
import { withNavigation } from '@react-navigation/compat';
|
||||
import { languageRestart } from '../../../utils/I18nUtils';
|
||||
import THEME_OPTIONS from '../../../constants/options/theme';
|
||||
|
||||
@ -53,7 +54,6 @@ import { VALUE as CURRENCY_VALUE } from '../../../constants/options/currency';
|
||||
import { VALUE as LANGUAGE_VALUE } from '../../../constants/options/language';
|
||||
import settingsTypes from '../../../constants/settingsTypes';
|
||||
|
||||
|
||||
// Utilities
|
||||
import { sendEmail } from '../../../utils/sendEmail';
|
||||
import { encryptKey, decryptKey } from '../../../utils/crypto';
|
||||
@ -62,7 +62,6 @@ import { encryptKey, decryptKey } from '../../../utils/crypto';
|
||||
import SettingsScreen from '../screen/settingsScreen';
|
||||
import { SERVER_LIST } from '../../../constants/options/api';
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
import { withNavigation } from '@react-navigation/compat';
|
||||
|
||||
/*
|
||||
* Props Name Description Value
|
||||
@ -212,6 +211,7 @@ class SettingsContainer extends Component {
|
||||
case 'notification.vote':
|
||||
case 'notification.comment':
|
||||
case 'notification.mention':
|
||||
case 'notification.favorite':
|
||||
case 'notification.reblog':
|
||||
case 'notification.transfers':
|
||||
this._handleNotification(action, actionType);
|
||||
@ -229,12 +229,11 @@ class SettingsContainer extends Component {
|
||||
isReset: true,
|
||||
isOldPinVerified: true,
|
||||
oldPinCode: Config.DEFAULT_PIN,
|
||||
})
|
||||
|
||||
});
|
||||
} else {
|
||||
navigation.navigate(ROUTES.SCREENS.PINCODE, {
|
||||
callback: () => this._enableDefaultUnlockPin(action),
|
||||
})
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
@ -242,7 +241,7 @@ class SettingsContainer extends Component {
|
||||
navigation.navigate(ROUTES.SCREENS.PINCODE, {
|
||||
callback: () => dispatch(setIsBiometricEnabled(action)),
|
||||
});
|
||||
|
||||
|
||||
break;
|
||||
case settingsTypes.SHOW_HIDE_IMGS:
|
||||
dispatch(setHidePostsThumbnails(!isHideImages));
|
||||
@ -261,6 +260,7 @@ class SettingsContainer extends Component {
|
||||
comment: 4,
|
||||
reblog: 5,
|
||||
transfers: 6,
|
||||
favorite: 13,
|
||||
};
|
||||
const notifyTypes = [];
|
||||
|
||||
@ -301,14 +301,14 @@ class SettingsContainer extends Component {
|
||||
switch (actionType) {
|
||||
case 'reset_pin':
|
||||
navigation.navigate(ROUTES.SCREENS.PINCODE, {
|
||||
isReset:true
|
||||
})
|
||||
isReset: true,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'feedback':
|
||||
this._handleSendFeedback();
|
||||
break;
|
||||
|
||||
|
||||
case settingsTypes.DELETE_ACCOUNT:
|
||||
this._handleDeleteAccount();
|
||||
break;
|
||||
@ -433,8 +433,7 @@ class SettingsContainer extends Component {
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
}
|
||||
};
|
||||
_clearUserData = async () => {
|
||||
const { otherAccounts, dispatch } = this.props;
|
||||
|
||||
@ -474,7 +473,6 @@ class SettingsContainer extends Component {
|
||||
}, 500);
|
||||
};
|
||||
|
||||
|
||||
_enableDefaultUnlockPin = (isEnabled) => {
|
||||
const { dispatch, encUnlockPin } = this.props;
|
||||
|
||||
@ -524,6 +522,7 @@ const mapStateToProps = (state) => ({
|
||||
commentNotification: state.application.notificationDetails.commentNotification,
|
||||
followNotification: state.application.notificationDetails.followNotification,
|
||||
mentionNotification: state.application.notificationDetails.mentionNotification,
|
||||
favoriteNotification: state.application.notificationDetails.favoriteNotification,
|
||||
reblogNotification: state.application.notificationDetails.reblogNotification,
|
||||
transfersNotification: state.application.notificationDetails.transfersNotification,
|
||||
voteNotification: state.application.notificationDetails.voteNotification,
|
||||
|
@ -37,6 +37,7 @@ const SettingsScreen = ({
|
||||
commentNotification,
|
||||
followNotification,
|
||||
mentionNotification,
|
||||
favoriteNotification,
|
||||
reblogNotification,
|
||||
transfersNotification,
|
||||
voteNotification,
|
||||
@ -247,6 +248,15 @@ const SettingsScreen = ({
|
||||
isOn={mentionNotification}
|
||||
handleOnChange={handleOnChange}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
id: 'settings.notification.favorite',
|
||||
})}
|
||||
type="toggle"
|
||||
actionType="notification.favorite"
|
||||
isOn={favoriteNotification}
|
||||
handleOnChange={handleOnChange}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
id: 'settings.notification.reblog',
|
||||
|
@ -1,7 +1,6 @@
|
||||
import getSlug from 'speakingurl';
|
||||
import { diff_match_patch as diffMatchPatch } from 'diff-match-patch';
|
||||
import VersionNumber from 'react-native-version-number';
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler';
|
||||
import MimeTypes from 'mime-types';
|
||||
|
||||
export const getWordsCount = (text) =>
|
||||
@ -46,8 +45,7 @@ export const generatePermlink = (title, random = false) => {
|
||||
return perm;
|
||||
};
|
||||
|
||||
;export const extractWordAtIndex = (text:string, index:number) => {
|
||||
|
||||
export const extractWordAtIndex = (text: string, index: number) => {
|
||||
const RANGE = 50;
|
||||
|
||||
const _start = index - RANGE;
|
||||
@ -56,32 +54,30 @@ export const generatePermlink = (title, random = false) => {
|
||||
const _length = text.length;
|
||||
|
||||
const textChunk = text.substring(_start > 0 ? _start : 0, _end < _length ? _end : _length);
|
||||
const indexChunk = index < 50 ? index : (
|
||||
_length - index < 50 ? textChunk.length - (_length - index) :
|
||||
RANGE
|
||||
);
|
||||
const indexChunk =
|
||||
index < 50 ? index : _length - index < 50 ? textChunk.length - (_length - index) : RANGE;
|
||||
|
||||
console.log('char at index: ', textChunk[indexChunk]);
|
||||
|
||||
const END_REGEX = /[\s,]/
|
||||
const END_REGEX = /[\s,]/;
|
||||
let word = '';
|
||||
for(let i = indexChunk; i >= 0 && (!END_REGEX.test(textChunk[i]) || i === indexChunk); i--){
|
||||
if(textChunk[i]){
|
||||
for (let i = indexChunk; i >= 0 && (!END_REGEX.test(textChunk[i]) || i === indexChunk); i--) {
|
||||
if (textChunk[i]) {
|
||||
word += textChunk[i];
|
||||
}
|
||||
}
|
||||
word = word.split('').reverse().join('');
|
||||
|
||||
if(!END_REGEX.test(textChunk[indexChunk])){
|
||||
for(let i = indexChunk + 1; i < textChunk.length && !END_REGEX.test(textChunk[i]); i++){
|
||||
if(textChunk[i]){
|
||||
|
||||
if (!END_REGEX.test(textChunk[indexChunk])) {
|
||||
for (let i = indexChunk + 1; i < textChunk.length && !END_REGEX.test(textChunk[i]); i++) {
|
||||
if (textChunk[i]) {
|
||||
word += textChunk[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return word;
|
||||
}
|
||||
};
|
||||
|
||||
export const generateReplyPermlink = (toAuthor) => {
|
||||
if (!toAuthor) {
|
||||
@ -169,52 +165,55 @@ export const makeJsonMetadataForUpdate = (oldJson, meta, tags) => {
|
||||
return Object.assign({}, oldJson, mergedMeta, { tags });
|
||||
};
|
||||
|
||||
|
||||
const extractUrls = (body:string) => {
|
||||
const extractUrls = (body: string) => {
|
||||
const urlReg = /(\b(https?|ftp):\/\/[A-Z0-9+&@#/%?=~_|!:,.;-]*[-A-Z0-9+&@#/%=~_|])/gim;
|
||||
const mUrls = body && body.match(urlReg);
|
||||
return mUrls || [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const extractImageUrls = ({body, urls}:{body?:string, urls?:string[]}) => {
|
||||
export const extractImageUrls = ({ body, urls }: { body?: string; urls?: string[] }) => {
|
||||
const imgReg = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif|heic|webp))/gim;
|
||||
|
||||
let imgUrls = [];
|
||||
const mUrls = urls || extractUrls(body);
|
||||
|
||||
mUrls.forEach((url)=>{
|
||||
mUrls.forEach((url) => {
|
||||
const isImage = url.match(imgReg);
|
||||
if (isImage) {
|
||||
imgUrls.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return imgUrls;
|
||||
}
|
||||
};
|
||||
|
||||
export const extractFilenameFromPath = ({path, mimeType}:{path:string, mimeType?:string}) => {
|
||||
try{
|
||||
if(!path){
|
||||
throw new Error("path not provided");
|
||||
export const extractFilenameFromPath = ({
|
||||
path,
|
||||
mimeType,
|
||||
}: {
|
||||
path: string;
|
||||
mimeType?: string;
|
||||
}) => {
|
||||
try {
|
||||
if (!path) {
|
||||
throw new Error('path not provided');
|
||||
}
|
||||
const filenameIndex = path.lastIndexOf('/') + 1;
|
||||
const extensionIndex = path.lastIndexOf('.');
|
||||
if(filenameIndex < 0 || extensionIndex <= filenameIndex){
|
||||
throw new Error("file name not present with extension");
|
||||
if (filenameIndex < 0 || extensionIndex <= filenameIndex) {
|
||||
throw new Error('file name not present with extension');
|
||||
}
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
|
||||
}catch(err){
|
||||
} catch (err) {
|
||||
let _ext = 'jpg';
|
||||
if(mimeType){
|
||||
_ext = MimeTypes.extension(mimeType)
|
||||
if (mimeType) {
|
||||
_ext = MimeTypes.extension(mimeType);
|
||||
}
|
||||
return `${generateRndStr()}.${_ext}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const extractMetadata = (body:string, thumbIndex?:number) => {
|
||||
export const extractMetadata = (body: string, thumbUrl?: string) => {
|
||||
const userReg = /(^|\s)(@[a-z][-.a-z\d]+[a-z\d])/gim;
|
||||
|
||||
const out = {};
|
||||
@ -222,16 +221,16 @@ export const extractMetadata = (body:string, thumbIndex?:number) => {
|
||||
const mUrls = extractUrls(body);
|
||||
const mUsers = body && body.match(userReg);
|
||||
|
||||
const matchedImages = extractImageUrls({urls:mUrls});
|
||||
const matchedImages = extractImageUrls({ urls: mUrls });
|
||||
const matchedLinks = [];
|
||||
const matchedUsers = [];
|
||||
|
||||
if (mUrls) {
|
||||
mUrls.forEach((url)=>{
|
||||
if(matchedImages.indexOf(url) < 0){
|
||||
mUrls.forEach((url) => {
|
||||
if (matchedImages.indexOf(url) < 0) {
|
||||
matchedLinks.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (matchedLinks.length) {
|
||||
@ -239,10 +238,10 @@ export const extractMetadata = (body:string, thumbIndex?:number) => {
|
||||
}
|
||||
|
||||
if (matchedImages.length) {
|
||||
if(thumbIndex){
|
||||
matchedImages.splice(0, 0, matchedImages.splice(thumbIndex, 1)[0]);
|
||||
if (thumbUrl) {
|
||||
matchedImages.sort((item) => (item === thumbUrl ? -1 : 1));
|
||||
}
|
||||
|
||||
|
||||
out.image = matchedImages;
|
||||
}
|
||||
|
||||
@ -271,4 +270,4 @@ export const createPatch = (text1, text2) => {
|
||||
return patch;
|
||||
};
|
||||
|
||||
export const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
export const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
||||
|
@ -104,7 +104,7 @@ export const migrateUserEncryption = async (dispatch, currentAccount, encUserPin
|
||||
}
|
||||
|
||||
|
||||
try{
|
||||
try {
|
||||
const pinData = {
|
||||
pinCode: Config.DEFAULT_PIN,
|
||||
username: currentAccount.username,
|
||||
@ -112,7 +112,7 @@ export const migrateUserEncryption = async (dispatch, currentAccount, encUserPin
|
||||
};
|
||||
|
||||
const response = updatePinCode(pinData)
|
||||
|
||||
|
||||
const _currentAccount = currentAccount;
|
||||
_currentAccount.local = response;
|
||||
|
||||
@ -125,10 +125,10 @@ export const migrateUserEncryption = async (dispatch, currentAccount, encUserPin
|
||||
const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
|
||||
dispatch(setPinCode(encryptedPin));
|
||||
|
||||
} catch(err){
|
||||
} catch (err) {
|
||||
console.warn('pin update failure: ', err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
dispatch(setEncryptedUnlockPin(encUserPin))
|
||||
|
||||
@ -139,54 +139,58 @@ export const migrateUserEncryption = async (dispatch, currentAccount, encUserPin
|
||||
_currentAccount.local = realmData[0];
|
||||
|
||||
try {
|
||||
const pinHash = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
|
||||
//migration script for previously mast key based logged in user not having access token
|
||||
if (
|
||||
realmData[0].authType !== AUTH_TYPE.STEEM_CONNECT &&
|
||||
realmData[0].accessToken === ''
|
||||
) {
|
||||
_currentAccount = await migrateToMasterKeyWithAccessToken(
|
||||
_currentAccount,
|
||||
realmData[0],
|
||||
pinHash,
|
||||
);
|
||||
}
|
||||
const pinHash = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY);
|
||||
//migration script for previously mast key based logged in user not having access token
|
||||
if (
|
||||
realmData[0].authType !== AUTH_TYPE.STEEM_CONNECT &&
|
||||
realmData[0].accessToken === ''
|
||||
) {
|
||||
_currentAccount = await migrateToMasterKeyWithAccessToken(
|
||||
_currentAccount,
|
||||
realmData[0],
|
||||
pinHash,
|
||||
);
|
||||
}
|
||||
|
||||
//refresh access token
|
||||
const encryptedAccessToken = await refreshSCToken(_currentAccount.local, Config.DEFAULT_PIN);
|
||||
_currentAccount.local.accessToken = encryptedAccessToken;
|
||||
//refresh access token
|
||||
const encryptedAccessToken = await refreshSCToken(_currentAccount.local, Config.DEFAULT_PIN);
|
||||
_currentAccount.local.accessToken = encryptedAccessToken;
|
||||
} catch (error) {
|
||||
onFailure(error)
|
||||
}
|
||||
|
||||
//get unread notifications
|
||||
try {
|
||||
_currentAccount.unread_activity_count = await getUnreadNotificationCount();
|
||||
_currentAccount.pointsSummary = await getPointsSummary(_currentAccount.username);
|
||||
_currentAccount.mutes = await getMutes(_currentAccount.username);
|
||||
_currentAccount.unread_activity_count = await getUnreadNotificationCount();
|
||||
_currentAccount.pointsSummary = await getPointsSummary(_currentAccount.username);
|
||||
_currentAccount.mutes = await getMutes(_currentAccount.username);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
'Optional user data fetch failed, account can still function without them',
|
||||
err,
|
||||
);
|
||||
console.warn(
|
||||
'Optional user data fetch failed, account can still function without them',
|
||||
err,
|
||||
);
|
||||
}
|
||||
|
||||
dispatch(updateCurrentAccount({ ..._currentAccount }));
|
||||
dispatch(fetchSubscribedCommunities(_currentAccount.username));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
const reduxMigrations = {
|
||||
0: (state) => {
|
||||
const upvotePercent = state.application.upvotePercent;
|
||||
state.application.postUpvotePercent = upvotePercent;
|
||||
state.application.commentUpvotePercent = upvotePercent
|
||||
state.application.upvotePercent = undefined;
|
||||
return state
|
||||
const upvotePercent = state.application.upvotePercent;
|
||||
state.application.postUpvotePercent = upvotePercent;
|
||||
state.application.commentUpvotePercent = upvotePercent
|
||||
state.application.upvotePercent = undefined;
|
||||
return state
|
||||
},
|
||||
1: (state) => {
|
||||
state.application.notificationDetails.favoriteNotification = true
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
migrateSettings,
|
||||
|
@ -125,12 +125,9 @@ export default (url) => {
|
||||
}
|
||||
|
||||
if (
|
||||
[
|
||||
'https://ecency.com',
|
||||
'https://hive.blog',
|
||||
'https://peakd.com',
|
||||
'https://leofinance.io',
|
||||
].some((x) => url.startsWith(x))
|
||||
['https://ecency.com', 'https://hive.blog', 'https://peakd.com', 'https://leofinance.io'].some(
|
||||
(x) => url.startsWith(x),
|
||||
)
|
||||
) {
|
||||
return parseAuthorPermlink(url);
|
||||
}
|
||||
|
@ -1,21 +1,39 @@
|
||||
import get from 'lodash/get';
|
||||
import { operationOrders } from '@hiveio/dhive/lib/utils';
|
||||
import { utils } from '@hiveio/dhive';
|
||||
import parseDate from './parseDate';
|
||||
import parseToken from './parseToken';
|
||||
import { vestsToHp } from './conversions';
|
||||
import { getAccount, getAccountHistory, getConversionRequests, getFeedHistory, getOpenOrders, getSavingsWithdrawFrom } from '../providers/hive/dhive';
|
||||
import {
|
||||
fetchGlobalProps,
|
||||
getAccount,
|
||||
getAccountHistory,
|
||||
getConversionRequests,
|
||||
getFeedHistory,
|
||||
getOpenOrders,
|
||||
getSavingsWithdrawFrom,
|
||||
} from '../providers/hive/dhive';
|
||||
import { getCurrencyTokenRate, getLatestQuotes } from '../providers/ecency/ecency';
|
||||
import { CoinActivitiesCollection, CoinActivity, CoinBase, CoinData, DataPair, QuoteItem } from '../redux/reducers/walletReducer';
|
||||
import {
|
||||
CoinActivitiesCollection,
|
||||
CoinActivity,
|
||||
CoinBase,
|
||||
CoinData,
|
||||
DataPair,
|
||||
QuoteItem,
|
||||
} from '../redux/reducers/walletReducer';
|
||||
import { GlobalProps } from '../redux/reducers/accountReducer';
|
||||
import { getEstimatedAmount } from './vote';
|
||||
import { getPointsSummary, getPointsHistory } from '../providers/ecency/ePoint';
|
||||
// Constant
|
||||
import POINTS from '../constants/options/points';
|
||||
import { COIN_IDS } from '../constants/defaultCoins';
|
||||
import { operationOrders } from '@hiveio/dhive/lib/utils';
|
||||
import { ConversionRequest, OpenOrderItem, OrdersData, SavingsWithdrawRequest } from '../providers/hive/hive.types';
|
||||
import {
|
||||
ConversionRequest,
|
||||
OpenOrderItem,
|
||||
SavingsWithdrawRequest,
|
||||
} from '../providers/hive/hive.types';
|
||||
import parseAsset from './parseAsset';
|
||||
import { utils } from '@hiveio/dhive';
|
||||
|
||||
|
||||
export const transferTypes = [
|
||||
'curation_reward',
|
||||
@ -39,24 +57,16 @@ export const transferTypes = [
|
||||
'fill_vesting_withdraw',
|
||||
];
|
||||
|
||||
const ECENCY_ACTIONS = [
|
||||
'dropdown_transfer', 'dropdown_promote', 'dropdown_boost'
|
||||
];
|
||||
const ECENCY_ACTIONS = ['dropdown_transfer', 'dropdown_promote', 'dropdown_boost'];
|
||||
const HIVE_ACTIONS = [
|
||||
'transfer_token',
|
||||
'transfer_to_savings',
|
||||
'transfer_to_vesting',
|
||||
'withdraw_hive'
|
||||
];
|
||||
const HBD_ACTIONS = [
|
||||
'transfer_token',
|
||||
'transfer_to_savings',
|
||||
'convert',
|
||||
'withdraw_hbd'
|
||||
'withdraw_hive',
|
||||
];
|
||||
const HBD_ACTIONS = ['transfer_token', 'transfer_to_savings', 'convert', 'withdraw_hbd'];
|
||||
const HIVE_POWER_ACTIONS = ['delegate', 'power_down'];
|
||||
|
||||
|
||||
export const groomingTransactionData = (transaction, hivePerMVests) => {
|
||||
if (!transaction || !hivePerMVests) {
|
||||
return [];
|
||||
@ -64,7 +74,7 @@ export const groomingTransactionData = (transaction, hivePerMVests) => {
|
||||
|
||||
const result = {
|
||||
iconType: 'MaterialIcons',
|
||||
trxIndex:transaction[0]
|
||||
trxIndex: transaction[0],
|
||||
};
|
||||
|
||||
[result.textKey] = transaction[1].op;
|
||||
@ -102,8 +112,9 @@ export const groomingTransactionData = (transaction, hivePerMVests) => {
|
||||
.toFixed(3)
|
||||
.replace(',', '.');
|
||||
|
||||
result.value = `${hbdPayout > 0 ? `${hbdPayout} HBD` : ''} ${hivePayout > 0 ? `${hivePayout} HIVE` : ''
|
||||
} ${vestingPayout > 0 ? `${vestingPayout} HP` : ''}`;
|
||||
result.value = `${hbdPayout > 0 ? `${hbdPayout} HBD` : ''} ${
|
||||
hivePayout > 0 ? `${hivePayout} HIVE` : ''
|
||||
} ${vestingPayout > 0 ? `${vestingPayout} HP` : ''}`;
|
||||
|
||||
result.details = author && permlink ? `@${author}/${permlink}` : null;
|
||||
if (result.textKey === 'comment_benefactor_reward') {
|
||||
@ -117,8 +128,9 @@ export const groomingTransactionData = (transaction, hivePerMVests) => {
|
||||
rewardHive = parseToken(rewardHive).toFixed(3).replace(',', '.');
|
||||
rewardVests = vestsToHp(parseToken(rewardVests), hivePerMVests).toFixed(3).replace(',', '.');
|
||||
|
||||
result.value = `${rewardHdb > 0 ? `${rewardHdb} HBD` : ''} ${rewardHive > 0 ? `${rewardHive} HIVE` : ''
|
||||
} ${rewardVests > 0 ? `${rewardVests} HP` : ''}`;
|
||||
result.value = `${rewardHdb > 0 ? `${rewardHdb} HBD` : ''} ${
|
||||
rewardHive > 0 ? `${rewardHive} HIVE` : ''
|
||||
} ${rewardVests > 0 ? `${rewardVests} HP` : ''}`;
|
||||
break;
|
||||
case 'transfer':
|
||||
case 'transfer_to_savings':
|
||||
@ -263,7 +275,7 @@ export const groomingWalletData = async (user, globalProps, userCurrency) => {
|
||||
walletData.nextVestingWithdrawal = Math.round(timeDiff / (1000 * 3600));
|
||||
|
||||
//TOOD: transfer history can be separated from here
|
||||
const op = utils.operationOrders
|
||||
const op = utils.operationOrders;
|
||||
const ops = [
|
||||
op.transfer, //HIVE
|
||||
op.author_reward, //HBD, HP
|
||||
@ -279,7 +291,7 @@ export const groomingWalletData = async (user, globalProps, userCurrency) => {
|
||||
op.sps_fund, //HBD
|
||||
op.comment_benefactor_reward, //HP
|
||||
op.return_vesting_delegation, //HP
|
||||
]
|
||||
];
|
||||
|
||||
const history = await getAccountHistory(get(user, 'name'), ops);
|
||||
|
||||
@ -291,10 +303,10 @@ export const groomingWalletData = async (user, globalProps, userCurrency) => {
|
||||
return walletData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const fetchPendingRequests = async (username: string, coinSymbol: string): Promise<CoinActivity[]> => {
|
||||
|
||||
const fetchPendingRequests = async (
|
||||
username: string,
|
||||
coinSymbol: string,
|
||||
): Promise<CoinActivity[]> => {
|
||||
const _rawConversions = await getConversionRequests(username);
|
||||
const _rawOpenOrdres = await getOpenOrders(username);
|
||||
const _rawWithdrawRequests = await getSavingsWithdrawFrom(username);
|
||||
@ -302,66 +314,63 @@ const fetchPendingRequests = async (username: string, coinSymbol: string): Promi
|
||||
console.log('fetched pending requests', _rawConversions, _rawOpenOrdres, _rawWithdrawRequests);
|
||||
|
||||
const openOrderRequests = _rawOpenOrdres
|
||||
.filter(request => request.sell_price.base.includes(coinSymbol))
|
||||
.filter((request) => request.sell_price.base.includes(coinSymbol))
|
||||
.map((request) => {
|
||||
const { base, quote } = request?.sell_price || {};
|
||||
return ({
|
||||
iconType: "MaterialIcons",
|
||||
return {
|
||||
iconType: 'MaterialIcons',
|
||||
textKey: 'open_order',
|
||||
expires: request.expiration,
|
||||
created: request.created,
|
||||
icon: 'reorder',
|
||||
value: base || '-- --',
|
||||
details: base && quote ? `@ ${base} = ${quote}` : '',
|
||||
} as CoinActivity)
|
||||
})
|
||||
} as CoinActivity;
|
||||
});
|
||||
|
||||
const withdrawRequests = _rawWithdrawRequests
|
||||
.filter(request => request.amount.includes(coinSymbol))
|
||||
.filter((request) => request.amount.includes(coinSymbol))
|
||||
.map((request) => {
|
||||
return ({
|
||||
iconType: "MaterialIcons",
|
||||
textKey: "withdraw_savings",
|
||||
return {
|
||||
iconType: 'MaterialIcons',
|
||||
textKey: 'withdraw_savings',
|
||||
created: request.complete,
|
||||
icon: "compare-arrows",
|
||||
icon: 'compare-arrows',
|
||||
value: request.amount,
|
||||
details: request.from && request.to ? `@${request.from} to @${request.to}` : null,
|
||||
memo: request.memo || null
|
||||
} as CoinActivity)
|
||||
})
|
||||
memo: request.memo || null,
|
||||
} as CoinActivity;
|
||||
});
|
||||
|
||||
const conversionRequests = _rawConversions
|
||||
.filter(request => request.amount.includes(coinSymbol))
|
||||
.filter((request) => request.amount.includes(coinSymbol))
|
||||
.map((request) => {
|
||||
return ({
|
||||
iconType: "MaterialIcons",
|
||||
textKey: "convert_request",
|
||||
return {
|
||||
iconType: 'MaterialIcons',
|
||||
textKey: 'convert_request',
|
||||
created: request.conversion_date,
|
||||
icon: "hourglass-full",
|
||||
value: request.amount
|
||||
} as CoinActivity)
|
||||
})
|
||||
icon: 'hourglass-full',
|
||||
value: request.amount,
|
||||
} as CoinActivity;
|
||||
});
|
||||
|
||||
const pendingRequests = [
|
||||
...openOrderRequests,
|
||||
...withdrawRequests,
|
||||
...conversionRequests
|
||||
];
|
||||
const pendingRequests = [...openOrderRequests, ...withdrawRequests, ...conversionRequests];
|
||||
|
||||
pendingRequests.sort((a, b) => (
|
||||
new Date(a.expires || a.created).getTime() > new Date(b.expires || b.created).getTime() ? 1 : -1
|
||||
))
|
||||
pendingRequests.sort((a, b) =>
|
||||
new Date(a.expires || a.created).getTime() > new Date(b.expires || b.created).getTime()
|
||||
? 1
|
||||
: -1,
|
||||
);
|
||||
|
||||
return pendingRequests;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param username
|
||||
* @param coinId
|
||||
* @param coinSymbol
|
||||
* @param globalProps
|
||||
*
|
||||
* @param username
|
||||
* @param coinId
|
||||
* @param coinSymbol
|
||||
* @param globalProps
|
||||
* @returns {Promise<CoinActivitiesCollection>}
|
||||
*/
|
||||
export const fetchCoinActivities = async (
|
||||
@ -370,131 +379,109 @@ export const fetchCoinActivities = async (
|
||||
coinSymbol: string,
|
||||
globalProps: GlobalProps,
|
||||
startIndex: number,
|
||||
limit:number
|
||||
|
||||
limit: number,
|
||||
): Promise<CoinActivitiesCollection> => {
|
||||
|
||||
const op = operationOrders;
|
||||
let history = [];
|
||||
|
||||
switch (coinId) {
|
||||
case COIN_IDS.ECENCY: {
|
||||
|
||||
//TODO: remove condition when we have a way to fetch paginated points data
|
||||
if(startIndex !== -1){
|
||||
if (startIndex !== -1) {
|
||||
return {
|
||||
completed:[],
|
||||
pending:[]
|
||||
}
|
||||
completed: [],
|
||||
pending: [],
|
||||
};
|
||||
}
|
||||
|
||||
const pointActivities = await getPointsHistory(username);
|
||||
console.log("Points Activities", pointActivities);
|
||||
const completed = pointActivities && pointActivities.length ?
|
||||
pointActivities.map((item) =>
|
||||
groomingPointsTransactionData({
|
||||
...item,
|
||||
icon: get(POINTS[get(item, 'type')], 'icon'),
|
||||
iconType: get(POINTS[get(item, 'type')], 'iconType'),
|
||||
textKey: get(POINTS[get(item, 'type')], 'textKey'),
|
||||
})
|
||||
) : [];
|
||||
console.log('Points Activities', pointActivities);
|
||||
const completed =
|
||||
pointActivities && pointActivities.length
|
||||
? pointActivities.map((item) =>
|
||||
groomingPointsTransactionData({
|
||||
...item,
|
||||
icon: get(POINTS[get(item, 'type')], 'icon'),
|
||||
iconType: get(POINTS[get(item, 'type')], 'iconType'),
|
||||
textKey: get(POINTS[get(item, 'type')], 'textKey'),
|
||||
}),
|
||||
)
|
||||
: [];
|
||||
return {
|
||||
completed,
|
||||
pending: [] as CoinActivity[]
|
||||
}
|
||||
pending: [] as CoinActivity[],
|
||||
};
|
||||
}
|
||||
case COIN_IDS.HIVE:
|
||||
history = await getAccountHistory(username, [
|
||||
op.transfer, //HIVE
|
||||
op.transfer_to_vesting, //HIVE, HP
|
||||
op.withdraw_vesting, //HIVE, HP
|
||||
op.transfer_to_savings, //HIVE, HBD
|
||||
op.transfer_from_savings, //HIVE, HBD
|
||||
op.fill_order, //HIVE, HBD
|
||||
], startIndex, limit);
|
||||
history = await getAccountHistory(
|
||||
username,
|
||||
[
|
||||
op.transfer, //HIVE
|
||||
op.transfer_to_vesting, //HIVE, HP
|
||||
op.withdraw_vesting, //HIVE, HP
|
||||
op.transfer_to_savings, //HIVE, HBD
|
||||
op.transfer_from_savings, //HIVE, HBD
|
||||
op.fill_order, //HIVE, HBD
|
||||
],
|
||||
startIndex,
|
||||
limit,
|
||||
);
|
||||
break;
|
||||
case COIN_IDS.HBD:
|
||||
history = await getAccountHistory(username, [
|
||||
op.transfer, //HIVE //HBD
|
||||
op.author_reward, //HBD, HP
|
||||
op.transfer_to_savings, //HIVE, HBD
|
||||
op.transfer_from_savings, //HIVE, HBD
|
||||
op.fill_convert_request, //HBD
|
||||
op.fill_order, //HIVE, HBD
|
||||
op.sps_fund, //HBD
|
||||
], startIndex, limit);
|
||||
history = await getAccountHistory(
|
||||
username,
|
||||
[
|
||||
op.transfer, //HIVE //HBD
|
||||
op.author_reward, //HBD, HP
|
||||
op.transfer_to_savings, //HIVE, HBD
|
||||
op.transfer_from_savings, //HIVE, HBD
|
||||
op.fill_convert_request, //HBD
|
||||
op.fill_order, //HIVE, HBD
|
||||
op.sps_fund, //HBD
|
||||
],
|
||||
startIndex,
|
||||
limit,
|
||||
);
|
||||
break;
|
||||
case COIN_IDS.HP:
|
||||
history = await getAccountHistory(username, [
|
||||
op.author_reward, //HBD, HP
|
||||
op.curation_reward, //HP
|
||||
op.transfer_to_vesting, //HIVE, HP
|
||||
op.withdraw_vesting, //HIVE, HP
|
||||
op.interest, //HP
|
||||
op.claim_reward_balance, //HP
|
||||
op.comment_benefactor_reward, //HP
|
||||
op.return_vesting_delegation, //HP
|
||||
], startIndex, limit);
|
||||
history = await getAccountHistory(
|
||||
username,
|
||||
[
|
||||
op.author_reward, //HBD, HP
|
||||
op.curation_reward, //HP
|
||||
op.transfer_to_vesting, //HIVE, HP
|
||||
op.withdraw_vesting, //HIVE, HP
|
||||
op.interest, //HP
|
||||
op.claim_reward_balance, //HP
|
||||
op.comment_benefactor_reward, //HP
|
||||
op.return_vesting_delegation, //HP
|
||||
],
|
||||
startIndex,
|
||||
limit,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
const transfers = history.filter((tx) => transferTypes.includes(get(tx[1], 'op[0]', false)));
|
||||
transfers.sort(compare);
|
||||
|
||||
const activities = transfers.map(item => groomingTransactionData(item, globalProps.hivePerMVests));
|
||||
const activities = transfers.map((item) =>
|
||||
groomingTransactionData(item, globalProps.hivePerMVests),
|
||||
);
|
||||
const filterdActivities: CoinActivity[] = activities
|
||||
? activities.filter((item) => {
|
||||
return (
|
||||
item &&
|
||||
item.value &&
|
||||
item.value.includes(coinSymbol)
|
||||
);
|
||||
})
|
||||
return item && item.value && item.value.includes(coinSymbol);
|
||||
})
|
||||
: [];
|
||||
|
||||
console.log('FILTERED comap', activities.length, filterdActivities.length)
|
||||
console.log('FILTERED comap', activities.length, filterdActivities.length);
|
||||
|
||||
const pendingRequests = await fetchPendingRequests(username, coinSymbol);
|
||||
return {
|
||||
completed: filterdActivities,
|
||||
pending: pendingRequests,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const calculateConvertingAmount = (requests: ConversionRequest[]): number => {
|
||||
if (!requests || !requests.length) {
|
||||
return 0;
|
||||
}
|
||||
//TODO: add method body
|
||||
// ecency-vision -> src/common/components/wallet-hive/index.tsx#fetchConvertingAmount
|
||||
throw new Error("calculateConvertingAmount method body not implemented yet");
|
||||
}
|
||||
|
||||
const calculateSavingsWithdrawalAmount = (requests: SavingsWithdrawRequest[], coinSymbol: string): number => {
|
||||
return requests.reduce((prevVal, curRequest) => {
|
||||
const _amount = curRequest.amount;
|
||||
return _amount.includes(coinSymbol)
|
||||
? prevVal + parseAsset(_amount).amount
|
||||
: prevVal
|
||||
}, 0);
|
||||
}
|
||||
|
||||
const calculateOpenOrdersAmount = (requests: OpenOrderItem[], coinSymbol: string): number => {
|
||||
return requests.reduce((prevVal, curRequest) => {
|
||||
const _basePrice = curRequest.sell_price.base;
|
||||
return _basePrice.includes(coinSymbol)
|
||||
? prevVal + parseAsset(_basePrice).amount
|
||||
: prevVal
|
||||
}, 0);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
export const fetchCoinsData = async ({
|
||||
coins,
|
||||
@ -505,36 +492,32 @@ export const fetchCoinsData = async ({
|
||||
refresh,
|
||||
quotes,
|
||||
}: {
|
||||
coins: CoinBase[],
|
||||
currentAccount: any,
|
||||
vsCurrency: string,
|
||||
currencyRate: number,
|
||||
globalProps: GlobalProps,
|
||||
quotes: { [key: string]: QuoteItem }
|
||||
refresh: boolean,
|
||||
})
|
||||
: Promise<{ [key: string]: CoinData }> => {
|
||||
|
||||
coins: CoinBase[];
|
||||
currentAccount: any;
|
||||
vsCurrency: string;
|
||||
currencyRate: number;
|
||||
globalProps: GlobalProps;
|
||||
quotes: { [key: string]: QuoteItem };
|
||||
refresh: boolean;
|
||||
}): Promise<{ [key: string]: CoinData }> => {
|
||||
const username = currentAccount.username;
|
||||
const { base, quote, hivePerMVests } = globalProps
|
||||
|
||||
const coinData = {} as { [key: string]: CoinData };
|
||||
const walletData = {} as any;
|
||||
|
||||
|
||||
if (!username) {
|
||||
return walletData;
|
||||
}
|
||||
|
||||
//fetch latest global props if refresh or data not available
|
||||
const { base, quote, hivePerMVests } =
|
||||
refresh || !globalProps || !globalProps.hivePerMVests ? await fetchGlobalProps() : globalProps;
|
||||
//TODO: Use already available accoutn for frist wallet start
|
||||
const userdata = refresh ? await getAccount(username) : currentAccount;
|
||||
const _pointsSummary = refresh ? await getPointsSummary(username) : currentAccount.pointsSummary
|
||||
const _pointsSummary = refresh ? await getPointsSummary(username) : currentAccount.pointsSummary;
|
||||
//TODO: cache data in redux or fetch once on wallet startup
|
||||
const _prices = !refresh && quotes ? quotes : await getLatestQuotes(currencyRate); //TODO: figure out a way to handle other currencies
|
||||
|
||||
|
||||
coins.forEach((coinBase) => {
|
||||
|
||||
switch (coinBase.id) {
|
||||
case COIN_IDS.ECENCY: {
|
||||
const balance = _pointsSummary.points ? parseFloat(_pointsSummary.points) : 0;
|
||||
@ -549,7 +532,7 @@ export const fetchCoinsData = async ({
|
||||
currentPrice: ppEstm,
|
||||
unclaimedBalance: unclaimedBalance,
|
||||
actions: ECENCY_ACTIONS,
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case COIN_IDS.HIVE: {
|
||||
@ -557,7 +540,6 @@ export const fetchCoinsData = async ({
|
||||
const savings = parseToken(userdata.savings_balance);
|
||||
const ppHive = _prices[coinBase.id].price;
|
||||
|
||||
|
||||
coinData[coinBase.id] = {
|
||||
balance: Math.round(balance * 1000) / 1000,
|
||||
estimateValue: (balance + savings) * ppHive,
|
||||
@ -566,7 +548,7 @@ export const fetchCoinsData = async ({
|
||||
currentPrice: ppHive,
|
||||
unclaimedBalance: '',
|
||||
actions: HIVE_ACTIONS,
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
@ -583,33 +565,27 @@ export const fetchCoinsData = async ({
|
||||
currentPrice: ppHbd,
|
||||
unclaimedBalance: '',
|
||||
actions: HBD_ACTIONS,
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case COIN_IDS.HP: {
|
||||
const _getBalanceStr = (val: number, cur: string) => (val ? Math.round(val * 1000) / 1000 + cur : '');
|
||||
const balance = Math.round(
|
||||
vestsToHp(parseToken(userdata.vesting_shares), hivePerMVests) * 1000,
|
||||
) / 1000;
|
||||
const _getBalanceStr = (val: number, cur: string) =>
|
||||
val ? Math.round(val * 1000) / 1000 + cur : '';
|
||||
const balance =
|
||||
Math.round(vestsToHp(parseToken(userdata.vesting_shares), hivePerMVests) * 1000) / 1000;
|
||||
|
||||
const receivedHP = vestsToHp(
|
||||
parseToken(userdata.received_vesting_shares),
|
||||
hivePerMVests,
|
||||
)
|
||||
const receivedHP = vestsToHp(parseToken(userdata.received_vesting_shares), hivePerMVests);
|
||||
|
||||
const delegatedHP = vestsToHp(
|
||||
parseToken(userdata.delegated_vesting_shares),
|
||||
hivePerMVests,
|
||||
)
|
||||
const delegatedHP = vestsToHp(parseToken(userdata.delegated_vesting_shares), hivePerMVests);
|
||||
|
||||
//agggregate claim button text
|
||||
const unclaimedBalance = [
|
||||
_getBalanceStr(parseToken(userdata.reward_hive_balance), ' HIVE'),
|
||||
_getBalanceStr(parseToken(userdata.reward_hbd_balance), ' HBD'),
|
||||
_getBalanceStr(parseToken(userdata.reward_vesting_hive), ' HP')
|
||||
_getBalanceStr(parseToken(userdata.reward_vesting_hive), ' HP'),
|
||||
].reduce(
|
||||
(prevVal, bal) => prevVal + (!bal ? '' : (`${prevVal !== '' ? ' ' : ''}${bal}`)),
|
||||
''
|
||||
(prevVal, bal) => prevVal + (!bal ? '' : `${prevVal !== '' ? ' ' : ''}${bal}`),
|
||||
'',
|
||||
);
|
||||
|
||||
//calculate power down
|
||||
@ -619,49 +595,57 @@ export const fetchCoinsData = async ({
|
||||
|
||||
const nextVestingSharesWithdrawal = isPoweringDown
|
||||
? Math.min(
|
||||
parseAsset(userdata.vesting_withdraw_rate).amount,
|
||||
(Number(userdata.to_withdraw) - Number(userdata.withdrawn)) / 1e6
|
||||
) : 0;
|
||||
const nextVestingSharesWithdrawalHive = isPoweringDown ? vestsToHp(nextVestingSharesWithdrawal, hivePerMVests) : 0;
|
||||
parseAsset(userdata.vesting_withdraw_rate).amount,
|
||||
(Number(userdata.to_withdraw) - Number(userdata.withdrawn)) / 1e6,
|
||||
)
|
||||
: 0;
|
||||
const nextVestingSharesWithdrawalHive = isPoweringDown
|
||||
? vestsToHp(nextVestingSharesWithdrawal, hivePerMVests)
|
||||
: 0;
|
||||
|
||||
const estimateVoteValueStr = '$ ' + getEstimatedAmount(userdata, globalProps);
|
||||
|
||||
//aaggregate extra data pairs
|
||||
const extraDataPairs:DataPair[] = [];
|
||||
const extraDataPairs: DataPair[] = [];
|
||||
|
||||
if (delegatedHP) {
|
||||
extraDataPairs.push({
|
||||
dataKey: 'delegated_hive_power',
|
||||
value: `- ${delegatedHP.toFixed(3)} HP`,
|
||||
isClickable: true
|
||||
})
|
||||
isClickable: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (receivedHP) {
|
||||
extraDataPairs.push({
|
||||
dataKey: 'received_hive_power',
|
||||
value: `+ ${receivedHP.toFixed(3)} HP`,
|
||||
isClickable: true
|
||||
})
|
||||
isClickable: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (nextVestingSharesWithdrawalHive) {
|
||||
extraDataPairs.push({
|
||||
dataKey: 'powering_down_hive_power',
|
||||
value: `- ${nextVestingSharesWithdrawalHive.toFixed(3)} HP`
|
||||
})
|
||||
value: `- ${nextVestingSharesWithdrawalHive.toFixed(3)} HP`,
|
||||
});
|
||||
}
|
||||
|
||||
extraDataPairs.concat([
|
||||
{
|
||||
dataKey: 'total_hive_power',
|
||||
value: `${(balance - delegatedHP + receivedHP - nextVestingSharesWithdrawalHive).toFixed(3)} HP`
|
||||
}, {
|
||||
value: `${(
|
||||
balance -
|
||||
delegatedHP +
|
||||
receivedHP -
|
||||
nextVestingSharesWithdrawalHive
|
||||
).toFixed(3)} HP`,
|
||||
},
|
||||
{
|
||||
dataKey: 'vote_value',
|
||||
value: estimateVoteValueStr
|
||||
}
|
||||
])
|
||||
|
||||
value: estimateVoteValueStr,
|
||||
},
|
||||
]);
|
||||
|
||||
const ppHive = _prices[COIN_IDS.HIVE].price;
|
||||
coinData[coinBase.id] = {
|
||||
@ -672,22 +656,29 @@ export const fetchCoinsData = async ({
|
||||
currentPrice: ppHive,
|
||||
actions: HIVE_POWER_ACTIONS,
|
||||
extraDataPairs: [
|
||||
...extraDataPairs, {
|
||||
...extraDataPairs,
|
||||
{
|
||||
dataKey: 'total_hive_power',
|
||||
value: `${(balance - delegatedHP + receivedHP - nextVestingSharesWithdrawalHive).toFixed(3)} HP`
|
||||
}, {
|
||||
value: `${(
|
||||
balance -
|
||||
delegatedHP +
|
||||
receivedHP -
|
||||
nextVestingSharesWithdrawalHive
|
||||
).toFixed(3)} HP`,
|
||||
},
|
||||
{
|
||||
dataKey: 'vote_value',
|
||||
value: estimateVoteValueStr
|
||||
}
|
||||
]
|
||||
}
|
||||
value: estimateVoteValueStr,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
//TODO:discard unnessacry data processings towards the end of PR
|
||||
walletData.rewardHiveBalance = parseToken(userdata.reward_hive_balance);
|
||||
@ -709,8 +700,6 @@ export const fetchCoinsData = async ({
|
||||
walletData.savingBalance = parseToken(userdata.savings_balance);
|
||||
walletData.savingBalanceHbd = parseToken(userdata.savings_hbd_balance);
|
||||
|
||||
|
||||
|
||||
walletData.hivePerMVests = hivePerMVests;
|
||||
const pricePerHive = base / quote;
|
||||
|
||||
@ -723,15 +712,12 @@ export const fetchCoinsData = async ({
|
||||
|
||||
walletData.estimatedValue = totalHive * pricePerHive + totalHbd;
|
||||
|
||||
|
||||
|
||||
walletData.showPowerDown = userdata.next_vesting_withdrawal !== '1969-12-31T23:59:59';
|
||||
const timeDiff = Math.abs(parseDate(userdata.next_vesting_withdrawal) - new Date());
|
||||
walletData.nextVestingWithdrawal = Math.round(timeDiff / (1000 * 3600));
|
||||
|
||||
|
||||
return coinData;
|
||||
}
|
||||
};
|
||||
|
||||
function compare(a, b) {
|
||||
if (a[1].block < b[1].block) {
|
||||
|
35
yarn.lock
35
yarn.lock
@ -1846,6 +1846,31 @@
|
||||
dependencies:
|
||||
type-detect "4.0.8"
|
||||
|
||||
"@tanstack/query-async-storage-persister@^4.3.9":
|
||||
version "4.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-4.3.9.tgz#d9954a19f41450152daf4a84c357284b36391a8a"
|
||||
integrity sha512-Xn6UbUfXIpSdEMYnhgY22eYPPzNBfAGiN8WYQV/UD7lJ0iPtcX93576QON/gsqQl0oN1mwO8k38Eg1ZW+kwacA==
|
||||
dependencies:
|
||||
"@tanstack/react-query-persist-client" "4.3.9"
|
||||
|
||||
"@tanstack/query-core@4.3.8":
|
||||
version "4.3.8"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.3.8.tgz#d5f07c1d9d4f83f16f0bed7f3b245fa0e557b037"
|
||||
integrity sha512-AEUWtCNBIImFZ9tMt/P8V86kIhMHpfoJqAI1auGOLR8Wzeq7Ymiue789PJG0rKYcyViUicBZeHjggMqyEQVMfQ==
|
||||
|
||||
"@tanstack/react-query-persist-client@4.3.9", "@tanstack/react-query-persist-client@^4.3.9":
|
||||
version "4.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-4.3.9.tgz#246acb070b8083078b6cdbf813bd6dfa2f6596e3"
|
||||
integrity sha512-oFZA8bo6BQHoQqJSHXTtIDaIAxbF46cQHwhF72FwiMvBhm6eEbySUIPhGAWah7Jys2t2RJIhJ1T+q9P0RRIjwg==
|
||||
|
||||
"@tanstack/react-query@^4.3.9":
|
||||
version "4.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.3.9.tgz#13332a1d4dd404baec24c2853883bcb3cc61ea92"
|
||||
integrity sha512-odfDW6WiSntCsCh+HFeJtUys3UnVOjfJMhykAtGtYvcklMyyDmCv9BVBt5KlSpbk/qW3kURPFCDapO+BFUlCwg==
|
||||
dependencies:
|
||||
"@tanstack/query-core" "4.3.8"
|
||||
use-sync-external-store "^1.2.0"
|
||||
|
||||
"@tradle/react-native-http@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@tradle/react-native-http/-/react-native-http-2.0.1.tgz#af19e240e1e580bfa249563924d1be472686f48b"
|
||||
@ -8901,11 +8926,6 @@ react-native-image-pan-zoom@^2.1.9:
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz#eb98bf56fb5610379bdbfdb63219cc1baca98fd2"
|
||||
integrity sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==
|
||||
|
||||
react-native-image-size@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-size/-/react-native-image-size-1.1.3.tgz#7d69c2cd4e1d1632947867e47643ed8cabb9de27"
|
||||
integrity sha512-jJvN6CjXVAm69LAVZNV7m7r50Qk9vuPZwLyrbs/k31/3Xs8bZyVCdvfP44FuBisITn/yFsiOo6i8NPrFBPH20w==
|
||||
|
||||
react-native-image-zoom-viewer@^2.2.27:
|
||||
version "2.2.27"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-2.2.27.tgz#fb3314c5dc86ac33da48cb31bf4920d97eecb6eb"
|
||||
@ -10965,6 +10985,11 @@ use-subscription@^1.0.0:
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
|
||||
use-sync-external-store@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
use@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
|
Loading…
Reference in New Issue
Block a user