mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-22 04:41:43 +03:00
Merge branch 'development' of https://github.com/ecency/ecency-mobile into sa/IAP-QR
This commit is contained in:
commit
aaad438287
@ -1,15 +1,12 @@
|
|||||||
import React, { useState, Fragment, useRef } from 'react';
|
import React, { useState, Fragment, useRef } from 'react';
|
||||||
import { View, Text, ActivityIndicator, SafeAreaView } from 'react-native';
|
import { View, Text, ActivityIndicator, SafeAreaView } from 'react-native';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { TextButton, Modal, BeneficiaryModal } from '../..';
|
import { TextButton } from '../..';
|
||||||
import { IconButton } from '../../iconButton';
|
import { IconButton } from '../../iconButton';
|
||||||
import { DropdownButton } from '../../dropdownButton';
|
import { DropdownButton } from '../../dropdownButton';
|
||||||
import { TextInput } from '../../textInput';
|
import { TextInput } from '../../textInput';
|
||||||
import { DateTimePicker } from '../../dateTimePicker';
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
// Styles
|
// Styles
|
||||||
@ -28,7 +25,6 @@ const BasicHeaderView = ({
|
|||||||
intl,
|
intl,
|
||||||
isDraftSaved,
|
isDraftSaved,
|
||||||
isDraftSaving,
|
isDraftSaving,
|
||||||
draftId,
|
|
||||||
isFormValid,
|
isFormValid,
|
||||||
isHasDropdown,
|
isHasDropdown,
|
||||||
isHasIcons,
|
isHasIcons,
|
||||||
@ -46,23 +42,14 @@ const BasicHeaderView = ({
|
|||||||
title,
|
title,
|
||||||
handleOnSubmit,
|
handleOnSubmit,
|
||||||
handleOnSearch,
|
handleOnSearch,
|
||||||
handleDatePickerChange,
|
|
||||||
handleRewardChange,
|
handleRewardChange,
|
||||||
handleBeneficiaries,
|
|
||||||
enableViewModeToggle,
|
enableViewModeToggle,
|
||||||
handleSettingsPress,
|
handleSettingsPress,
|
||||||
showThumbSelectionModal,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [isInputVisible, setIsInputVisible] = useState(false);
|
const [isInputVisible, setIsInputVisible] = useState(false);
|
||||||
const [beneficiaryModal, setBeneficiaryModal] = useState(false);
|
|
||||||
const [showScheduleModal, setShowScheduleModal] = useState(false);
|
|
||||||
const [scheduledDate, setScheduledDate] = useState('');
|
|
||||||
|
|
||||||
const username = useSelector((state) => state.account.currentAccount.name);
|
|
||||||
|
|
||||||
const settingMenuRef = useRef(null);
|
|
||||||
const rewardMenuRef = useRef(null);
|
const rewardMenuRef = useRef(null);
|
||||||
const scheduleRef = useRef(null);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -90,27 +77,6 @@ const BasicHeaderView = ({
|
|||||||
handleOnSearch(value);
|
handleOnSearch(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const _handleSettingMenuSelect = (index) => {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
setShowScheduleModal(true);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (showThumbSelectionModal) {
|
|
||||||
showThumbSelectionModal();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rewardMenuRef.current.show();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
setBeneficiaryModal(true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const _handleRewardMenuSelect = (index) => {
|
const _handleRewardMenuSelect = (index) => {
|
||||||
let rewardType = 'default';
|
let rewardType = 'default';
|
||||||
@ -131,32 +97,7 @@ const BasicHeaderView = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _handleOnSaveBeneficiaries = (beneficiaries) => {
|
|
||||||
const _beneficiaries = beneficiaries.map((item) => ({
|
|
||||||
account: item.account,
|
|
||||||
weight: item.weight,
|
|
||||||
}));
|
|
||||||
setBeneficiaryModal(false);
|
|
||||||
if (handleBeneficiaries) {
|
|
||||||
handleBeneficiaries(_beneficiaries);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const _handleDatePickerChange = (datePickerValue) => {
|
|
||||||
setScheduledDate(datePickerValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const _onPressDone = () => {
|
|
||||||
let dateString = scheduledDate;
|
|
||||||
|
|
||||||
if (dateString === '') {
|
|
||||||
dateString = moment().format();
|
|
||||||
}
|
|
||||||
|
|
||||||
setScheduledDate('');
|
|
||||||
handleDatePickerChange(dateString);
|
|
||||||
setShowScheduleModal(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -291,57 +232,8 @@ const BasicHeaderView = ({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<Modal
|
|
||||||
isOpen={beneficiaryModal}
|
|
||||||
isFullScreen
|
|
||||||
isCloseButton
|
|
||||||
presentationStyle="formSheet"
|
|
||||||
handleOnModalClose={() => setBeneficiaryModal(false)}
|
|
||||||
title={intl.formatMessage({ id: 'editor.beneficiaries' })}
|
|
||||||
animationType="slide"
|
|
||||||
style={styles.beneficiaryModal}
|
|
||||||
>
|
|
||||||
<BeneficiaryModal
|
|
||||||
username={username}
|
|
||||||
handleOnSaveBeneficiaries={_handleOnSaveBeneficiaries}
|
|
||||||
draftId={draftId}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
<Modal
|
|
||||||
isFullScreen={false}
|
|
||||||
isOpen={showScheduleModal}
|
|
||||||
isBottomModal
|
|
||||||
isTransparent
|
|
||||||
isRadius
|
|
||||||
coverScreen={false}
|
|
||||||
title={intl.formatMessage({ id: 'editor.schedule_modal_title' })}
|
|
||||||
hasRightText
|
|
||||||
rightText="Done"
|
|
||||||
onPressRightText={_onPressDone}
|
|
||||||
onBackdropPress={() => setShowScheduleModal(false)}
|
|
||||||
>
|
|
||||||
<SafeAreaView style={styles.dateTimeModal}>
|
|
||||||
<DateTimePicker
|
|
||||||
type="datetime"
|
|
||||||
onChanged={_handleDatePickerChange}
|
|
||||||
disabled={!isFormValid}
|
|
||||||
ref={scheduleRef}
|
|
||||||
/>
|
|
||||||
</SafeAreaView>
|
|
||||||
</Modal>
|
|
||||||
<OptionsModal
|
|
||||||
ref={settingMenuRef}
|
|
||||||
options={[
|
|
||||||
intl.formatMessage({ id: 'editor.setting_schedule' }),
|
|
||||||
intl.formatMessage({ id: 'editor.setting_thumb' }),
|
|
||||||
intl.formatMessage({ id: 'editor.setting_reward' }),
|
|
||||||
intl.formatMessage({ id: 'editor.setting_beneficiary' }),
|
|
||||||
intl.formatMessage({ id: 'alert.cancel' }),
|
|
||||||
]}
|
|
||||||
cancelButtonIndex={4}
|
|
||||||
title={intl.formatMessage({ id: 'editor.options' })}
|
|
||||||
onPress={_handleSettingMenuSelect}
|
|
||||||
/>
|
|
||||||
<OptionsModal
|
<OptionsModal
|
||||||
ref={rewardMenuRef}
|
ref={rewardMenuRef}
|
||||||
options={[
|
options={[
|
||||||
@ -354,6 +246,7 @@ const BasicHeaderView = ({
|
|||||||
title="Reward"
|
title="Reward"
|
||||||
onPress={_handleRewardMenuSelect}
|
onPress={_handleRewardMenuSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -53,9 +53,13 @@ import { walkthrough } from '../../../redux/constants/walkthroughConstants';
|
|||||||
|
|
||||||
const MIN_BODY_INPUT_HEIGHT = 300;
|
const MIN_BODY_INPUT_HEIGHT = 300;
|
||||||
|
|
||||||
|
//These variable keep track of body text input state,
|
||||||
|
//this helps keep load on minimal compared to both useState and useRef;
|
||||||
|
var bodyText = '';
|
||||||
|
var bodySelection = {start: 0, end: 0};
|
||||||
|
|
||||||
const MarkdownEditorView = ({
|
const MarkdownEditorView = ({
|
||||||
draftBody,
|
draftBody,
|
||||||
handleIsFormValid,
|
|
||||||
handleOpenImagePicker,
|
handleOpenImagePicker,
|
||||||
intl,
|
intl,
|
||||||
isPreviewActive,
|
isPreviewActive,
|
||||||
@ -64,9 +68,6 @@ const MarkdownEditorView = ({
|
|||||||
isUploading,
|
isUploading,
|
||||||
initialFields,
|
initialFields,
|
||||||
onChange,
|
onChange,
|
||||||
handleOnTextChange,
|
|
||||||
handleIsValid,
|
|
||||||
componentID,
|
|
||||||
uploadedImage,
|
uploadedImage,
|
||||||
isEdit,
|
isEdit,
|
||||||
post,
|
post,
|
||||||
@ -82,8 +83,6 @@ const MarkdownEditorView = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [text, setText] = useState(draftBody || '');
|
|
||||||
const [selection, setSelection] = useState({ start: 0, end: 0 });
|
|
||||||
const [editable, setEditable] = useState(true);
|
const [editable, setEditable] = useState(true);
|
||||||
const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT);
|
const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT);
|
||||||
const [isSnippetsOpen, setIsSnippetsOpen] = useState(false);
|
const [isSnippetsOpen, setIsSnippetsOpen] = useState(false);
|
||||||
@ -103,9 +102,14 @@ const MarkdownEditorView = ({
|
|||||||
const draftBtnTooltipRegistered = draftBtnTooltipState.get(walkthrough.EDITOR_DRAFT_BTN);
|
const draftBtnTooltipRegistered = draftBtnTooltipState.get(walkthrough.EDITOR_DRAFT_BTN);
|
||||||
const headerText = post && (post.summary || postBodySummary(post, 150, Platform.OS));
|
const headerText = post && (post.summary || postBodySummary(post, 150, Platform.OS));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
bodyText = '';
|
||||||
|
bodySelection = {start:0, end:0};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPreviewActive) {
|
if (!isPreviewActive) {
|
||||||
_setTextAndSelection({ selection: { start: 0, end: 0 }, text });
|
_setTextAndSelection({ selection: { start: 0, end: 0 }, text: bodyText });
|
||||||
}
|
}
|
||||||
}, [isPreviewActive]);
|
}, [isPreviewActive]);
|
||||||
|
|
||||||
@ -121,7 +125,7 @@ const MarkdownEditorView = ({
|
|||||||
}, [onLoadDraftPress]);
|
}, [onLoadDraftPress]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (text === '' && draftBody !== '') {
|
if (bodyText === '' && draftBody !== '') {
|
||||||
let draftBodyLength = draftBody.length;
|
let draftBodyLength = draftBody.length;
|
||||||
_setTextAndSelection({
|
_setTextAndSelection({
|
||||||
selection: { start: draftBodyLength, end: draftBodyLength },
|
selection: { start: draftBodyLength, end: draftBodyLength },
|
||||||
@ -165,8 +169,8 @@ const MarkdownEditorView = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (uploadedImage && uploadedImage.shouldInsert && !isUploading) {
|
if (uploadedImage && uploadedImage.shouldInsert && !isUploading) {
|
||||||
applyMediaLink({
|
applyMediaLink({
|
||||||
text,
|
text: bodyText,
|
||||||
selection,
|
selection: bodySelection,
|
||||||
setTextAndSelection: _setTextAndSelection,
|
setTextAndSelection: _setTextAndSelection,
|
||||||
items: [{ url: uploadedImage.url, text: uploadedImage.hash }],
|
items: [{ url: uploadedImage.url, text: uploadedImage.hash }],
|
||||||
});
|
});
|
||||||
@ -178,7 +182,7 @@ const MarkdownEditorView = ({
|
|||||||
}, [uploadedImage, isUploading]);
|
}, [uploadedImage, isUploading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setText(draftBody);
|
bodyText = draftBody;
|
||||||
}, [draftBody]);
|
}, [draftBody]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -190,17 +194,7 @@ const MarkdownEditorView = ({
|
|||||||
}
|
}
|
||||||
}, [autoFocusText]);
|
}, [autoFocusText]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const nextText = text.replace(text, '');
|
|
||||||
|
|
||||||
if (nextText && nextText.length > 0) {
|
|
||||||
_changeText(text);
|
|
||||||
|
|
||||||
if (handleIsFormValid) {
|
|
||||||
handleIsFormValid(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [text]);
|
|
||||||
|
|
||||||
const changeUser = async () => {
|
const changeUser = async () => {
|
||||||
dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet));
|
dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet));
|
||||||
@ -208,8 +202,8 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
const _onApplyUsername = (username) => {
|
const _onApplyUsername = (username) => {
|
||||||
applyUsername({
|
applyUsername({
|
||||||
text,
|
text: bodyText,
|
||||||
selection,
|
selection: bodySelection,
|
||||||
setTextAndSelection: _setTextAndSelection,
|
setTextAndSelection: _setTextAndSelection,
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
@ -217,23 +211,17 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const _changeText = useCallback((input) => {
|
const _changeText = useCallback((input) => {
|
||||||
setText(input);
|
bodyText = input;
|
||||||
|
|
||||||
|
//NOTE: onChange method is called by direct parent of MarkdownEditor that is PostForm, do not remove
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(input);
|
onChange(input);
|
||||||
}
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (handleIsValid) {
|
|
||||||
handleIsValid(componentID, !!(input && input.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handleOnTextChange) {
|
|
||||||
handleOnTextChange(input);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const _handleOnSelectionChange = async (event) => {
|
const _handleOnSelectionChange = async (event) => {
|
||||||
setSelection(event.nativeEvent.selection);
|
bodySelection = event.nativeEvent.selection;
|
||||||
};
|
};
|
||||||
|
|
||||||
const _handleOnContentSizeChange = async (event) => {
|
const _handleOnContentSizeChange = async (event) => {
|
||||||
@ -243,35 +231,38 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const _setTextAndSelection = useCallback(({ selection: _selection, text: _text }) => {
|
const _setTextAndSelection = useCallback(({ selection: _selection, text: _text }) => {
|
||||||
console.log('_text : ', _text);
|
// console.log('_text : ', _text);
|
||||||
inputRef.current.setNativeProps({
|
inputRef.current.setNativeProps({
|
||||||
text: _text,
|
text: _text,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Workaround for iOS selection update issue
|
const _updateSelection = () => {
|
||||||
const isIos = Platform.OS === 'ios';
|
bodySelection = _selection
|
||||||
if (isIos) {
|
|
||||||
setTimeout(() => {
|
|
||||||
inputRef.current.setNativeProps({
|
|
||||||
selection: _selection,
|
|
||||||
});
|
|
||||||
setSelection(_selection);
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
inputRef.current.setNativeProps({
|
inputRef.current.setNativeProps({
|
||||||
selection: _selection,
|
selection: _selection,
|
||||||
});
|
});
|
||||||
setSelection(_selection);
|
|
||||||
}
|
}
|
||||||
setIsSnippetsOpen(false);
|
|
||||||
_changeText(_text);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('text : ', text);
|
// Workaround for iOS selection update issue
|
||||||
|
if (Platform.OS === 'ios') {
|
||||||
|
setTimeout(() => {
|
||||||
|
_updateSelection();
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
_updateSelection()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSnippetsOpen) {
|
||||||
|
setIsSnippetsOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_changeText(_text);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const _renderPreview = () => (
|
const _renderPreview = () => (
|
||||||
<ScrollView style={styles.previewContainer}>
|
<ScrollView style={styles.previewContainer}>
|
||||||
{text ? (
|
{bodyText ? (
|
||||||
<PostBody body={renderPostBody(text, true, Platform.OS === 'ios' ? false : true)} />
|
<PostBody body={renderPostBody(bodyText, true, Platform.OS === 'ios' ? false : true)} />
|
||||||
) : (
|
) : (
|
||||||
<Text>...</Text>
|
<Text>...</Text>
|
||||||
)}
|
)}
|
||||||
@ -280,8 +271,8 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
const _handleOnSnippetReceived = (snippetText) => {
|
const _handleOnSnippetReceived = (snippetText) => {
|
||||||
applySnippet({
|
applySnippet({
|
||||||
text,
|
text: bodyText,
|
||||||
selection,
|
selection: bodySelection,
|
||||||
setTextAndSelection: _setTextAndSelection,
|
setTextAndSelection: _setTextAndSelection,
|
||||||
snippetText: `\n${snippetText}\n`,
|
snippetText: `\n${snippetText}\n`,
|
||||||
});
|
});
|
||||||
@ -295,8 +286,8 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
if (items.length) {
|
if (items.length) {
|
||||||
applyMediaLink({
|
applyMediaLink({
|
||||||
text,
|
text: bodyText,
|
||||||
selection,
|
selection: bodySelection,
|
||||||
setTextAndSelection: _setTextAndSelection,
|
setTextAndSelection: _setTextAndSelection,
|
||||||
items,
|
items,
|
||||||
});
|
});
|
||||||
@ -305,8 +296,8 @@ const MarkdownEditorView = ({
|
|||||||
|
|
||||||
const _handleOnAddLinkPress = () => {
|
const _handleOnAddLinkPress = () => {
|
||||||
insertLinkModalRef.current?.showModal({
|
insertLinkModalRef.current?.showModal({
|
||||||
selectedText: text.slice(selection.start, selection.end),
|
selectedText: bodyText.slice(bodySelection.start, bodySelection.end),
|
||||||
selection: selection,
|
selection: bodySelection,
|
||||||
});
|
});
|
||||||
inputRef.current?.blur();
|
inputRef.current?.blur();
|
||||||
};
|
};
|
||||||
@ -315,7 +306,7 @@ const MarkdownEditorView = ({
|
|||||||
};
|
};
|
||||||
const _handleInsertLink = ({ snippetText, selection }) => {
|
const _handleInsertLink = ({ snippetText, selection }) => {
|
||||||
applySnippet({
|
applySnippet({
|
||||||
text,
|
text: bodyText,
|
||||||
selection,
|
selection,
|
||||||
setTextAndSelection: _setTextAndSelection,
|
setTextAndSelection: _setTextAndSelection,
|
||||||
snippetText,
|
snippetText,
|
||||||
@ -332,7 +323,12 @@ const MarkdownEditorView = ({
|
|||||||
iconType={item.iconType}
|
iconType={item.iconType}
|
||||||
name={item.icon}
|
name={item.icon}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
item.onPress({ text, selection, setTextAndSelection: _setTextAndSelection, item })
|
item.onPress({
|
||||||
|
text: bodyText,
|
||||||
|
selection: bodySelection,
|
||||||
|
setTextAndSelection: _setTextAndSelection,
|
||||||
|
item
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -427,7 +423,7 @@ const MarkdownEditorView = ({
|
|||||||
const _handleClear = (index) => {
|
const _handleClear = (index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
initialFields();
|
initialFields();
|
||||||
setText('');
|
|
||||||
_setTextAndSelection({ text: '', selection: { start: 0, end: 0 } });
|
_setTextAndSelection({ text: '', selection: { start: 0, end: 0 } });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -513,7 +509,7 @@ const MarkdownEditorView = ({
|
|||||||
const _innerContent = (
|
const _innerContent = (
|
||||||
<>
|
<>
|
||||||
{isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()}
|
{isAndroidOreo() ? _renderEditorWithoutScroll() : _renderEditorWithScroll()}
|
||||||
<UsernameAutofillBar text={text} selection={selection} onApplyUsername={_onApplyUsername} />
|
<UsernameAutofillBar text={bodyText} selection={bodySelection} onApplyUsername={_onApplyUsername} />
|
||||||
{_renderFloatingDraftButton()}
|
{_renderFloatingDraftButton()}
|
||||||
{!isPreviewActive && _renderEditorButtons()}
|
{!isPreviewActive && _renderEditorButtons()}
|
||||||
</>
|
</>
|
@ -1,4 +1,4 @@
|
|||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect, useCallback} from 'react';
|
||||||
import { View, FlatList, Text, TouchableOpacity } from "react-native"
|
import { View, FlatList, Text, TouchableOpacity } from "react-native"
|
||||||
import { UserAvatar } from '../..';
|
import { UserAvatar } from '../..';
|
||||||
import { lookupAccounts } from '../../../providers/hive/dhive';
|
import { lookupAccounts } from '../../../providers/hive/dhive';
|
||||||
@ -22,21 +22,25 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) =>
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selection.start === selection.end && text) {
|
if (selection.start === selection.end && text) {
|
||||||
const word = extractWordAtIndex(text, selection.start);
|
_processTextForSearch(text, selection.start);
|
||||||
console.log('selection word is: ', word);
|
|
||||||
if (word.startsWith('@') && word.length > 3) {
|
|
||||||
_handleUserSearch(word.substring(1));
|
|
||||||
} else {
|
|
||||||
setSearchedUsers([]);
|
|
||||||
setQuery('')
|
|
||||||
_handleUserSearch.cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [text, selection])
|
}, [text, selection])
|
||||||
|
|
||||||
|
|
||||||
|
const _processTextForSearch = useCallback(debounce((text:string, index:number) => {
|
||||||
|
const word = extractWordAtIndex(text, index);
|
||||||
|
console.log('selection word is: ', word);
|
||||||
|
if (word.startsWith('@') && word.length > 1) {
|
||||||
|
_handleUserSearch(word.substring(1));
|
||||||
|
} else {
|
||||||
|
setSearchedUsers([]);
|
||||||
|
setQuery('')
|
||||||
|
_handleUserSearch.cancel();
|
||||||
|
}
|
||||||
|
}, 300, {leading:true}),[]);
|
||||||
|
|
||||||
const _handleUserSearch = debounce(async (username) => {
|
|
||||||
|
const _handleUserSearch = useCallback(debounce(async (username) => {
|
||||||
if(query !== username){
|
if(query !== username){
|
||||||
let users = [];
|
let users = [];
|
||||||
if (username) {
|
if (username) {
|
||||||
@ -47,7 +51,7 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) =>
|
|||||||
setSearchedUsers(users);
|
setSearchedUsers(users);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, 200, {leading:true});
|
}, 200, {leading:true}), []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { PureComponent, Fragment } from 'react';
|
import React, { PureComponent, Fragment } from 'react';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
class PostFormView extends PureComponent {
|
class PostFormView extends PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -18,9 +19,12 @@ class PostFormView extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleOnChange = (componentID, value, isValid = null) => {
|
_handleOnChange = (componentID, value, isValid = null) => {
|
||||||
const { handleFormUpdate } = this.props;
|
const { handleFormUpdate, handleBodyChange } = this.props;
|
||||||
|
console.log('update fields state :', componentID, value);
|
||||||
handleFormUpdate(componentID, value, !!isValid || !!value);
|
handleFormUpdate(componentID, value, !!isValid || !!value);
|
||||||
|
if (componentID === 'body') {
|
||||||
|
handleBodyChange(value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -33,7 +37,10 @@ class PostFormView extends PureComponent {
|
|||||||
return React.cloneElement(child, {
|
return React.cloneElement(child, {
|
||||||
onSubmitEditing: (item) =>
|
onSubmitEditing: (item) =>
|
||||||
this._handleOnSubmitEditing(child.props.returnKeyType, item),
|
this._handleOnSubmitEditing(child.props.returnKeyType, item),
|
||||||
onChange: (value) => this._handleOnChange(child.props.componentID, value),
|
onChange: debounce(
|
||||||
|
(value) => this._handleOnChange(child.props.componentID, value),
|
||||||
|
500,
|
||||||
|
),
|
||||||
returnKeyType: isFormValid ? 'done' : 'next',
|
returnKeyType: isFormValid ? 'done' : 'next',
|
||||||
isPreviewActive,
|
isPreviewActive,
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
import styles from './quickReplyModalStyles';
|
import styles from './quickReplyModalStyles';
|
||||||
import { View, Text, Alert, TouchableOpacity, Keyboard, Platform } from 'react-native';
|
import { View, Text, Alert, TouchableOpacity, Keyboard, Platform } from 'react-native';
|
||||||
@ -14,11 +14,12 @@ import {
|
|||||||
updateDraftCache,
|
updateDraftCache,
|
||||||
} from '../../redux/actions/cacheActions';
|
} from '../../redux/actions/cacheActions';
|
||||||
import { default as ROUTES } from '../../constants/routeNames';
|
import { default as ROUTES } from '../../constants/routeNames';
|
||||||
import get from 'lodash/get';
|
import {get, debounce} from 'lodash';
|
||||||
import { navigate } from '../../navigation/service';
|
import { navigate } from '../../navigation/service';
|
||||||
import { postBodySummary } from '@ecency/render-helper';
|
import { postBodySummary } from '@ecency/render-helper';
|
||||||
import { Draft } from '../../redux/reducers/cacheReducer';
|
import { Draft } from '../../redux/reducers/cacheReducer';
|
||||||
import { RootState } from '../../redux/store/store';
|
import { RootState } from '../../redux/store/store';
|
||||||
|
import comment from '../../constants/options/comment';
|
||||||
|
|
||||||
export interface QuickReplyModalContentProps {
|
export interface QuickReplyModalContentProps {
|
||||||
fetchPost?: any;
|
fetchPost?: any;
|
||||||
@ -43,7 +44,7 @@ export const QuickReplyModalContent = ({
|
|||||||
|
|
||||||
const [commentValue, setCommentValue] = useState('');
|
const [commentValue, setCommentValue] = useState('');
|
||||||
const [isSending, setIsSending] = useState(false);
|
const [isSending, setIsSending] = useState(false);
|
||||||
const [quickCommentDraft, setQuickCommentDraft] = useState<Draft>(null);
|
|
||||||
|
|
||||||
const headerText =
|
const headerText =
|
||||||
selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any));
|
selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any));
|
||||||
@ -60,7 +61,6 @@ export const QuickReplyModalContent = ({
|
|||||||
if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) {
|
if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) {
|
||||||
const quickComment: Draft = drafts.get(draftId);
|
const quickComment: Draft = drafts.get(draftId);
|
||||||
setCommentValue(quickComment.body);
|
setCommentValue(quickComment.body);
|
||||||
setQuickCommentDraft(quickComment);
|
|
||||||
} else {
|
} else {
|
||||||
setCommentValue('');
|
setCommentValue('');
|
||||||
}
|
}
|
||||||
@ -73,25 +73,24 @@ export const QuickReplyModalContent = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// add quick comment value into cache
|
// add quick comment value into cache
|
||||||
const _addQuickCommentIntoCache = () => {
|
const _addQuickCommentIntoCache = (value = commentValue) => {
|
||||||
const date = new Date();
|
|
||||||
const updatedStamp = date.toISOString().substring(0, 19);
|
|
||||||
|
|
||||||
const quickCommentDraftData: Draft = {
|
const quickCommentDraftData: Draft = {
|
||||||
author: currentAccount.name,
|
author: currentAccount.name,
|
||||||
body: commentValue,
|
body: value
|
||||||
created: quickCommentDraft ? quickCommentDraft.created : updatedStamp,
|
|
||||||
updated: updatedStamp,
|
|
||||||
expiresAt: date.getTime() + 604800000, // 7 days expiry time
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//add quick comment cache entry
|
//add quick comment cache entry
|
||||||
dispatch(updateDraftCache(draftId, quickCommentDraftData));
|
dispatch(updateDraftCache(draftId, quickCommentDraftData));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// handle close press
|
// handle close press
|
||||||
const _handleClosePress = () => {
|
const _handleClosePress = () => {
|
||||||
sheetModalRef.current?.setModalVisible(false);
|
sheetModalRef.current?.setModalVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// navigate to post on summary press
|
// navigate to post on summary press
|
||||||
const _handleOnSummaryPress = () => {
|
const _handleOnSummaryPress = () => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
@ -105,6 +104,7 @@ export const QuickReplyModalContent = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// handle submit reply
|
// handle submit reply
|
||||||
const _submitReply = async () => {
|
const _submitReply = async () => {
|
||||||
let stateTimer;
|
let stateTimer;
|
||||||
@ -207,12 +207,22 @@ export const QuickReplyModalContent = ({
|
|||||||
params: {
|
params: {
|
||||||
isReply: true,
|
isReply: true,
|
||||||
post: selectedPost,
|
post: selectedPost,
|
||||||
quickReplyText: commentValue,
|
|
||||||
fetchPost,
|
fetchPost,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500),[])
|
||||||
|
|
||||||
|
const _onChangeText = (value) => {
|
||||||
|
setCommentValue(value);
|
||||||
|
_deboucedCacheUpdate(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//VIEW_RENDERERS
|
//VIEW_RENDERERS
|
||||||
|
|
||||||
const _renderSheetHeader = () => (
|
const _renderSheetHeader = () => (
|
||||||
@ -284,9 +294,7 @@ export const QuickReplyModalContent = ({
|
|||||||
<View style={styles.inputContainer}>
|
<View style={styles.inputContainer}>
|
||||||
<TextInput
|
<TextInput
|
||||||
innerRef={inputRef}
|
innerRef={inputRef}
|
||||||
onChangeText={(value) => {
|
onChangeText={_onChangeText}
|
||||||
setCommentValue(value);
|
|
||||||
}}
|
|
||||||
value={commentValue}
|
value={commentValue}
|
||||||
// autoFocus
|
// autoFocus
|
||||||
placeholder={intl.formatMessage({
|
placeholder={intl.formatMessage({
|
||||||
|
@ -69,6 +69,7 @@ export const UploadsGalleryModal = forwardRef(({
|
|||||||
}, [uploadedImage])
|
}, [uploadedImage])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//save image to user gallery
|
//save image to user gallery
|
||||||
const _addUploadedImageToGallery = async () => {
|
const _addUploadedImageToGallery = async () => {
|
||||||
try {
|
try {
|
||||||
@ -138,6 +139,8 @@ export const UploadsGalleryModal = forwardRef(({
|
|||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//renders footer with add snipept button and shows new snippet modal
|
//renders footer with add snipept button and shows new snippet modal
|
||||||
const _renderFloatingPanel = () => {
|
const _renderFloatingPanel = () => {
|
||||||
|
|
||||||
@ -242,7 +245,7 @@ export const UploadsGalleryModal = forwardRef(({
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const _renderHeaderContent = (
|
const _renderHeaderContent = () => (
|
||||||
<>
|
<>
|
||||||
{isUploading && <ProgressBar progress={uploadProgress} />}
|
{isUploading && <ProgressBar progress={uploadProgress} />}
|
||||||
</>
|
</>
|
||||||
@ -251,30 +254,33 @@ export const UploadsGalleryModal = forwardRef(({
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const _renderContent = (
|
const _renderContent = () => {
|
||||||
<View style={styles.container}>
|
console.log("Rendering uploaded images")
|
||||||
<View style={styles.bodyWrapper}>
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.bodyWrapper}>
|
||||||
|
|
||||||
{_renderHeaderContent}
|
{_renderHeaderContent()}
|
||||||
<FlatList
|
<FlatList
|
||||||
data={mediaUploads}
|
data={mediaUploads}
|
||||||
keyExtractor={(item) => `item_${item.url}`}
|
keyExtractor={(item) => `item_${item.url}`}
|
||||||
renderItem={_renderItem}
|
renderItem={_renderItem}
|
||||||
ListEmptyComponent={_renderEmptyContent}
|
ListEmptyComponent={_renderEmptyContent}
|
||||||
ListFooterComponent={<View style={styles.listEmptyFooter} />}
|
ListFooterComponent={<View style={styles.listEmptyFooter} />}
|
||||||
extraData={indices}
|
extraData={indices}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
<RefreshControl
|
<RefreshControl
|
||||||
refreshing={isLoading}
|
refreshing={isLoading}
|
||||||
onRefresh={_getMediaUploads}
|
onRefresh={_getMediaUploads}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
|
{_renderFloatingPanel()}
|
||||||
</View>
|
</View>
|
||||||
{_renderFloatingPanel()}
|
)
|
||||||
</View>
|
}
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -290,7 +296,7 @@ export const UploadsGalleryModal = forwardRef(({
|
|||||||
animationType="slide"
|
animationType="slide"
|
||||||
style={styles.modalStyle}
|
style={styles.modalStyle}
|
||||||
>
|
>
|
||||||
{_renderContent}
|
{showModal && _renderContent()}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -2,93 +2,92 @@ import { renderPostBody } from '@ecency/render-helper';
|
|||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import { makeJsonMetadataReply } from '../../utils/editor';
|
import { makeJsonMetadataReply } from '../../utils/editor';
|
||||||
import {
|
import {
|
||||||
UPDATE_VOTE_CACHE,
|
UPDATE_VOTE_CACHE,
|
||||||
PURGE_EXPIRED_CACHE,
|
PURGE_EXPIRED_CACHE,
|
||||||
UPDATE_COMMENT_CACHE,
|
UPDATE_COMMENT_CACHE,
|
||||||
DELETE_COMMENT_CACHE_ENTRY,
|
DELETE_COMMENT_CACHE_ENTRY,
|
||||||
UPDATE_DRAFT_CACHE,
|
UPDATE_DRAFT_CACHE,
|
||||||
DELETE_DRAFT_CACHE_ENTRY,
|
DELETE_DRAFT_CACHE_ENTRY,
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
import { Comment, Draft, Vote } from '../reducers/cacheReducer';
|
import { Comment, Draft, Vote } from '../reducers/cacheReducer';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const updateVoteCache = (postPath:string, vote:Vote) => ({
|
export const updateVoteCache = (postPath: string, vote: Vote) => ({
|
||||||
payload:{
|
payload: {
|
||||||
postPath,
|
postPath,
|
||||||
vote
|
vote
|
||||||
},
|
},
|
||||||
type: UPDATE_VOTE_CACHE
|
type: UPDATE_VOTE_CACHE
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
interface CommentCacheOptions {
|
interface CommentCacheOptions {
|
||||||
isUpdate?:boolean;
|
isUpdate?: boolean;
|
||||||
parentTags?:Array<string>;
|
parentTags?: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateCommentCache = (commentPath:string, comment:Comment, options:CommentCacheOptions = {isUpdate:false}) => {
|
export const updateCommentCache = (commentPath: string, comment: Comment, options: CommentCacheOptions = { isUpdate: false }) => {
|
||||||
|
|
||||||
console.log("body received:", comment.markdownBody);
|
console.log("body received:", comment.markdownBody);
|
||||||
const updated = new Date();
|
const updated = new Date();
|
||||||
updated.setSeconds(updated.getSeconds() - 5); //make cache delayed by 5 seconds to avoid same updated stamp in post data
|
updated.setSeconds(updated.getSeconds() - 5); //make cache delayed by 5 seconds to avoid same updated stamp in post data
|
||||||
const updatedStamp = updated.toISOString().substring(0, 19); //server only return 19 character time string without timezone part
|
const updatedStamp = updated.toISOString().substring(0, 19); //server only return 19 character time string without timezone part
|
||||||
|
|
||||||
if(options.isUpdate && !comment.created){
|
if (options.isUpdate && !comment.created) {
|
||||||
throw new Error("For comment update, created prop must be provided from original comment data to update local cache");
|
throw new Error("For comment update, created prop must be provided from original comment data to update local cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!options.parentTags && !comment.json_metadata){
|
if (!options.parentTags && !comment.json_metadata) {
|
||||||
throw new Error("either of json_metadata in comment data or parentTags in options must be provided");
|
throw new Error("either of json_metadata in comment data or parentTags in options must be provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
comment.created = comment.created || updatedStamp; //created will be set only once for new comment;
|
comment.created = comment.created || updatedStamp; //created will be set only once for new comment;
|
||||||
comment.updated = comment.updated || updatedStamp;
|
comment.updated = comment.updated || updatedStamp;
|
||||||
comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000;//600000;
|
comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000;//600000;
|
||||||
comment.active_votes = comment.active_votes || [];
|
comment.active_votes = comment.active_votes || [];
|
||||||
comment.net_rshares = comment.net_rshares || 0;
|
comment.net_rshares = comment.net_rshares || 0;
|
||||||
comment.author_reputation = comment.author_reputation || 25;
|
comment.author_reputation = comment.author_reputation || 25;
|
||||||
comment.total_payout = comment.total_payout || 0;
|
comment.total_payout = comment.total_payout || 0;
|
||||||
comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags)
|
comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags)
|
||||||
comment.isDeletable = comment.isDeletable || true;
|
comment.isDeletable = comment.isDeletable || true;
|
||||||
|
|
||||||
comment.body = renderPostBody({
|
comment.body = renderPostBody({
|
||||||
author:comment.author,
|
author: comment.author,
|
||||||
permlink:comment.permlink,
|
permlink: comment.permlink,
|
||||||
last_update:comment.updated,
|
last_update: comment.updated,
|
||||||
body:comment.markdownBody,
|
body: comment.markdownBody,
|
||||||
}, true, Platform.OS === 'android');
|
}, true, Platform.OS === 'android');
|
||||||
|
|
||||||
return ({
|
return ({
|
||||||
payload:{
|
payload: {
|
||||||
commentPath,
|
commentPath,
|
||||||
comment
|
comment
|
||||||
},
|
|
||||||
type: UPDATE_COMMENT_CACHE
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteCommentCacheEntry = (commentPath:string) => ({
|
|
||||||
payload:commentPath,
|
|
||||||
type: DELETE_COMMENT_CACHE_ENTRY
|
|
||||||
})
|
|
||||||
|
|
||||||
export const updateDraftCache = (id:string, draft:Draft) => ({
|
|
||||||
payload:{
|
|
||||||
id,
|
|
||||||
draft
|
|
||||||
},
|
},
|
||||||
type: UPDATE_DRAFT_CACHE
|
type: UPDATE_COMMENT_CACHE
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const deleteDraftCacheEntry = (id:string) => ({
|
export const deleteCommentCacheEntry = (commentPath: string) => ({
|
||||||
payload:id,
|
payload: commentPath,
|
||||||
type: DELETE_DRAFT_CACHE_ENTRY
|
type: DELETE_COMMENT_CACHE_ENTRY
|
||||||
})
|
})
|
||||||
|
|
||||||
export const purgeExpiredCache = () => ({
|
export const updateDraftCache = (id: string, draft: Draft) => ({
|
||||||
type: PURGE_EXPIRED_CACHE
|
payload: {
|
||||||
})
|
id,
|
||||||
|
draft
|
||||||
|
},
|
||||||
|
type: UPDATE_DRAFT_CACHE
|
||||||
|
})
|
||||||
|
|
||||||
|
export const deleteDraftCacheEntry = (id: string) => ({
|
||||||
|
payload: id,
|
||||||
|
type: DELETE_DRAFT_CACHE_ENTRY
|
||||||
|
})
|
||||||
|
|
||||||
|
export const purgeExpiredCache = () => ({
|
||||||
|
type: PURGE_EXPIRED_CACHE
|
||||||
|
})
|
||||||
|
|
@ -113,6 +113,7 @@ export const UPDATE_COMMENT_CACHE = 'UPDATE_COMMENT_CACHE';
|
|||||||
export const DELETE_COMMENT_CACHE_ENTRY = 'DELETE_COMMENT_CACHE_ENTRY';
|
export const DELETE_COMMENT_CACHE_ENTRY = 'DELETE_COMMENT_CACHE_ENTRY';
|
||||||
export const UPDATE_DRAFT_CACHE = 'UPDATE_DRAFT_CACHE';
|
export const UPDATE_DRAFT_CACHE = 'UPDATE_DRAFT_CACHE';
|
||||||
export const DELETE_DRAFT_CACHE_ENTRY = 'DELETE_DRAFT_CACHE_ENTRY';
|
export const DELETE_DRAFT_CACHE_ENTRY = 'DELETE_DRAFT_CACHE_ENTRY';
|
||||||
|
export const DEFAULT_USER_DRAFT_ID = 'DEFAULT_USER_DRAFT_ID_';
|
||||||
|
|
||||||
// TOOLTIPS
|
// TOOLTIPS
|
||||||
export const REGISTER_TOOLTIP = 'REGISTER_TOOLTIP';
|
export const REGISTER_TOOLTIP = 'REGISTER_TOOLTIP';
|
||||||
|
@ -28,10 +28,12 @@ export interface Comment {
|
|||||||
|
|
||||||
export interface Draft {
|
export interface Draft {
|
||||||
author: string,
|
author: string,
|
||||||
body?:string,
|
body:string,
|
||||||
created?:string,
|
title?:string,
|
||||||
updated?:string,
|
tags?:string,
|
||||||
expiresAt:number;
|
created?:number,
|
||||||
|
updated?:number,
|
||||||
|
expiresAt?:number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -93,7 +95,16 @@ const initialState:State = {
|
|||||||
if(!state.drafts){
|
if(!state.drafts){
|
||||||
state.drafts = new Map<string, Draft>();
|
state.drafts = new Map<string, Draft>();
|
||||||
}
|
}
|
||||||
state.drafts.set(payload.id, payload.draft);
|
|
||||||
|
const curTime = new Date().getTime();
|
||||||
|
const curDraft = state.drafts.get(payload.id);
|
||||||
|
const payloadDraft = payload.draft;
|
||||||
|
|
||||||
|
payloadDraft.created = curDraft ? curDraft.created : curTime;
|
||||||
|
payloadDraft.updated = curTime;
|
||||||
|
payloadDraft.expiresAt = curTime + 604800000 // 7 days ms
|
||||||
|
|
||||||
|
state.drafts.set(payload.id, payloadDraft);
|
||||||
return {
|
return {
|
||||||
...state, //spread operator in requried here, otherwise persist do not register change
|
...state, //spread operator in requried here, otherwise persist do not register change
|
||||||
lastUpdate: {
|
lastUpdate: {
|
||||||
|
@ -114,7 +114,7 @@ const PostOptionsModal = forwardRef(({
|
|||||||
handleThumbSelection(index)
|
handleThumbSelection(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
const _renderContent = (
|
const _renderContent = () => (
|
||||||
<View style={styles.fillSpace}>
|
<View style={styles.fillSpace}>
|
||||||
<KeyboardAwareScrollView style={styles.fillSpace} >
|
<KeyboardAwareScrollView style={styles.fillSpace} >
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
@ -214,7 +214,7 @@ const PostOptionsModal = forwardRef(({
|
|||||||
animationType="slide"
|
animationType="slide"
|
||||||
style={styles.modalStyle}
|
style={styles.modalStyle}
|
||||||
>
|
>
|
||||||
{_renderContent}
|
{_renderContent()}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import { Alert, Platform } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
import ImagePicker from 'react-native-image-crop-picker';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
@ -25,7 +25,6 @@ import {
|
|||||||
reblog,
|
reblog,
|
||||||
postComment,
|
postComment,
|
||||||
} from '../../../providers/hive/dhive';
|
} from '../../../providers/hive/dhive';
|
||||||
import { setDraftPost, getDraftPost } from '../../../realm/realm';
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { default as ROUTES } from '../../../constants/routeNames';
|
import { default as ROUTES } from '../../../constants/routeNames';
|
||||||
@ -45,8 +44,8 @@ import {
|
|||||||
import EditorScreen from '../screen/editorScreen';
|
import EditorScreen from '../screen/editorScreen';
|
||||||
import bugsnapInstance from '../../../config/bugsnag';
|
import bugsnapInstance from '../../../config/bugsnag';
|
||||||
import { removeBeneficiaries, setBeneficiaries } from '../../../redux/actions/editorActions';
|
import { removeBeneficiaries, setBeneficiaries } from '../../../redux/actions/editorActions';
|
||||||
import { TEMP_BENEFICIARIES_ID } from '../../../redux/constants/constants';
|
import { DEFAULT_USER_DRAFT_ID, TEMP_BENEFICIARIES_ID } from '../../../redux/constants/constants';
|
||||||
import { updateCommentCache } from '../../../redux/actions/cacheActions';
|
import { deleteDraftCacheEntry, updateCommentCache, updateDraftCache } from '../../../redux/actions/cacheActions';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Props Name Description Value
|
* Props Name Description Value
|
||||||
@ -90,7 +89,7 @@ class EditorContainer extends Component<any, any> {
|
|||||||
const { currentAccount, navigation } = this.props;
|
const { currentAccount, navigation } = this.props;
|
||||||
const username = currentAccount && currentAccount.name ? currentAccount.name : '';
|
const username = currentAccount && currentAccount.name ? currentAccount.name : '';
|
||||||
let isReply;
|
let isReply;
|
||||||
let quickReplyText;
|
let draftId;
|
||||||
let isEdit;
|
let isEdit;
|
||||||
let post;
|
let post;
|
||||||
let _draft;
|
let _draft;
|
||||||
@ -133,12 +132,19 @@ class EditorContainer extends Component<any, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (navigationParams.isReply) {
|
if (navigationParams.isReply) {
|
||||||
({ isReply, quickReplyText } = navigationParams);
|
({ isReply } = navigationParams);
|
||||||
|
if(post){
|
||||||
|
draftId = `${currentAccount.name}/${post.author}/${post.permlink}`
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isReply,
|
isReply,
|
||||||
quickReplyText,
|
draftId,
|
||||||
autoFocusText: true,
|
autoFocusText: true,
|
||||||
});
|
});
|
||||||
|
if (draftId) {
|
||||||
|
this._getStorageDraft(username, isReply, { _id: draftId });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (navigationParams.isEdit) {
|
if (navigationParams.isEdit) {
|
||||||
@ -158,7 +164,7 @@ class EditorContainer extends Component<any, any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEdit && !_draft && !hasSharedIntent) {
|
if (!isEdit && !_draft && !draftId && !hasSharedIntent) {
|
||||||
this._fetchDraftsForComparison(isReply);
|
this._fetchDraftsForComparison(isReply);
|
||||||
}
|
}
|
||||||
this._requestKeyboardFocus();
|
this._requestKeyboardFocus();
|
||||||
@ -194,49 +200,54 @@ class EditorContainer extends Component<any, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getStorageDraft = async (username, isReply, paramDraft) => {
|
_getStorageDraft = async (username, isReply, paramDraft) => {
|
||||||
if (isReply) {
|
const { drafts } = this.props;
|
||||||
const draftReply = await AsyncStorage.getItem('temp-reply');
|
|
||||||
|
|
||||||
if (draftReply) {
|
if (isReply) {
|
||||||
|
const _draft = drafts.get(paramDraft._id);
|
||||||
|
if (_draft && _draft.body) {
|
||||||
this.setState({
|
this.setState({
|
||||||
draftPost: {
|
draftPost: {
|
||||||
body: draftReply,
|
body: _draft.body,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getDraftPost(username, paramDraft && paramDraft._id).then((result) => {
|
//TOOD: get draft from redux after reply side is complete
|
||||||
//if result is return and param draft available, compare timestamp, use latest
|
const _draftId = paramDraft ? paramDraft._id : DEFAULT_USER_DRAFT_ID + username;
|
||||||
//if no draft, use result anayways
|
const _localDraft = drafts.get(_draftId);
|
||||||
if (result && (!paramDraft || paramDraft.timestamp < result.timestamp)) {
|
|
||||||
this.setState({
|
|
||||||
draftPost: {
|
|
||||||
body: get(result, 'body', ''),
|
|
||||||
title: get(result, 'title', ''),
|
|
||||||
tags: get(result, 'tags', '').split(','),
|
|
||||||
isDraft: paramDraft ? true : false,
|
|
||||||
draftId: paramDraft ? paramDraft._id : null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//if above fails with either no result returned or timestamp is old,
|
//if _draft is returned and param draft is available, compare timestamp, use latest
|
||||||
// and use draft form nav param if available.
|
//if no draft, use result anayways
|
||||||
else if (paramDraft) {
|
|
||||||
const _tags = paramDraft.tags.includes(' ')
|
if (_localDraft && (!paramDraft || paramDraft.timestamp < _localDraft.updated)) {
|
||||||
? paramDraft.tags.split(' ')
|
this.setState({
|
||||||
: paramDraft.tags.split(',');
|
draftPost: {
|
||||||
this.setState({
|
body: get(_localDraft, 'body', ''),
|
||||||
draftPost: {
|
title: get(_localDraft, 'title', ''),
|
||||||
title: paramDraft.title,
|
tags: get(_localDraft, 'tags', '').split(','),
|
||||||
body: paramDraft.body,
|
isDraft: paramDraft ? true : false,
|
||||||
tags: _tags,
|
draftId: paramDraft ? paramDraft._id : null,
|
||||||
},
|
},
|
||||||
isDraft: true,
|
});
|
||||||
draftId: paramDraft._id,
|
}
|
||||||
});
|
|
||||||
}
|
//if above fails with either no result returned or timestamp is old,
|
||||||
});
|
// and use draft form nav param if available.
|
||||||
|
else if (paramDraft) {
|
||||||
|
const _tags = paramDraft.tags.includes(' ')
|
||||||
|
? paramDraft.tags.split(' ')
|
||||||
|
: paramDraft.tags.split(',');
|
||||||
|
this.setState({
|
||||||
|
draftPost: {
|
||||||
|
title: paramDraft.title,
|
||||||
|
body: paramDraft.body,
|
||||||
|
tags: _tags,
|
||||||
|
},
|
||||||
|
isDraft: true,
|
||||||
|
draftId: paramDraft._id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -251,14 +262,14 @@ class EditorContainer extends Component<any, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this fucntion is run if editor is access used mid tab or reply section
|
* this fucntion is run if editor is access fused mid tab or reply section
|
||||||
* it fetches fresh drafts and run some comparions to load one of following
|
* it fetches fresh drafts and run some comparions to load one of following
|
||||||
* empty editor, load non-remote draft or most recent remote draft based on timestamps
|
* empty editor, load non-remote draft or most recent remote draft based on timestamps
|
||||||
* prompts user as well
|
* prompts user as well
|
||||||
* @param isReply
|
* @param isReply
|
||||||
**/
|
**/
|
||||||
_fetchDraftsForComparison = async (isReply) => {
|
_fetchDraftsForComparison = async (isReply) => {
|
||||||
const { currentAccount, isLoggedIn, intl, dispatch } = this.props;
|
const { currentAccount, isLoggedIn, intl, dispatch, drafts } = this.props;
|
||||||
const username = get(currentAccount, 'name', '');
|
const username = get(currentAccount, 'name', '');
|
||||||
|
|
||||||
//initilizes editor with reply or non remote id less draft
|
//initilizes editor with reply or non remote id less draft
|
||||||
@ -282,28 +293,29 @@ class EditorContainer extends Component<any, any> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const drafts = await getDrafts(username);
|
const remoteDrafts = await getDrafts(username);
|
||||||
const idLessDraft = await getDraftPost(username);
|
|
||||||
|
const idLessDraft = drafts.get(DEFAULT_USER_DRAFT_ID + username)
|
||||||
|
|
||||||
const loadRecentDraft = () => {
|
const loadRecentDraft = () => {
|
||||||
//if no draft available means local draft is recent
|
//if no draft available means local draft is recent
|
||||||
if (drafts.length == 0) {
|
if (remoteDrafts.length == 0) {
|
||||||
_getStorageDraftGeneral(false);
|
_getStorageDraftGeneral(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//sort darts based on timestamps
|
//sort darts based on timestamps
|
||||||
drafts.sort((d1, d2) =>
|
remoteDrafts.sort((d1, d2) =>
|
||||||
new Date(d1.modified).getTime() < new Date(d2.modified).getTime() ? 1 : -1,
|
new Date(d1.modified).getTime() < new Date(d2.modified).getTime() ? 1 : -1,
|
||||||
);
|
);
|
||||||
const _draft = drafts[0];
|
const _draft = remoteDrafts[0];
|
||||||
|
|
||||||
//if unsaved local draft is more latest then remote draft, use that instead
|
//if unsaved local draft is more latest then remote draft, use that instead
|
||||||
//if editor was opened from draft screens, this code will be skipped anyways.
|
//if editor was opened from draft screens, this code will be skipped anyways.
|
||||||
if (
|
if (
|
||||||
idLessDraft &&
|
idLessDraft &&
|
||||||
(idLessDraft.title !== '' || idLessDraft.tags !== '' || idLessDraft.body !== '') &&
|
(idLessDraft.title !== '' || idLessDraft.tags !== '' || idLessDraft.body !== '') &&
|
||||||
new Date(_draft.modified).getTime() < idLessDraft.timestamp
|
new Date(_draft.modified).getTime() < idLessDraft.updated
|
||||||
) {
|
) {
|
||||||
_getStorageDraftGeneral(false);
|
_getStorageDraftGeneral(false);
|
||||||
return;
|
return;
|
||||||
@ -317,7 +329,7 @@ class EditorContainer extends Component<any, any> {
|
|||||||
this._getStorageDraft(username, isReply, _draft);
|
this._getStorageDraft(username, isReply, _draft);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (drafts.length > 0 || (idLessDraft && idLessDraft.timestamp > 0)) {
|
if (remoteDrafts.length > 0 || (idLessDraft && idLessDraft.updated > 0)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
onLoadDraftPress: loadRecentDraft,
|
onLoadDraftPress: loadRecentDraft,
|
||||||
});
|
});
|
||||||
@ -523,9 +535,14 @@ class EditorContainer extends Component<any, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_saveDraftToDB = async (fields, saveAsNew = false) => {
|
_saveDraftToDB = async (fields, saveAsNew = false) => {
|
||||||
const { isDraftSaved, draftId, thumbIndex } = this.state;
|
const { isDraftSaved, draftId, thumbIndex, isReply } = this.state;
|
||||||
const { currentAccount, dispatch, intl } = this.props;
|
const { currentAccount, dispatch, intl } = this.props;
|
||||||
|
|
||||||
|
if (isReply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const beneficiaries = this._extractBeneficiaries();
|
const beneficiaries = this._extractBeneficiaries();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -574,16 +591,8 @@ class EditorContainer extends Component<any, any> {
|
|||||||
|
|
||||||
//clear local copy if darft save is successful
|
//clear local copy if darft save is successful
|
||||||
const username = get(currentAccount, 'name', '');
|
const username = get(currentAccount, 'name', '');
|
||||||
setDraftPost(
|
|
||||||
{
|
dispatch(deleteDraftCacheEntry(draftId || (DEFAULT_USER_DRAFT_ID + username)))
|
||||||
title: '',
|
|
||||||
body: '',
|
|
||||||
tags: '',
|
|
||||||
timestamp: 0,
|
|
||||||
},
|
|
||||||
username,
|
|
||||||
saveAsNew ? draftId : undefined
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -626,26 +635,28 @@ class EditorContainer extends Component<any, any> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { currentAccount } = this.props;
|
const { currentAccount, dispatch } = this.props;
|
||||||
const username = currentAccount && currentAccount.name ? currentAccount.name : '';
|
const username = currentAccount && currentAccount.name ? currentAccount.name : '';
|
||||||
|
|
||||||
const draftField = {
|
const draftField = {
|
||||||
...fields,
|
title: fields.title,
|
||||||
|
body: fields.body,
|
||||||
tags: fields.tags && fields.tags.length > 0 ? fields.tags.toString() : '',
|
tags: fields.tags && fields.tags.length > 0 ? fields.tags.toString() : '',
|
||||||
};
|
author: username,
|
||||||
|
}
|
||||||
|
|
||||||
//save reply data
|
//save reply data
|
||||||
if (isReply && draftField.body !== null) {
|
if (isReply && draftField.body !== null) {
|
||||||
await AsyncStorage.setItem('temp-reply', draftField.body);
|
dispatch(updateDraftCache(draftId, draftField))
|
||||||
|
|
||||||
//save existing draft data locally
|
//save existing draft data locally
|
||||||
} else if (draftId) {
|
} else if (draftId) {
|
||||||
setDraftPost(draftField, username, draftId);
|
dispatch(updateDraftCache(draftId, draftField))
|
||||||
}
|
}
|
||||||
|
|
||||||
//update editor data locally
|
//update editor data locally
|
||||||
else if (!isReply) {
|
else if (!isReply) {
|
||||||
setDraftPost(draftField, username);
|
dispatch(updateDraftCache(DEFAULT_USER_DRAFT_ID + username, draftField));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -744,15 +755,7 @@ class EditorContainer extends Component<any, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//post publish updates
|
//post publish updates
|
||||||
setDraftPost(
|
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name))
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
body: '',
|
|
||||||
tags: '',
|
|
||||||
timestamp: 0,
|
|
||||||
},
|
|
||||||
currentAccount.name,
|
|
||||||
);
|
|
||||||
|
|
||||||
dispatch(removeBeneficiaries(TEMP_BENEFICIARIES_ID))
|
dispatch(removeBeneficiaries(TEMP_BENEFICIARIES_ID))
|
||||||
if (draftId) {
|
if (draftId) {
|
||||||
@ -1139,15 +1142,8 @@ class EditorContainer extends Component<any, any> {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
setDraftPost(
|
|
||||||
{
|
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + currentAccount.name))
|
||||||
title: '',
|
|
||||||
body: '',
|
|
||||||
tags: '',
|
|
||||||
timestamp: 0,
|
|
||||||
},
|
|
||||||
currentAccount.name,
|
|
||||||
);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigation.replace(ROUTES.SCREENS.DRAFTS,
|
navigation.replace(ROUTES.SCREENS.DRAFTS,
|
||||||
@ -1167,17 +1163,10 @@ class EditorContainer extends Component<any, any> {
|
|||||||
_initialEditor = () => {
|
_initialEditor = () => {
|
||||||
const {
|
const {
|
||||||
currentAccount: { name },
|
currentAccount: { name },
|
||||||
|
dispatch
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
setDraftPost(
|
dispatch(deleteDraftCacheEntry(DEFAULT_USER_DRAFT_ID + name))
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
body: '',
|
|
||||||
tags: '',
|
|
||||||
timestamp: 0,
|
|
||||||
},
|
|
||||||
name,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
uploadedImage: null,
|
uploadedImage: null,
|
||||||
@ -1271,7 +1260,8 @@ const mapStateToProps = (state) => ({
|
|||||||
isDefaultFooter: state.account.isDefaultFooter,
|
isDefaultFooter: state.account.isDefaultFooter,
|
||||||
isLoggedIn: state.application.isLoggedIn,
|
isLoggedIn: state.application.isLoggedIn,
|
||||||
pinCode: state.application.pin,
|
pinCode: state.application.pin,
|
||||||
beneficiariesMap: state.editor.beneficiariesMap
|
beneficiariesMap: state.editor.beneficiariesMap,
|
||||||
|
drafts: state.cache.drafts,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(injectIntl(EditorContainer));
|
export default connect(mapStateToProps)(injectIntl(EditorContainer));
|
||||||
|
@ -39,7 +39,6 @@ class EditorScreen extends Component {
|
|||||||
* ------------------------------------------------
|
* ------------------------------------------------
|
||||||
* @prop { type } name - Description....
|
* @prop { type } name - Description....
|
||||||
*/
|
*/
|
||||||
thumbSelectionModalRef = null;
|
|
||||||
postOptionsModalRef = null;
|
postOptionsModalRef = null;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -206,12 +205,6 @@ class EditorScreen extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_showThumbSelectionModal = () => {
|
|
||||||
const { fields } = this.state;
|
|
||||||
if (this.thumbSelectionModalRef) {
|
|
||||||
this.thumbSelectionModalRef.show(fields.body);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_handleScheduleChange = (datetime:string|null) => {
|
_handleScheduleChange = (datetime:string|null) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -367,7 +360,6 @@ class EditorScreen extends Component {
|
|||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isPostSending,
|
isPostSending,
|
||||||
isReply,
|
isReply,
|
||||||
quickReplyText,
|
|
||||||
isUploading,
|
isUploading,
|
||||||
post,
|
post,
|
||||||
uploadedImage,
|
uploadedImage,
|
||||||
@ -406,8 +398,8 @@ class EditorScreen extends Component {
|
|||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
console.log('fields :', fields);
|
|
||||||
console.log('quickReplyText : ', quickReplyText);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={globalStyles.defaultContainer}>
|
<View style={globalStyles.defaultContainer}>
|
||||||
@ -430,11 +422,11 @@ console.log('quickReplyText : ', quickReplyText);
|
|||||||
isReply={isReply}
|
isReply={isReply}
|
||||||
quickTitle={wordsCount > 0 && `${wordsCount} words`}
|
quickTitle={wordsCount > 0 && `${wordsCount} words`}
|
||||||
rightButtonText={rightButtonText}
|
rightButtonText={rightButtonText}
|
||||||
showThumbSelectionModal={this._showThumbSelectionModal}
|
|
||||||
handleSettingsPress={this._handleSettingsPress}
|
handleSettingsPress={this._handleSettingsPress}
|
||||||
/>
|
/>
|
||||||
<PostForm
|
<PostForm
|
||||||
handleFormUpdate={this._handleFormUpdate}
|
handleFormUpdate={this._handleFormUpdate}
|
||||||
|
handleBodyChange={this._setWordsCount}
|
||||||
handleOnSubmit={this._handleOnSubmit}
|
handleOnSubmit={this._handleOnSubmit}
|
||||||
isFormValid={isFormValid}
|
isFormValid={isFormValid}
|
||||||
isPreviewActive={isPreviewActive}
|
isPreviewActive={isPreviewActive}
|
||||||
@ -451,10 +443,7 @@ console.log('quickReplyText : ', quickReplyText);
|
|||||||
)}
|
)}
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
componentID="body"
|
componentID="body"
|
||||||
draftBody={isReply ? quickReplyText : fields && fields.body}
|
draftBody={fields && fields.body}
|
||||||
handleOnTextChange={this._setWordsCount}
|
|
||||||
handleFormUpdate={this._handleFormUpdate}
|
|
||||||
handleIsFormValid={this._handleIsFormValid}
|
|
||||||
isFormValid={isFormValid}
|
isFormValid={isFormValid}
|
||||||
handleOpenImagePicker={handleOnImagePicker}
|
handleOpenImagePicker={handleOnImagePicker}
|
||||||
intl={intl}
|
intl={intl}
|
||||||
@ -476,12 +465,9 @@ console.log('quickReplyText : ', quickReplyText);
|
|||||||
uploadProgress={uploadProgress}
|
uploadProgress={uploadProgress}
|
||||||
/>
|
/>
|
||||||
</PostForm>
|
</PostForm>
|
||||||
|
|
||||||
{_renderCommunityModal()}
|
{_renderCommunityModal()}
|
||||||
<ThumbSelectionModal
|
|
||||||
ref={(componentRef) => (this.thumbSelectionModalRef = componentRef)}
|
|
||||||
thumbIndex={thumbIndex}
|
|
||||||
onThumbSelection={this._handleOnThumbSelection}
|
|
||||||
/>
|
|
||||||
<PostOptionsModal
|
<PostOptionsModal
|
||||||
ref={(componentRef) => (this.postOptionsModalRef = componentRef)}
|
ref={(componentRef) => (this.postOptionsModalRef = componentRef)}
|
||||||
body={fields.body}
|
body={fields.body}
|
||||||
|
@ -45,25 +45,40 @@ export const generatePermlink = (title, random = false) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const extractWordAtIndex = (text:string, index:number) => {
|
export const extractWordAtIndex = (text:string, index:number) => {
|
||||||
|
|
||||||
|
const RANGE = 50;
|
||||||
|
|
||||||
|
const _start = index - RANGE;
|
||||||
|
const _end = index + RANGE;
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('char at index: ', textChunk[indexChunk]);
|
||||||
|
|
||||||
const END_REGEX = /[\s,]/
|
const END_REGEX = /[\s,]/
|
||||||
let word = '';
|
let word = '';
|
||||||
for(let i = index; i >= 0 && (!END_REGEX.test(text[i]) || i === index); i--){
|
for(let i = indexChunk; i >= 0 && (!END_REGEX.test(textChunk[i]) || i === indexChunk); i--){
|
||||||
if(text[i]){
|
if(textChunk[i]){
|
||||||
word += text[i];
|
word += textChunk[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
word = word.split('').reverse().join('');
|
word = word.split('').reverse().join('');
|
||||||
|
|
||||||
if(!END_REGEX.test(text[index])){
|
if(!END_REGEX.test(textChunk[indexChunk])){
|
||||||
for(let i = index + 1; i < text.length && !END_REGEX.test(text[i]); i++){
|
for(let i = indexChunk + 1; i < textChunk.length && !END_REGEX.test(textChunk[i]); i++){
|
||||||
if(text[i]){
|
if(textChunk[i]){
|
||||||
word += text[i];
|
word += textChunk[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return word;
|
return word;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateReplyPermlink = (toAuthor) => {
|
export const generateReplyPermlink = (toAuthor) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user