From 22121d9952e1268b8197baa55eb6969ac0b52dcd Mon Sep 17 00:00:00 2001
From: Szymon Szlachtowicz <38212223+Szymx95@users.noreply.github.com>
Date: Wed, 14 Jul 2021 10:46:25 +0200
Subject: [PATCH] Improve useCommunities (#113)
---
.../components/directory/DirectoryCards.tsx | 10 ++-
.../DApp/src/components/votes/VotingCards.tsx | 10 ++-
.../DApp/src/helpers/communityFiltering.ts | 78 ++++++++---------
packages/DApp/src/hooks/useCommunities.ts | 84 ++++---------------
.../DApp/src/hooks/useCommunityDetails.ts | 27 ++----
.../DApp/src/hooks/useDirectoryCommunities.ts | 22 ++---
.../DApp/src/hooks/useVotingCommunities.ts | 31 ++++---
packages/DApp/src/index.tsx | 5 +-
.../src/providers/communities/provider.tsx | 31 +++++++
9 files changed, 134 insertions(+), 164 deletions(-)
create mode 100644 packages/DApp/src/providers/communities/provider.tsx
diff --git a/packages/DApp/src/components/directory/DirectoryCards.tsx b/packages/DApp/src/components/directory/DirectoryCards.tsx
index 4bb62b2..5bbbad7 100644
--- a/packages/DApp/src/components/directory/DirectoryCards.tsx
+++ b/packages/DApp/src/components/directory/DirectoryCards.tsx
@@ -101,9 +101,13 @@ export function DirectoryCards() {
- {communities.map((community) => (
-
- ))}
+ {communities.map((community, idx) => {
+ if (community) {
+ return
+ } else {
+ return
+ }
+ })}
{communities.length === 0 && }
>
diff --git a/packages/DApp/src/components/votes/VotingCards.tsx b/packages/DApp/src/components/votes/VotingCards.tsx
index 593dfb9..116702b 100644
--- a/packages/DApp/src/components/votes/VotingCards.tsx
+++ b/packages/DApp/src/components/votes/VotingCards.tsx
@@ -45,9 +45,13 @@ export function VotingCards() {
- {roomsToShow.map((room: any) => (
-
- ))}
+ {roomsToShow.map((room: any, idx) => {
+ if (room?.details) {
+ return
+ } else {
+ return
+ }
+ })}
{roomsToShow.length === 0 && }
)
diff --git a/packages/DApp/src/helpers/communityFiltering.ts b/packages/DApp/src/helpers/communityFiltering.ts
index 9438cbd..43ca732 100644
--- a/packages/DApp/src/helpers/communityFiltering.ts
+++ b/packages/DApp/src/helpers/communityFiltering.ts
@@ -26,63 +26,65 @@ export function isTypeInRoom(voteType: string, room: any) {
}
export function sortVotingFunction(sortedBy: VotingSortingEnum) {
- switch (sortedBy) {
- case VotingSortingEnum.AtoZ:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => (a.details.name < b.details.name ? -1 : 1)
- case VotingSortingEnum.ZtoA:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => (a.details.name < b.details.name ? 1 : -1)
- case VotingSortingEnum.EndingLatest:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
+ return (a: DetailedVotingRoom | undefined, b: DetailedVotingRoom | undefined) => {
+ if (!a) {
+ return 1
+ }
+ if (!b) {
+ return -1
+ }
+ let aSum
+ let bSum
+ switch (sortedBy) {
+ case VotingSortingEnum.AtoZ:
+ return a.details.name < b.details.name ? -1 : 1
+ case VotingSortingEnum.ZtoA:
+ return a.details.name < b.details.name ? 1 : -1
+ case VotingSortingEnum.EndingLatest:
return a.endAt < b.endAt ? -1 : 1
- }
- case VotingSortingEnum.EndingSoonest:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
+ case VotingSortingEnum.EndingSoonest:
return a.endAt < b.endAt ? 1 : -1
- }
- case VotingSortingEnum.MostVotes:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
- const aSum = a.totalVotesAgainst.add(a.totalVotesFor)
- const bSum = b.totalVotesAgainst.add(b.totalVotesFor)
+ case VotingSortingEnum.MostVotes:
+ aSum = a.totalVotesAgainst.add(a.totalVotesFor)
+ bSum = b.totalVotesAgainst.add(b.totalVotesFor)
return aSum < bSum ? 1 : -1
- }
- case VotingSortingEnum.LeastVotes:
- return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
- const aSum = a.totalVotesAgainst.add(a.totalVotesFor)
- const bSum = b.totalVotesAgainst.add(b.totalVotesFor)
+ case VotingSortingEnum.LeastVotes:
+ aSum = a.totalVotesAgainst.add(a.totalVotesFor)
+ bSum = b.totalVotesAgainst.add(b.totalVotesFor)
return aSum < bSum ? -1 : 1
- }
+ }
}
}
export function sortDirectoryFunction(sortedBy: DirectorySortingEnum) {
- switch (sortedBy) {
- case DirectorySortingEnum.AtoZ:
- return (a: CommunityDetail, b: CommunityDetail) => (a.name < b.name ? -1 : 1)
- case DirectorySortingEnum.ZtoA:
- return (a: CommunityDetail, b: CommunityDetail) => (a.name < b.name ? 1 : -1)
- case DirectorySortingEnum.IncludedLongAgo:
- return (a: CommunityDetail, b: CommunityDetail) => {
+ return (a: CommunityDetail | undefined, b: CommunityDetail | undefined) => {
+ if (!a) {
+ return 1
+ }
+ if (!b) {
+ return -1
+ }
+ switch (sortedBy) {
+ case DirectorySortingEnum.AtoZ:
+ return a.name < b.name ? -1 : 1
+ case DirectorySortingEnum.ZtoA:
+ return a.name < b.name ? 1 : -1
+ case DirectorySortingEnum.IncludedLongAgo:
if (!a.directoryInfo) return 1
if (!b.directoryInfo) return -1
return a?.directoryInfo?.additionDate < b?.directoryInfo?.additionDate ? -1 : 1
- }
- case DirectorySortingEnum.IncludedRecently:
- return (a: CommunityDetail, b: CommunityDetail) => {
+ case DirectorySortingEnum.IncludedRecently:
if (!a.directoryInfo) return -1
if (!b.directoryInfo) return 1
return a?.directoryInfo?.additionDate < b?.directoryInfo?.additionDate ? 1 : -1
- }
- case DirectorySortingEnum.MostVotes:
- return (a: CommunityDetail, b: CommunityDetail) => {
+ case DirectorySortingEnum.MostVotes:
if (!a.directoryInfo?.featureVotes) return 1
if (!b.directoryInfo?.featureVotes) return -1
return a?.directoryInfo?.featureVotes < b?.directoryInfo?.featureVotes ? 1 : -1
- }
- case DirectorySortingEnum.LeastVotes:
- return (a: CommunityDetail, b: CommunityDetail) => {
+ case DirectorySortingEnum.LeastVotes:
if (!a.directoryInfo?.featureVotes) return 1
if (!b.directoryInfo?.featureVotes) return -1
return a?.directoryInfo?.featureVotes < b?.directoryInfo?.featureVotes ? -1 : 1
- }
+ }
}
}
diff --git a/packages/DApp/src/hooks/useCommunities.ts b/packages/DApp/src/hooks/useCommunities.ts
index 2ce89ec..286e6a7 100644
--- a/packages/DApp/src/hooks/useCommunities.ts
+++ b/packages/DApp/src/hooks/useCommunities.ts
@@ -1,72 +1,24 @@
-import { useState, useEffect } from 'react'
-import { CommunityDetail } from '../models/community'
-import { APIOptions, APIFunction } from './../models/api'
+import { getCommunityDetails } from '../helpers/apiMock'
+import { useCommunitiesProvider } from '../providers/communities/provider'
-export function useCommunities(API: APIFunction, options: APIOptions) {
- const [communities, setCommunities] = useState([])
- const [page, setPage] = useState(0)
- const [increment, setIncrement] = useState(false)
- const [loading, setLoading] = useState(true)
+export function useCommunities(publicKeys: string[]) {
+ const { communitiesDetails, dispatch } = useCommunitiesProvider()
- const handleScroll = (e: Event) => {
- if (e.target) {
- const scrollingElement = (e.target as HTMLDocument).scrollingElement
- if (!scrollingElement?.scrollHeight || !scrollingElement?.scrollTop || !scrollingElement?.clientHeight) {
- return
- }
- if (scrollingElement.scrollHeight - scrollingElement.scrollTop <= scrollingElement.clientHeight + 60) {
- setPage((prevPage) => prevPage + 1)
- window.removeEventListener('scroll', handleScroll)
- }
- }
- }
-
- useEffect(() => {
- if (increment) {
- if (document.scrollingElement?.clientHeight || document.scrollingElement?.scrollHeight) {
- if (document.scrollingElement?.clientHeight >= document.scrollingElement?.scrollHeight) {
- setPage((prevPage) => prevPage + 1)
- } else {
- window.addEventListener('scroll', handleScroll)
+ return publicKeys.map((publicKey) => {
+ const detail = communitiesDetails[publicKey]
+ if (detail) {
+ return { ...detail }
+ } else {
+ if (publicKey) {
+ const setCommunity = async () => {
+ const communityDetail = await getCommunityDetails(publicKey)
+ if (communityDetail) {
+ dispatch(communityDetail)
+ }
}
+ setCommunity()
}
+ return undefined
}
- return () => {
- window.removeEventListener('scroll', handleScroll)
- }
- }, [increment])
-
- useEffect(() => {
- const getCommunities = async () => {
- setLoading(true)
- const communities = (await API(0, options)).communities
- setCommunities(communities)
- setLoading(false)
- setIncrement(true)
- }
-
- setCommunities([])
- setPage(0)
- setIncrement(false)
- getCommunities()
- }, [options.filterKeyword, options.sortedBy, options.voteType])
-
- useEffect(() => {
- const updateCommunities = async () => {
- setLoading(true)
- const newCommunities = (await API(page, options)).communities
- setCommunities((oldCommunities) => [...oldCommunities, ...newCommunities])
- if (newCommunities.length === options.numberPerPage) {
- setIncrement(true)
- }
- setLoading(false)
- }
-
- if (page === 0) return
-
- setIncrement(false)
- updateCommunities()
- }, [page])
-
- return { communities, loading }
+ })
}
diff --git a/packages/DApp/src/hooks/useCommunityDetails.ts b/packages/DApp/src/hooks/useCommunityDetails.ts
index 13eaa8b..1e4cca2 100644
--- a/packages/DApp/src/hooks/useCommunityDetails.ts
+++ b/packages/DApp/src/hooks/useCommunityDetails.ts
@@ -1,27 +1,14 @@
-import { useEffect, useRef, useState } from 'react'
-import { getCommunityDetails } from '../helpers/apiMock'
+import { useEffect } from 'react'
import { CommunityDetail } from '../models/community'
+import { useCommunities } from './useCommunities'
export function useCommunityDetails(publicKey: string, setCommunityDetail: (val: CommunityDetail | undefined) => void) {
- const [loading, setLoading] = useState(false)
- const loadingIdx = useRef(0)
+ const [CommunityDetail] = useCommunities([publicKey])
useEffect(() => {
- const getDetails = async (key: string) => {
- const idx = ++loadingIdx.current
- setLoading(true)
- setCommunityDetail(await getCommunityDetails(key))
- if (idx === loadingIdx.current) {
- setLoading(false)
- }
- }
- setCommunityDetail(undefined)
- if (publicKey) {
- getDetails(publicKey)
- }
- }, [publicKey])
+ setCommunityDetail(CommunityDetail)
+ return () => setCommunityDetail(undefined)
+ }, [JSON.stringify(CommunityDetail)])
- useEffect(() => setCommunityDetail(undefined), [])
-
- return loading
+ return !CommunityDetail
}
diff --git a/packages/DApp/src/hooks/useDirectoryCommunities.ts b/packages/DApp/src/hooks/useDirectoryCommunities.ts
index a1ffe38..6c8d998 100644
--- a/packages/DApp/src/hooks/useDirectoryCommunities.ts
+++ b/packages/DApp/src/hooks/useDirectoryCommunities.ts
@@ -1,8 +1,8 @@
import { useContractCall } from '@usedapp/core'
import { useEffect, useState } from 'react'
-import { getCommunityDetails } from '../helpers/apiMock'
import { isTextInDetails, sortDirectoryFunction } from '../helpers/communityFiltering'
import { CommunityDetail, DirectorySortingEnum } from '../models/community'
+import { useCommunities } from './useCommunities'
import { useContracts } from './useContracts'
export function useDirectoryCommunities(filterKeyword: string, sortedBy: DirectorySortingEnum) {
@@ -14,28 +14,18 @@ export function useDirectoryCommunities(filterKeyword: string, sortedBy: Directo
args: [],
}) ?? [[]]
- const [unfilteredComm, setUnfilteredComm] = useState(communities)
- const [filteredCommunities, setFilteredCommunities] = useState([])
+ const unfilteredComm = useCommunities(communities)
+ const [filteredCommunities, setFilteredCommunities] = useState<(CommunityDetail | undefined)[]>([])
useEffect(() => {
- const getDetails = async () => {
- if (communities.length > 0) {
- const detailedComm = await Promise.all(communities.map(async (key: string) => await getCommunityDetails(key)))
- setUnfilteredComm(detailedComm)
- }
- }
- getDetails()
- }, [JSON.stringify(communities)])
-
- useEffect(() => {
- const filterCommunities = unfilteredComm.filter((comm: CommunityDetail) => {
+ const filterCommunities = unfilteredComm.filter((comm: CommunityDetail | undefined) => {
if (comm) {
return isTextInDetails(filterKeyword, comm)
}
- return false
+ return true
})
setFilteredCommunities(filterCommunities.sort(sortDirectoryFunction(sortedBy)))
- }, [unfilteredComm, sortedBy, filterKeyword])
+ }, [JSON.stringify(unfilteredComm), sortedBy, filterKeyword])
return filteredCommunities
}
diff --git a/packages/DApp/src/hooks/useVotingCommunities.ts b/packages/DApp/src/hooks/useVotingCommunities.ts
index 5989379..fac2502 100644
--- a/packages/DApp/src/hooks/useVotingCommunities.ts
+++ b/packages/DApp/src/hooks/useVotingCommunities.ts
@@ -1,10 +1,10 @@
import { useContractCall, useContractCalls } from '@usedapp/core'
import { useEffect, useState } from 'react'
-import { getCommunityDetails } from '../helpers/apiMock'
import { VotingSortingEnum } from '../models/community'
import { DetailedVotingRoom } from '../models/smartContract'
import { useContracts } from './useContracts'
import { isTextInDetails, isTypeInRoom, sortVotingFunction } from '../helpers/communityFiltering'
+import { useCommunities } from './useCommunities'
export function useVotingCommunities(
filterKeyword: string,
@@ -32,31 +32,28 @@ export function useVotingCommunities(
})
const votingRooms = useContractCalls(contractCalls)
+ const publicKeys = votingRooms.map((votingRoom: any) => votingRoom?.community)
+ const communitiesDetails = useCommunities(publicKeys)
useEffect(() => {
if (votingRooms.length > 0) {
- const getPromises = async () => {
- const rooms = await Promise.all(
- votingRooms.map(async (el: any) => {
- if (el) {
- return { ...el, details: await getCommunityDetails(el.community) }
- }
- return undefined
- })
- )
- setRoomsWithCommunity(rooms)
- }
- getPromises()
+ const rooms = votingRooms.map((el: any) => {
+ if (el) {
+ return { ...el, details: communitiesDetails.find((comm) => comm?.publicKey === el.community) }
+ }
+ return undefined
+ })
+ setRoomsWithCommunity(rooms)
}
- }, [JSON.stringify(votingRooms)])
+ }, [JSON.stringify(votingRooms), JSON.stringify(communitiesDetails)])
useEffect(() => {
const filteredRooms = roomsWithCommunity.filter((room: any) => {
- if (room) {
+ if (room && room.details) {
return isTextInDetails(filterKeyword, room.details) && isTypeInRoom(voteType, room)
}
- return false
- })
+ return true
+ }) as (any | undefined)[]
setFilteredRooms(filteredRooms.sort(sortVotingFunction(sortedBy)))
}, [roomsWithCommunity, filterKeyword, voteType, sortedBy])
diff --git a/packages/DApp/src/index.tsx b/packages/DApp/src/index.tsx
index e5945cc..94afbca 100644
--- a/packages/DApp/src/index.tsx
+++ b/packages/DApp/src/index.tsx
@@ -5,6 +5,7 @@ import { DAppProvider, ChainId } from '@usedapp/core'
import { DEFAULT_CONFIG } from '@usedapp/core/dist/cjs/src/model/config/default'
import { ConfigProvider } from './providers/config/provider'
import { WakuProvider } from './providers/waku/provider'
+import { CommunitiesProvider } from './providers/communities/provider'
const config = {
readOnlyChainId: ChainId.Ropsten,
@@ -23,7 +24,9 @@ render(
-
+
+
+
diff --git a/packages/DApp/src/providers/communities/provider.tsx b/packages/DApp/src/providers/communities/provider.tsx
new file mode 100644
index 0000000..111c092
--- /dev/null
+++ b/packages/DApp/src/providers/communities/provider.tsx
@@ -0,0 +1,31 @@
+import React, { ReactNode, useReducer, createContext, useContext } from 'react'
+import { CommunityDetail } from '../../models/community'
+
+type CommunitiesDetails = {
+ [publicKey: string]: CommunityDetail
+}
+
+const CommunitiesContext = createContext<{
+ communitiesDetails: CommunitiesDetails
+ dispatch: (details: CommunityDetail) => void
+}>({
+ communitiesDetails: {},
+ dispatch: () => undefined,
+})
+
+export function useCommunitiesProvider() {
+ return useContext(CommunitiesContext)
+}
+
+function communitiesReducer(state: CommunitiesDetails, action: CommunityDetail) {
+ return { ...state, [action.publicKey]: action }
+}
+
+interface CommunitiesProviderProps {
+ children: ReactNode
+}
+
+export function CommunitiesProvider({ children }: CommunitiesProviderProps) {
+ const [communitiesDetails, dispatch] = useReducer(communitiesReducer, {})
+ return
+}