Merge pull request #2365 from ecency/sa/cache-in-communities

Implemenetd cache on existing communities structure
This commit is contained in:
Feruz M 2022-07-06 15:41:03 +03:00 committed by GitHub
commit e489c2df45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 402 additions and 90 deletions

View File

@ -27,6 +27,7 @@ import { getUnreadNotificationCount } from '../../../providers/ecency/ecency';
import { decryptKey } from '../../../utils/crypto';
import { getPointsSummary} from '../../../providers/ecency/ePoint';
import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction';
import { clearSubscribedCommunitiesCache } from '../../../redux/actions/cacheActions';
const AccountsBottomSheetContainer = ({ navigation }) => {
const intl = useIntl();
@ -110,6 +111,7 @@ const AccountsBottomSheetContainer = ({ navigation }) => {
_currentAccount.mutes = await getMutes(_currentAccount.username);
dispatch(updateCurrentAccount(_currentAccount));
dispatch(clearSubscribedCommunitiesCache());
dispatch(fetchSubscribedCommunities(_currentAccount.username))
}

View File

@ -16,6 +16,7 @@ const CommunitiesList = ({
isLoggedIn,
noResult,
screen,
isDiscoversLoading,
}) => {
const _renderItem = ({ item, index }) => {
return (
@ -45,28 +46,29 @@ const CommunitiesList = ({
const _renderEmptyContent = () => {
return (
<>
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
</>
isDiscoversLoading && (
<>
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
<CommunitiesPlaceHolder />
</>
)
);
};
return (
<SafeAreaView style={styles.container}>
{!noResult && (
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
renderItem={_renderItem}
ListEmptyComponent={_renderEmptyContent}
/>
)}
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
renderItem={true && _renderItem}
ListEmptyComponent={_renderEmptyContent}
ListFooterComponent={isDiscoversLoading && <CommunitiesPlaceHolder />}
/>
</SafeAreaView>
);
};

View File

@ -28,7 +28,10 @@ const CommunitiesListItem = ({
const intl = useIntl();
const _handleSubscribeButtonPress = () => {
handleSubscribeButtonPress({ isSubscribed: isSubscribed, communityId: name }, screen);
handleSubscribeButtonPress(
{ isSubscribed: isSubscribed, communityId: name, communityTitle: title },
screen,
);
};
return (

View File

@ -14,15 +14,18 @@ import {
fetchSubscribedCommunities,
fetchSubscribedCommunitiesSuccess,
} from '../../../../redux/actions/communitiesAction';
import { mergeSubCommunitiesCacheInSubList } from '../../../../utils/communitiesUtils';
const SelectCommunityModalContainer = ({ onPressCommunity, currentAccount, onCloseModal }) => {
const dispatch = useDispatch();
const [searchedCommunities, setSearchedCommunities] = useState([]);
const [showSearchedCommunities, setShowSearchedCommunities] = useState(false);
const [subscriptions, setSubscriptions] = useState(null);
const topCommunities = useSelector((state) => state.communities.communities);
const subscribedCommunities = useSelector((state) => state.communities.subscribedCommunities);
const subscribedCommunitiesCache = useSelector((state) => state.cache.subscribedCommunities);
useEffect(() => {
callTopCommunities();
@ -31,7 +34,22 @@ const SelectCommunityModalContainer = ({ onPressCommunity, currentAccount, onClo
const callTopCommunities = () => dispatch(fetchCommunities('', 15, '', 'rank'));
const callSubscribedCommunities = () => dispatch(fetchSubscribedCommunities(currentAccount.name));
const callSubscribedCommunities = () => {
if (
subscribedCommunities &&
subscribedCommunities.data &&
subscribedCommunities.data.length > 0
) {
const updatedSubsList = mergeSubCommunitiesCacheInSubList(
subscribedCommunities.data,
subscribedCommunitiesCache,
);
if (updatedSubsList && updatedSubsList.length > 0) {
setSubscriptions(updatedSubsList.filter((item) => item[4] === true));
}
}
dispatch(fetchSubscribedCommunities(currentAccount.name));
};
const handleChangeSearch = (text) => {
if (text.length >= 3) {
@ -53,7 +71,7 @@ const SelectCommunityModalContainer = ({ onPressCommunity, currentAccount, onClo
<SelectCommunityModalView
onPressCommunity={onPressCommunity}
topCommunities={topCommunities}
subscribedCommunities={subscribedCommunities}
subscribedCommunities={subscriptions}
onChangeSearch={debounce(handleChangeSearch, 500)}
searchedCommunities={searchedCommunities}
showSearchedCommunities={showSearchedCommunities}

View File

@ -60,32 +60,30 @@ const SelectCommunityModalView = ({
}}
onPress={() => onPressCommunity(null)}
/>
{!subscribedCommunities.loading &&
!subscribedCommunities.error &&
subscribedCommunities.data?.length > 0 && (
<View>
<Text style={[globalStyles.label, styles.title]}>
{intl.formatMessage({ id: 'editor.my_communities' }).toUpperCase()}
</Text>
<FlatList
ItemSeparatorComponent={() => <Separator />}
showsVerticalScrollIndicator={false}
data={subscribedCommunities.data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index, separators }) => {
const community = { name: item[0], title: item[1] };
return (
<CommunityCard
community={community}
key={community.name}
onPress={onPressCommunity}
separators={separators}
/>
);
}}
/>
</View>
)}
{subscribedCommunities && (
<View>
<Text style={[globalStyles.label, styles.title]}>
{intl.formatMessage({ id: 'editor.my_communities' }).toUpperCase()}
</Text>
<FlatList
ItemSeparatorComponent={() => <Separator />}
showsVerticalScrollIndicator={false}
data={subscribedCommunities}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index, separators }) => {
const community = { name: item[0], title: item[1] };
return (
<CommunityCard
community={community}
key={community.name}
onPress={onPressCommunity}
separators={separators}
/>
);
}}
/>
</View>
)}
{!topCommunities.loading && !topCommunities.error && topCommunities.data?.length > 0 && (
<View>
<Text style={[globalStyles.label, styles.title]}>

View File

@ -79,8 +79,11 @@ const SubscribedCommunitiesListView = ({
onPress={() =>
handleSubscribeButtonPress(
{
isSubscribed: item[4],
communityId: item[0],
communityTitle: item[1],
userRole: item[2],
userLabel: item[3],
isSubscribed: item[4],
},
'communitiesScreenJoinedTab',
)

View File

@ -8,8 +8,11 @@ import {
DELETE_COMMENT_CACHE_ENTRY,
UPDATE_DRAFT_CACHE,
DELETE_DRAFT_CACHE_ENTRY,
UPDATE_SUBSCRIBED_COMMUNITY_CACHE,
DELETE_SUBSCRIBED_COMMUNITY_CACHE,
CLEAR_SUBSCRIBED_COMMUNITIES_CACHE,
} from '../constants/constants';
import { Comment, Draft, Vote } from '../reducers/cacheReducer';
import { Comment, Draft, SubscribedCommunity, Vote } from '../reducers/cacheReducer';
@ -87,6 +90,37 @@ export const deleteDraftCacheEntry = (id: string) => ({
type: DELETE_DRAFT_CACHE_ENTRY
})
export const updateSubscribedCommunitiesCache = (data: any) => {
const path = data.communityId;
const created = new Date();
const communityTitle = data.communityTitle ? data.communityTitle : '';
const userRole = data.userRole ? data.userRole : '';
const userLabel = data.userLabel ? data.userLabel : '';
const subscribedCommunity:SubscribedCommunity = {
data : [data.communityId, communityTitle, userRole, userLabel, !data.isSubscribed],
expiresAt : created.getTime() + 86400000,
};
return ({
payload: {
path,
subscribedCommunity
},
type: UPDATE_SUBSCRIBED_COMMUNITY_CACHE
})
}
export const deleteSubscribedCommunityCacheEntry = (path: string) => ({
payload: path,
type: DELETE_SUBSCRIBED_COMMUNITY_CACHE
})
export const clearSubscribedCommunitiesCache = () => ({
type: CLEAR_SUBSCRIBED_COMMUNITIES_CACHE
})
export const purgeExpiredCache = () => ({
type: PURGE_EXPIRED_CACHE
})

View File

@ -45,7 +45,11 @@ export const fetchSubscribedCommunities = (username) => {
return (dispatch) => {
dispatch({ type: FETCH_SUBSCRIBED_COMMUNITIES });
getSubscriptions(username)
.then((res) => dispatch(fetchSubscribedCommunitiesSuccess(res)))
.then((res) => {
res.forEach((item) => item.push(true)); //add true value for subscribe status
res.sort((a, b) => a[1].localeCompare(b[1]));
dispatch(fetchSubscribedCommunitiesSuccess(res));
})
.catch((err) => dispatch(fetchSubscribedCommunitiesFail(err)));
};
};

View File

@ -0,0 +1,6 @@
export const statusMessage = {
PENDING : 'PENDING',
SUCCESS : 'SUCCESS',
FAIL : 'FAIL',
};

View File

@ -114,6 +114,9 @@ export const DELETE_COMMENT_CACHE_ENTRY = 'DELETE_COMMENT_CACHE_ENTRY';
export const UPDATE_DRAFT_CACHE = 'UPDATE_DRAFT_CACHE';
export const DELETE_DRAFT_CACHE_ENTRY = 'DELETE_DRAFT_CACHE_ENTRY';
export const DEFAULT_USER_DRAFT_ID = 'DEFAULT_USER_DRAFT_ID_';
export const UPDATE_SUBSCRIBED_COMMUNITY_CACHE = 'UPDATE_SUBSCRIBED_COMMUNITY_CACHE';
export const DELETE_SUBSCRIBED_COMMUNITY_CACHE = 'DELETE_SUBSCRIBED_COMMUNITY_CACHE';
export const CLEAR_SUBSCRIBED_COMMUNITIES_CACHE = 'CLEAR_SUBSCRIBED_COMMUNITIES_CACHE';
// TOOLTIPS
export const REGISTER_TOOLTIP = 'REGISTER_TOOLTIP';

View File

@ -1,4 +1,4 @@
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY, DELETE_DRAFT_CACHE_ENTRY, UPDATE_DRAFT_CACHE, } from "../constants/constants";
import { PURGE_EXPIRED_CACHE, UPDATE_VOTE_CACHE, UPDATE_COMMENT_CACHE, DELETE_COMMENT_CACHE_ENTRY, DELETE_DRAFT_CACHE_ENTRY, UPDATE_DRAFT_CACHE, UPDATE_SUBSCRIBED_COMMUNITY_CACHE, DELETE_SUBSCRIBED_COMMUNITY_CACHE, CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, } from "../constants/constants";
export interface Vote {
amount:number;
@ -37,10 +37,15 @@ export interface Draft {
expiresAt?:number;
}
export interface SubscribedCommunity {
data: Array<any>,
expiresAt?:number;
}
interface State {
votes:Map<string, Vote>
comments:Map<string, Comment> //TODO: handle comment array per post, if parent is same
drafts: Map<string, Draft>
subscribedCommunities: Map<string, SubscribedCommunity>
lastUpdate:{
postPath:string,
updatedAt:number,
@ -52,6 +57,7 @@ const initialState:State = {
votes:new Map(),
comments:new Map(),
drafts: new Map(),
subscribedCommunities: new Map(),
lastUpdate:null,
};
@ -121,6 +127,28 @@ const initialState:State = {
}
return { ...state }
case UPDATE_SUBSCRIBED_COMMUNITY_CACHE:
if(!state.subscribedCommunities){
state.subscribedCommunities = new Map<string, SubscribedCommunity>();
}
const subscribedCommunities = new Map(state.subscribedCommunities);
subscribedCommunities.set(payload.path, payload.subscribedCommunity);
return {
...state, //spread operator in requried here, otherwise persist do not register change
subscribedCommunities: subscribedCommunities
};
case DELETE_SUBSCRIBED_COMMUNITY_CACHE:
if (state.subscribedCommunities && state.subscribedCommunities.has(payload)) {
state.subscribedCommunities.delete(payload);
}
return { ...state }
case CLEAR_SUBSCRIBED_COMMUNITIES_CACHE:
state.subscribedCommunities = new Map<string, SubscribedCommunity>();
return {...state}
case PURGE_EXPIRED_CACHE:
const currentTime = new Date().getTime();
@ -147,6 +175,14 @@ const initialState:State = {
}
})
}
if(state.subscribedCommunities && state.subscribedCommunities.size){
Array.from(state.subscribedCommunities).forEach((entry)=>{
if(entry[1].expiresAt < currentTime){
state.subscribedCommunities.delete(entry[0]);
}
})
}
return {
...state

View File

@ -12,6 +12,7 @@ import {
LEAVE_COMMUNITY_SUCCESS,
LEAVE_COMMUNITY_FAIL,
} from '../constants/constants';
import { statusMessage } from '../constants/communitiesConstants';
const initialState = {
communities: {
@ -23,6 +24,7 @@ const initialState = {
data: [],
loading: false,
error: false,
status: statusMessage.PENDING,
},
subscribingCommunitiesInFeedScreen: {
//['name']: {
@ -90,6 +92,7 @@ export default function (state = initialState, action) {
data: [],
loading: true,
error: false,
status: statusMessage.PENDING,
},
};
case FETCH_SUBSCRIBED_COMMUNITIES_SUCCESS:
@ -99,6 +102,7 @@ export default function (state = initialState, action) {
data: action.payload || [],
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
};
case FETCH_SUBSCRIBED_COMMUNITIES_FAIL:
@ -108,6 +112,7 @@ export default function (state = initialState, action) {
data: [],
loading: false,
error: action.payload,
status: statusMessage.FAIL,
},
};
case SUBSCRIBE_COMMUNITY:
@ -121,6 +126,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -133,6 +139,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -145,6 +152,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -157,6 +165,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -174,6 +183,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -186,6 +196,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -198,6 +209,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -210,6 +222,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -227,6 +240,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -239,6 +253,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -251,6 +266,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -263,6 +279,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -280,6 +297,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -292,6 +310,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -304,6 +323,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -316,6 +336,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: true,
error: false,
status: statusMessage.PENDING,
},
},
};
@ -333,6 +354,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -345,6 +367,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -357,6 +380,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -369,6 +393,7 @@ export default function (state = initialState, action) {
isSubscribed: false,
loading: false,
error: false,
status: statusMessage.SUCCESS,
},
},
};
@ -386,6 +411,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -398,6 +424,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -410,6 +437,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};
@ -422,6 +450,7 @@ export default function (state = initialState, action) {
isSubscribed: true,
loading: false,
error: true,
status: statusMessage.FAIL,
},
},
};

View File

@ -13,12 +13,14 @@ const transformCacheVoteMap = createTransform(
votes : Array.from(inboundState.votes),
comments : Array.from(inboundState.comments),
drafts : Array.from(inboundState.drafts),
subscribedCommunities: Array.from(inboundState.subscribedCommunities)
}),
(outboundState) => ({
...outboundState,
votes:new Map(outboundState.votes),
comments:new Map(outboundState.comments),
drafts: new Map(outboundState.drafts)
drafts: new Map(outboundState.drafts),
subscribedCommunities: new Map(outboundState.subscribedCommunities)
}),
{whitelist:['cache']}
);

View File

@ -1,14 +1,27 @@
import { useState, useEffect } from 'react';
import { withNavigation } from 'react-navigation';
import { useSelector, useDispatch } from 'react-redux';
import { shuffle } from 'lodash';
import { shuffle, isEmpty } from 'lodash';
import { useIntl } from 'react-intl';
import ROUTES from '../../../constants/routeNames';
import { getCommunities, getSubscriptions } from '../../../providers/hive/dhive';
import { subscribeCommunity, leaveCommunity } from '../../../redux/actions/communitiesAction';
import {
subscribeCommunity,
leaveCommunity,
fetchSubscribedCommunitiesSuccess,
} from '../../../redux/actions/communitiesAction';
import { statusMessage } from '../../../redux/constants/communitiesConstants';
import {
deleteSubscribedCommunityCacheEntry,
updateSubscribedCommunitiesCache,
} from '../../../redux/actions/cacheActions';
import {
mergeSubCommunitiesCacheInDiscoverList,
mergeSubCommunitiesCacheInSubList,
} from '../../../utils/communitiesUtils';
const CommunitiesContainer = ({ children, navigation }) => {
const dispatch = useDispatch();
@ -17,23 +30,67 @@ const CommunitiesContainer = ({ children, navigation }) => {
const [discovers, setDiscovers] = useState([]);
const [subscriptions, setSubscriptions] = useState([]);
const [isSubscriptionsLoading, setIsSubscriptionsLoading] = useState(true);
const [isDiscoversLoading, setIsDiscoversLoading] = useState(true);
const [selectedCommunityItem, setSelectedCommunityItem] = useState(null);
const currentAccount = useSelector((state) => state.account.currentAccount);
const pinCode = useSelector((state) => state.application.pin);
const subscribedCommunities = useSelector((state) => state.communities.subscribedCommunities);
const subscribingCommunitiesInDiscoverTab = useSelector(
(state) => state.communities.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
);
const subscribingCommunitiesInJoinedTab = useSelector(
(state) => state.communities.subscribingCommunitiesInCommunitiesScreenJoinedTab,
);
const subscribedCommunitiesCache = useSelector((state) => state.cache.subscribedCommunities);
useEffect(() => {
_getSubscriptions();
}, []);
// handle cache in joined/membership tab
useEffect(() => {
if (subscribingCommunitiesInJoinedTab && selectedCommunityItem) {
const { status } = subscribingCommunitiesInJoinedTab[selectedCommunityItem.communityId];
if (status === statusMessage.SUCCESS) {
dispatch(updateSubscribedCommunitiesCache(selectedCommunityItem));
}
}
}, [subscribingCommunitiesInJoinedTab]);
// handle cache in discover tab
useEffect(() => {
if (subscribingCommunitiesInDiscoverTab && selectedCommunityItem) {
const { status } = subscribingCommunitiesInDiscoverTab[selectedCommunityItem.communityId];
if (status === statusMessage.SUCCESS) {
dispatch(updateSubscribedCommunitiesCache(selectedCommunityItem));
}
}
}, [subscribingCommunitiesInDiscoverTab]);
// side effect for subscribed communities cache update
useEffect(() => {
if (
subscribedCommunitiesCache &&
subscribedCommunitiesCache.size &&
subscriptions &&
subscriptions.length > 0
) {
const updatedSubsList = mergeSubCommunitiesCacheInSubList(
subscriptions,
subscribedCommunitiesCache,
);
const updatedDiscoversList = mergeSubCommunitiesCacheInDiscoverList(
discovers,
subscribedCommunitiesCache,
);
setSubscriptions(updatedSubsList.slice());
setDiscovers(updatedDiscoversList);
}
}, [subscribedCommunitiesCache]);
useEffect(() => {
const discoversData = [...discovers];
Object.keys(subscribingCommunitiesInDiscoverTab).map((communityId) => {
if (!subscribingCommunitiesInDiscoverTab[communityId].loading) {
if (!subscribingCommunitiesInDiscoverTab[communityId].error) {
@ -58,36 +115,54 @@ const CommunitiesContainer = ({ children, navigation }) => {
}, [subscribingCommunitiesInDiscoverTab]);
useEffect(() => {
const subscribedsData = [...subscriptions];
Object.keys(subscribingCommunitiesInJoinedTab).map((communityId) => {
if (!subscribingCommunitiesInJoinedTab[communityId].loading) {
if (!subscribingCommunitiesInJoinedTab[communityId].error) {
if (subscribingCommunitiesInJoinedTab[communityId].isSubscribed) {
subscribedsData.forEach((item) => {
if (item[0] === communityId) {
item[4] = true;
}
});
} else {
subscribedsData.forEach((item) => {
if (item[0] === communityId) {
item[4] = false;
}
});
if (!isEmpty(subscribingCommunitiesInJoinedTab)) {
const subscribedsData = mergeSubCommunitiesCacheInSubList(
subscribedCommunities.data,
subscribedCommunitiesCache,
);
Object.keys(subscribingCommunitiesInJoinedTab).map((communityId) => {
if (!subscribingCommunitiesInJoinedTab[communityId].loading) {
if (!subscribingCommunitiesInJoinedTab[communityId].error) {
if (subscribingCommunitiesInJoinedTab[communityId].isSubscribed) {
subscribedsData.forEach((item) => {
if (item[0] === communityId) {
item[4] = true;
}
});
} else {
subscribedsData.forEach((item) => {
if (item[0] === communityId) {
item[4] = false;
}
});
}
}
}
}
});
});
setSubscriptions(subscribedsData);
setSubscriptions(subscribedsData);
}
}, [subscribingCommunitiesInJoinedTab]);
const _getSubscriptions = () => {
setIsSubscriptionsLoading(true);
setIsDiscoversLoading(true);
if (
subscribedCommunities &&
subscribedCommunities.data &&
subscribedCommunities.data.length > 0
) {
const updatedSubsList = mergeSubCommunitiesCacheInSubList(
subscribedCommunities.data,
subscribedCommunitiesCache,
);
setSubscriptions(updatedSubsList.slice());
setIsSubscriptionsLoading(false);
}
getSubscriptions(currentAccount.username)
.then((subs) => {
subs.forEach((item) => item.push(true));
_invalidateSubscribedCommunityCache(subs); // invalidate subscribed communities cache item when latest data is available
getCommunities('', 50, null, 'rank').then((communities) => {
communities.forEach((community) =>
Object.assign(community, {
@ -97,17 +172,30 @@ const CommunitiesContainer = ({ children, navigation }) => {
}),
);
setSubscriptions(subs);
setDiscovers(shuffle(communities));
setSubscriptions(mergeSubCommunitiesCacheInSubList(subs, subscribedCommunitiesCache)); //merge cache with fetched data
setDiscovers(communities);
setIsSubscriptionsLoading(false);
setIsDiscoversLoading(false);
dispatch(
fetchSubscribedCommunitiesSuccess(subs.sort((a, b) => a[1].localeCompare(b[1]))),
); //register subscribed data in communities store
});
})
.catch((err) => {
console.warn('Failed to get subscriptions', err);
setIsSubscriptionsLoading(false);
setIsDiscoversLoading(false);
});
};
const _invalidateSubscribedCommunityCache = (fetchedList) => {
fetchedList.map((listItem) => {
let itemExists = subscribedCommunitiesCache.get(listItem[0]);
if (itemExists) {
dispatch(deleteSubscribedCommunityCacheEntry(listItem[0]));
}
});
};
// Component Functions
const _handleOnPress = (name) => {
navigation.navigate({
@ -119,6 +207,7 @@ const CommunitiesContainer = ({ children, navigation }) => {
};
const _handleSubscribeButtonPress = (data, screen) => {
setSelectedCommunityItem(data); //set selected item to handle its cache
let subscribeAction;
let successToastText = '';
let failToastText = '';
@ -156,6 +245,7 @@ const CommunitiesContainer = ({ children, navigation }) => {
subscribingCommunitiesInDiscoverTab,
subscribingCommunitiesInJoinedTab,
isSubscriptionsLoading,
isDiscoversLoading,
handleOnPress: _handleOnPress,
handleSubscribeButtonPress: _handleSubscribeButtonPress,
handleGetSubscriptions: _getSubscriptions,

View File

@ -47,6 +47,7 @@ const CommunitiesScreen = () => {
subscribingCommunitiesInJoinedTab,
handleGetSubscriptions,
isSubscriptionsLoading,
isDiscoversLoading,
}) => {
return (
<View style={styles.container}>
@ -87,6 +88,7 @@ const CommunitiesScreen = () => {
isLoggedIn={true}
noResult={discovers.length === 0}
screen="communitiesScreenDiscoverTab"
isDiscoversLoading={isDiscoversLoading}
/>
</View>
</ScrollableTabView>

View File

@ -1,7 +1,7 @@
import { useState, useEffect } from 'react';
import { withNavigation } from 'react-navigation';
import get from 'lodash/get';
import { connect, useDispatch } from 'react-redux';
import { connect, useDispatch, useSelector } from 'react-redux';
import { useIntl } from 'react-intl';
import { getCommunity, getSubscriptions } from '../../../providers/hive/dhive';
@ -9,14 +9,32 @@ import { getCommunity, getSubscriptions } from '../../../providers/hive/dhive';
import { subscribeCommunity, leaveCommunity } from '../../../redux/actions/communitiesAction';
import ROUTES from '../../../constants/routeNames';
import { updateSubscribedCommunitiesCache } from '../../../redux/actions/cacheActions';
import { statusMessage } from '../../../redux/constants/communitiesConstants';
const CommunityContainer = ({ children, navigation, currentAccount, pinCode, isLoggedIn }) => {
const [data, setData] = useState(null);
const [isSubscribed, setIsSubscribed] = useState(false);
const [selectedCommunityItem, setSelectedCommunityItem] = useState(null);
const tag = get(navigation, 'state.params.tag');
const dispatch = useDispatch();
const intl = useIntl();
const subscribingCommunitiesInDiscoverTab = useSelector(
(state) => state.communities.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
);
const subscribedCommunitiesCache = useSelector((state) => state.cache.subscribedCommunities);
useEffect(() => {
if (subscribingCommunitiesInDiscoverTab && selectedCommunityItem) {
const { status } = subscribingCommunitiesInDiscoverTab[selectedCommunityItem.communityId];
if (status === statusMessage.SUCCESS) {
dispatch(updateSubscribedCommunitiesCache(selectedCommunityItem));
}
}
}, [subscribingCommunitiesInDiscoverTab]);
useEffect(() => {
getCommunity(tag)
.then((res) => {
@ -29,17 +47,26 @@ const CommunityContainer = ({ children, navigation, currentAccount, pinCode, isL
useEffect(() => {
if (data) {
//check and set user role
getSubscriptions(currentAccount.username)
.then((result) => {
if (result) {
const _isSubscribed = result.some((item) => item[0] === data.name);
setIsSubscribed(_isSubscribed);
}
})
.catch((e) => {
console.log(e);
});
if (
subscribedCommunitiesCache &&
subscribedCommunitiesCache.size &&
subscribedCommunitiesCache.get(data.name)
) {
const itemExistInCache = subscribedCommunitiesCache.get(data.name);
setIsSubscribed(itemExistInCache.data[4]); //if item exist in cache, get isSubscribed value from cache
} else {
//check and set user role
getSubscriptions(currentAccount.username)
.then((result) => {
if (result) {
const _isSubscribed = result.some((item) => item[0] === data.name);
setIsSubscribed(_isSubscribed);
}
})
.catch((e) => {
console.log(e);
});
}
}
}, [data]);
@ -48,6 +75,7 @@ const CommunityContainer = ({ children, navigation, currentAccount, pinCode, isL
isSubscribed: isSubscribed,
communityId: data.name,
};
setSelectedCommunityItem(_data); //set selected item to handle its cache
const screen = 'communitiesScreenDiscoverTab';
let subscribeAction;
let successToastText = '';

View File

@ -33,7 +33,7 @@ const CommunitiesResultsContainer = ({ children, navigation, searchValue }) => {
const [data, setData] = useState([]);
const [noResult, setNoResult] = useState(false);
const [isDiscoversLoading, setIsDiscoversLoading] = useState(false);
const pinCode = useSelector((state) => state.application.pin);
const currentAccount = useSelector((state) => state.account.currentAccount);
const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
@ -44,7 +44,7 @@ const CommunitiesResultsContainer = ({ children, navigation, searchValue }) => {
useEffect(() => {
setData([]);
setNoResult(false);
setIsDiscoversLoading(true);
getCommunities('', searchValue ? 100 : 20, searchValue || null, 'rank')
.then((communities) => {
if (currentAccount && currentAccount.username) {
@ -78,10 +78,12 @@ const CommunitiesResultsContainer = ({ children, navigation, searchValue }) => {
setNoResult(true);
}
}
setIsDiscoversLoading(false);
})
.catch((err) => {
setNoResult(true);
setData([]);
setIsDiscoversLoading(false);
});
}, [searchValue]);
@ -160,6 +162,7 @@ const CommunitiesResultsContainer = ({ children, navigation, searchValue }) => {
handleSubscribeButtonPress: _handleSubscribeButtonPress,
isLoggedIn,
noResult,
isDiscoversLoading,
})
);
};

View File

@ -18,6 +18,7 @@ const CommunitiesResultsScreen = ({ navigation, searchValue }) => {
handleSubscribeButtonPress,
isLoggedIn,
noResult,
isDiscoversLoading,
}) =>
noResult ? (
<EmptyScreen />
@ -30,6 +31,7 @@ const CommunitiesResultsScreen = ({ navigation, searchValue }) => {
isLoggedIn={isLoggedIn}
noResult={noResult}
screen="searchResultsScreen"
isDiscoversLoading={isDiscoversLoading}
/>
)
}

View File

@ -0,0 +1,47 @@
import { SubscribedCommunity } from '../redux/reducers/cacheReducer';
/**
* Accepts Array of subscription items arrays as 1st argument, community cache map as second argument.
* Returns single array with union of both lists, sorted alphabatically
* Example subList = [['id', 'title', 'role', 'label', 'true/false'],['id', 'title', 'role', 'label', 'true/false']]
*
**/
export const mergeSubCommunitiesCacheInSubList = (
subList: any[],
cacheMap: Map<string, SubscribedCommunity>,
) => {
if (!cacheMap || !cacheMap.size) {
return subList.sort((a, b) => a[1].localeCompare(b[1]));
}
const cacheList = Array.from(cacheMap, ([path, item]) => item.data);
cacheList.map((cacheListItem) => {
let index = subList.findIndex((subListItem) => subListItem[0] === cacheListItem[0]);
if (index !== -1) {
subList[index] = [...cacheListItem];
} else {
subList.push(cacheListItem);
}
});
return subList.sort((a, b) => a[1].localeCompare(b[1]));
};
/**
* Accepts Array of discover items arrays as 1st argument, community cache map as second argument.
* Returns discovers list with updated isSubscribed status
*
**/
export const mergeSubCommunitiesCacheInDiscoverList = (
discoverList: any[],
cacheMap: Map<string, SubscribedCommunity>,
) => {
if (!cacheMap || !cacheMap.size) {
return discoverList;
}
discoverList.forEach((discoverListItem) => {
let itemExist = cacheMap.get(discoverListItem.name);
if (itemExist) {
discoverListItem.isSubscribed = itemExist.data[4];
}
});
return discoverList;
};