mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-17 18:31:36 +03:00
Merge branch 'development' into sa/limit-meta-imgs
This commit is contained in:
commit
ff87e77b38
@ -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",
|
||||
|
@ -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,28 +28,31 @@ 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);
|
||||
}
|
||||
}, [isDeleting]);
|
||||
|
||||
const _onItemPress = () => {
|
||||
if (isSchedules) {
|
||||
moveActionSheet.current.show();
|
||||
return;
|
||||
}
|
||||
return () => {
|
||||
_isMounted = true;
|
||||
|
||||
handleOnPressItem(id);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// consts
|
||||
const scheduleStatus =
|
||||
@ -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: {
|
||||
|
||||
},
|
||||
container: {},
|
||||
textInput: {
|
||||
color: '$primaryBlack',
|
||||
fontSize: 15,
|
||||
@ -14,7 +12,7 @@ export default EStyleSheet.create({
|
||||
borderTopColor: '$primaryLightGray',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '$primaryLightGray',
|
||||
height: isAndroidOreo() ? 36: 40
|
||||
height: isAndroidOreo() ? 36 : 40,
|
||||
},
|
||||
warning: {
|
||||
color: '$primaryRed',
|
||||
|
@ -17,7 +17,7 @@ export default EStyleSheet.create({
|
||||
color: '$primaryBlack',
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
textAlignVertical: 'top',
|
||||
maxHeight: isAndroidOreo() ? '$deviceHeight':undefined
|
||||
maxHeight: isAndroidOreo() ? '$deviceHeight' : undefined,
|
||||
},
|
||||
previewContainer: {
|
||||
flex: 1,
|
||||
|
@ -5,13 +5,18 @@ 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 }) => (
|
||||
<PersistQueryClientProvider {...queryClientProviderProps}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<IntlProvider locale={locale} messages={flattenMessages(messages[locale])}>
|
||||
<SafeAreaProvider>
|
||||
@ -21,6 +26,7 @@ const _renderApp = ({ locale }) => (
|
||||
</SafeAreaProvider>
|
||||
</IntlProvider>
|
||||
</PersistGate>
|
||||
</PersistQueryClientProvider>
|
||||
);
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
|
@ -6,10 +6,19 @@ import { upload } from '../../config/imageApi';
|
||||
import serverList from '../../config/serverListApi';
|
||||
import { SERVER_LIST } from '../../constants/options/api';
|
||||
import { parsePost } from '../../utils/postParser';
|
||||
import { convertCommentHistory, convertLatestQuotes, convertReferral, convertReferralStat } from './converters';
|
||||
import { CommentHistoryItem, LatestMarketPrices, ReceivedVestingShare, Referral, ReferralStat } from './ecency.types';
|
||||
|
||||
|
||||
import {
|
||||
convertCommentHistory,
|
||||
convertLatestQuotes,
|
||||
convertReferral,
|
||||
convertReferralStat,
|
||||
} from './converters';
|
||||
import {
|
||||
CommentHistoryItem,
|
||||
LatestMarketPrices,
|
||||
ReceivedVestingShare,
|
||||
Referral,
|
||||
ReferralStat,
|
||||
} from './ecency.types';
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -30,10 +39,10 @@ export const getCurrencyRate = (currency) =>
|
||||
export const getLatestQuotes = async (currencyRate: number): Promise<LatestMarketPrices> => {
|
||||
try {
|
||||
console.log('using currency rate', currencyRate);
|
||||
const res = await ecencyApi.get(`/private-api/market-data/latest`);
|
||||
const res = await ecencyApi.get('/private-api/market-data/latest');
|
||||
|
||||
if (!res.data) {
|
||||
throw new Error("No quote data returned");
|
||||
throw new Error('No quote data returned');
|
||||
}
|
||||
|
||||
const data = convertLatestQuotes(res.data, currencyRate);
|
||||
@ -43,10 +52,9 @@ export const getLatestQuotes = async (currencyRate: number): Promise<LatestMarke
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
console.warn(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const getCurrencyTokenRate = (currency, token) =>
|
||||
ecencyApi
|
||||
@ -57,27 +65,22 @@ export const getCurrencyTokenRate = (currency, token) =>
|
||||
return 0;
|
||||
});
|
||||
|
||||
|
||||
export const getReceivedVestingShares = async (username: string): Promise<ReceivedVestingShare[]> => {
|
||||
export const getReceivedVestingShares = async (
|
||||
username: string,
|
||||
): Promise<ReceivedVestingShare[]> => {
|
||||
try {
|
||||
const res = await ecencyApi.get(`/private-api/received-vesting/${username}`);
|
||||
console.log("Vesting Shares User", username, res.data);
|
||||
console.log('Vesting Shares User', username, res.data);
|
||||
if (!res.data || !res.data.list) {
|
||||
throw new Error("No vesting shares for user")
|
||||
throw new Error('No vesting shares for user');
|
||||
}
|
||||
return res.data.list;
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
console.warn(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* returns list of saved drafts on ecency server
|
||||
@ -85,29 +88,26 @@ export const getReceivedVestingShares = async (username: string): Promise<Receiv
|
||||
export const getDrafts = async () => {
|
||||
try {
|
||||
const res = await ecencyApi.post('/private-api/drafts');
|
||||
return res.data;
|
||||
return res.data || [];
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @params draftId
|
||||
*/
|
||||
export const deleteDraft = async (draftId: string) => {
|
||||
try {
|
||||
const data = { id: draftId }
|
||||
const res = await ecencyApi.post(`/private-api/drafts-delete`, data);
|
||||
return res.data
|
||||
const data = { id: draftId };
|
||||
const res = await ecencyApi.post('/private-api/drafts-delete', data);
|
||||
return res.data || [];
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @params title
|
||||
@ -117,8 +117,8 @@ export const deleteDraft = async (draftId: string) => {
|
||||
*/
|
||||
export const addDraft = async (title: string, body: string, tags: string, meta: Object) => {
|
||||
try {
|
||||
const data = { title, body, tags, meta }
|
||||
const res = await ecencyApi.post('/private-api/drafts-add', data)
|
||||
const data = { title, body, tags, meta };
|
||||
const res = await ecencyApi.post('/private-api/drafts-add', data);
|
||||
const { drafts } = res.data;
|
||||
if (drafts) {
|
||||
return drafts.pop(); //return recently saved last draft in the list
|
||||
@ -129,8 +129,7 @@ export const addDraft = async (title: string, body: string, tags: string, meta:
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @params draftId
|
||||
@ -139,14 +138,20 @@ export const addDraft = async (title: string, body: string, tags: string, meta:
|
||||
* @params tags
|
||||
* @params meta
|
||||
*/
|
||||
export const updateDraft = async (draftId: string, title: string, body: string, tags: string, meta: Object) => {
|
||||
export const updateDraft = async (
|
||||
draftId: string,
|
||||
title: string,
|
||||
body: string,
|
||||
tags: string,
|
||||
meta: Object,
|
||||
) => {
|
||||
try {
|
||||
const data = { id: draftId, title, body, tags, meta }
|
||||
const res = await ecencyApi.post(`/private-api/drafts-update`, data)
|
||||
const data = { id: draftId, title, body, tags, meta };
|
||||
const res = await ecencyApi.post('/private-api/drafts-update', data);
|
||||
if (res.data) {
|
||||
return res.data
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error("No data returned in response")
|
||||
throw new Error('No data returned in response');
|
||||
}
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
@ -154,8 +159,6 @@ export const updateDraft = async (draftId: string, title: string, body: string,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
* BOOKMARKS ECENCY APIS IMPLEMENTATION
|
||||
@ -171,14 +174,14 @@ export const updateDraft = async (draftId: string, title: string, body: string,
|
||||
export const addBookmark = async (author: string, permlink: string) => {
|
||||
try {
|
||||
const data = { author, permlink };
|
||||
const response = await ecencyApi.post(`/private-api/bookmarks-add`, data);
|
||||
const response = await ecencyApi.post('/private-api/bookmarks-add', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to add bookmark", error)
|
||||
bugsnagInstance.notify(error)
|
||||
throw error
|
||||
}
|
||||
console.warn('Failed to add bookmark', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fetches saved bookmarks of user
|
||||
@ -186,15 +189,14 @@ export const addBookmark = async (author: string, permlink: string) => {
|
||||
*/
|
||||
export const getBookmarks = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/bookmarks`);
|
||||
const response = await ecencyApi.post('/private-api/bookmarks');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to get saved bookmarks", error)
|
||||
bugsnagInstance.notify(error)
|
||||
throw error
|
||||
console.warn('Failed to get saved bookmarks', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes bookmark from user's saved bookmarks
|
||||
@ -203,46 +205,42 @@ export const getBookmarks = async () => {
|
||||
*/
|
||||
export const deleteBookmark = async (bookmarkId: string) => {
|
||||
try {
|
||||
const data = { id: bookmarkId }
|
||||
const response = await ecencyApi.post(`/private-api/bookmarks-delete`, data);
|
||||
const data = { id: bookmarkId };
|
||||
const response = await ecencyApi.post('/private-api/bookmarks-delete', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to delete bookmark", error)
|
||||
bugsnagInstance.notify(error)
|
||||
throw error
|
||||
console.warn('Failed to delete bookmark', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const addReport = async (type: 'content' | 'user', data: string) => {
|
||||
try {
|
||||
const response = await api
|
||||
.post('/report', {
|
||||
const response = await api.post('/report', {
|
||||
type,
|
||||
data
|
||||
})
|
||||
return response.data
|
||||
data,
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.warn("Failed to report to ecency")
|
||||
console.warn('Failed to report to ecency');
|
||||
bugsnagInstance.notify(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteAccount = async (username: string) => {
|
||||
try {
|
||||
const response = await api
|
||||
.post('/request-delete', {
|
||||
const response = await api.post('/request-delete', {
|
||||
username,
|
||||
})
|
||||
return response.data
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.warn("Failed to report to ecency")
|
||||
console.warn('Failed to report to ecency');
|
||||
bugsnagInstance.notify(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -256,14 +254,14 @@ export const deleteAccount = async (username: string) => {
|
||||
*/
|
||||
export const getFavorites = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/favorites`)
|
||||
const response = await ecencyApi.post('/private-api/favorites');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to get favorites", error);
|
||||
console.warn('Failed to get favorites', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if user is precent in current user's favourites
|
||||
@ -273,13 +271,13 @@ export const getFavorites = async () => {
|
||||
export const checkFavorite = async (targetUsername: string) => {
|
||||
try {
|
||||
const data = { account: targetUsername };
|
||||
const response = await ecencyApi.post(`/private-api/favorites-check`, data);
|
||||
const response = await ecencyApi.post('/private-api/favorites-check', data);
|
||||
return response.data || false;
|
||||
} catch (error) {
|
||||
console.warn("Failed to check favorite", error);
|
||||
console.warn('Failed to check favorite', error);
|
||||
bugsnagInstance.notify(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds taget user to current user's favourites
|
||||
@ -289,15 +287,14 @@ export const checkFavorite = async (targetUsername: string) => {
|
||||
export const addFavorite = async (targetUsername: string) => {
|
||||
try {
|
||||
const data = { account: targetUsername };
|
||||
const response = await ecencyApi.post(`/private-api/favorites-add`, data);
|
||||
const response = await ecencyApi.post('/private-api/favorites-add', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to add user favorites", error);
|
||||
console.warn('Failed to add user favorites', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes taget user to current user's favourites
|
||||
@ -307,15 +304,14 @@ export const addFavorite = async (targetUsername: string) => {
|
||||
export const deleteFavorite = async (targetUsername: string) => {
|
||||
try {
|
||||
const data = { account: targetUsername };
|
||||
const response = await ecencyApi.post(`/private-api/favorites-delete`, data);
|
||||
const response = await ecencyApi.post('/private-api/favorites-delete', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to add user favorites", error);
|
||||
console.warn('Failed to add user favorites', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -323,22 +319,20 @@ export const deleteFavorite = async (targetUsername: string) => {
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all saved user fragments/snippets from ecency
|
||||
* @returns array of fragments
|
||||
*/
|
||||
export const getFragments = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/fragments`);
|
||||
const response = await ecencyApi.post('/private-api/fragments');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to get fragments", error);
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to get fragments', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds new fragment/snippets to user's saved fragments/snippets
|
||||
@ -350,14 +344,14 @@ export const getFragments = async () => {
|
||||
export const addFragment = async (title: string, body: string) => {
|
||||
try {
|
||||
const data = { title, body };
|
||||
const response = await ecencyApi.post(`/private-api/fragments-add`, data);
|
||||
const response = await ecencyApi.post('/private-api/fragments-add', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to add fragment", error);
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to add fragment', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates a fragment content using fragment id
|
||||
@ -369,14 +363,14 @@ export const addFragment = async (title: string, body: string) => {
|
||||
export const updateFragment = async (fragmentId: string, title: string, body: string) => {
|
||||
try {
|
||||
const data = { id: fragmentId, title, body };
|
||||
const response = await ecencyApi.post(`/private-api/fragments-update`, data);
|
||||
const response = await ecencyApi.post('/private-api/fragments-update', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to update fragment", error);
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to update fragment', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes user saved fragment using specified fragment id
|
||||
@ -386,16 +380,14 @@ export const updateFragment = async (fragmentId: string, title: string, body: st
|
||||
export const deleteFragment = async (fragmentId: string) => {
|
||||
try {
|
||||
const data = { id: fragmentId };
|
||||
const response = await ecencyApi.post(`/private-api/fragments-delete`, data);
|
||||
const response = await ecencyApi.post('/private-api/fragments-delete', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to delete fragment", error);
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to delete fragment', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -405,7 +397,7 @@ export const deleteFragment = async (fragmentId: string) => {
|
||||
|
||||
export const getLeaderboard = async (duration: 'day' | 'week' | 'month') => {
|
||||
try {
|
||||
const response = await ecencyApi.get(`private-api/leaderboard/${duration}`)
|
||||
const response = await ecencyApi.get(`private-api/leaderboard/${duration}`);
|
||||
|
||||
const rawData = response.data;
|
||||
if (!rawData || !isArray(rawData)) {
|
||||
@ -413,10 +405,10 @@ export const getLeaderboard = async (duration: 'day' | 'week' | 'month') => {
|
||||
}
|
||||
return rawData;
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error)
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fetches notifications from ecency server using filter and since props
|
||||
@ -424,62 +416,59 @@ export const getLeaderboard = async (duration: 'day' | 'week' | 'month') => {
|
||||
* @returns array of notifications
|
||||
*/
|
||||
export const getNotifications = async (data: {
|
||||
filter?: "rvotes" | "mentions" | "follows" | "replies" | "reblogs" | "transfers" | "delegations",
|
||||
since?: string
|
||||
filter?: 'rvotes' | 'mentions' | 'follows' | 'replies' | 'reblogs' | 'transfers' | 'delegations';
|
||||
since?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/notifications`, data);
|
||||
const response = await ecencyApi.post('/private-api/notifications', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to get notifications", error)
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to get notifications', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const getUnreadNotificationCount = async (accessToken?: string) => {
|
||||
try {
|
||||
const data = accessToken ? { code: accessToken } : {}
|
||||
const response = await ecencyApi.post(`/private-api/notifications/unread`, data)
|
||||
const data = accessToken ? { code: accessToken } : {};
|
||||
const response = await ecencyApi.post('/private-api/notifications/unread', data);
|
||||
return response.data ? response.data.count : 0;
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const markNotifications = async (id: string | null = null) => {
|
||||
try {
|
||||
const data = id ? { id } : {};
|
||||
const response = await ecencyApi.post((`/private-api/notifications/mark`), data);
|
||||
return response.data
|
||||
const response = await ecencyApi.post('/private-api/notifications/mark', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const setPushToken = async (data, accessToken = null) => {
|
||||
try {
|
||||
if (!data.username) {
|
||||
console.log("skipping push token setting, as no user is provided")
|
||||
console.log('skipping push token setting, as no user is provided');
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessToken) {
|
||||
data.code = accessToken
|
||||
data.code = accessToken;
|
||||
}
|
||||
|
||||
const res = await await ecencyApi.post((`/private-api/register-device`), data);
|
||||
const res = await await ecencyApi.post('/private-api/register-device', data);
|
||||
return res.data;
|
||||
|
||||
} catch (error) {
|
||||
console.warn("Failed to set push token on server")
|
||||
console.warn('Failed to set push token on server');
|
||||
bugsnagInstance.notify(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -488,22 +477,21 @@ export const setPushToken = async (data, accessToken = null) => {
|
||||
*/
|
||||
|
||||
export const search = async (data: {
|
||||
q: string,
|
||||
sort: string,
|
||||
hideLow: string,
|
||||
since?: string,
|
||||
scroll_id?: string
|
||||
q: string;
|
||||
sort: string;
|
||||
hideLow: string;
|
||||
since?: string;
|
||||
scroll_id?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await ecencyApi.post('/search-api/search', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Search failed", error);
|
||||
console.warn('Search failed', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@ -516,12 +504,11 @@ export const searchPath = async (q: string) => {
|
||||
const response = await ecencyApi.post('/search-api/search-path', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("path search failed", error)
|
||||
console.warn('path search failed', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@ -536,16 +523,15 @@ export const searchAccount = async (q: string = '', limit: number = 20, random:
|
||||
q,
|
||||
limit,
|
||||
random,
|
||||
}
|
||||
const response = await ecencyApi.post(`/search-api/search-account`, data)
|
||||
};
|
||||
const response = await ecencyApi.post('/search-api/search-account', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("account search failed", error)
|
||||
console.warn('account search failed', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@ -560,17 +546,15 @@ export const searchTag = async (q: string = '', limit: number = 20, random: numb
|
||||
q,
|
||||
limit,
|
||||
random,
|
||||
}
|
||||
const response = await ecencyApi.post(`/search-api/search-tag`, data);
|
||||
};
|
||||
const response = await ecencyApi.post('/search-api/search-tag', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("tag search failed", error)
|
||||
console.warn('tag search failed', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -594,7 +578,7 @@ export const addSchedule = async (
|
||||
body: string,
|
||||
meta: any,
|
||||
options: any,
|
||||
scheduleDate: string
|
||||
scheduleDate: string,
|
||||
) => {
|
||||
try {
|
||||
const data = {
|
||||
@ -605,16 +589,15 @@ export const addSchedule = async (
|
||||
schedule: scheduleDate,
|
||||
options,
|
||||
reblog: 0,
|
||||
}
|
||||
const response = await ecencyApi
|
||||
.post('/private-api/schedules-add', data)
|
||||
};
|
||||
const response = await ecencyApi.post('/private-api/schedules-add', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to add post to schedule", error)
|
||||
console.warn('Failed to add post to schedule', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches all scheduled posts against current user
|
||||
@ -622,14 +605,14 @@ export const addSchedule = async (
|
||||
*/
|
||||
export const getSchedules = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/schedules`)
|
||||
return response.data;
|
||||
const response = await ecencyApi.post('/private-api/schedules');
|
||||
return response.data || [];
|
||||
} catch (error) {
|
||||
console.warn("Failed to get schedules")
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to get schedules');
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes post from scheduled posts using post id;
|
||||
@ -639,14 +622,14 @@ export const getSchedules = async () => {
|
||||
export const deleteScheduledPost = async (id: string) => {
|
||||
try {
|
||||
const data = { id };
|
||||
const response = await ecencyApi.post(`/private-api/schedules-delete`, data);
|
||||
return response;
|
||||
const response = await ecencyApi.post('/private-api/schedules-delete', data);
|
||||
return response.data || [];
|
||||
} catch (error) {
|
||||
console.warn("Failed to delete scheduled post")
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to delete scheduled post');
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves scheduled post to draft using schedule id
|
||||
@ -655,15 +638,15 @@ export const deleteScheduledPost = async (id: string) => {
|
||||
*/
|
||||
export const moveScheduledToDraft = async (id: string) => {
|
||||
try {
|
||||
const data = { id }
|
||||
const response = await ecencyApi.post(`/private-api/schedules-move`, data);
|
||||
const data = { id };
|
||||
const response = await ecencyApi.post('/private-api/schedules-move', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("Failed to move scheduled post to drafts")
|
||||
bugsnagInstance.notify(error)
|
||||
console.warn('Failed to move scheduled post to drafts');
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Old image service
|
||||
/**
|
||||
@ -672,40 +655,39 @@ export const moveScheduledToDraft = async (id: string) => {
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
|
||||
export const getImages = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post('/private-api/images')
|
||||
const response = await ecencyApi.post('/private-api/images');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn('Failed to get images', error);
|
||||
bugsnagInstance.notify(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const addImage = async (url: string) => {
|
||||
try {
|
||||
const data = { url };
|
||||
const response = await ecencyApi.post(`/private-api/images-add`, data);
|
||||
const response = await ecencyApi.post('/private-api/images-add', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn('Failed to add image', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteImage = async (id: string) => {
|
||||
try {
|
||||
const data = { id };
|
||||
const response = await ecencyApi.post(`/private-api/images-delete`, data);
|
||||
const response = await ecencyApi.post('/private-api/images-delete', data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn('Failed to delete image', error);
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const uploadImage = async (media, username, sign, uploadProgress = null) => {
|
||||
try {
|
||||
@ -719,15 +701,14 @@ export const uploadImage = async (media, username, sign, uploadProgress = null)
|
||||
const fData = new FormData();
|
||||
fData.append('file', file);
|
||||
|
||||
const res = await upload(fData, username, sign, uploadProgress)
|
||||
const res = await upload(fData, username, sign, uploadProgress);
|
||||
if (!res || !res.data) {
|
||||
throw new Error("Returning response missing media data");
|
||||
throw new Error('Returning response missing media data');
|
||||
}
|
||||
return res;
|
||||
|
||||
} catch (error) {
|
||||
console.warn("Image upload failed", error)
|
||||
return { error }
|
||||
console.warn('Image upload failed', error);
|
||||
return { error };
|
||||
}
|
||||
};
|
||||
|
||||
@ -735,8 +716,6 @@ export const uploadImage = async (media, username, sign, uploadProgress = null)
|
||||
|
||||
export const getNodes = () => serverList.get().then((resp) => resp.data.hived || SERVER_LIST);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* refreshes access token using refresh token
|
||||
* @param code refresh token
|
||||
@ -746,16 +725,14 @@ export const getSCAccessToken = async (code: string) => {
|
||||
try {
|
||||
const response = await ecencyApi.post('/auth-api/hs-token-refresh', {
|
||||
code,
|
||||
})
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.warn("failed to refresh token")
|
||||
console.warn('failed to refresh token');
|
||||
bugsnagInstance.notify(error);
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* fetches promoted posts for tab content
|
||||
@ -771,29 +748,24 @@ export const getPromotedEntries = async (username: string) => {
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn("Failed to get promoted enties")
|
||||
console.warn('Failed to get promoted enties');
|
||||
bugsnagInstance.notify(error);
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const purchaseOrder = (data) =>
|
||||
api
|
||||
.post('/purchase-order', data)
|
||||
.then((resp) => resp.data)
|
||||
.catch((error) => bugsnagInstance.notify(error));
|
||||
|
||||
|
||||
|
||||
export const getPostReblogs = (data) =>
|
||||
api
|
||||
.get(`/post-reblogs/${data.author}/${data.permlink}`)
|
||||
.then((resp) => resp.data)
|
||||
.catch((error) => bugsnagInstance.notify(error));
|
||||
|
||||
|
||||
/**
|
||||
* Registers new user with ecency and hive, on confirmation sends
|
||||
* details to user email
|
||||
@ -807,8 +779,8 @@ export const signUp = async (username: string, email: string, referral?: string)
|
||||
const data = {
|
||||
username,
|
||||
email,
|
||||
referral
|
||||
}
|
||||
referral,
|
||||
};
|
||||
const response = await ecencyApi.post('/private-api/account-create', data);
|
||||
return response.status === 202;
|
||||
} catch (error) {
|
||||
@ -823,25 +795,29 @@ export const signUp = async (username: string, email: string, referral?: string)
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
export const getReferralsList = async (username: string, maxId: number | undefined): Promise<Referral[]> => {
|
||||
export const getReferralsList = async (
|
||||
username: string,
|
||||
maxId: number | undefined,
|
||||
): Promise<Referral[]> => {
|
||||
try {
|
||||
const res = await ecencyApi.get(`/private-api/referrals/${username}`, {
|
||||
params: {
|
||||
max_id: maxId
|
||||
}
|
||||
max_id: maxId,
|
||||
},
|
||||
});
|
||||
console.log('Referrals List', username, res.data);
|
||||
if (!res.data) {
|
||||
throw new Error('No Referrals for this user!');
|
||||
}
|
||||
const referralsList = res.data.length > 0 ? res.data.map((referralItem: any) => convertReferral(referralItem)) : [];
|
||||
const referralsList =
|
||||
res.data.length > 0 ? res.data.map((referralItem: any) => convertReferral(referralItem)) : [];
|
||||
return referralsList;
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
console.warn(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getReferralsStats = async (username: string): Promise<ReferralStat> => {
|
||||
try {
|
||||
@ -856,7 +832,7 @@ export const getReferralsStats = async (username: string): Promise<ReferralStat>
|
||||
console.warn(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@ -864,12 +840,15 @@ export const getReferralsStats = async (username: string): Promise<ReferralStat>
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
export const getCommentHistory = async (author: string, permlink: string): Promise<CommentHistoryItem[]> => {
|
||||
export const getCommentHistory = async (
|
||||
author: string,
|
||||
permlink: string,
|
||||
): Promise<CommentHistoryItem[]> => {
|
||||
try {
|
||||
const data = {
|
||||
author,
|
||||
permlink
|
||||
}
|
||||
permlink,
|
||||
};
|
||||
const res = await ecencyApi.post('/private-api/comment-history', data);
|
||||
console.log('comment history', res.data);
|
||||
if (!res.data) {
|
||||
@ -880,5 +859,4 @@ export const getCommentHistory = async (author: string, permlink: string): Promi
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
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;
|
@ -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,53 +2,58 @@ 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 styles from './postOptionsModalStyles';
|
||||
import ThumbSelectionContent from './thumbSelectionContent';
|
||||
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';
|
||||
|
||||
const REWARD_TYPES = [
|
||||
{
|
||||
key: 'default',
|
||||
intlId:'editor.reward_default'
|
||||
intlId: 'editor.reward_default',
|
||||
},
|
||||
{
|
||||
key: 'sp',
|
||||
intlId:'editor.reward_power_up'
|
||||
intlId: 'editor.reward_power_up',
|
||||
},
|
||||
{
|
||||
key: 'dp',
|
||||
intlId:'editor.reward_decline'
|
||||
intlId: 'editor.reward_decline',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
];
|
||||
|
||||
export interface PostOptionsModalRef {
|
||||
showModal: () => void;
|
||||
}
|
||||
|
||||
|
||||
interface PostOptionsModalProps {
|
||||
body: string;
|
||||
draftId: string;
|
||||
thumbIndex:number,
|
||||
thumbUrl: string;
|
||||
isEdit: boolean;
|
||||
isCommunityPost: boolean;
|
||||
rewardType: string;
|
||||
isUploading: boolean;
|
||||
handleRewardChange: (rewardType: string) => void;
|
||||
handleThumbSelection:(index:number)=>void;
|
||||
handleThumbSelection: (url: string) => void;
|
||||
handleScheduleChange: (datetime: string | null) => void;
|
||||
handleShouldReblogChange: (shouldReblog: boolean) => void;
|
||||
handleFormUpdate: () => void;
|
||||
}
|
||||
|
||||
const PostOptionsModal = forwardRef(({
|
||||
const PostOptionsModal = forwardRef(
|
||||
(
|
||||
{
|
||||
body,
|
||||
draftId,
|
||||
thumbIndex,
|
||||
thumbUrl,
|
||||
isEdit,
|
||||
isCommunityPost,
|
||||
rewardType,
|
||||
@ -57,8 +62,10 @@ const PostOptionsModal = forwardRef(({
|
||||
handleThumbSelection,
|
||||
handleScheduleChange,
|
||||
handleShouldReblogChange,
|
||||
handleFormUpdate
|
||||
}: PostOptionsModalProps, ref) => {
|
||||
handleFormUpdate,
|
||||
}: PostOptionsModalProps,
|
||||
ref,
|
||||
) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@ -72,29 +79,29 @@ const PostOptionsModal = forwardRef(({
|
||||
|
||||
useEffect(() => {
|
||||
if (!scheduleLater) {
|
||||
handleScheduleChange(null)
|
||||
handleScheduleChange(null);
|
||||
} else if (scheduledFor) {
|
||||
handleScheduleChange(scheduledFor)
|
||||
handleScheduleChange(scheduledFor);
|
||||
}
|
||||
}, [scheduleLater, scheduledFor])
|
||||
}, [scheduleLater, scheduledFor]);
|
||||
|
||||
useEffect(() => {
|
||||
handleShouldReblogChange(shouldReblog)
|
||||
}, [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)
|
||||
let rewardTypeKey = REWARD_TYPES.findIndex((item) => item.key === rewardType);
|
||||
setRewardTypeIndex(rewardTypeKey);
|
||||
}
|
||||
},[rewardType])
|
||||
}, [rewardType]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: () => {
|
||||
@ -102,28 +109,27 @@ const PostOptionsModal = forwardRef(({
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const _handleRewardChange = (index: number) => {
|
||||
setRewardTypeIndex(index)
|
||||
const rewardTypeKey = REWARD_TYPES[index].key
|
||||
setRewardTypeIndex(index);
|
||||
const rewardTypeKey = REWARD_TYPES[index].key;
|
||||
if (handleRewardChange) {
|
||||
handleRewardChange(rewardTypeKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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}>
|
||||
@ -136,8 +142,8 @@ const PostOptionsModal = forwardRef(({
|
||||
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) => {
|
||||
@ -156,7 +162,6 @@ const PostOptionsModal = forwardRef(({
|
||||
disabled={true}
|
||||
/>
|
||||
</AnimatedView>
|
||||
|
||||
)}
|
||||
|
||||
<SettingsItem
|
||||
@ -165,14 +170,11 @@ const PostOptionsModal = forwardRef(({
|
||||
})}
|
||||
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({
|
||||
@ -187,22 +189,16 @@ const PostOptionsModal = forwardRef(({
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
<ThumbSelectionContent
|
||||
body={body}
|
||||
thumbIndex={thumbIndex}
|
||||
thumbUrl={thumbUrl}
|
||||
isUploading={isUploading}
|
||||
onThumbSelection={_handleThumbIndexSelection}
|
||||
/>
|
||||
|
||||
{!isEdit && (
|
||||
<BeneficiarySelectionContent
|
||||
draftId={draftId}
|
||||
setDisableDone={setDisableDone}
|
||||
/>
|
||||
<BeneficiarySelectionContent draftId={draftId} setDisableDone={setDisableDone} />
|
||||
)}
|
||||
|
||||
|
||||
</View>
|
||||
</KeyboardAwareScrollView>
|
||||
|
||||
@ -210,13 +206,10 @@ const PostOptionsModal = forwardRef(({
|
||||
style={{ ...styles.saveButton }}
|
||||
isDisable={disableDone}
|
||||
onPress={_onDonePress}
|
||||
text={intl.formatMessage({id:"editor.done"})}
|
||||
text={intl.formatMessage({ id: 'editor.done' })}
|
||||
/>
|
||||
</View>
|
||||
|
||||
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -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>
|
||||
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export default PostOptionsModal
|
||||
export default PostOptionsModal;
|
||||
|
@ -1,16 +1,14 @@
|
||||
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
|
||||
zIndex: 999,
|
||||
},
|
||||
thumbStyle: {
|
||||
width: 72,
|
||||
@ -18,11 +16,14 @@ export default EStyleSheet.create({
|
||||
marginVertical: 8,
|
||||
marginRight: 8,
|
||||
borderRadius: 12,
|
||||
backgroundColor:'$primaryLightGray'
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
selectedStyle:{
|
||||
borderWidth:4,
|
||||
borderColor:'$primaryBlack'
|
||||
checkContainer: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 6,
|
||||
backgroundColor: '$pureWhite',
|
||||
borderRadius: 12,
|
||||
},
|
||||
settingLabel: {
|
||||
color: '$primaryDarkGray',
|
||||
@ -35,7 +36,7 @@ export default EStyleSheet.create({
|
||||
paddingBottom: getBottomSpace() + 16,
|
||||
},
|
||||
container: {
|
||||
paddingVertical:16
|
||||
paddingVertical: 16,
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom: 20 },
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
||||
@ -55,5 +56,5 @@ export default EStyleSheet.create({
|
||||
doneButton: { borderRadius: 16, backgroundColor: '$primaryBlue' },
|
||||
thumbSelectContainer: {
|
||||
marginTop: 12,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -1,73 +1,96 @@
|
||||
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;
|
||||
thumbUrl: string;
|
||||
isUploading: boolean;
|
||||
onThumbSelection: (index: number) => void;
|
||||
onThumbSelection: (url: string) => void;
|
||||
}
|
||||
|
||||
const ThumbSelectionContent = ({ body, thumbIndex, onThumbSelection, isUploading }: ThumbSelectionContentProps) => {
|
||||
const ThumbSelectionContent = ({
|
||||
body,
|
||||
thumbUrl,
|
||||
onThumbSelection,
|
||||
isUploading,
|
||||
}: ThumbSelectionContentProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
const [needMore, setNeedMore] = useState(true);
|
||||
const [thumbIndex, setThumbIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const urls = extractImageUrls({ body });
|
||||
|
||||
if (urls.length < 2) {
|
||||
setNeedMore(true);
|
||||
onThumbSelection(0);
|
||||
setImageUrls([])
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
setImageUrls([]);
|
||||
} else {
|
||||
setNeedMore(false);
|
||||
setImageUrls(urls)
|
||||
setImageUrls(urls);
|
||||
}
|
||||
}, [body])
|
||||
|
||||
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 _renderImageItem = ({ item, index }: { item: string; index: number }) => {
|
||||
const _onPress = () => {
|
||||
onThumbSelection(index);
|
||||
}
|
||||
onThumbSelection(item);
|
||||
setThumbIndex(index);
|
||||
};
|
||||
|
||||
const selectedStyle = index === thumbIndex ? styles.selectedStyle : null
|
||||
const isSelected = item === thumbUrl && index === thumbIndex;
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => _onPress()}>
|
||||
<FastImage
|
||||
source={{ uri: item }}
|
||||
style={{ ...styles.thumbStyle, ...selectedStyle }}
|
||||
resizeMode='cover'
|
||||
<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 &&
|
||||
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>
|
||||
{needMore ? (
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({ id: 'editor.add_more_imgs' })}
|
||||
</Text>
|
||||
) : (
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
@ -76,10 +99,9 @@ const ThumbSelectionContent = ({ body, thumbIndex, onThumbSelection, isUploading
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false} />
|
||||
)
|
||||
}
|
||||
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
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[]>([]);
|
||||
@ -25,51 +23,45 @@ const ThumbSelectionModal = ({ onThumbSelection, thumbIndex }:ThumbSelectionModa
|
||||
//CALLBACK_METHODS
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: (postBody: string) => {
|
||||
console.log("Showing action modal")
|
||||
console.log('Showing action modal');
|
||||
|
||||
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'})
|
||||
)
|
||||
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) => {
|
||||
onThumbSelection(index);
|
||||
sheetModalRef.current?.setModalVisible(false);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({item, index}:{item:string, index:number}) => {
|
||||
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'
|
||||
resizeMode="cover"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
const _renderContent = () => {
|
||||
return (
|
||||
@ -84,10 +76,8 @@ const ThumbSelectionModal = ({ onThumbSelection, thumbIndex }:ThumbSelectionModa
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionSheet
|
||||
|
@ -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);
|
||||
}
|
||||
@ -125,7 +124,7 @@ class EditorContainer extends Component<any, any> {
|
||||
if (navigationParams.isReply) {
|
||||
({ isReply } = navigationParams);
|
||||
if (post) {
|
||||
draftId = `${currentAccount.name}/${post.author}/${post.permlink}`
|
||||
draftId = `${currentAccount.name}/${post.author}/${post.permlink}`;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
@ -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],
|
||||
});
|
||||
}
|
||||
|
||||
@ -263,11 +274,13 @@ 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
|
||||
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
|
||||
@ -312,7 +325,7 @@ 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();
|
||||
|
||||
@ -396,10 +415,10 @@ class EditorContainer extends Component<any, any> {
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
_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) => {
|
||||
this.setState({
|
||||
isUploading:status
|
||||
})
|
||||
}
|
||||
|
||||
isUploading: status,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isLoggedIn, isDarkTheme, currentAccount, route } = this.props;
|
||||
@ -1072,7 +1062,7 @@ class EditorContainer extends Component<any, any> {
|
||||
community,
|
||||
sharedSnippetText,
|
||||
onLoadDraftPress,
|
||||
thumbIndex,
|
||||
thumbUrl,
|
||||
uploadProgress,
|
||||
rewardType,
|
||||
} = this.state;
|
||||
@ -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()} />,
|
||||
),
|
||||
);
|
||||
|
@ -145,21 +145,21 @@ class EditorScreen extends Component {
|
||||
_handleOnSaveButtonPress = () => {
|
||||
const { draftId, intl } = this.props;
|
||||
if (draftId) {
|
||||
Alert.alert(
|
||||
intl.formatMessage({id:'editor.draft_save_title'}),
|
||||
"",
|
||||
[{
|
||||
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)
|
||||
},{
|
||||
onPress: () => this._saveDraftToDB(true),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'alert.cancel' }),
|
||||
onPress: () => {},
|
||||
style:'cancel'
|
||||
}]
|
||||
)
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
this._saveDraftToDB();
|
||||
@ -174,7 +174,7 @@ class EditorScreen extends Component {
|
||||
|
||||
this.changeTimer = setTimeout(() => {
|
||||
// saveCurrentDraft(fields);
|
||||
updateDraftFields(fields)
|
||||
updateDraftFields(fields);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
@ -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) => {
|
||||
this.setState({
|
||||
scheduledFor: datetime,
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
_handleRewardChange = (value) => {
|
||||
const { handleRewardChange } = this.props;
|
||||
handleRewardChange(value);
|
||||
}
|
||||
};
|
||||
_handleSettingsPress = () => {
|
||||
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,7 +247,7 @@ 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,
|
||||
@ -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}
|
||||
|
@ -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,14 +54,12 @@ 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]) {
|
||||
@ -81,7 +77,7 @@ export const generatePermlink = (title, random = false) => {
|
||||
}
|
||||
|
||||
return word;
|
||||
}
|
||||
};
|
||||
|
||||
export const generateReplyPermlink = (toAuthor) => {
|
||||
if (!toAuthor) {
|
||||
@ -169,15 +165,13 @@ export const makeJsonMetadataForUpdate = (oldJson, meta, tags) => {
|
||||
return Object.assign({}, oldJson, mergedMeta, { tags });
|
||||
};
|
||||
|
||||
|
||||
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 = [];
|
||||
@ -188,33 +182,38 @@ export const extractImageUrls = ({body, urls}:{body?:string, urls?:string[]}) =>
|
||||
if (isImage) {
|
||||
imgUrls.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return imgUrls;
|
||||
}
|
||||
};
|
||||
|
||||
export const extractFilenameFromPath = ({path, mimeType}:{path:string, mimeType?:string}) => {
|
||||
export const extractFilenameFromPath = ({
|
||||
path,
|
||||
mimeType,
|
||||
}: {
|
||||
path: string;
|
||||
mimeType?: string;
|
||||
}) => {
|
||||
try {
|
||||
if (!path) {
|
||||
throw new Error("path not provided");
|
||||
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");
|
||||
throw new Error('file name not present with extension');
|
||||
}
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
|
||||
} catch (err) {
|
||||
let _ext = 'jpg';
|
||||
if (mimeType) {
|
||||
_ext = MimeTypes.extension(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 = {};
|
||||
@ -231,7 +230,7 @@ export const extractMetadata = (body:string, thumbIndex?:number) => {
|
||||
if (matchedImages.indexOf(url) < 0) {
|
||||
matchedLinks.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (matchedLinks.length) {
|
||||
@ -239,8 +238,8 @@ 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));
|
||||
|
@ -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,7 +112,8 @@ export const groomingTransactionData = (transaction, hivePerMVests) => {
|
||||
.toFixed(3)
|
||||
.replace(',', '.');
|
||||
|
||||
result.value = `${hbdPayout > 0 ? `${hbdPayout} HBD` : ''} ${hivePayout > 0 ? `${hivePayout} HIVE` : ''
|
||||
result.value = `${hbdPayout > 0 ? `${hbdPayout} HBD` : ''} ${
|
||||
hivePayout > 0 ? `${hivePayout} HIVE` : ''
|
||||
} ${vestingPayout > 0 ? `${vestingPayout} HP` : ''}`;
|
||||
|
||||
result.details = author && permlink ? `@${author}/${permlink}` : null;
|
||||
@ -117,7 +128,8 @@ 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` : ''
|
||||
result.value = `${rewardHdb > 0 ? `${rewardHdb} HBD` : ''} ${
|
||||
rewardHive > 0 ? `${rewardHive} HIVE` : ''
|
||||
} ${rewardVests > 0 ? `${rewardVests} HP` : ''}`;
|
||||
break;
|
||||
case 'transfer':
|
||||
@ -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,59 +314,56 @@ 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@ -370,52 +379,58 @@ 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) {
|
||||
return {
|
||||
completed: [],
|
||||
pending:[]
|
||||
}
|
||||
pending: [],
|
||||
};
|
||||
}
|
||||
|
||||
const pointActivities = await getPointsHistory(username);
|
||||
console.log("Points Activities", pointActivities);
|
||||
const completed = pointActivities && pointActivities.length ?
|
||||
pointActivities.map((item) =>
|
||||
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, [
|
||||
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);
|
||||
],
|
||||
startIndex,
|
||||
limit,
|
||||
);
|
||||
break;
|
||||
case COIN_IDS.HBD:
|
||||
history = await getAccountHistory(username, [
|
||||
history = await getAccountHistory(
|
||||
username,
|
||||
[
|
||||
op.transfer, //HIVE //HBD
|
||||
op.author_reward, //HBD, HP
|
||||
op.transfer_to_savings, //HIVE, HBD
|
||||
@ -423,10 +438,15 @@ export const fetchCoinActivities = async (
|
||||
op.fill_convert_request, //HBD
|
||||
op.fill_order, //HIVE, HBD
|
||||
op.sps_fund, //HBD
|
||||
], startIndex, limit);
|
||||
],
|
||||
startIndex,
|
||||
limit,
|
||||
);
|
||||
break;
|
||||
case COIN_IDS.HP:
|
||||
history = await getAccountHistory(username, [
|
||||
history = await getAccountHistory(
|
||||
username,
|
||||
[
|
||||
op.author_reward, //HBD, HP
|
||||
op.curation_reward, //HP
|
||||
op.transfer_to_vesting, //HIVE, HP
|
||||
@ -435,66 +455,33 @@ export const fetchCoinActivities = async (
|
||||
op.claim_reward_balance, //HP
|
||||
op.comment_benefactor_reward, //HP
|
||||
op.return_vesting_delegation, //HP
|
||||
], startIndex, limit);
|
||||
],
|
||||
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
|
||||
@ -620,9 +596,12 @@ 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;
|
||||
(Number(userdata.to_withdraw) - Number(userdata.withdrawn)) / 1e6,
|
||||
)
|
||||
: 0;
|
||||
const nextVestingSharesWithdrawalHive = isPoweringDown
|
||||
? vestsToHp(nextVestingSharesWithdrawal, hivePerMVests)
|
||||
: 0;
|
||||
|
||||
const estimateVoteValueStr = '$ ' + getEstimatedAmount(userdata, globalProps);
|
||||
|
||||
@ -633,35 +612,40 @@ export const fetchCoinsData = async ({
|
||||
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