mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-16 18:03:14 +03:00
Merge branch 'development' into nt/use-query-notifications
# Conflicts: # src/providers/ecency/ecency.ts
This commit is contained in:
commit
320de3310b
@ -107,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,
|
||||
@ -45,32 +38,13 @@ const DraftListItemView = ({
|
||||
}) => {
|
||||
const actionSheet = useRef(null);
|
||||
const moveActionSheet = useRef(null);
|
||||
|
||||
const [calcImgHeight, setCalcImgHeight] = useState(300);
|
||||
|
||||
const [deleteRequested, setIsDeleteRequested] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (deleteRequested && !isDeleting) {
|
||||
setIsDeleteRequested(false);
|
||||
}
|
||||
}, [isDeleting]);
|
||||
|
||||
// Component Life Cycles
|
||||
useEffect(() => {
|
||||
let _isMounted = false;
|
||||
if (image) {
|
||||
if (!_isMounted) {
|
||||
ImageSize.getSize(thumbnail.uri).then((size) => {
|
||||
setCalcImgHeight(Math.floor((size.height / size.width) * dim.width));
|
||||
});
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
_isMounted = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const _onItemPress = () => {
|
||||
if (isSchedules) {
|
||||
moveActionSheet.current.show();
|
||||
@ -85,24 +59,24 @@ const DraftListItemView = ({
|
||||
status === ScheduledPostStatus.PENDING
|
||||
? intl.formatMessage({ id: 'schedules.pending' })
|
||||
: status === ScheduledPostStatus.POSTPONED
|
||||
? intl.formatMessage({ id: 'schedules.postponed' })
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? intl.formatMessage({ id: 'schedules.published' })
|
||||
: intl.formatMessage({ id: 'schedules.error' });
|
||||
? intl.formatMessage({ id: 'schedules.postponed' })
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? intl.formatMessage({ id: 'schedules.published' })
|
||||
: intl.formatMessage({ id: 'schedules.error' });
|
||||
const statusIcon =
|
||||
status === ScheduledPostStatus.PENDING
|
||||
? 'timer'
|
||||
: status === ScheduledPostStatus.POSTPONED
|
||||
? 'schedule'
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? 'check-circle'
|
||||
: 'error';
|
||||
? 'schedule'
|
||||
: status === ScheduledPostStatus.PUBLISHED
|
||||
? 'check-circle'
|
||||
: 'error';
|
||||
const statusIconColor =
|
||||
status === ScheduledPostStatus.PUBLISHED
|
||||
? '#4FD688'
|
||||
: status === ScheduledPostStatus.ERROR
|
||||
? '#e63535'
|
||||
: '#c1c5c7';
|
||||
? '#e63535'
|
||||
: '#c1c5c7';
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@ -145,13 +119,10 @@ const DraftListItemView = ({
|
||||
<View style={styles.body}>
|
||||
<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]}>
|
@ -6,14 +6,24 @@ 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, NotificationFilters, ReceivedVestingShare, Referral, ReferralStat } from './ecency.types';
|
||||
import {
|
||||
convertCommentHistory,
|
||||
convertLatestQuotes,
|
||||
convertReferral,
|
||||
convertReferralStat,
|
||||
} from './converters';
|
||||
import {
|
||||
CommentHistoryItem,
|
||||
LatestMarketPrices,
|
||||
NotificationFilters,
|
||||
ReceivedVestingShare,
|
||||
Referral,
|
||||
ReferralStat,
|
||||
} from './ecency.types';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* CURRENCY APIS IMPLEMENTATION
|
||||
* CURRENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
@ -30,10 +40,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 +53,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 +66,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
|
||||
@ -90,24 +94,21 @@ export const getDrafts = async () => {
|
||||
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 +118,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 +130,7 @@ export const addDraft = async (title: string, body: string, tags: string, meta:
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @params draftId
|
||||
@ -139,14 +139,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,31 +160,29 @@ export const updateDraft = async (draftId: string, title: string, body: string,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* BOOKMARKS ECENCY APIS IMPLEMENTATION
|
||||
* BOOKMARKS ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds post to user's bookmarks
|
||||
* @param author
|
||||
* @param permlink
|
||||
* @param author
|
||||
* @param permlink
|
||||
* @returns array of saved bookmarks
|
||||
*/
|
||||
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 +190,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,52 +206,48 @@ 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', {
|
||||
type,
|
||||
data
|
||||
})
|
||||
return response.data
|
||||
const response = await api.post('/report', {
|
||||
type,
|
||||
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', {
|
||||
username,
|
||||
})
|
||||
return response.data
|
||||
const response = await api.post('/request-delete', {
|
||||
username,
|
||||
});
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.warn("Failed to report to ecency")
|
||||
console.warn('Failed to report to ecency');
|
||||
bugsnagInstance.notify(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
* FAVOURITES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
/**
|
||||
* ************************************
|
||||
* FAVOURITES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches user favourites
|
||||
@ -256,14 +255,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 +272,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 +288,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,38 +305,35 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* SNIPPETS ECENCY APIS IMPLEMENTATION
|
||||
* SNIPPETS ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 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 +345,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 +364,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,26 +381,24 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
* ACTIVITES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
/**
|
||||
* ************************************
|
||||
* ACTIVITES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
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 +406,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
|
||||
@ -429,85 +422,81 @@ export const getNotifications = async (data: {
|
||||
limit?: number,
|
||||
}) => {
|
||||
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
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* SEARCH ECENCY APIS IMPLEMENTATION
|
||||
* SEARCH ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param q query
|
||||
* @returns array of path strings
|
||||
*/
|
||||
@ -517,15 +506,14 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param q query
|
||||
* @param limit number of posts to fetch
|
||||
* @param random random
|
||||
@ -537,19 +525,18 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param q query
|
||||
* @param limit number of posts to fetch
|
||||
* @param random random
|
||||
@ -561,32 +548,30 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* SCHEDULES ECENCY APIS IMPLEMENTATION
|
||||
* SCHEDULES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds new post to scheduled posts
|
||||
* @param permlink
|
||||
* @param title
|
||||
* @param body
|
||||
* @param meta
|
||||
* @param options
|
||||
* @param scheduleDate
|
||||
* @param permlink
|
||||
* @param title
|
||||
* @param body
|
||||
* @param meta
|
||||
* @param options
|
||||
* @param scheduleDate
|
||||
* @returns All scheduled posts
|
||||
*/
|
||||
export const addSchedule = async (
|
||||
@ -595,7 +580,7 @@ export const addSchedule = async (
|
||||
body: string,
|
||||
meta: any,
|
||||
options: any,
|
||||
scheduleDate: string
|
||||
scheduleDate: string,
|
||||
) => {
|
||||
try {
|
||||
const data = {
|
||||
@ -606,16 +591,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
|
||||
@ -623,90 +607,89 @@ export const addSchedule = async (
|
||||
*/
|
||||
export const getSchedules = async () => {
|
||||
try {
|
||||
const response = await ecencyApi.post(`/private-api/schedules`)
|
||||
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;
|
||||
* @param id
|
||||
* @param id
|
||||
* @returns array of scheduled posts
|
||||
*/
|
||||
export const deleteScheduledPost = async (id: string) => {
|
||||
try {
|
||||
const data = { id };
|
||||
const response = await ecencyApi.post(`/private-api/schedules-delete`, data);
|
||||
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
|
||||
* @param id
|
||||
* @param id
|
||||
* @returns Array of scheduled posts
|
||||
*/
|
||||
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
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* IMAGES ECENCY APIS IMPLEMENTATION
|
||||
* IMAGES ECENCY APIS IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
|
||||
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,16 +702,15 @@ 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 };
|
||||
}
|
||||
};
|
||||
|
||||
@ -736,8 +718,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
|
||||
@ -747,16 +727,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
|
||||
@ -772,31 +750,26 @@ 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
|
||||
* Registers new user with ecency and hive, on confirmation sends
|
||||
* details to user email
|
||||
* @param username for new user
|
||||
* @param email of new user
|
||||
@ -808,8 +781,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) {
|
||||
@ -818,31 +791,35 @@ export const signUp = async (username: string, email: string, referral?: string)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* REFERRAL API IMPLEMENTATION
|
||||
* REFERRAL API IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
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 {
|
||||
@ -857,20 +834,23 @@ export const getReferralsStats = async (username: string): Promise<ReferralStat>
|
||||
console.warn(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* ************************************
|
||||
* EDIT HISTORY API IMPLEMENTATION
|
||||
* EDIT HISTORY API IMPLEMENTATION
|
||||
* ************************************
|
||||
*/
|
||||
|
||||
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) {
|
||||
@ -881,5 +861,4 @@ export const getCommentHistory = async (author: string, permlink: string): Promi
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -2,105 +2,105 @@ 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 {
|
||||
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);
|
||||
return useQuery([QUERIES.DRAFTS.GET], _getDrafts);
|
||||
};
|
||||
|
||||
/** used to return user schedules */
|
||||
export const useGetSchedulesQuery = () => {
|
||||
return useQuery([QUERIES.SCHEDULES.GET], _getSchedules);
|
||||
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' })));
|
||||
}
|
||||
})
|
||||
}
|
||||
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' })));
|
||||
}
|
||||
})
|
||||
}
|
||||
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 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');
|
||||
}
|
||||
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');
|
||||
}
|
||||
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();
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.schedule).getTime();
|
||||
const dateB = new Date(b.schedule).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
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();
|
||||
data.sort((a, b) => {
|
||||
const dateA = new Date(a.created).getTime();
|
||||
const dateB = new Date(b.created).getTime();
|
||||
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
return dateB > dateA ? 1 : -1;
|
||||
});
|
||||
|
@ -2,63 +2,70 @@ import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'rea
|
||||
import { useIntl } from 'react-intl';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { BeneficiarySelectionContent, DateTimePicker, MainButton, Modal, SettingsItem } from '../../../components';
|
||||
import { View as AnimatedView } from 'react-native-animatable';
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||
import {
|
||||
BeneficiarySelectionContent,
|
||||
DateTimePicker,
|
||||
MainButton,
|
||||
Modal,
|
||||
SettingsItem,
|
||||
} from '../../../components';
|
||||
import styles from './postOptionsModalStyles';
|
||||
import ThumbSelectionContent from './thumbSelectionContent';
|
||||
import {View as AnimatedView} from 'react-native-animatable';
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||
|
||||
const REWARD_TYPES = [
|
||||
{
|
||||
key:'default',
|
||||
intlId:'editor.reward_default'
|
||||
key: 'default',
|
||||
intlId: 'editor.reward_default',
|
||||
},
|
||||
{
|
||||
key:'sp',
|
||||
intlId:'editor.reward_power_up'
|
||||
key: 'sp',
|
||||
intlId: 'editor.reward_power_up',
|
||||
},
|
||||
{
|
||||
key:'dp',
|
||||
intlId:'editor.reward_decline'
|
||||
key: 'dp',
|
||||
intlId: 'editor.reward_decline',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
];
|
||||
|
||||
export interface PostOptionsModalRef {
|
||||
showModal:()=>void;
|
||||
showModal: () => void;
|
||||
}
|
||||
|
||||
|
||||
interface PostOptionsModalProps {
|
||||
body:string;
|
||||
draftId:string;
|
||||
thumbUrl:string,
|
||||
isEdit:boolean;
|
||||
isCommunityPost:boolean;
|
||||
body: string;
|
||||
draftId: string;
|
||||
thumbUrl: string;
|
||||
isEdit: boolean;
|
||||
isCommunityPost: boolean;
|
||||
rewardType: string;
|
||||
isUploading: boolean;
|
||||
handleRewardChange:(rewardType:string)=>void;
|
||||
handleThumbSelection:(url:string)=>void;
|
||||
handleScheduleChange:(datetime:string|null)=>void;
|
||||
handleShouldReblogChange:(shouldReblog:boolean)=>void;
|
||||
handleFormUpdate:()=>void;
|
||||
handleRewardChange: (rewardType: string) => void;
|
||||
handleThumbSelection: (url: string) => void;
|
||||
handleScheduleChange: (datetime: string | null) => void;
|
||||
handleShouldReblogChange: (shouldReblog: boolean) => void;
|
||||
handleFormUpdate: () => void;
|
||||
}
|
||||
|
||||
const PostOptionsModal = forwardRef(({
|
||||
body,
|
||||
draftId,
|
||||
thumbUrl,
|
||||
isEdit,
|
||||
isCommunityPost,
|
||||
rewardType,
|
||||
isUploading,
|
||||
handleRewardChange,
|
||||
handleThumbSelection,
|
||||
handleScheduleChange,
|
||||
handleShouldReblogChange,
|
||||
handleFormUpdate
|
||||
}: PostOptionsModalProps, ref) => {
|
||||
const PostOptionsModal = forwardRef(
|
||||
(
|
||||
{
|
||||
body,
|
||||
draftId,
|
||||
thumbUrl,
|
||||
isEdit,
|
||||
isCommunityPost,
|
||||
rewardType,
|
||||
isUploading,
|
||||
handleRewardChange,
|
||||
handleThumbSelection,
|
||||
handleScheduleChange,
|
||||
handleShouldReblogChange,
|
||||
handleFormUpdate,
|
||||
}: PostOptionsModalProps,
|
||||
ref,
|
||||
) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@ -70,84 +77,83 @@ const PostOptionsModal = forwardRef(({
|
||||
|
||||
// removed the useeffect causing index reset bug
|
||||
|
||||
useEffect(()=>{
|
||||
if(!scheduleLater){
|
||||
handleScheduleChange(null)
|
||||
}else if(scheduledFor) {
|
||||
handleScheduleChange(scheduledFor)
|
||||
}
|
||||
}, [scheduleLater, scheduledFor])
|
||||
|
||||
useEffect(() => {
|
||||
handleShouldReblogChange(shouldReblog)
|
||||
}, [shouldReblog])
|
||||
if (!scheduleLater) {
|
||||
handleScheduleChange(null);
|
||||
} else if (scheduledFor) {
|
||||
handleScheduleChange(scheduledFor);
|
||||
}
|
||||
}, [scheduleLater, scheduledFor]);
|
||||
|
||||
useEffect(() => {
|
||||
if(!isCommunityPost && shouldReblog){
|
||||
handleShouldReblogChange(shouldReblog);
|
||||
}, [shouldReblog]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCommunityPost && shouldReblog) {
|
||||
setShouldReblog(false);
|
||||
}
|
||||
}, [isCommunityPost])
|
||||
}, [isCommunityPost]);
|
||||
|
||||
// load rewardtype from props if it is already saved in drafts
|
||||
useEffect(() => {
|
||||
if(rewardType){
|
||||
let rewardTypeKey = REWARD_TYPES.findIndex((item) => item.key === rewardType)
|
||||
if (rewardType) {
|
||||
let rewardTypeKey = REWARD_TYPES.findIndex((item) => item.key === rewardType);
|
||||
setRewardTypeIndex(rewardTypeKey);
|
||||
}
|
||||
},[rewardType])
|
||||
}, [rewardType]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: () => {
|
||||
setShowModal(true);
|
||||
},
|
||||
}));
|
||||
show: () => {
|
||||
setShowModal(true);
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const _handleRewardChange = (index:number) => {
|
||||
setRewardTypeIndex(index)
|
||||
const rewardTypeKey = REWARD_TYPES[index].key
|
||||
const _handleRewardChange = (index: number) => {
|
||||
setRewardTypeIndex(index);
|
||||
const rewardTypeKey = REWARD_TYPES[index].key;
|
||||
if (handleRewardChange) {
|
||||
handleRewardChange(rewardTypeKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _handleDatePickerChange = (date:string) => {
|
||||
const _handleDatePickerChange = (date: string) => {
|
||||
setScheduledFor(date);
|
||||
}
|
||||
};
|
||||
|
||||
const _onDonePress = () => {
|
||||
setShowModal(false);
|
||||
handleFormUpdate();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// handle index change here instead of useeffetc
|
||||
const _handleThumbIndexSelection = (url:string) => {
|
||||
handleThumbSelection(url)
|
||||
}
|
||||
const _handleThumbIndexSelection = (url: string) => {
|
||||
handleThumbSelection(url);
|
||||
};
|
||||
|
||||
const _renderContent = () => (
|
||||
<View style={styles.fillSpace}>
|
||||
<KeyboardAwareScrollView style={styles.fillSpace} >
|
||||
<KeyboardAwareScrollView style={styles.fillSpace}>
|
||||
<View style={styles.container}>
|
||||
{!isEdit && (
|
||||
<>
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({id:'editor.scheduled_for'}) }
|
||||
title={intl.formatMessage({ id: 'editor.scheduled_for' })}
|
||||
type="dropdown"
|
||||
actionType="reward"
|
||||
options={[
|
||||
intl.formatMessage({id:"editor.scheduled_immediate"}),
|
||||
intl.formatMessage({id:"editor.scheduled_later"}),
|
||||
intl.formatMessage({ id: 'editor.scheduled_immediate' }),
|
||||
intl.formatMessage({ id: 'editor.scheduled_later' }),
|
||||
]}
|
||||
selectedOptionIndex={scheduleLater ? 1 : 0}
|
||||
handleOnChange={(index)=> {
|
||||
handleOnChange={(index) => {
|
||||
setScheduleLater(index === 1);
|
||||
if (index !== 1) {
|
||||
handleScheduleChange(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
{scheduleLater && (
|
||||
<AnimatedView animation="flipInX" duration={700}>
|
||||
<DateTimePicker
|
||||
@ -156,23 +162,19 @@ const PostOptionsModal = forwardRef(({
|
||||
disabled={true}
|
||||
/>
|
||||
</AnimatedView>
|
||||
|
||||
)}
|
||||
|
||||
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
id: 'editor.setting_reward',
|
||||
})}
|
||||
type="dropdown"
|
||||
actionType="reward"
|
||||
options={
|
||||
REWARD_TYPES.map((type)=>intl.formatMessage({ id: type.intlId}))
|
||||
}
|
||||
options={REWARD_TYPES.map((type) => intl.formatMessage({ id: type.intlId }))}
|
||||
selectedOptionIndex={rewardTypeIndex}
|
||||
handleOnChange={_handleRewardChange}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{isCommunityPost && (
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
@ -184,42 +186,33 @@ const PostOptionsModal = forwardRef(({
|
||||
handleOnChange={setShouldReblog}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
<ThumbSelectionContent
|
||||
|
||||
<ThumbSelectionContent
|
||||
body={body}
|
||||
thumbUrl={thumbUrl}
|
||||
isUploading={isUploading}
|
||||
onThumbSelection={_handleThumbIndexSelection}
|
||||
/>
|
||||
|
||||
|
||||
{!isEdit && (
|
||||
<BeneficiarySelectionContent
|
||||
draftId={draftId}
|
||||
setDisableDone={setDisableDone}
|
||||
/>
|
||||
<BeneficiarySelectionContent draftId={draftId} setDisableDone={setDisableDone} />
|
||||
)}
|
||||
|
||||
|
||||
</View>
|
||||
</KeyboardAwareScrollView>
|
||||
|
||||
<MainButton
|
||||
style={{...styles.saveButton }}
|
||||
style={{ ...styles.saveButton }}
|
||||
isDisable={disableDone}
|
||||
onPress={_onDonePress}
|
||||
text={intl.formatMessage({id:"editor.done"})}
|
||||
/>
|
||||
text={intl.formatMessage({ id: 'editor.done' })}
|
||||
/>
|
||||
</View>
|
||||
|
||||
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
return (
|
||||
<Modal
|
||||
isOpen={showModal}
|
||||
handleOnModalClose={() => {
|
||||
setShowModal(false);
|
||||
@ -228,14 +221,14 @@ const PostOptionsModal = forwardRef(({
|
||||
isFullScreen
|
||||
isCloseButton
|
||||
presentationStyle="formSheet"
|
||||
title={intl.formatMessage({id:"editor.settings_title"})}
|
||||
title={intl.formatMessage({ id: 'editor.settings_title' })}
|
||||
animationType="slide"
|
||||
style={styles.modalStyle}
|
||||
>
|
||||
{_renderContent()}
|
||||
</Modal>
|
||||
|
||||
);
|
||||
});
|
||||
{_renderContent()}
|
||||
</Modal>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default PostOptionsModal
|
||||
export default PostOptionsModal;
|
||||
|
@ -2,60 +2,59 @@ import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position:'absolute',
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
zIndex:999
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 999,
|
||||
},
|
||||
thumbStyle: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
marginVertical: 8,
|
||||
marginRight: 8,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
checkContainer: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 6,
|
||||
backgroundColor: '$pureWhite',
|
||||
borderRadius: 12,
|
||||
},
|
||||
settingLabel: {
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign: 'left',
|
||||
},
|
||||
listContainer: {
|
||||
paddingBottom: getBottomSpace() + 16,
|
||||
},
|
||||
container: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom: 20 },
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
||||
contentLabel: { color: '$iconColor', marginTop: 4, textAlign: 'left' },
|
||||
weightInput: { width: 80 },
|
||||
weightFormInput: { flex: 1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex: 1, color: '$primaryBlack', marginLeft: 16 },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop: 16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton: { borderRadius: 16, backgroundColor: '$primaryBlue' },
|
||||
thumbSelectContainer: {
|
||||
marginTop: 12,
|
||||
},
|
||||
thumbStyle:{
|
||||
width:72,
|
||||
height:72,
|
||||
marginVertical:8,
|
||||
marginRight:8,
|
||||
borderRadius:12,
|
||||
backgroundColor:'$primaryLightGray'
|
||||
},
|
||||
checkContainer:{
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 6,
|
||||
backgroundColor: '$pureWhite',
|
||||
borderRadius: 12
|
||||
},
|
||||
settingLabel:{
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign:'left',
|
||||
},
|
||||
listContainer:{
|
||||
paddingBottom:getBottomSpace() + 16,
|
||||
},
|
||||
container:{
|
||||
paddingVertical:16
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom:20},
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center'},
|
||||
contentLabel: { color: '$iconColor', marginTop:4, textAlign:'left' },
|
||||
weightInput: {width:80},
|
||||
weightFormInput: { flex:1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex:1, color: '$primaryBlack', marginLeft: 16 },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop:16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton:{borderRadius:16, backgroundColor:'$primaryBlue'},
|
||||
thumbSelectContainer:{
|
||||
marginTop:12,
|
||||
}
|
||||
});
|
||||
|
@ -3,115 +3,107 @@ import { useIntl } from 'react-intl';
|
||||
import { ActivityIndicator, Alert, Text, TouchableOpacity, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import styles from './styles';
|
||||
import ESStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { Icon } from '../../../components';
|
||||
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 { Icon } from '../../../components';
|
||||
|
||||
interface ThumbSelectionContentProps {
|
||||
body: string;
|
||||
thumbUrl: string;
|
||||
isUploading: boolean;
|
||||
onThumbSelection: (url: string) => void;
|
||||
body: string;
|
||||
thumbUrl: string;
|
||||
isUploading: boolean;
|
||||
onThumbSelection: (url: string) => void;
|
||||
}
|
||||
|
||||
const ThumbSelectionContent = ({ body, thumbUrl, onThumbSelection, isUploading }: ThumbSelectionContentProps) => {
|
||||
const intl = useIntl();
|
||||
const ThumbSelectionContent = ({
|
||||
body,
|
||||
thumbUrl,
|
||||
onThumbSelection,
|
||||
isUploading,
|
||||
}: ThumbSelectionContentProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
const [needMore, setNeedMore] = useState(true);
|
||||
const [thumbIndex, setThumbIndex] = useState(0);
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
const [needMore, setNeedMore] = useState(true);
|
||||
const [thumbIndex, setThumbIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const urls = extractImageUrls({ body });
|
||||
|
||||
useEffect(() => {
|
||||
const urls = extractImageUrls({ body });
|
||||
|
||||
if (urls.length < 2) {
|
||||
setNeedMore(true);
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
setImageUrls([])
|
||||
} else {
|
||||
setNeedMore(false);
|
||||
setImageUrls(urls)
|
||||
}
|
||||
|
||||
const _urlIndex = urls.indexOf(thumbUrl)
|
||||
if (_urlIndex < 0) {
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
} else {
|
||||
setThumbIndex(_urlIndex)
|
||||
}
|
||||
|
||||
}, [body])
|
||||
|
||||
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({ item, index }: { item: string, index: number }) => {
|
||||
const _onPress = () => {
|
||||
onThumbSelection(item);
|
||||
setThumbIndex(index);
|
||||
}
|
||||
|
||||
const isSelected = item === thumbUrl && index === thumbIndex;
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => _onPress()} >
|
||||
<FastImage
|
||||
source={{ uri: item }}
|
||||
style={styles.thumbStyle}
|
||||
resizeMode='cover'
|
||||
/>
|
||||
{isSelected && (
|
||||
|
||||
<AnimatedView duration={300} animation='zoomIn' style={styles.checkContainer}>
|
||||
<Icon
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
iconType="MaterialCommunityIcons"
|
||||
name={'checkbox-marked-circle'}
|
||||
size={20}
|
||||
/>
|
||||
</AnimatedView>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
</TouchableOpacity>
|
||||
)
|
||||
if (urls.length < 2) {
|
||||
setNeedMore(true);
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
setImageUrls([]);
|
||||
} else {
|
||||
setNeedMore(false);
|
||||
setImageUrls(urls);
|
||||
}
|
||||
|
||||
const _renderHeader = () => (
|
||||
isUploading &&
|
||||
<View style={{ flex: 1, justifyContent: 'center', marginRight: 16 }}>
|
||||
<ActivityIndicator color={ESStyleSheet.value('$primaryBlack')} />
|
||||
</View>
|
||||
const _urlIndex = urls.indexOf(thumbUrl);
|
||||
if (_urlIndex < 0) {
|
||||
onThumbSelection(urls[0] || '');
|
||||
setThumbIndex(0);
|
||||
} else {
|
||||
setThumbIndex(_urlIndex);
|
||||
}
|
||||
}, [body]);
|
||||
|
||||
)
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({ item, index }: { item: string; index: number }) => {
|
||||
const _onPress = () => {
|
||||
onThumbSelection(item);
|
||||
setThumbIndex(index);
|
||||
};
|
||||
|
||||
const isSelected = item === thumbUrl && index === thumbIndex;
|
||||
|
||||
return (
|
||||
<View style={styles.thumbSelectContainer}>
|
||||
<Text style={styles.settingLabel}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
{
|
||||
needMore ? (
|
||||
<Text style={styles.contentLabel}>{intl.formatMessage({ id: 'editor.add_more_imgs' })}</Text>
|
||||
) : (
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
ListHeaderComponent={_renderHeader}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false} />
|
||||
)
|
||||
}
|
||||
|
||||
</View>
|
||||
<TouchableOpacity onPress={() => _onPress()}>
|
||||
<FastImage source={{ uri: item }} style={styles.thumbStyle} resizeMode="cover" />
|
||||
{isSelected && (
|
||||
<AnimatedView duration={300} animation="zoomIn" style={styles.checkContainer}>
|
||||
<Icon
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
iconType="MaterialCommunityIcons"
|
||||
name="checkbox-marked-circle"
|
||||
size={20}
|
||||
/>
|
||||
</AnimatedView>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderHeader = () =>
|
||||
isUploading && (
|
||||
<View style={{ flex: 1, justifyContent: 'center', marginRight: 16 }}>
|
||||
<ActivityIndicator color={ESStyleSheet.value('$primaryBlack')} />
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.thumbSelectContainer}>
|
||||
<Text style={styles.settingLabel}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
{needMore ? (
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({ id: 'editor.add_more_imgs' })}
|
||||
</Text>
|
||||
) : (
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
ListHeaderComponent={_renderHeader}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThumbSelectionContent;
|
||||
|
@ -1,22 +1,20 @@
|
||||
import React, { useImperativeHandle, useRef, useState } from 'react';
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef } from 'react';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import ActionSheet from 'react-native-actions-sheet';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import styles from './styles';
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
import { View, Text, Alert, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { extractImageUrls } from '../../../utils/editor';
|
||||
import styles from './styles';
|
||||
|
||||
export interface ThumbSelectionModalProps {
|
||||
thumbUrl:string;
|
||||
onThumbSelection:(index:number)=>void;
|
||||
thumbUrl: string;
|
||||
onThumbSelection: (index: number) => void;
|
||||
}
|
||||
|
||||
|
||||
const ThumbSelectionModal = ({ onThumbSelection, thumbUrl }:ThumbSelectionModalProps, ref) => {
|
||||
const ThumbSelectionModal = ({ onThumbSelection, thumbUrl }: ThumbSelectionModalProps, ref) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [imageUrls, setImageUrls] = useState<string[]>([]);
|
||||
@ -24,82 +22,74 @@ const ThumbSelectionModal = ({ onThumbSelection, thumbUrl }:ThumbSelectionModalP
|
||||
|
||||
//CALLBACK_METHODS
|
||||
useImperativeHandle(ref, () => ({
|
||||
show: (postBody:string) => {
|
||||
console.log("Showing action modal")
|
||||
show: (postBody: string) => {
|
||||
console.log('Showing action modal');
|
||||
|
||||
const urls = extractImageUrls({body:postBody});
|
||||
const urls = extractImageUrls({ body: postBody });
|
||||
|
||||
if(urls.length < 2){
|
||||
console.log("Skipping modal show as post images are less than 2");
|
||||
Alert.alert(
|
||||
intl.formatMessage({id:'editor.two_thumbs_required'})
|
||||
)
|
||||
onThumbSelection(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setImageUrls(urls);
|
||||
sheetModalRef.current?.setModalVisible(true);
|
||||
if (urls.length < 2) {
|
||||
console.log('Skipping modal show as post images are less than 2');
|
||||
Alert.alert(intl.formatMessage({ id: 'editor.two_thumbs_required' }));
|
||||
onThumbSelection(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setImageUrls(urls);
|
||||
sheetModalRef.current?.setModalVisible(true);
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
const _onSelection = (index:number) => {
|
||||
const _onSelection = (index: number) => {
|
||||
onThumbSelection(index);
|
||||
sheetModalRef.current?.setModalVisible(false);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
//VIEW_RENDERERS
|
||||
const _renderImageItem = ({item, index}:{item:string, index:number}) => {
|
||||
const _onPress = () => {
|
||||
_onSelection(index);
|
||||
}
|
||||
const _renderImageItem = ({ item, index }: { item: string; index: number }) => {
|
||||
const _onPress = () => {
|
||||
_onSelection(index);
|
||||
};
|
||||
|
||||
const selectedStyle = item === thumbUrl ? styles.selectedStyle : null
|
||||
const selectedStyle = item === thumbUrl ? styles.selectedStyle : null;
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => _onPress()} >
|
||||
<FastImage
|
||||
source={{uri:item}}
|
||||
style={{...styles.thumbStyle, ...selectedStyle}}
|
||||
resizeMode='cover'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
<TouchableOpacity onPress={() => _onPress()}>
|
||||
<FastImage
|
||||
source={{ uri: item }}
|
||||
style={{ ...styles.thumbStyle, ...selectedStyle }}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderContent = () => {
|
||||
return (
|
||||
<View style={{alignItems:'center'}} >
|
||||
<Text style={styles.title}>{intl.formatMessage({id:'editor.select_thumb'})}</Text>
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
keyExtractor={(item, index)=>`${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Text style={styles.title}>{intl.formatMessage({ id: 'editor.select_thumb' })}</Text>
|
||||
<FlatList
|
||||
data={imageUrls}
|
||||
renderItem={_renderImageItem}
|
||||
keyExtractor={(item, index) => `${item}-${index}`}
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={false}
|
||||
hideUnderlay
|
||||
containerStyle={styles.sheetContent}
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
|
||||
>
|
||||
{_renderContent()}
|
||||
</ActionSheet>
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={false}
|
||||
hideUnderlay
|
||||
containerStyle={styles.sheetContent}
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
|
||||
>
|
||||
{_renderContent()}
|
||||
</ActionSheet>
|
||||
);
|
||||
};
|
||||
|
||||
export default forwardRef(ThumbSelectionModal);
|
||||
export default forwardRef(ThumbSelectionModal);
|
||||
|
@ -172,12 +172,10 @@ class EditorContainer extends Component<any, any> {
|
||||
this._fetchDraftsForComparison(isReply);
|
||||
}
|
||||
this._requestKeyboardFocus();
|
||||
|
||||
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<any>): void {
|
||||
if (
|
||||
prevState.rewardType !== this.state.rewardType ||
|
||||
@ -193,12 +191,12 @@ class EditorContainer extends Component<any, any> {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
_handleAppStateChange = (nextAppState:AppStateStatus) => {
|
||||
_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 } = this.props;
|
||||
|
@ -143,23 +143,23 @@ class EditorScreen extends Component {
|
||||
};
|
||||
|
||||
_handleOnSaveButtonPress = () => {
|
||||
const {draftId, intl} = this.props;
|
||||
if(draftId){
|
||||
Alert.alert(
|
||||
intl.formatMessage({id:'editor.draft_save_title'}),
|
||||
"",
|
||||
[{
|
||||
text:intl.formatMessage({id:'editor.draft_update'}),
|
||||
onPress:()=>this._saveDraftToDB(),
|
||||
},{
|
||||
text:intl.formatMessage({id:'editor.draft_save_new'}),
|
||||
onPress:()=>this._saveDraftToDB(true)
|
||||
},{
|
||||
text:intl.formatMessage({id:'alert.cancel'}),
|
||||
onPress:()=>{},
|
||||
style:'cancel'
|
||||
}]
|
||||
)
|
||||
const { draftId, intl } = this.props;
|
||||
if (draftId) {
|
||||
Alert.alert(intl.formatMessage({ id: 'editor.draft_save_title' }), '', [
|
||||
{
|
||||
text: intl.formatMessage({ id: 'editor.draft_update' }),
|
||||
onPress: () => this._saveDraftToDB(),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'editor.draft_save_new' }),
|
||||
onPress: () => this._saveDraftToDB(true),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'alert.cancel' }),
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
this._saveDraftToDB();
|
||||
@ -174,7 +174,7 @@ class EditorScreen extends Component {
|
||||
|
||||
this.changeTimer = setTimeout(() => {
|
||||
// saveCurrentDraft(fields);
|
||||
updateDraftFields(fields)
|
||||
updateDraftFields(fields);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
@ -182,7 +182,7 @@ class EditorScreen extends Component {
|
||||
const { handleOnSubmit, handleSchedulePress } = this.props;
|
||||
const { fields, scheduledFor } = this.state;
|
||||
|
||||
if(scheduledFor && handleSchedulePress){
|
||||
if (scheduledFor && handleSchedulePress) {
|
||||
handleSchedulePress(scheduledFor, fields);
|
||||
return;
|
||||
}
|
||||
@ -192,29 +192,28 @@ class EditorScreen extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleOnThumbSelection = (url:string) => {
|
||||
_handleOnThumbSelection = (url: string) => {
|
||||
const { setThumbUrl } = this.props;
|
||||
if (setThumbUrl) {
|
||||
setThumbUrl(url);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_handleScheduleChange = (datetime:string|null) => {
|
||||
_handleScheduleChange = (datetime: string | null) => {
|
||||
this.setState({
|
||||
scheduledFor:datetime,
|
||||
})
|
||||
}
|
||||
scheduledFor: datetime,
|
||||
});
|
||||
};
|
||||
|
||||
_handleRewardChange = (value) => {
|
||||
const { handleRewardChange } = this.props;
|
||||
handleRewardChange(value);
|
||||
}
|
||||
};
|
||||
_handleSettingsPress = () => {
|
||||
if(this.postOptionsModalRef){
|
||||
if (this.postOptionsModalRef) {
|
||||
this.postOptionsModalRef.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_handleIsFormValid = (bodyText) => {
|
||||
const { fields } = this.state;
|
||||
@ -255,7 +254,7 @@ class EditorScreen extends Component {
|
||||
});
|
||||
const jsonMeta = makeJsonMetadata(meta, fields.tags);
|
||||
fields.meta = jsonMeta;
|
||||
|
||||
|
||||
if (
|
||||
get(fields, 'body', '').trim() !== get(_fields, 'body', '').trim() ||
|
||||
get(fields, 'title', '').trim() !== get(_fields, 'title', '').trim() ||
|
||||
@ -264,7 +263,7 @@ class EditorScreen extends Component {
|
||||
) {
|
||||
console.log('jsonMeta : ', jsonMeta);
|
||||
handleFormChanged();
|
||||
|
||||
|
||||
this._saveCurrentDraft(fields);
|
||||
}
|
||||
|
||||
@ -338,7 +337,7 @@ class EditorScreen extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
_saveDraftToDB(saveAsNew?:boolean) {
|
||||
_saveDraftToDB(saveAsNew?: boolean) {
|
||||
const { saveDraftToDB } = this.props;
|
||||
const { fields } = this.state;
|
||||
|
||||
@ -388,10 +387,15 @@ class EditorScreen extends Component {
|
||||
} = 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
|
||||
|
@ -45,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;
|
||||
@ -55,32 +54,30 @@ export const generatePermlink = (title, random = false) => {
|
||||
const _length = text.length;
|
||||
|
||||
const textChunk = text.substring(_start > 0 ? _start : 0, _end < _length ? _end : _length);
|
||||
const indexChunk = index < 50 ? index : (
|
||||
_length - index < 50 ? textChunk.length - (_length - index) :
|
||||
RANGE
|
||||
);
|
||||
const indexChunk =
|
||||
index < 50 ? index : _length - index < 50 ? textChunk.length - (_length - index) : RANGE;
|
||||
|
||||
console.log('char at index: ', textChunk[indexChunk]);
|
||||
|
||||
const END_REGEX = /[\s,]/
|
||||
const END_REGEX = /[\s,]/;
|
||||
let word = '';
|
||||
for(let i = indexChunk; i >= 0 && (!END_REGEX.test(textChunk[i]) || i === indexChunk); i--){
|
||||
if(textChunk[i]){
|
||||
for (let i = indexChunk; i >= 0 && (!END_REGEX.test(textChunk[i]) || i === indexChunk); i--) {
|
||||
if (textChunk[i]) {
|
||||
word += textChunk[i];
|
||||
}
|
||||
}
|
||||
word = word.split('').reverse().join('');
|
||||
|
||||
if(!END_REGEX.test(textChunk[indexChunk])){
|
||||
for(let i = indexChunk + 1; i < textChunk.length && !END_REGEX.test(textChunk[i]); i++){
|
||||
if(textChunk[i]){
|
||||
|
||||
if (!END_REGEX.test(textChunk[indexChunk])) {
|
||||
for (let i = indexChunk + 1; i < textChunk.length && !END_REGEX.test(textChunk[i]); i++) {
|
||||
if (textChunk[i]) {
|
||||
word += textChunk[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return word;
|
||||
}
|
||||
};
|
||||
|
||||
export const generateReplyPermlink = (toAuthor) => {
|
||||
if (!toAuthor) {
|
||||
@ -168,52 +165,55 @@ export const makeJsonMetadataForUpdate = (oldJson, meta, tags) => {
|
||||
return Object.assign({}, oldJson, mergedMeta, { tags });
|
||||
};
|
||||
|
||||
|
||||
const extractUrls = (body:string) => {
|
||||
const extractUrls = (body: string) => {
|
||||
const urlReg = /(\b(https?|ftp):\/\/[A-Z0-9+&@#/%?=~_|!:,.;-]*[-A-Z0-9+&@#/%=~_|])/gim;
|
||||
const mUrls = body && body.match(urlReg);
|
||||
return mUrls || [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const extractImageUrls = ({body, urls}:{body?:string, urls?:string[]}) => {
|
||||
export const extractImageUrls = ({ body, urls }: { body?: string; urls?: string[] }) => {
|
||||
const imgReg = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif|heic|webp))/gim;
|
||||
|
||||
let imgUrls = [];
|
||||
const mUrls = urls || extractUrls(body);
|
||||
|
||||
mUrls.forEach((url)=>{
|
||||
mUrls.forEach((url) => {
|
||||
const isImage = url.match(imgReg);
|
||||
if (isImage) {
|
||||
imgUrls.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return imgUrls;
|
||||
}
|
||||
};
|
||||
|
||||
export const extractFilenameFromPath = ({path, mimeType}:{path:string, mimeType?:string}) => {
|
||||
try{
|
||||
if(!path){
|
||||
throw new Error("path not provided");
|
||||
export const extractFilenameFromPath = ({
|
||||
path,
|
||||
mimeType,
|
||||
}: {
|
||||
path: string;
|
||||
mimeType?: string;
|
||||
}) => {
|
||||
try {
|
||||
if (!path) {
|
||||
throw new Error('path not provided');
|
||||
}
|
||||
const filenameIndex = path.lastIndexOf('/') + 1;
|
||||
const extensionIndex = path.lastIndexOf('.');
|
||||
if(filenameIndex < 0 || extensionIndex <= filenameIndex){
|
||||
throw new Error("file name not present with extension");
|
||||
if (filenameIndex < 0 || extensionIndex <= filenameIndex) {
|
||||
throw new Error('file name not present with extension');
|
||||
}
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
|
||||
}catch(err){
|
||||
} catch (err) {
|
||||
let _ext = 'jpg';
|
||||
if(mimeType){
|
||||
_ext = MimeTypes.extension(mimeType)
|
||||
if (mimeType) {
|
||||
_ext = MimeTypes.extension(mimeType);
|
||||
}
|
||||
return `${generateRndStr()}.${_ext}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const extractMetadata = (body:string, thumbUrl?:string) => {
|
||||
export const extractMetadata = (body: string, thumbUrl?: string) => {
|
||||
const userReg = /(^|\s)(@[a-z][-.a-z\d]+[a-z\d])/gim;
|
||||
|
||||
const out = {};
|
||||
@ -221,16 +221,16 @@ export const extractMetadata = (body:string, thumbUrl?:string) => {
|
||||
const mUrls = extractUrls(body);
|
||||
const mUsers = body && body.match(userReg);
|
||||
|
||||
const matchedImages = extractImageUrls({urls:mUrls});
|
||||
const matchedImages = extractImageUrls({ urls: mUrls });
|
||||
const matchedLinks = [];
|
||||
const matchedUsers = [];
|
||||
|
||||
if (mUrls) {
|
||||
mUrls.forEach((url)=>{
|
||||
if(matchedImages.indexOf(url) < 0){
|
||||
mUrls.forEach((url) => {
|
||||
if (matchedImages.indexOf(url) < 0) {
|
||||
matchedLinks.push(url);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (matchedLinks.length) {
|
||||
@ -238,10 +238,10 @@ export const extractMetadata = (body:string, thumbUrl?:string) => {
|
||||
}
|
||||
|
||||
if (matchedImages.length) {
|
||||
if(thumbUrl){
|
||||
matchedImages.sort((item)=>item === thumbUrl ? -1 : 1);
|
||||
if (thumbUrl) {
|
||||
matchedImages.sort((item) => (item === thumbUrl ? -1 : 1));
|
||||
}
|
||||
|
||||
|
||||
out.image = matchedImages;
|
||||
}
|
||||
|
||||
@ -270,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));
|
||||
|
@ -8926,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"
|
||||
|
Loading…
Reference in New Issue
Block a user